@codefast/cli 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +345 -151
  3. package/dist/arrange/command.d.ts +7 -0
  4. package/dist/arrange/command.js +96 -132
  5. package/dist/arrange/domain/ast/ast-node.d.ts +394 -0
  6. package/dist/arrange/domain/ast/collectors-cn.d.ts +26 -0
  7. package/dist/arrange/domain/ast/collectors-jsx.d.ts +8 -0
  8. package/dist/arrange/domain/ast/collectors-tv.d.ts +34 -0
  9. package/dist/arrange/domain/ast/helpers.d.ts +36 -0
  10. package/dist/arrange/domain/ast/helpers.js +1 -0
  11. package/dist/arrange/domain/ast/simplify-targets.d.ts +22 -0
  12. package/dist/arrange/domain/ast/simplify-targets.js +18 -23
  13. package/dist/arrange/domain/ast/targets.d.ts +20 -0
  14. package/dist/arrange/domain/ast/translator.d.ts +32 -0
  15. package/dist/arrange/{typescript-ast-translator.js → domain/ast/translator.js} +19 -22
  16. package/dist/arrange/domain/constants.d.ts +111 -0
  17. package/dist/arrange/domain/grouping-service.d.ts +100 -0
  18. package/dist/arrange/domain/grouping.d.ts +21 -0
  19. package/dist/arrange/domain/imports.d.ts +14 -0
  20. package/dist/arrange/domain/source-text-formatters.d.ts +33 -0
  21. package/dist/arrange/domain/tailwind-token.d.ts +24 -0
  22. package/dist/arrange/domain/token-classifier.d.ts +47 -0
  23. package/dist/arrange/domain/types.d.ts +208 -0
  24. package/dist/arrange/group/cli-result.d.ts +7 -0
  25. package/dist/arrange/group/cli-result.js +12 -0
  26. package/dist/arrange/group/cli-schema.d.ts +17 -0
  27. package/dist/arrange/group/cli-schema.js +13 -0
  28. package/dist/arrange/group/output.d.ts +7 -0
  29. package/dist/arrange/group/output.js +10 -0
  30. package/dist/arrange/group/suggest.d.ts +8 -0
  31. package/dist/arrange/inspect/cli-result.d.ts +7 -0
  32. package/dist/arrange/inspect/cli-result.js +8 -0
  33. package/dist/arrange/inspect/cli-schema.d.ts +15 -0
  34. package/dist/arrange/inspect/cli-schema.js +9 -0
  35. package/dist/arrange/inspect/domain/analyze-service.d.ts +18 -0
  36. package/dist/arrange/inspect/output.d.ts +7 -0
  37. package/dist/arrange/inspect/output.js +42 -0
  38. package/dist/arrange/inspect/run.d.ts +10 -0
  39. package/dist/arrange/{analyze.js → inspect/run.js} +2 -2
  40. package/dist/arrange/prepare.d.ts +13 -0
  41. package/dist/arrange/{workspace.js → prepare.js} +5 -8
  42. package/dist/arrange/regroup/cli-result.d.ts +13 -0
  43. package/dist/arrange/regroup/cli-result.js +23 -0
  44. package/dist/arrange/regroup/cli-schema.d.ts +20 -0
  45. package/dist/arrange/regroup/cli-schema.js +14 -0
  46. package/dist/arrange/regroup/output.d.ts +14 -0
  47. package/dist/arrange/regroup/output.js +72 -0
  48. package/dist/arrange/regroup/process-file.d.ts +11 -0
  49. package/dist/arrange/regroup/run.d.ts +11 -0
  50. package/dist/arrange/{sync.js → regroup/run.js} +2 -2
  51. package/dist/arrange/resolve-target.d.ts +10 -0
  52. package/dist/arrange/resolve-target.js +3 -16
  53. package/dist/arrange/scan-target.d.ts +7 -0
  54. package/dist/arrange/simplify/cli-result.d.ts +7 -0
  55. package/dist/arrange/simplify/cli-result.js +8 -0
  56. package/dist/arrange/simplify/cli-schema.d.ts +17 -0
  57. package/dist/arrange/simplify/cli-schema.js +11 -0
  58. package/dist/arrange/simplify/fold-targets.d.ts +13 -0
  59. package/dist/arrange/simplify/fold-targets.js +139 -0
  60. package/dist/arrange/simplify/output.d.ts +7 -0
  61. package/dist/arrange/simplify/output.js +15 -0
  62. package/dist/arrange/simplify/process-file.d.ts +13 -0
  63. package/dist/arrange/simplify/process-file.js +49 -0
  64. package/dist/arrange/simplify/run.d.ts +14 -0
  65. package/dist/arrange/simplify/run.js +38 -0
  66. package/dist/arrange/simplify/variant-classname-probe.d.ts +35 -0
  67. package/dist/arrange/simplify/variant-classname-probe.js +95 -0
  68. package/dist/arrange/source-parse.d.ts +7 -0
  69. package/dist/arrange/source-parse.js +1 -1
  70. package/dist/audit/command.d.ts +8 -0
  71. package/dist/audit/command.js +134 -211
  72. package/dist/audit/comments/cli-result.d.ts +13 -0
  73. package/dist/audit/comments/cli-result.js +22 -0
  74. package/dist/audit/comments/cli-schema.d.ts +19 -0
  75. package/dist/audit/comments/cli-schema.js +13 -0
  76. package/dist/audit/comments/domain/comment-content.d.ts +26 -0
  77. package/dist/audit/comments/domain/comment-dividers.d.ts +62 -0
  78. package/dist/audit/comments/domain/link-references.d.ts +40 -0
  79. package/dist/audit/comments/domain/since-versions.d.ts +26 -0
  80. package/dist/audit/comments/domain/tsdoc-syntax.d.ts +20 -0
  81. package/dist/audit/comments/output.d.ts +7 -0
  82. package/dist/audit/comments/output.js +27 -0
  83. package/dist/audit/comments/prepare.d.ts +16 -0
  84. package/dist/audit/comments/prepare.js +12 -0
  85. package/dist/audit/comments/run.d.ts +17 -0
  86. package/dist/audit/{run-comments.js → comments/run.js} +5 -5
  87. package/dist/audit/display-names/cli-result.d.ts +13 -0
  88. package/dist/audit/display-names/cli-result.js +22 -0
  89. package/dist/audit/display-names/cli-schema.d.ts +18 -0
  90. package/dist/audit/display-names/cli-schema.js +12 -0
  91. package/dist/audit/display-names/domain/display-names.d.ts +11 -0
  92. package/dist/audit/display-names/output.d.ts +7 -0
  93. package/dist/audit/display-names/output.js +21 -0
  94. package/dist/audit/display-names/prepare.d.ts +16 -0
  95. package/dist/audit/display-names/prepare.js +12 -0
  96. package/dist/audit/display-names/run.d.ts +14 -0
  97. package/dist/audit/{run-display-names.js → display-names/run.js} +1 -1
  98. package/dist/audit/domain/types.d.ts +171 -0
  99. package/dist/audit/imports/cli-result.d.ts +13 -0
  100. package/dist/audit/imports/cli-result.js +22 -0
  101. package/dist/audit/imports/cli-schema.d.ts +18 -0
  102. package/dist/audit/imports/cli-schema.js +12 -0
  103. package/dist/audit/imports/domain/import-policy.d.ts +34 -0
  104. package/dist/audit/imports/domain/import-policy.js +140 -0
  105. package/dist/audit/imports/output.d.ts +7 -0
  106. package/dist/audit/imports/output.js +21 -0
  107. package/dist/audit/imports/prepare.d.ts +16 -0
  108. package/dist/audit/imports/prepare.js +12 -0
  109. package/dist/audit/imports/run.d.ts +14 -0
  110. package/dist/audit/{run-react.js → imports/run.js} +15 -5
  111. package/dist/audit/links/cli-result.d.ts +13 -0
  112. package/dist/audit/links/cli-result.js +22 -0
  113. package/dist/audit/links/cli-schema.d.ts +18 -0
  114. package/dist/audit/links/cli-schema.js +12 -0
  115. package/dist/audit/links/domain/markdown-links.d.ts +44 -0
  116. package/dist/audit/links/output.d.ts +7 -0
  117. package/dist/audit/links/output.js +21 -0
  118. package/dist/audit/links/prepare.d.ts +16 -0
  119. package/dist/audit/links/prepare.js +12 -0
  120. package/dist/audit/links/run.d.ts +14 -0
  121. package/dist/audit/{run-links.js → links/run.js} +1 -1
  122. package/dist/audit/prepare.d.ts +31 -0
  123. package/dist/audit/prepare.js +11 -134
  124. package/dist/audit/rtl/cli-result.d.ts +13 -0
  125. package/dist/audit/rtl/cli-result.js +22 -0
  126. package/dist/audit/rtl/cli-schema.d.ts +18 -0
  127. package/dist/audit/rtl/cli-schema.js +12 -0
  128. package/dist/audit/rtl/domain/audit-file.d.ts +7 -0
  129. package/dist/audit/{domain → rtl/domain}/audit-file.js +2 -2
  130. package/dist/audit/rtl/domain/mappings.d.ts +45 -0
  131. package/dist/audit/rtl/domain/tokenize.d.ts +14 -0
  132. package/dist/audit/rtl/output.d.ts +7 -0
  133. package/dist/audit/rtl/output.js +21 -0
  134. package/dist/audit/rtl/prepare.d.ts +13 -0
  135. package/dist/audit/rtl/prepare.js +41 -0
  136. package/dist/audit/rtl/run.d.ts +14 -0
  137. package/dist/audit/{run.js → rtl/run.js} +1 -1
  138. package/dist/bin.d.ts +2 -0
  139. package/dist/cli.d.ts +6 -0
  140. package/dist/core/cli/command-pipeline.d.ts +91 -0
  141. package/dist/core/cli/command-pipeline.js +83 -0
  142. package/dist/core/cli/format-error.d.ts +7 -0
  143. package/dist/core/cli/global-options.d.ts +15 -0
  144. package/dist/core/cli/global-options.js +1 -1
  145. package/dist/core/cli/positional.d.ts +6 -0
  146. package/dist/core/cli/resolve-root.d.ts +9 -0
  147. package/dist/core/cli/resolve-root.js +16 -0
  148. package/dist/core/cli/result-handle.d.ts +13 -0
  149. package/dist/core/cli/result-handle.js +0 -13
  150. package/dist/core/config/define-config.d.ts +7 -0
  151. package/dist/core/config/define-config.js +8 -0
  152. package/dist/core/config/loader.d.ts +18 -0
  153. package/dist/core/config/loader.js +2 -7
  154. package/dist/core/config/schema.d.ts +99 -0
  155. package/dist/core/config/schema.js +8 -86
  156. package/dist/core/config/warnings.d.ts +6 -0
  157. package/dist/core/config.d.ts +12 -0
  158. package/dist/core/errors.d.ts +25 -0
  159. package/dist/core/exit-codes.d.ts +18 -0
  160. package/dist/core/filesystem/filesystem.d.ts +44 -0
  161. package/dist/core/filesystem/node.d.ts +7 -0
  162. package/dist/core/filesystem/node.js +2 -1
  163. package/dist/core/glob.d.ts +19 -0
  164. package/dist/core/logger.d.ts +9 -0
  165. package/dist/core/result.d.ts +30 -0
  166. package/dist/core/schema-parse.d.ts +9 -0
  167. package/dist/core/source-text-edit.d.ts +47 -0
  168. package/dist/core/source-text-edit.js +22 -0
  169. package/dist/core/verbose-diagnostics.d.ts +6 -0
  170. package/dist/core/workspace/ancestor-directories.d.ts +12 -0
  171. package/dist/core/workspace/ancestor-directories.js +30 -0
  172. package/dist/core/workspace/markdown-walk.d.ts +7 -0
  173. package/dist/core/workspace/markdown-walk.js +2 -20
  174. package/dist/core/workspace/package-version.d.ts +9 -0
  175. package/dist/core/workspace/package-version.js +8 -12
  176. package/dist/core/workspace/resolver.d.ts +39 -0
  177. package/dist/core/workspace/resolver.js +58 -75
  178. package/dist/core/workspace/skip-directories.d.ts +6 -0
  179. package/dist/core/workspace/source-walk.d.ts +16 -0
  180. package/dist/core/workspace/source-walk.js +2 -19
  181. package/dist/core/workspace/typescript-walk.d.ts +7 -0
  182. package/dist/core/workspace/typescript-walk.js +2 -23
  183. package/dist/core/workspace/walk-files.d.ts +7 -0
  184. package/dist/core/workspace/walk-files.js +27 -0
  185. package/dist/core/workspace/well-known-files.d.ts +18 -0
  186. package/dist/core/workspace/well-known-files.js +18 -0
  187. package/dist/index.d.ts +6 -0
  188. package/dist/index.js +5 -0
  189. package/dist/mirror/cli-result.d.ts +13 -0
  190. package/dist/mirror/cli-schema.d.ts +8 -0
  191. package/dist/mirror/cli-schema.js +1 -1
  192. package/dist/mirror/command.d.ts +7 -0
  193. package/dist/mirror/command.js +31 -60
  194. package/dist/mirror/dist-filesystem-node.d.ts +8 -0
  195. package/dist/mirror/{dist-filesystem-impl.js → dist-filesystem-node.js} +1 -1
  196. package/dist/mirror/domain/constants.d.ts +18 -0
  197. package/dist/mirror/domain/constants.js +0 -12
  198. package/dist/mirror/domain/dirent-guard.d.ts +10 -0
  199. package/dist/mirror/domain/dist-filesystem.d.ts +9 -0
  200. package/dist/mirror/domain/errors.d.ts +24 -0
  201. package/dist/mirror/domain/exports.d.ts +36 -0
  202. package/dist/mirror/domain/package-display-name.d.ts +8 -0
  203. package/dist/mirror/domain/path-normalizer.d.ts +6 -0
  204. package/dist/mirror/domain/types.d.ts +188 -0
  205. package/dist/mirror/output.d.ts +21 -0
  206. package/dist/mirror/output.js +126 -1
  207. package/dist/mirror/package-path.d.ts +19 -0
  208. package/dist/mirror/prepare.d.ts +15 -0
  209. package/dist/mirror/prepare.js +6 -10
  210. package/dist/mirror/run.d.ts +12 -0
  211. package/dist/mirror/{sync.js → run.js} +5 -3
  212. package/dist/mirror/supplement-exports.d.ts +27 -0
  213. package/dist/mirror/supplement-exports.js +2 -2
  214. package/dist/mirror/sync-workspace-package.d.ts +9 -0
  215. package/dist/mirror/sync-workspace-package.js +4 -4
  216. package/dist/mirror/write-exports.d.ts +15 -0
  217. package/dist/pack-slim/cli-result.d.ts +13 -0
  218. package/dist/pack-slim/cli-schema.d.ts +17 -0
  219. package/dist/pack-slim/cli-schema.js +1 -1
  220. package/dist/pack-slim/command.d.ts +7 -0
  221. package/dist/pack-slim/command.js +31 -66
  222. package/dist/pack-slim/domain/transform.d.ts +69 -0
  223. package/dist/pack-slim/domain/types.d.ts +46 -0
  224. package/dist/pack-slim/output.d.ts +15 -0
  225. package/dist/pack-slim/prepare.d.ts +21 -0
  226. package/dist/pack-slim/prepare.js +14 -0
  227. package/dist/pack-slim/run.d.ts +23 -0
  228. package/dist/pack-slim/{sync.js → run.js} +4 -4
  229. package/dist/pack-slim/working-tree.d.ts +20 -0
  230. package/dist/tag/cli-result.d.ts +13 -0
  231. package/dist/tag/cli-result.js +14 -1
  232. package/dist/tag/cli-schema.d.ts +8 -0
  233. package/dist/tag/cli-schema.js +3 -4
  234. package/dist/tag/command.d.ts +7 -0
  235. package/dist/tag/command.js +33 -60
  236. package/dist/tag/domain/skip-filter.d.ts +13 -0
  237. package/dist/tag/domain/skip-filter.js +29 -0
  238. package/dist/tag/domain/types.d.ts +131 -0
  239. package/dist/tag/domain/version-summary.d.ts +13 -0
  240. package/dist/tag/domain/version-summary.js +24 -0
  241. package/dist/tag/output.d.ts +17 -0
  242. package/dist/tag/output.js +6 -9
  243. package/dist/tag/prepare.d.ts +13 -0
  244. package/dist/tag/prepare.js +4 -4
  245. package/dist/tag/run.d.ts +10 -0
  246. package/dist/tag/{sync.js → run.js} +20 -50
  247. package/dist/tag/target/candidates.d.ts +8 -0
  248. package/dist/tag/{target-candidates.js → target/candidates.js} +2 -2
  249. package/dist/tag/target/resolve-path.d.ts +10 -0
  250. package/dist/tag/target/runner.d.ts +8 -0
  251. package/dist/tag/{target-runner.js → target/runner.js} +2 -2
  252. package/dist/tag/writer/since-writer.d.ts +32 -0
  253. package/dist/tag/writer/version-resolver.d.ts +7 -0
  254. package/package.json +21 -2
  255. package/dist/arrange/cli-schema.js +0 -34
  256. package/dist/arrange/output.js +0 -127
  257. package/dist/arrange/simplify-process-file.js +0 -30
  258. package/dist/arrange/simplify-sync.js +0 -30
  259. package/dist/audit/cli-schema.js +0 -66
  260. package/dist/audit/domain/react-imports.js +0 -91
  261. package/dist/audit/output.js +0 -213
  262. package/dist/mirror/sync-reporter.js +0 -124
  263. package/dist/mirror/sync-types.js +0 -1
  264. /package/dist/arrange/{suggest.js → group/suggest.js} +0 -0
  265. /package/dist/arrange/{domain → inspect/domain}/analyze-service.js +0 -0
  266. /package/dist/arrange/{process-file.js → regroup/process-file.js} +0 -0
  267. /package/dist/audit/{domain → comments/domain}/comment-content.js +0 -0
  268. /package/dist/audit/{domain → comments/domain}/comment-dividers.js +0 -0
  269. /package/dist/audit/{domain → comments/domain}/link-references.js +0 -0
  270. /package/dist/audit/{domain → comments/domain}/since-versions.js +0 -0
  271. /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.js +0 -0
  272. /package/dist/audit/{domain → display-names/domain}/display-names.js +0 -0
  273. /package/dist/audit/{domain → links/domain}/markdown-links.js +0 -0
  274. /package/dist/audit/{domain → rtl/domain}/mappings.js +0 -0
  275. /package/dist/audit/{domain → rtl/domain}/tokenize.js +0 -0
  276. /package/dist/core/filesystem/{port.js → filesystem.js} +0 -0
  277. /package/dist/tag/{resolve-target-path.js → target/resolve-path.js} +0 -0
  278. /package/dist/tag/{since-writer.js → writer/since-writer.js} +0 -0
  279. /package/dist/tag/{version-resolver.js → writer/version-resolver.js} +0 -0
package/README.md CHANGED
@@ -1,74 +1,109 @@
1
1
  # @codefast/cli
2
2
 
3
- The `codefast` command line for the [codefast monorepo](https://github.com/codefastlabs/codefast): `arrange` Tailwind
4
- class strings, `audit` source conventions, `mirror` export maps from `dist/`, `pack-slim` the publish artifact, and
5
- `tag` exported APIs with `@since`.
3
+ `codefast` is a small, dependency-light CLI toolkit for TypeScript projects — a **pnpm workspace** or a **single
4
+ package**. It reorders Tailwind classes, generates `package.json#exports` from a package's built `dist/`, slims the npm
5
+ tarball at publish time, stamps `@since` on your public API, and audits a handful of source and documentation
6
+ conventions.
7
+
8
+ It was built for — and is exercised daily by — the [codefast monorepo](https://github.com/codefastlabs/codefast), but
9
+ nothing here is codefast-only: run it in any pnpm workspace, or in a standalone package, and it works. A few audits
10
+ encode an opinionated house style (called out below) that you can adopt, ignore, or narrow with an allowlist.
6
11
 
7
12
  [![npm version](https://img.shields.io/npm/v/@codefast/cli)](https://www.npmjs.com/package/@codefast/cli)
8
13
  [![license](https://img.shields.io/npm/l/@codefast/cli)](./LICENSE)
9
14
 
10
- ## Overview
11
-
12
- `codefast` is the command line for the [codefast monorepo](https://github.com/codefastlabs/codefast). It has five
13
- commands: `arrange` regroups Tailwind class strings, `audit` checks source conventions, `mirror` writes
14
- `package.json#exports` from `dist/`, `pack-slim` slims the publish artifact down to what a consumer reads, and `tag`
15
- stamps exported APIs with `@since`.
15
+ ## Design principles
16
16
 
17
- This is repo tooling, published to npm. It runs in any pnpm workspace with a similar layout, but its flags and defaults
18
- follow the codefast conventions rather than aiming to be a general-purpose product.
19
-
20
- - **Safe by default.** Every writing command has `--dry-run`, and every audit is read-only except
17
+ - **Safe by default.** Every writing command supports `--dry-run`, and every audit is read-only except
21
18
  `audit comments --fix`.
22
- - **Scriptable.** `--json` prints one JSON object on stdout and suppresses human progress output.
23
- - **CI-ready.** Audits exit non-zero when findings remain, so they gate a pipeline without extra glue.
19
+ - **Scriptable.** `--json` prints one JSON object on stdout and suppresses the human progress output.
20
+ - **CI-ready.** Audits exit non-zero when findings remain, so they gate a pipeline with no extra glue.
24
21
  - **Configurable.** An optional `codefast.config.*` file, validated by a strict schema, adjusts every command.
25
22
 
26
- ## Installation and usage
23
+ ## Requirements
24
+
25
+ - **Node.js ≥ 24** (the CLI is published as ESM).
26
+ - **A project root — workspace or single package.** Commands resolve their root by walking up from the current
27
+ directory: the nearest `pnpm-workspace.yaml` marks a **workspace** (every package under it is in scope), and with no
28
+ workspace file the nearest `package.json` marks a **single package** (that one package is the whole scope). Only
29
+ `arrange group` needs no project at all — it just formats a string you paste in.
30
+ - **pnpm is not required to _run_ the CLI** — npm, npx, or a plain `node` invocation are all fine. pnpm matters only for
31
+ workspace-wide behavior, which is keyed off `pnpm-workspace.yaml`.
27
32
 
28
- Inside the codefast monorepo, the CLI runs from its built output via root `package.json` scripts:
33
+ ## Install
34
+
35
+ Install it globally, or run it once without installing:
29
36
 
30
37
  ```bash
31
- pnpm --filter @codefast/cli build # produce dist/bin.js first
38
+ # global install (pick your package manager)
39
+ pnpm add -g @codefast/cli
40
+ npm install -g @codefast/cli
32
41
 
33
- pnpm run codefast <command> # generic entry: node ./packages/cli/dist/bin.js
42
+ # one-off, no install
43
+ pnpm dlx @codefast/cli --help
44
+ npx @codefast/cli --help
45
+ ```
34
46
 
35
- # Convenience wrappers
36
- pnpm run cli:arrange # codefast arrange
37
- pnpm run cli:arrange:inspect # codefast arrange inspect
38
- pnpm run cli:arrange:preview # codefast arrange --dry-run
39
- pnpm run cli:arrange:simplify # codefast arrange simplify
40
- pnpm run cli:arrange:simplify:preview
41
- pnpm run cli:mirror # codefast mirror
42
- pnpm run cli:mirror:preview # codefast mirror --dry-run
43
- pnpm run cli:audit:rtl # codefast audit rtl
44
- pnpm run cli:audit:links # codefast audit links
45
- pnpm run cli:audit:comments # codefast audit comments
46
- pnpm run cli:audit:react # codefast audit react
47
- pnpm run cli:audit:display-names # codefast audit display-names
47
+ As a project dev dependency:
48
+
49
+ ```bash
50
+ pnpm add -D @codefast/cli
51
+ pnpm exec codefast --help
48
52
  ```
49
53
 
50
- `pnpm run version-packages` runs `changeset version` and then `codefast tag`, so published APIs are stamped at release.
54
+ The package is published on the `0.x` line and versioned on its own track: **breaking changes ship as minor versions**,
55
+ so pin the minor (`@codefast/cli@~0.9.0`) when you need stability.
51
56
 
52
- Standalone install (Node >= 24):
57
+ ## Quick start
53
58
 
54
59
  ```bash
55
- pnpm add -g @codefast/cli
56
- # or one-off
57
- pnpm dlx @codefast/cli --help
60
+ codefast --help # list commands
61
+ codefast arrange group "flex h-10 w-full rounded-md bg-primary" # works anywhere, no project needed
62
+
63
+ # in a workspace or a single-package project:
64
+ codefast arrange inspect packages/ui/src # read-only report of arrange findings
65
+ codefast arrange --dry-run packages/ui/src # preview a class reorder
66
+ codefast mirror --dry-run # preview generated exports for each package in scope
67
+ codefast audit links # find broken markdown cross-references
58
68
  ```
59
69
 
60
- The package is published on 0.x and versioned on its own track: breaking changes ship as minor versions, so pin the
61
- minor version when you need stability.
62
-
63
- Every writing command writes by default; pass `--dry-run` to preview. The global `--no-color` flag must come before the
64
- command name (`codefast --no-color mirror`). Commands that accept `--json` print a single JSON object on stdout and
65
- suppress human progress output.
70
+ ## Global options and conventions
71
+
72
+ - `codefast --help` lists the commands, and `--help` on any command shows its usage; `codefast --version` prints the
73
+ installed version.
74
+ - **The global `--no-color` flag must come _before_ the command name** — `codefast --no-color mirror`, not
75
+ `codefast mirror --no-color`.
76
+ - **Writing commands write by default; pass `--dry-run` to preview.** The audits are read-only — the one exception is
77
+ `audit comments --fix`, which repairs section dividers in place.
78
+ - **`--json` prints a single JSON object on stdout** and suppresses the human-readable progress output, so any command
79
+ can gate a script or a CI job.
80
+
81
+ ## Commands at a glance
82
+
83
+ | Command | What it does | Writes? |
84
+ | --------------------- | -------------------------------------------------------------------------- | ----------------- |
85
+ | `arrange` | Regroup Tailwind classes in `cn()` / `tv()` calls in render-pipeline order | yes (`--dry-run`) |
86
+ | `mirror` | Write each package's `package.json#exports` from its built `dist/` | yes (`--dry-run`) |
87
+ | `pack-slim` | Strip the dev-only surface from a package right before publish | yes (`--dry-run`) |
88
+ | `tag` | Stamp `@since <version>` on exported declarations that lack one | yes (`--dry-run`) |
89
+ | `audit links` | Report markdown cross-references that resolve to nothing | no |
90
+ | `audit rtl` | Report physical-direction Tailwind classes that should be logical | no |
91
+ | `audit imports` | Enforce the import policy (React by-name, Zod namespace in front-end) | no (report only) |
92
+ | `audit comments` | Check doc-comment conventions; repair section dividers | `--fix` only |
93
+ | `audit display-names` | Enforce the `namespace:Name` display-name convention | no |
94
+
95
+ **Which of these are for you?** `arrange`, `mirror`, `pack-slim`, `tag`, and `audit links` are general-purpose — they
96
+ work for any pnpm workspace or single package that builds with `tsc`. The other four audits encode codefast's own house
97
+ style (logical Tailwind directions, named React imports, a specific comment/divider grammar, a `namespace:Name` scheme
98
+ for `@codefast/di` tokens). Adopt them if they fit your project; otherwise skip them, or use an allowlist to narrow
99
+ their scope.
66
100
 
67
101
  ## `arrange`
68
102
 
69
103
  Rewrites Tailwind class strings inside `cn()` and `tv()` calls, regrouping utilities in render-pipeline order —
70
104
  existence, position, layout, sizing, spacing, shape, background, shadow, typography, composite, motion, starting,
71
- behavior, state, selector — instead of alphabetically.
105
+ behavior, state, selector — rather than alphabetically. (This is codefast's ordering, deliberately different from the
106
+ official Prettier Tailwind plugin's sort.)
72
107
 
73
108
  ```bash
74
109
  codefast arrange inspect packages/ui/src # read-only report
@@ -76,16 +111,21 @@ codefast arrange --dry-run packages/ui/src # preview the rewrite
76
111
  codefast arrange packages/ui/src # write
77
112
  ```
78
113
 
79
- When `[target]` is omitted, `arrange` uses the nearest directory with a `package.json` found by walking up from the
80
- current working directory. Directory scans skip test files (`*.test.*` / `*.spec.*`), because a `cn()` inside an
81
- assertion is intentional; pass such a file explicitly to process it.
114
+ When `[target]` is omitted, `arrange` uses the nearest directory with a `package.json`, walking up from the current
115
+ directory. Directory scans skip test files (`*.test.*` / `*.spec.*`), because a `cn()` inside an assertion is
116
+ intentional; pass such a file explicitly to process it.
117
+
118
+ `arrange` rewrites a `cn()` / `tv()` call only when its binding is imported from a recognized module — `clsx`,
119
+ `class-variance-authority`, `tailwind-variants`, `@codefast/tailwind-variants`, a `@/lib/utils` / `~/lib/utils` /
120
+ `#lib/utils` re-export, any `…/utils` path, or a dedicated `cn.ts` module — so an unrelated local `cn` is left alone.
121
+ Long static JSX `className` strings are regrouped regardless of where `cn` comes from.
82
122
 
83
123
  | Flag | Description |
84
124
  | -------------------- | ----------------------------------------------------------------------------- |
85
125
  | `--dry-run` | Preview suggested replacements without writing files. |
86
126
  | `--with-classname` | Append `className` as the final `cn()` argument (alias: `--with-class-name`). |
87
127
  | `--cn-import <spec>` | Override the module specifier used when a missing `cn` import is added. |
88
- | `--json` | Print one JSON object on stdout (suppresses human progress). |
128
+ | `--json` | Print one JSON summary on stdout (suppresses human progress). |
89
129
 
90
130
  Exits `1` when the `arrange.onAfterWrite` hook fails, `0` otherwise.
91
131
 
@@ -96,11 +136,26 @@ Read-only report of long strings, nested `cn` inside `tv()`, and related finding
96
136
  ### `arrange simplify [target]`
97
137
 
98
138
  Flattens grouped arrays and static-only `cn()` calls back to plain strings in `tv()` slots — the inverse cleanup pass.
99
- Accepts `--dry-run` and `--json`.
139
+ In a mixed `cn()` call it coalesces only _adjacent_ static literals and keeps argument order, so tailwind-merge
140
+ precedence is unchanged (a later argument still overrides an earlier one).
141
+
142
+ | Flag | Description |
143
+ | -------------------------- | -------------------------------------------------------------------------------------------------------- |
144
+ | `--dry-run` | Show what simplify would change without writing files. |
145
+ | `--fold-variant-classname` | Fold `cn()` overrides into a variant function's `className` option (alias: `--fold-variant-class-name`). |
146
+ | `--json` | Print one JSON summary on stdout. |
147
+
148
+ With `--fold-variant-classname`, `cn(buttonVariants({ size: "sm" }), "flex-1")` becomes
149
+ `buttonVariants({ size: "sm", className: "flex-1" })`, and a dynamic or multi-part override folds into a `className`
150
+ array. The fold fires only when the native TypeScript type server confirms the callee's options accept a `className` (or
151
+ `class`) of the right shape, so it loads the `typescript` package (an optional peer, v7) and needs the target inside a
152
+ `tsconfig`; files outside a project keep the base pass. Run a formatter afterward — a folded call can exceed the print
153
+ width until it is wrapped.
100
154
 
101
155
  ### `arrange group <tokens...>`
102
156
 
103
- Groups a pasted class string without touching the filesystem — useful for checking how classes would be bucketed:
157
+ Groups a pasted class string without touching the filesystem — the one command that needs no workspace, useful for
158
+ checking how classes would be bucketed:
104
159
 
105
160
  ```bash
106
161
  codefast arrange group "relative flex h-10 w-full items-center rounded-md bg-primary"
@@ -115,10 +170,10 @@ codefast arrange group --tv "flex items-center gap-2"
115
170
 
116
171
  ## `mirror`
117
172
 
118
- Scans each workspace package's built `dist/` tree and writes its `package.json#exports` map, plus top-level `main`,
119
- `module`, and `types` mirrored from the root export and a `files` entry for `dist`. The workspace root is the directory
120
- holding `pnpm-workspace.yaml`, so it runs from anywhere inside the repo. Build first — `mirror` reads `dist/`, and stale
121
- output produces stale exports.
173
+ Scans each package's built `dist/` tree and writes its `package.json#exports` map, plus top-level `main`, `module`, and
174
+ `types` mirrored from the root export and a `files` entry for `dist`. In a workspace it processes every package under
175
+ `pnpm-workspace.yaml`; in a single-package project it processes that one package. **Build first** — `mirror` reads
176
+ `dist/`, and stale output produces stale exports.
122
177
 
123
178
  ```bash
124
179
  codefast mirror # all workspace packages
@@ -134,21 +189,45 @@ codefast mirror --dry-run # report changes without writing
134
189
 
135
190
  Exits `1` when any package fails, `0` otherwise.
136
191
 
192
+ ### Per-package `mirror` configuration
193
+
194
+ The `mirror` config is a record keyed by package name, set under `mirror` in `codefast.config.*`. Set a package to
195
+ `false` to skip it entirely; omit a package to process it with defaults. For a package you do configure, these keys
196
+ apply (see the [Configuration](#configuration) example for their shape):
197
+
198
+ - **`source`** (`boolean | string`, default `true`) — emit a `source` condition pointing at the original `.ts` so a
199
+ consumer using the `source` condition resolves your `src/`. A string overrides the root-export source path explicitly.
200
+ - **`types`** (`boolean`, default `true`) — emit the `types` condition when a matching `.d.ts` exists.
201
+ - **`import`** (`boolean`, default `true`) — emit the `import` condition.
202
+ - **`preserve`** (`boolean`) — keep the existing `package.json#exports` map as written and only fill in the missing
203
+ `source` / `types` / `import` conditions; no `dist/` scan runs, so the public surface stays exactly what you declared.
204
+ - **`strip`** (`string`) — a `dist/` path prefix to flatten out of the generated specifiers, so `./components/button` is
205
+ published as `./button` rather than leaking the internal folder.
206
+ - **`exclude`** (`string[]`) — specifiers to leave out of the generated map, making a package's public surface a
207
+ decision rather than a consequence of its `dist/` layout. Matched against the specifier as it appears in `exports`
208
+ (after `strip`); a trailing `/*` excludes a whole subtree. The root export and `./package.json` are never excluded.
209
+ - **`exports`** (`Record<string, string>`) — extra or overriding entries merged into the generated map, for specifiers
210
+ the `dist/` scan does not produce (for example a raw CSS source path).
211
+ - **`css`** (`boolean | { enabled?, forceExportFiles?, customExports? }`) — how CSS files in `dist/` become exports:
212
+ `true` enables the default wildcard handling, and the object form tunes it (`enabled` toggles it, `forceExportFiles`
213
+ adds them to `files`, `customExports` sets explicit per-file CSS entries).
214
+
215
+ `source`, `types`, and `import` default to `true`, so an empty config object still emits all three.
216
+
137
217
  ## `pack-slim`
138
218
 
139
- Slims published packages down to what a consumer's `tsc` and Node read, so the npm tarball ships `dist` runtime and
140
- types only and its `package.json` describes nothing else. Where `mirror` writes the full exports — including the
141
- `source` condition — for repo dev, `pack-slim` removes the development lane for publish: it drops `src` from `files`,
142
- every `source` condition from `exports`/`imports`, every `imports` entry left pointing outside `files` (the `#/tests/*`
143
- and `#/examples/*` aliases), every script that is not an install or publish lifecycle hook, `devDependencies`, and the
144
- `dist` source maps plus their dangling `sourceMappingURL` directives. Private packages are skipped, since
145
- `changeset publish` never publishes them. It is meant to run on an ephemeral CI checkout right before publish (the
146
- release workflow runs it as its publish step), so it is never committed.
219
+ Slims a published package down to what a consumer's `tsc` and Node actually read, so the npm tarball ships `dist`
220
+ runtime and types only. Where `mirror` writes the full exports — including the `source` condition — for local
221
+ development, `pack-slim` removes that development lane for publish: it drops `src` from `files`, every `source`
222
+ condition from `exports`/`imports`, every `imports` entry left pointing outside `files`, every script that is not an
223
+ install or publish lifecycle hook, `devDependencies`, and the `dist` source maps plus their dangling `sourceMappingURL`
224
+ directives. Private packages are skipped. It is meant to run on an ephemeral CI checkout right before publish, so its
225
+ result is **never committed**.
147
226
 
148
- Because its result must never be committed, `pack-slim` refuses to write when the git working tree has uncommitted
149
- tracked changes — guarding against an accidental local run landing on real work. `--dry-run` is exempt (it writes
150
- nothing) and `--force` overrides the guard. In CI the check is transparent: `dist` is gitignored, so the tree is clean
151
- when the release workflow runs it.
227
+ Because that result must never be committed, `pack-slim` refuses to write when the git working tree has uncommitted
228
+ tracked changes — a guard against an accidental local run landing on real work. `--dry-run` is exempt (it writes
229
+ nothing) and `--force` overrides the guard. In CI the guard is invisible: `dist` is gitignored, so the tree is already
230
+ clean when the release workflow runs `pack-slim`.
152
231
 
153
232
  ```bash
154
233
  codefast pack-slim # every published package
@@ -164,33 +243,37 @@ codefast pack-slim --dry-run # report what would be stripped without touch
164
243
 
165
244
  Exits `1` when any package fails, `0` otherwise.
166
245
 
167
- ## `audit rtl`
246
+ ## `tag`
168
247
 
169
- Read-only scan for physical-direction Tailwind classes (e.g. `ml-*`, `left-*`, `text-left`) that should use logical
170
- equivalents (`ms-*`, `start-*`, `text-start`) or an `rtl:` companion (`translate-x`, `space-x`, resize cursors). Exits
171
- non-zero when violations remain so it can gate CI.
248
+ Adds `@since <version>` tags to the doc comments of exported declarations that lack one, creating the doc block when
249
+ there is none. The version comes from the nearest `package.json` above each target file, and declarations that already
250
+ carry `@since` are left alone. Run it at release time so published APIs carry accurate version metadata — never
251
+ hand-write `@since`.
172
252
 
173
253
  ```bash
174
- codefast audit rtl # uses audit.rtl.target from config
175
- codefast audit rtl packages/ui/src # explicit target
176
- codefast audit rtl --json # machine-readable summary
254
+ codefast tag # auto-discover packages from cwd (or the single package)
255
+ codefast tag packages/ui/src # tag one directory or file
256
+ codefast tag --dry-run # summary only, no writes
177
257
  ```
178
258
 
179
- | Flag | Description |
180
- | -------- | --------------------------------- |
181
- | `--json` | Print one JSON summary on stdout. |
259
+ | Flag | Description |
260
+ | ----------- | ------------------------------------------------------------- |
261
+ | `--dry-run` | Show summary without writing files. |
262
+ | `--json` | Print one JSON summary on stdout (suppresses human progress). |
263
+
264
+ Exits `1` when no target is selected, when any target fails, or when the `tag.onAfterWrite` hook fails.
182
265
 
183
- With no `[target]`, the scan root is `audit.rtl.target` from the config; when neither is set the command fails.
184
- Configure intentional exceptions via `audit.rtl.allowlist` — each entry is a bare class token or
185
- `repo/relative/path.tsx:token`.
266
+ ## `audit`
186
267
 
187
- ## `audit links`
268
+ Every audit is read-only, exits non-zero when findings remain (so it gates a CI pipeline with no extra glue), and takes
269
+ an optional `[target]` plus `--json`. Each also reads an `allowlist` from configuration for intentional exceptions.
188
270
 
189
- Read-only scan for markdown cross-references that point at nothing: a relative path that does not exist, an in-document
190
- anchor with no matching heading or `<a id>`, and an anchor into another document that the target does not offer. That
191
- last one is the reason this exists — a browser fails it silently by scrolling to the top. External URLs are not checked,
192
- and links inside fenced code are treated as examples rather than references. Exits non-zero when breakages remain so it
193
- can gate CI.
271
+ ### `audit links`
272
+
273
+ _General-purpose._ Scans markdown for cross-references that point at nothing: a relative path that does not exist, an
274
+ in-document anchor with no matching heading or `<a id>`, and an anchor into another document that the target does not
275
+ offer. That last case is the reason this exists — a browser fails it silently by scrolling to the top. External URLs are
276
+ not checked, and links inside fenced code are treated as examples rather than references.
194
277
 
195
278
  ```bash
196
279
  codefast audit links # whole repo
@@ -198,20 +281,48 @@ codefast audit links packages/di # explicit target
198
281
  codefast audit links --json # machine-readable summary
199
282
  ```
200
283
 
201
- | Flag | Description |
202
- | -------- | --------------------------------- |
203
- | `--json` | Print one JSON summary on stdout. |
284
+ Configure exceptions via `audit.links.allowlist` — each entry is a bare link target or `repo/relative/doc.md:target`.
285
+
286
+ ### `audit rtl`
287
+
288
+ _House style._ Scans for physical-direction Tailwind classes (e.g. `ml-*`, `left-*`, `text-left`) that should use
289
+ logical equivalents (`ms-*`, `start-*`, `text-start`) or an `rtl:` companion (`translate-x`, `space-x`, resize cursors).
290
+
291
+ ```bash
292
+ codefast audit rtl # uses audit.rtl.target from config
293
+ codefast audit rtl packages/ui/src # explicit target
294
+ codefast audit rtl --json # machine-readable summary
295
+ ```
296
+
297
+ With no `[target]`, the scan root is `audit.rtl.target` from the config; when neither is set the command fails.
298
+ Configure exceptions via `audit.rtl.allowlist` — each entry is a bare class token or `repo/relative/path.tsx:token`.
204
299
 
205
- Configure intentional exceptions via `audit.links.allowlist` — each entry is a bare link target or
206
- `repo/relative/doc.md:target`.
300
+ ### `audit imports`
207
301
 
208
- ## `audit comments`
302
+ _House style._ Enforces the monorepo's import policy over `.ts`/`.tsx` files:
209
303
 
210
- Scans source comments for the repo's comment conventions. Section dividers that are not in the one allowed form are
211
- mechanical, so `--fix` rewrites them in place. The rest is reported for a person to fix: TSDoc grammar errors, JSDoc
212
- `{type}` payloads, comments pointing at repo documents, `@param` lists that name some parameters but not all, `@param`
213
- descriptions without the `-` separator, `@since` tags out of position or naming a version the package has not reached,
214
- and comment links to missing paths. Exits non-zero when unfixed findings remain so it can gate CI.
304
+ - **React** — members must be imported by name. Flags `import * as React` and default `React` imports (type-only
305
+ included), plus an implicit `React.*` UMD-global type reference (`e: React.FormEvent` with no import) that `tsc`
306
+ accepts silently through the `export as namespace React` declaration in `@types/react`.
307
+ - **Zod** (front-end packages only) — flags a named `import { z } from "zod"`, which pins Zod's full locale set into the
308
+ bundle; `import * as z from "zod"` lets bundlers tree-shake it.
309
+
310
+ ```bash
311
+ codefast audit imports # whole repo
312
+ codefast audit imports apps/web/src # explicit target
313
+ codefast audit imports --json # machine-readable summary
314
+ ```
315
+
316
+ Configure exceptions via `audit.imports.allowlist` — each entry is the offending source text as written or
317
+ `repo/relative/path.tsx:<text>`.
318
+
319
+ ### `audit comments`
320
+
321
+ _House style._ Checks doc-comment conventions. Section dividers not in the one allowed form are mechanical, so `--fix`
322
+ rewrites them in place. The rest is reported for a person to fix: TSDoc grammar errors, JSDoc `{type}` payloads,
323
+ comments pointing at repo documents, `@param` lists that name some parameters but not all, `@param` descriptions without
324
+ the `-` separator, `@since` tags out of position or naming a version the package has not reached, and comment links to
325
+ missing paths.
215
326
 
216
327
  ```bash
217
328
  codefast audit comments # whole repo
@@ -225,80 +336,121 @@ codefast audit comments --json # machine-readable summary
225
336
  | `--fix` | Rewrite every mechanically fixable divider in place. |
226
337
  | `--json` | Print one JSON summary on stdout. |
227
338
 
228
- Configure intentional exceptions via `audit.comments.allowlist` — each entry is a divider line as written or
339
+ Configure exceptions via `audit.comments.allowlist` — each entry is a divider line as written or
229
340
  `repo/relative/path.ts:<divider>`.
230
341
 
231
- ## `audit react`
342
+ ### `audit display-names`
232
343
 
233
- Read-only scan enforcing the repo's React import policy: members are imported by name. Flags `import * as React` and
234
- default `React` imports (type-only included), plus an implicit `React.*` UMD-global type reference (`e: React.FormEvent`
235
- with no import), which `tsc` accepts silently through the `export as namespace React` declaration in `@types/react`.
236
- Exits non-zero when violations remain so it can gate CI.
344
+ _House style._ Enforces the display-name convention for every string a `token()`, `tag()`, or module factory takes: a
345
+ name is spelled like the TS symbol it stands for, under its owner's namespace — `namespace:Name`. The namespace is a
346
+ kebab-case package, app, or feature slug (or a scoped package name); a token or module name is PascalCase, a tag key is
347
+ camelCase. It scans TypeScript and markdown alike, since a doc sample is what a reader copies, and skips `tests/`,
348
+ `benchmarks/`, `.changeset/`, and `CHANGELOG.md`.
237
349
 
238
350
  ```bash
239
- codefast audit react # whole repo
240
- codefast audit react apps/web/src # explicit target
241
- codefast audit react --json # machine-readable summary
351
+ codefast audit display-names # whole repo
352
+ codefast audit display-names packages/di/examples # explicit target
353
+ codefast audit display-names --json # machine-readable summary
242
354
  ```
243
355
 
244
- | Flag | Description |
245
- | -------- | --------------------------------- |
246
- | `--json` | Print one JSON summary on stdout. |
356
+ Configure exceptions via `audit.displayNames.allowlist` — each entry is the call as written, through its closing quote
357
+ (or parenthesis when the name is the only argument), or `repo/relative/path.ts:<call>`.
247
358
 
248
- Configure intentional exceptions via `audit.react.allowlist` — each entry is the offending source text as written or
249
- `repo/relative/path.tsx:<text>`.
359
+ ## Configuration
250
360
 
251
- ## `audit display-names`
361
+ **You do not need a config file.** Every command has sensible defaults and works with none. Add a `codefast.config.*`
362
+ file at your project root only to change a default — and add only the sections for the commands you actually use.
252
363
 
253
- Read-only scan enforcing the display-name convention for every string a `token()`, `tag()` or module factory takes: a
254
- name is spelled like the TS symbol it stands for, under its owner's namespace — `<namespace>:<Name>`. The namespace is a
255
- kebab-case package, app or feature slug (or a scoped package name); a token or module name is PascalCase, because it
256
- stands for a type or a unit of composition; a tag key is camelCase, because it names an attribute. Scans TypeScript and
257
- markdown alike, since a doc sample is what a reader copies; skips `tests/`, `benchmarks/`, `.changeset/` and
258
- `CHANGELOG.md`, where a name is scoped by its file or quoted as it was. Exits non-zero when violations remain so it can
259
- gate CI.
364
+ **Where it goes and how it loads.** The CLI walks up from the working directory and uses the first match, checking
365
+ `codefast.config.mjs`, `codefast.config.js`, `codefast.config.cjs`, then `codefast.config.json` in each directory. JS
366
+ configs are loaded via [jiti](https://github.com/unjs/jiti) — so **only run the CLI in repositories you trust**, and
367
+ note that only a JS config can define `onAfterWrite` hooks (JSON can't hold functions). The schema is **strict**: an
368
+ unknown key is an error, which catches typos immediately.
260
369
 
261
- ```bash
262
- codefast audit display-names # whole repo
263
- codefast audit display-names packages/di/examples # explicit target
264
- codefast audit display-names --json # machine-readable summary
370
+ ### Start small
371
+
372
+ The smallest valid config is empty. Grow it one section at a time — each top-level key configures one command:
373
+
374
+ ```js
375
+ // codefast.config.js
376
+ export default {};
265
377
  ```
266
378
 
267
- | Flag | Description |
268
- | -------- | --------------------------------- |
269
- | `--json` | Print one JSON summary on stdout. |
379
+ | Key | Command | What it configures |
380
+ | --------- | --------- | ---------------------------------------------------------------------------------------------- |
381
+ | `mirror` | `mirror` | per-package `exports` generation — see [per-package config](#per-package-mirror-configuration) |
382
+ | `tag` | `tag` | package names to skip, and a hook to run after writing |
383
+ | `arrange` | `arrange` | a hook to run after writing |
384
+ | `audit` | `audit *` | each audit's default scan target and its `allowlist` of accepted exceptions |
270
385
 
271
- Configure intentional exceptions via `audit.displayNames.allowlist` — each entry is the call as written, through its
272
- closing quote (or parenthesis when the name is the only argument), or `repo/relative/path.ts:<call>`.
386
+ ### Author it with types
273
387
 
274
- ## `tag`
388
+ Don't memorize the shape. Import `defineConfig` (or annotate with the `CodefastConfig` type) and your editor completes
389
+ every key, checks the values, and catches typos **before you run anything** — the types _are_ the reference for what's
390
+ valid, and the strict runtime schema is the backstop.
275
391
 
276
- Adds `@since <version>` tags to the doc comments of exported declarations that lack one, creating the doc block when
277
- there is none. The version comes from the nearest `package.json` above each target file. Declarations that already carry
278
- `@since` are left alone.
392
+ ```ts
393
+ // codefast.config.ts
394
+ import { defineConfig } from "@codefast/cli";
279
395
 
280
- ```bash
281
- codefast tag # auto-discover workspace packages from cwd
282
- codefast tag packages/ui/src # tag one directory or file
283
- codefast tag --dry-run # summary only, no writes
396
+ export default defineConfig({
397
+ mirror: { "@acme/ui": { strip: "./components/" } }, // autocomplete: strip, exclude, source, types, css, …
398
+ });
284
399
  ```
285
400
 
286
- | Flag | Description |
287
- | ----------- | ------------------------------------------------------------- |
288
- | `--dry-run` | Show summary without writing files. |
289
- | `--json` | Print one JSON summary on stdout (suppresses human progress). |
401
+ A plain `.js` config gets the same help through a JSDoc type — no build step, no `.ts`:
290
402
 
291
- Exits `1` when no target is selected, when any target fails, or when the `tag.onAfterWrite` hook fails. In this repo,
292
- `tag` runs inside `pnpm run version-packages` so published APIs carry accurate version metadata — never hand-write
293
- `@since` tags.
403
+ ```js
404
+ // codefast.config.js
405
+ /** @type {import("@codefast/cli").CodefastConfig} */
406
+ export default {
407
+ mirror: { "@acme/ui": { strip: "./components/" } },
408
+ };
409
+ ```
294
410
 
295
- ## Configuration
411
+ ### Common recipes
296
412
 
297
- An optional `codefast.config.*` file adjusts `mirror`, `tag`, `arrange`, and `audit`. The CLI walks up from the working
298
- directory and uses the first match, checking `codefast.config.mjs`, `codefast.config.js`, `codefast.config.cjs`, then
299
- `codefast.config.json` in each directory. JS configs are loaded via [jiti](https://github.com/unjs/jiti), so only run
300
- the CLI in repositories you trust; JSON configs cannot define hooks. The schema is strict: an unknown key is a
301
- configuration error.
413
+ **Run a formatter after a command rewrites files.** `tag` and `arrange` take an `onAfterWrite` hook (sync or async). It
414
+ runs only when files were actually written — never on `--dry-run`:
415
+
416
+ ```js
417
+ // codefast.config.js
418
+ import { execSync } from "node:child_process";
419
+
420
+ const format = ({ files }) => execSync(`oxfmt ${files.join(" ")}`, { stdio: "inherit" });
421
+
422
+ export default {
423
+ tag: { onAfterWrite: format },
424
+ arrange: { onAfterWrite: format },
425
+ };
426
+ ```
427
+
428
+ **Skip packages.** `tag.skipPackages` takes globs matched against package names; `mirror` skips any package set to
429
+ `false`:
430
+
431
+ ```js
432
+ export default {
433
+ tag: { skipPackages: ["@acme/internal", "@apps/*"] },
434
+ mirror: { "@acme/internal": false },
435
+ };
436
+ ```
437
+
438
+ **Accept a known audit finding.** Every audit takes an `allowlist`. An entry is the offending text exactly as it
439
+ appears, or `repo/relative/path:<text>` to scope it to a single file:
440
+
441
+ ```js
442
+ export default {
443
+ audit: {
444
+ imports: { allowlist: [`packages/legacy/src/x.ts:import { z } from "zod";`] },
445
+ rtl: { allowlist: ["packages/ui/src/variants/sheet.ts:data-open:slide-in-from-left-10"] },
446
+ },
447
+ };
448
+ ```
449
+
450
+ ### Complete reference
451
+
452
+ Every section together — see [per-package `mirror` configuration](#per-package-mirror-configuration) for the `mirror`
453
+ keys:
302
454
 
303
455
  ```js
304
456
  // codefast.config.js
@@ -336,13 +488,15 @@ export default {
336
488
  },
337
489
  links: { allowlist: [] }, // bare link target, or `repo/relative/doc.md:target`
338
490
  comments: { allowlist: [] }, // divider as written, or `repo/relative/path.ts:<divider>`
339
- react: { allowlist: [] }, // offending text as written, or `repo/relative/path.tsx:<text>`
491
+ imports: { allowlist: [] }, // offending import text as written, or `repo/relative/path.tsx:<text>`
492
+ displayNames: { allowlist: [] }, // call as written, or `repo/relative/path.ts:<call>`
340
493
  },
341
494
  };
342
495
  ```
343
496
 
344
- `source`, `types`, and `import` default to `true`. The `onAfterWrite` hooks (sync or async) run only when files were
345
- actually written — never on `--dry-run`. A hook failure is reported on stderr and the command exits `1`.
497
+ `source`, `types`, and `import` default to `true`, so an empty `mirror` entry still emits all three. The `onAfterWrite`
498
+ hooks run only when files were actually written — never on `--dry-run`; a hook failure is reported on stderr and the
499
+ command exits `1`.
346
500
 
347
501
  ## Exit codes
348
502
 
@@ -352,6 +506,46 @@ actually written — never on `--dry-run`. A hook failure is reported on stderr
352
506
  | `1` | General failure (missing paths, failed packages, failed hooks). |
353
507
  | `2` | Invalid arguments or configuration. |
354
508
 
509
+ ## Programmatic use
510
+
511
+ `@codefast/cli` is importable as well as executable. `runCli` runs the same CLI in-process and resolves to the exit code
512
+ it would have exited with — the `codefast` binary is a thin wrapper around it.
513
+
514
+ ```ts
515
+ import { runCli } from "@codefast/cli";
516
+
517
+ // `argv` follows the `process.argv` layout: the first two entries are ignored,
518
+ // exactly as when Node runs the binary.
519
+ const exitCode = await runCli(["node", "codefast", "mirror", "--dry-run", "--json"]);
520
+
521
+ if (exitCode !== 0) {
522
+ throw new Error(`codefast exited with ${exitCode}`);
523
+ }
524
+ ```
525
+
526
+ The command still writes its human or `--json` output to stdout/stderr; `runCli` does not capture it. Read stdout
527
+ yourself when you need the structured summary.
528
+
529
+ ## How the codefast monorepo uses it
530
+
531
+ The tool is general; the codefast monorepo just wires convenience scripts and a release step around it — a good template
532
+ if you adopt the CLI in your own workspace. It runs from the built output via root `package.json` scripts:
533
+
534
+ ```bash
535
+ pnpm run codefast <command> # generic entry: node ./packages/cli/dist/bin.js
536
+
537
+ pnpm run cli:arrange # codefast arrange
538
+ pnpm run cli:mirror # codefast mirror
539
+ pnpm run cli:audit:links # codefast audit links
540
+ pnpm run cli:audit:rtl # codefast audit rtl
541
+ pnpm run cli:audit:comments # codefast audit comments
542
+ pnpm run cli:audit:imports # codefast audit imports
543
+ pnpm run cli:audit:display-names # codefast audit display-names
544
+ ```
545
+
546
+ `pnpm run version-packages` runs `changeset version` and then `codefast tag`, so published APIs are stamped at release,
547
+ and the release workflow runs `codefast pack-slim` as its publish step on a clean CI checkout.
548
+
355
549
  ## Documentation
356
550
 
357
551
  - [codefastlabs.com/docs/cli](https://codefastlabs.com/docs/cli) — this document, rendered.