Skip to content
codefastlabs

Command Palette

Search for a command to run...

v0.14.0· Changelog

@codefast/cli

0.14.0

Minor Changes

  • #1007 Add codefast audit layers, which holds a package's src/ to the layering its architecture states. audit.layers.packages lists 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 dynamic import() 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.allowlist takes the offending import as written, or path:<import>.

  • #990 Remove codefast audit constants, the audit that required every upper-case numeric const to name its kind in the comment above it.

    Breaking: the audit constants subcommand is gone, and audit.constants is no longer a config key, so a codefast.config that still sets it fails validation as an unknown key; delete that section.

  • #992 codefast tag stamps every overload signature again, each in its own doc block. Since the move to oxc-parser it stamped only an overloaded function's implementation, the one signature a .d.ts drops, so a released overload reached consumers with no @since on 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 (which audit comments rejects) or split a directive from the code it governs. The run names each such declaration by file and line, lists it under blockedDeclarations in --json, leaves its file untouched, and exits 1: once a release ships the declaration unstamped, a later run can only stamp a version that did not introduce it. The --json ok field now follows the exit code, so a failed target also reports ok: false.

0.13.0

Minor Changes

  • #951 Add codefast audit assertions, which reports every double type assertion through unknown or any — x as unknown as T, (x as unknown) as T, <T><unknown>x and the any spellings — in .ts/.tsx files, 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 in audit.assertions.allowlist.

    Filesystem.readdir is replaced by readdirEntries(path, { recursive }), which always returns directory entries: every caller asked for them, and the old string[] | DirectoryEntry[] union forced each one to cast or guard.

  • #894 codefast audit constants reports every upper-case const bound 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.target and audit.constants.allowlist in codefast.config scope and except it.

  • #980 audit publish also reports a shipped stylesheet whose Tailwind @source paths reach none of the files the slimmed tarball ships, naming any files entry missing on disk so an unbuilt dist reads as such. A workspace resolves those paths against src, so only the published layout used to show the failure.

  • #976 engines.node is 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 typescript peer is now >=7.0.0. It was published as the repository's own ^7.0.2 pin, which excluded TypeScript 8 and would have risen with each pin bump instead of staying at the supported floor.

  • #965 README.md now 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 4c97c5b Thanks @thevuong! - Add codefast 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 any exports/imports target the slimmed publish manifest would not ship. It joins the audit family and gates CI, replacing an external publint step.

Patch Changes

  • #885 8580a2b Thanks @thevuong! - Match GitHub's heading-slug algorithm in audit 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 @remarks already claimed GitHub parity the code did not deliver.

  • #892 4c97c5b Thanks @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.node becomes >=22.12.0 across 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/node is 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/di keeps its own Map upsert helpers rather than the ES2025 Map.prototype.getOrInsert (which would raise the floor to 26) and its lib stays ES2024. @codefast/cli's mirror step now calls the node:path functions directly instead of aliasing them, which the floor's types correctly flag as unbound methods.

    The shared @codefast/typescript-config presets pin lib and target to ES2024 (was ESNext) so the compiler's ECMAScript surface matches the Node floor: an ES2025 builtin such as Map.prototype.getOrInsert now fails to type-check rather than compiling and crashing on Node 22.12. @codefast/di and @codefast/di-testing already pinned lib and are unchanged.

    Internal subpath imports move from a #/ prefix to a bare # (#core/token, not #/core/token), and the package.json#imports keys become #*/#tests/*/#examples/* to match. Node's native ESM resolver rejects a #/-prefixed specifier with ERR_INVALID_MODULE_SPECIFIER on the whole Node 22 line (and on Node 24 before 24.14), and each package ships those specifiers verbatim inside its published dist/*.js for 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 4c97c5b Thanks @thevuong! - Fix pack-slim stripping the stylesheet source of packages that export CSS.

    codefast pack-slim removed the whole src directory from a package's published files, but @codefast/ui and @codefast/tracking ship 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 the src subtrees a surviving exports/imports target still points into (e.g. src/css) and drops the rest of src, so the stylesheets ship while the TypeScript source stays out. Surfaced and now guarded by the new codefast audit publish check.

0.11.0

Minor Changes

  • #855 76cf7a6 Thanks @thevuong! - Fix codefast arrange simplify changing rendered output: a mixed cn() 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 folds cn(buttonVariants({ size: "sm" }), "flex-1") into buttonVariants({ size: "sm", className: "flex-1" }). The fold is gated on the native TypeScript type server confirming the callee accepts a className/class, so it loads the typescript package (a new optional peer, v7) and applies only inside a tsconfig; the default pass is unchanged.

    The fold splices className in 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 nested cn()/variant pair — so nested calls no longer corrupt the output.

  • #854 a7ad2d8 Thanks @thevuong! - codefast audit imports now enforces the Zod namespace form (import * as z from "zod") in every workspace package, not only the front-end/bundled ones. The rule's scope restriction is dropped, so a named import { z } from "zod" is flagged everywhere — backend/tsc packages such as cli itself included. Type-only imports (import type { ZodType } from "zod") stay allowed; only the value z is banned.

Patch Changes

  • #855 9e481c5 Thanks @thevuong! - Fix codefast arrange --dry-run --json printing 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; --json writes a single JSON object.

  • #854 504a61a Thanks @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 every audit/arrange subcommand 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 d959e09 Thanks @thevuong! - Generalize audit react into audit imports — a rule-driven import-policy audit. It keeps the React policy (members imported by name; no import * as React, default React, or implicit React.* UMD-global type reference) and adds a Zod policy for front-end packages: a named import { 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 (was audit react), the config key is audit.imports (was audit.react), and the convenience script is cli:audit:imports (was cli:audit:react).

  • #853 bfa9908 Thanks @thevuong! - Export defineConfig and the CodefastConfig type so codefast.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 .js config. The mirror per-package source/types/import fields are now optional in the type (they already default to true), so a minimal entry type-checks.

  • #849 0574761 Thanks @thevuong! - Expose a programmatic entry point. @codefast/cli is now importable — import { runCli } from "@codefast/cli" runs the CLI in-process and resolves to its exit code — in addition to the codefast binary. The package ships type declarations for this entry.

  • #849 0401f20 Thanks @thevuong! - Support single-package projects, not just pnpm workspaces. Commands now resolve their root by walking up from the current directory: the nearest pnpm-workspace.yaml marks a workspace (every package under it is in scope), and with no workspace file the nearest package.json marks a single package (that one package is the whole scope). Previously every command except arrange group required a pnpm-workspace.yaml and exited otherwise. The root now follows where you run the CLI (cwd) rather than where the CLI is installed. arrange also recognizes cn / tv imported from #/lib/utils.

0.9.0

Minor Changes

  • #848 a34b944 Thanks @thevuong! - New codefast audit display-names: reports every token(), 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, skipping tests/, benchmarks/, .changeset/ and CHANGELOG.md. Exceptions go in audit.displayNames.allowlist. Wired into the repo as pnpm cli:audit:display-names and into CI.

  • #844 24fbe04 Thanks @thevuong! - audit comments now enforces the section-divider convention in ignore files. .gitignore, .dockerignore, .npmignore, .prettierignore, and .eslintignore are scanned for #-comment dividers, checked for the canonical width, and rewritten by --fix — the same treatment .ts, .tsx, and .css already get. The code-only content rules (@since, TSDoc grammar, banned fragments) stay off ignore files, which carry the divider convention alone.

  • #827 3285708 Thanks @thevuong! - pack-slim now slims the whole development lane out of the publish manifest, not only the source lane. Alongside src, the source conditions, and the dist source maps it drops every imports entry left pointing outside files (the #/tests/* and #/examples/* aliases), every script that is not an install or publish lifecycle hook, and devDependencies, so the package.json npm shows describes only what a consumer's tsc and Node resolve. The CLI's own tarball now ships its CHANGELOG.md.

0.8.1

Patch Changes

  • #812 f051471 Thanks @thevuong! - Raise the published dependency floors: zod to 4.5.4 (@codefast/cli, @codefast/theme), lucide-react to 1.41.0 and react-hook-form to 7.87.0 (@codefast/ui).

  • #810 75c63d2 Thanks @thevuong! - Enable exactOptionalPropertyTypes for the packages that were temporarily opted out when it became the base.json default (@codefast/cli, @codefast/tailwind-variants, and the private benchmark packages). Only @codefast/cli and @codefast/benchmark-viewer needed 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 37a212b Thanks @thevuong! - Point the README's license badge and "License" section at the package's own LICENSE file instead of the monorepo root.

  • #796 ba04d27 Thanks @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 c868dfd Thanks @thevuong! - New audit react subcommand enforcing the repo's React import policy: flags import * as React and default React imports (type-only included), plus implicit React.* UMD-global type references — the variant both tsc and the linter accept silently through export as namespace React in @types/react. Configurable via audit.react.allowlist in codefast.config; exits non-zero on violations so it can gate CI. The shared workspace walk also skips .tanstack and .nitro, keeping TanStack/Nitro build caches out of every scan.

  • #748 bde6d1b Thanks @thevuong! - audit comments gains a since-impossible rule: an @since tag 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 wrong package.json version dies in CI instead of fossilizing. The tag subcommand's version lookup moves into core/workspace so both subcommands share one implementation.

0.7.0

0.6.2

0.6.1

0.6.0

Minor Changes

  • #698 9b24461 Thanks @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 #fragment fails 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.allowlist as a bare target or repo/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 c37da6f Thanks @thevuong! - Teach codefast audit comments three TSDoc checks: a {@link} whose target has no mention outside links (a rename that orphaned it), a @param/@typeParam missing the hyphen before its description, and a @since that is not the block's last tag. The link check resolves against the scanned tree, so it runs on full-tree scans only.

  • #727 5118ee2 Thanks @thevuong! - Enforce all-or-none @param coverage in codefast 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 like useCallback.

  • #727 de713ad Thanks @thevuong! - Add codefast 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 --fix from green.

  • #727 5118ee2 Thanks @thevuong! - Run the official @microsoft/tsdoc parser over every doc block in codefast 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. @since is registered as the repo's one custom tag.

  • #727 fba2a39 Thanks @thevuong! - Teach codefast audit comments two 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 --fix covers.

  • #727 5118ee2 Thanks @thevuong! - Teach codefast audit comments to 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 0bbb11c Thanks @thevuong! - Add mirror.<pkg>.exclude — a list of specifiers to leave out of the generated package.json#exports, so a package's public surface is a decision rather than a consequence of its dist/ layout. Patterns are matched against the specifier as it would appear in exports (after strip), a trailing /* drops a whole subtree, and the root export is never excluded.

    Until now the only levers were strip, extra exports, and preserve: true — and preserve skips the dist scan entirely, so curating a surface meant hand-editing the map that the tool exists to generate. exclude closes that gap.

  • #529 ca90f1c Thanks @thevuong! - codefast tag now matches tag.skipPackages entries as glob patterns (picomatch), so a single @apps/* entry skips every private app instead of listing each by name. This fixes the release Publish packages step 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 single createAnyGlobMatcher helper, also used by workspace-package discovery.

  • #676 641e233 Thanks @thevuong! - Collapse the types and default lanes of package.json#imports from 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_FOUND rather than trying the second. ./dist/*/index.js and ./dist/*/index.d.ts could therefore never be reached, so they read as a safety net that does not exist. The source lane keeps its extension candidates, which only tsc and Vite read and both probe.

0.5.0-canary.9

Patch Changes

  • #676 641e233 Thanks @thevuong! - Collapse the types and default lanes of package.json#imports from 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_FOUND rather than trying the second. ./dist/*/index.js and ./dist/*/index.d.ts could therefore never be reached, so they read as a safety net that does not exist. The source lane keeps its extension candidates, which only tsc and Vite read and both probe.

0.5.0-canary.8

Patch Changes

  • #646 0bbb11c Thanks @thevuong! - Add mirror.<pkg>.exclude — a list of specifiers to leave out of the generated package.json#exports, so a package's public surface is a decision rather than a consequence of its dist/ layout. Patterns are matched against the specifier as it would appear in exports (after strip), a trailing /* drops a whole subtree, and the root export is never excluded.

    Until now the only levers were strip, extra exports, and preserve: true — and preserve skips the dist scan entirely, so curating a surface meant hand-editing the map that the tool exists to generate. exclude closes that gap.

0.5.0-canary.7

0.5.0-canary.6

Patch Changes

  • #529 ca90f1c Thanks @thevuong! - codefast tag now matches tag.skipPackages entries as glob patterns (picomatch), so a single @apps/* entry skips every private app instead of listing each by name. This fixes the release Publish packages step 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 single createAnyGlobMatcher helper, 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.