0.14.0
Minor Changes
#1007 Add
codefast audit layers, which holds a package'ssrc/to the layering its architecture states.audit.layers.packageslists each package's layers bottom to top, every entry a family directly under the root — a directory, or a lone module sitting flat — and the audit reports every value import or re-export that points up the list, plus every module no layer places. Type-only imports pass whichever way they point; a dynamicimport()counts as a value import. A configured name the workspace does not hold, an entry nested below the root, and a family placed twice are refused before anything is scanned.audit.layers.allowlisttakes the offending import as written, orpath:<import>.#990 Remove
codefast audit constants, the audit that required every upper-case numericconstto name its kind in the comment above it.Breaking: the
audit constantssubcommand is gone, andaudit.constantsis no longer a config key, so acodefast.configthat still sets it fails validation as an unknown key; delete that section.#992
codefast tagstamps every overload signature again, each in its own doc block. Since the move tooxc-parserit stamped only an overloaded function's implementation, the one signature a.d.tsdrops, so a released overload reached consumers with no@sinceon any signature they can see.A declaration with no doc block and a
//comment on the line above it now fails the run instead of getting a fresh block there, where the block would stack under a note (whichaudit commentsrejects) or split a directive from the code it governs. The run names each such declaration by file and line, lists it underblockedDeclarationsin--json, leaves its file untouched, and exits1: once a release ships the declaration unstamped, a later run can only stamp a version that did not introduce it. The--jsonokfield now follows the exit code, so a failed target also reportsok: false.
0.13.0
Minor Changes
#951 Add
codefast audit assertions, which reports every double type assertion throughunknownorany—x as unknown as T,(x as unknown) as T,<T><unknown>xand theanyspellings — in.ts/.tsxfiles, tests included. Where the erasure is the point, keep one with// codefast-allow-double-assertion: <reason>on its line or the line above; a directive with no reason, or one that keeps no assertion, is reported too. Exceptions can also go inaudit.assertions.allowlist.Filesystem.readdiris replaced byreaddirEntries(path, { recursive }), which always returns directory entries: every caller asked for them, and the oldstring[] | DirectoryEntry[]union forced each one to cast or guard.#894
codefast audit constantsreports every upper-caseconstbound to a number in a library's sources whose comment names none of the three kinds a number may be — a constant of the machine, a value the contract fixes, or one derived from bind-time data. Sentinel values (0,1,-1) are exempt;audit.constants.targetandaudit.constants.allowlistincodefast.configscope and except it.#980
audit publishalso reports a shipped stylesheet whose Tailwind@sourcepaths reach none of the files the slimmed tarball ships, naming anyfilesentry missing on disk so an unbuiltdistreads as such. A workspace resolves those paths againstsrc, so only the published layout used to show the failure.#976
engines.nodeis now>=24.0.0, up from>=22.12.0, and Node 22 is no longer supported. Node 24.0.0 is the first release with explicit resource management built in (using,await using,DisposableStack,AsyncDisposableStack,SuppressedError) and all of ES2025, so the packages use both as the platform ships them instead of shimming them for an older line, and the CI matrix runs the unit suite on 24.0.0 itself. Move to Node 24, or stay on the current minor while a deployment still runs Node 22.
Patch Changes
#965 The optional
typescriptpeer is now>=7.0.0. It was published as the repository's own^7.0.2pin, which excluded TypeScript 8 and would have risen with each pin bump instead of staying at the supported floor.#965
README.mdnow states TypeScript 7 or later as the floor for the package's types — the one compiler every@codefast/*package is built and checked with. No code or declaration changed.
0.12.0
Minor Changes
- #892
4c97c5bThanks @thevuong! - Addcodefast audit publish, a static publish-surface check. It flags#/-prefixed internal import specifiers — valid to the in-repo runners but rejected by Node's ESM resolver on the supported floor, so they break the published package — and anyexports/importstarget the slimmed publish manifest would not ship. It joins theauditfamily and gates CI, replacing an externalpublintstep.
Patch Changes
#885
8580a2bThanks @thevuong! - Match GitHub's heading-slug algorithm inaudit links, so a cross-reference that resolves on GitHub resolves in the audit.Heading anchors are now slugged the way GitHub does: each space becomes its own hyphen with runs left intact, underscores are kept as slug characters, and repeated headings gain
-1,-2, … suffixes in heading order. The previous slugger collapsed whitespace, dropped underscores, and offered only the base slug for duplicates, so a link a browser lands on could be reported as dangling — the@remarksalready claimed GitHub parity the code did not deliver.#892
4c97c5bThanks @thevuong! - Lower the monorepo's Node floor from 24 to 22.12, so the packages install and run on the active Node 22 LTS line.engines.nodebecomes>=22.12.0across every package — the floor the shared toolchain (oxlint, Vite, Vitest, TanStack Start) already requires. Development stays on the latest Node (.node-version) for speed, and a CI matrix exercises the floor and the active LTS directly, so the floor is a contract CI proves rather than one everyone has to run.@types/nodeis pinned to the floor's major (^22), with a workspace override holding the whole tree there so a dev tool's@types/node: "*"peer can no longer pull a newer major and mask an API the floor lacks. The floor stays mechanical, not advisory:@codefast/dikeeps its ownMapupsert helpers rather than the ES2025Map.prototype.getOrInsert(which would raise the floor to 26) and itslibstaysES2024.@codefast/cli's mirror step now calls thenode:pathfunctions directly instead of aliasing them, which the floor's types correctly flag as unbound methods.The shared
@codefast/typescript-configpresets pinlibandtargettoES2024(wasESNext) so the compiler's ECMAScript surface matches the Node floor: an ES2025 builtin such asMap.prototype.getOrInsertnow fails to type-check rather than compiling and crashing on Node 22.12.@codefast/diand@codefast/di-testingalready pinnedliband are unchanged.Internal subpath imports move from a
#/prefix to a bare#(#core/token, not#/core/token), and thepackage.json#importskeys become#*/#tests/*/#examples/*to match. Node's native ESM resolver rejects a#/-prefixed specifier withERR_INVALID_MODULE_SPECIFIERon the whole Node 22 line (and on Node 24 before 24.14), and each package ships those specifiers verbatim inside its publisheddist/*.jsfor a consumer's Node to resolve — so this rename is what actually lets the packages import on the new floor. Purely internal: a consumer's own import paths are unchanged.#892
4c97c5bThanks @thevuong! - Fixpack-slimstripping the stylesheet source of packages that export CSS.codefast pack-slimremoved the wholesrcdirectory from a package's publishedfiles, but@codefast/uiand@codefast/trackingship Tailwind source through./css/*→./src/css/*, so their published tarballs went out with no CSS at all and the./css/*export resolved to nothing. pack-slim now keeps thesrcsubtrees a survivingexports/importstarget still points into (e.g.src/css) and drops the rest ofsrc, so the stylesheets ship while the TypeScript source stays out. Surfaced and now guarded by the newcodefast audit publishcheck.
0.11.0
Minor Changes
#855
76cf7a6Thanks @thevuong! - Fixcodefast arrange simplifychanging rendered output: a mixedcn()call moved every static literal to the front, which flipped tailwind-merge precedence and dropped overrides that sat after a variant call. It now coalesces only adjacent static literals and preserves argument order.Add
codefast arrange simplify --fold-variant-classname(alias--fold-variant-class-name), which foldscn(buttonVariants({ size: "sm" }), "flex-1")intobuttonVariants({ size: "sm", className: "flex-1" }). The fold is gated on the native TypeScript type server confirming the callee accepts aclassName/class, so it loads thetypescriptpackage (a new optional peer, v7) and applies only inside atsconfig; the default pass is unchanged.The fold splices
classNamein after the last option, so a trailing comma or line comment in the options object no longer breaks the rewrite. Overlapping edits are now resolved before they are applied — keeping the outermost of any nestedcn()/variant pair — so nested calls no longer corrupt the output.#854
a7ad2d8Thanks @thevuong! -codefast audit importsnow enforces the Zod namespace form (import * as z from "zod") in every workspace package, not only the front-end/bundled ones. The rule'sscoperestriction is dropped, so a namedimport { z } from "zod"is flagged everywhere — backend/tsc packages such ascliitself included. Type-only imports (import type { ZodType } from "zod") stay allowed; only the valuezis banned.
Patch Changes
#855
9e481c5Thanks @thevuong! - Fixcodefast arrange --dry-run --jsonprinting human-readable preview lines to stdout ahead of the JSON summary, which broke piping the output to a JSON parser. Dry-run previews are now emitted only in human mode;--jsonwrites a single JSON object.#854
504a61aThanks @thevuong! - Reorganize the CLI source into a uniform per-command and per-subcommand directory layout. Each command follows one skeleton (command.ts,cli-schema.ts,prepare.ts,run*.ts,output.ts,cli-result.ts,domain/), and everyaudit/arrangesubcommand is now its own mini-command directory (audit/rtl/,arrange/inspect/, …) with the shared runner and grouping engine kept at the command root. Internal refactor only — no public API or behavior change.
0.10.0
Minor Changes
#852
d959e09Thanks @thevuong! - Generalizeaudit reactintoaudit imports— a rule-driven import-policy audit. It keeps the React policy (members imported by name; noimport * as React, defaultReact, or implicitReact.*UMD-global type reference) and adds a Zod policy for front-end packages: a namedimport { z } from "zod"pins Zod's full locale set into the bundle, so the namespace form (import * as z from "zod") is required there. Adding another library is one rule entry.Breaking: the subcommand is now
audit imports(wasaudit react), the config key isaudit.imports(wasaudit.react), and the convenience script iscli:audit:imports(wascli:audit:react).#853
bfa9908Thanks @thevuong! - ExportdefineConfigand theCodefastConfigtype socodefast.config.*is authored with full editor autocomplete and type-checking instead of by memory —import { defineConfig } from "@codefast/cli", or a/** @type {import("@codefast/cli").CodefastConfig} */JSDoc annotation in a plain.jsconfig. Themirrorper-packagesource/types/importfields are now optional in the type (they already default totrue), so a minimal entry type-checks.#849
0574761Thanks @thevuong! - Expose a programmatic entry point.@codefast/cliis now importable —import { runCli } from "@codefast/cli"runs the CLI in-process and resolves to its exit code — in addition to thecodefastbinary. The package ships type declarations for this entry.#849
0401f20Thanks @thevuong! - Support single-package projects, not just pnpm workspaces. Commands now resolve their root by walking up from the current directory: the nearestpnpm-workspace.yamlmarks a workspace (every package under it is in scope), and with no workspace file the nearestpackage.jsonmarks a single package (that one package is the whole scope). Previously every command exceptarrange grouprequired apnpm-workspace.yamland exited otherwise. The root now follows where you run the CLI (cwd) rather than where the CLI is installed.arrangealso recognizescn/tvimported from#/lib/utils.
0.9.0
Minor Changes
#848
a34b944Thanks @thevuong! - Newcodefast audit display-names: reports everytoken(),tag()and module display name off the repo's convention —<namespace>:<Name>, with a kebab-case (or scoped-package) namespace, PascalCase for a token or module and camelCase for a tag key — across TypeScript and markdown, skippingtests/,benchmarks/,.changeset/andCHANGELOG.md. Exceptions go inaudit.displayNames.allowlist. Wired into the repo aspnpm cli:audit:display-namesand into CI.#844
24fbe04Thanks @thevuong! -audit commentsnow enforces the section-divider convention in ignore files..gitignore,.dockerignore,.npmignore,.prettierignore, and.eslintignoreare scanned for#-comment dividers, checked for the canonical width, and rewritten by--fix— the same treatment.ts,.tsx, and.cssalready get. The code-only content rules (@since, TSDoc grammar, banned fragments) stay off ignore files, which carry the divider convention alone.#827
3285708Thanks @thevuong! -pack-slimnow slims the whole development lane out of the publish manifest, not only the source lane. Alongsidesrc, thesourceconditions, and thedistsource maps it drops everyimportsentry left pointing outsidefiles(the#/tests/*and#/examples/*aliases), every script that is not an install or publish lifecycle hook, anddevDependencies, so thepackage.jsonnpm shows describes only what a consumer'stscand Node resolve. The CLI's own tarball now ships itsCHANGELOG.md.
0.8.1
Patch Changes
#812
f051471Thanks @thevuong! - Raise the published dependency floors:zodto 4.5.4 (@codefast/cli,@codefast/theme),lucide-reactto 1.41.0 andreact-hook-formto 7.87.0 (@codefast/ui).#810
75c63d2Thanks @thevuong! - EnableexactOptionalPropertyTypesfor the packages that were temporarily opted out when it became thebase.jsondefault (@codefast/cli,@codefast/tailwind-variants, and the private benchmark packages). Only@codefast/cliand@codefast/benchmark-viewerneeded code: the optional fields the flag surfaces on their exported request/option/prop types are widened to?: T | undefined. Backward-compatible type change — no runtime effect.#791
37a212bThanks @thevuong! - Point the README's license badge and "License" section at the package's ownLICENSEfile instead of the monorepo root.#796
ba04d27Thanks @thevuong! - Rewrite the README around one structure — what the package is, installation and requirements, a complete quick start, the concepts in learning order, then the documents and the license — with every API claim checked against the current code and no figures that go stale.
0.8.0
Minor Changes
#750
c868dfdThanks @thevuong! - Newaudit reactsubcommand enforcing the repo's React import policy: flagsimport * as Reactand defaultReactimports (type-only included), plus implicitReact.*UMD-global type references — the variant bothtscand the linter accept silently throughexport as namespace Reactin@types/react. Configurable viaaudit.react.allowlistincodefast.config; exits non-zero on violations so it can gate CI. The shared workspace walk also skips.tanstackand.nitro, keeping TanStack/Nitro build caches out of every scan.#748
bde6d1bThanks @thevuong! -audit commentsgains asince-impossiblerule: an@sincetag naming a version above the owning package's current version (compared by SemVer precedence, prerelease-aware) now fails the audit, so a stamp minted from a wrongpackage.jsonversion dies in CI instead of fossilizing. The tag subcommand's version lookup moves intocore/workspaceso both subcommands share one implementation.
0.7.0
0.6.2
0.6.1
0.6.0
Minor Changes
#698
9b24461Thanks @thevuong! -codefast audit links— a read-only scan for markdown cross-references that resolve to nothing.It reports three things: a relative path that does not exist, an in-document anchor with no matching heading or
<a id>, and an anchor into another document that the target does not offer. The third is why the command exists — a wrong#fragmentfails silently in a browser by scrolling to the top, so unlike a broken path it leaves no trace to notice. Six such breakages had accumulated in this repo before anything looked.External URLs are skipped as somebody else's to verify, and so are links inside fenced code, which are examples rather than references. Exits non-zero when breakages remain, so it can gate CI; intentional exceptions go in
audit.links.allowlistas a bare target orrepo/relative/doc.md:target.The scan defaults to the repo root rather than a configured path. A link audit scoped to one package cannot see the cross-package references, which are the ones most likely to rot.
#727
c37da6fThanks @thevuong! - Teachcodefast audit commentsthree TSDoc checks: a{@link}whose target has no mention outside links (a rename that orphaned it), a@param/@typeParammissing the hyphen before its description, and a@sincethat is not the block's last tag. The link check resolves against the scanned tree, so it runs on full-tree scans only.#727
5118ee2Thanks @thevuong! - Enforce all-or-none@paramcoverage incodefast audit comments: a doc block naming any parameter must name every parameter of that signature — a partial list reads as complete. The check parses the declaration's own parameter list, skips destructured parameters it cannot match by name, and refuses to guess through wrapper calls likeuseCallback.#727
de713adThanks @thevuong! - Addcodefast audit comments, which reports section dividers that are not in the repo's one allowed form and rewrites them with--fix. A divider is a label and nothing else, so a rule-framed comment carrying prose is read as a doc block and left alone; everything the audit does report is mechanical, which makes a red run one--fixfrom green.#727
5118ee2Thanks @thevuong! - Run the official@microsoft/tsdocparser over every doc block incodefast audit comments, reporting each grammar diagnostic at its line — bare@words, unescaped braces, split code spans, indented fences — instead of approximating the grammar with regexes.@sinceis registered as the repo's one custom tag.#727
fba2a39Thanks @thevuong! - Teachcodefast audit commentstwo content checks alongside the divider form: a comment that points at a repo document (see …*.md) and JSDoc{type}payloads. Neither is--fix-able — the writer restates the invariant or lets the declaration carry the type — so the report says which defects--fixcovers.#727
5118ee2Thanks @thevuong! - Teachcodefast audit commentsto catch a doc block detached from its declaration by a//run — TSDoc binds to the nearest declaration, so the wedged comment silently orphans every tag above it.
0.5.0
Patch Changes
#646
0bbb11cThanks @thevuong! - Addmirror.<pkg>.exclude— a list of specifiers to leave out of the generatedpackage.json#exports, so a package's public surface is a decision rather than a consequence of itsdist/layout. Patterns are matched against the specifier as it would appear inexports(afterstrip), a trailing/*drops a whole subtree, and the root export is never excluded.Until now the only levers were
strip, extraexports, andpreserve: true— andpreserveskips the dist scan entirely, so curating a surface meant hand-editing the map that the tool exists to generate.excludecloses that gap.#529
ca90f1cThanks @thevuong! -codefast tagnow matchestag.skipPackagesentries as glob patterns (picomatch), so a single@apps/*entry skips every private app instead of listing each by name. This fixes the releasePublish packagesstep failing on@apps/start-demo(a private, version-less app the command tried to tag). The compile-patterns-then-match-any logic is now shared via a singlecreateAnyGlobMatcherhelper, also used by workspace-package discovery.#676
641e233Thanks @thevuong! - Collapse thetypesanddefaultlanes ofpackage.json#importsfrom fallback arrays to single strings.Node resolves an imports array by taking the first candidate it can parse, without checking that the file exists and without falling through — a specifier whose first candidate is missing throws
ERR_MODULE_NOT_FOUNDrather than trying the second../dist/*/index.jsand./dist/*/index.d.tscould therefore never be reached, so they read as a safety net that does not exist. Thesourcelane keeps its extension candidates, which onlytscand Vite read and both probe.
0.5.0-canary.9
Patch Changes
#676
641e233Thanks @thevuong! - Collapse thetypesanddefaultlanes ofpackage.json#importsfrom fallback arrays to single strings.Node resolves an imports array by taking the first candidate it can parse, without checking that the file exists and without falling through — a specifier whose first candidate is missing throws
ERR_MODULE_NOT_FOUNDrather than trying the second../dist/*/index.jsand./dist/*/index.d.tscould therefore never be reached, so they read as a safety net that does not exist. Thesourcelane keeps its extension candidates, which onlytscand Vite read and both probe.
0.5.0-canary.8
Patch Changes
#646
0bbb11cThanks @thevuong! - Addmirror.<pkg>.exclude— a list of specifiers to leave out of the generatedpackage.json#exports, so a package's public surface is a decision rather than a consequence of itsdist/layout. Patterns are matched against the specifier as it would appear inexports(afterstrip), a trailing/*drops a whole subtree, and the root export is never excluded.Until now the only levers were
strip, extraexports, andpreserve: true— andpreserveskips the dist scan entirely, so curating a surface meant hand-editing the map that the tool exists to generate.excludecloses that gap.
0.5.0-canary.7
0.5.0-canary.6
Patch Changes
- #529
ca90f1cThanks @thevuong! -codefast tagnow matchestag.skipPackagesentries as glob patterns (picomatch), so a single@apps/*entry skips every private app instead of listing each by name. This fixes the releasePublish packagesstep failing on@apps/start-demo(a private, version-less app the command tried to tag). The compile-patterns-then-match-any logic is now shared via a singlecreateAnyGlobMatcherhelper, also used by workspace-package discovery.
1.0.0-canary.7
1.0.0-canary.6
0.5.0-canary.5
Showing the latest 20 releases; the full changelog on GitHub has 26 more releases.