@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
@@ -0,0 +1,13 @@
1
+ import type { AuditCommandPrelude } from "#/audit/prepare";
2
+ import { AppError } from "#/core/errors";
3
+ import type { Filesystem } from "#/core/filesystem/filesystem";
4
+ import type { Result } from "#/core/result";
5
+ /**
6
+ * Loads config and resolves the scan target for `audit rtl`.
7
+ *
8
+ * @since 0.5.0-canary.6
9
+ */
10
+ export declare function prepareRtlAudit(fs: Filesystem, args: {
11
+ readonly currentWorkingDirectory: string;
12
+ readonly rawTarget: string | undefined;
13
+ }): Promise<Result<AuditCommandPrelude, AppError>>;
@@ -0,0 +1,41 @@
1
+ import { resolveRepoRelativePath } from "#/audit/prepare";
2
+ import { loadCodefastConfig } from "#/core/config";
3
+ import { AppError, messageFrom } from "#/core/errors";
4
+ import { err, ok } from "#/core/result";
5
+ import { resolveProjectRoot } from "#/core/workspace/resolver";
6
+ /**
7
+ * Loads config and resolves the scan target for `audit rtl`.
8
+ *
9
+ * @since 0.5.0-canary.6
10
+ */
11
+ export async function prepareRtlAudit(fs, args) {
12
+ let rootDir;
13
+ try {
14
+ // Realpath so allowlist keys (`path.relative(rootDir, file)`) stay stable when cwd is a symlink.
15
+ rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
16
+ }
17
+ catch (caughtError) {
18
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
19
+ }
20
+ const loadedOutcome = await loadCodefastConfig(rootDir, fs);
21
+ if (!loadedOutcome.ok) {
22
+ return loadedOutcome;
23
+ }
24
+ const { config } = loadedOutcome.value;
25
+ const rtlConfig = config.audit?.rtl ?? {};
26
+ const targetFromCli = args.rawTarget;
27
+ const targetFromConfig = rtlConfig.target;
28
+ const resolvedTargetInput = targetFromCli ?? targetFromConfig;
29
+ if (resolvedTargetInput === undefined) {
30
+ return err(new AppError("VALIDATION_ERROR", "Missing scan target: pass a path argument or set audit.rtl.target in codefast.config"));
31
+ }
32
+ const targetPath = resolveRepoRelativePath(targetFromCli !== undefined ? args.currentWorkingDirectory : rootDir, resolvedTargetInput);
33
+ if (!fs.existsSync(targetPath)) {
34
+ return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
35
+ }
36
+ return ok({
37
+ rootDir,
38
+ targetPath: fs.canonicalPathSync(targetPath),
39
+ allowlist: rtlConfig.allowlist ?? [],
40
+ });
41
+ }
@@ -0,0 +1,14 @@
1
+ import type { RtlAuditResult } from "#/audit/domain/types";
2
+ import { AppError } from "#/core/errors";
3
+ import type { Filesystem } from "#/core/filesystem/filesystem";
4
+ import type { Result } from "#/core/result";
5
+ /**
6
+ * Scans a target path for physical-direction Tailwind class violations.
7
+ *
8
+ * @since 0.5.0-canary.6
9
+ */
10
+ export declare function runRtlAudit(fs: Filesystem, args: {
11
+ readonly rootDir: string;
12
+ readonly targetPath: string;
13
+ readonly allowlist: ReadonlyArray<string>;
14
+ }): Result<RtlAuditResult, AppError>;
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { auditFileContent } from "#/audit/domain/audit-file";
2
+ import { auditFileContent } from "#/audit/rtl/domain/audit-file";
3
3
  import { AppError, messageFrom } from "#/core/errors";
4
4
  import { err, ok } from "#/core/result";
5
5
  import { walkTsxFiles } from "#/core/workspace/typescript-walk";
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Runs the `codefast` CLI over the given argv and returns the process exit code.
3
+ *
4
+ * @since 0.3.16-canary.0
5
+ */
6
+ export declare function runCli(argv: Array<string>): Promise<number>;
@@ -0,0 +1,91 @@
1
+ import type { Command } from "commander";
2
+ import type { ZodType } from "zod";
3
+ import type { GlobalCliOptions } from "#/core/cli/global-options";
4
+ import type { AppError } from "#/core/errors";
5
+ import type { Filesystem } from "#/core/filesystem/filesystem";
6
+ import type { Result } from "#/core/result";
7
+ /**
8
+ * The options every command shares: the `--json` machine-output flag. Per-command option shapes extend this.
9
+ *
10
+ * @since 0.11.0
11
+ */
12
+ export interface BaseCommandOptions {
13
+ readonly json?: boolean | undefined;
14
+ }
15
+ /**
16
+ * A pipeline's `prepare` slot: resolves the argv context (cwd, positional, global options) into the command's prelude.
17
+ *
18
+ * @since 0.11.0
19
+ */
20
+ export type CommandPrepare<Prelude> = (fs: Filesystem, input: {
21
+ readonly currentWorkingDirectory: string;
22
+ readonly rawArg: string | undefined;
23
+ readonly globals: GlobalCliOptions;
24
+ }) => Promise<Result<Prelude, AppError>>;
25
+ /** The prelude and options a request is built from, before the run. */
26
+ interface BuildInput<Prelude, Opts> {
27
+ readonly prelude: Prelude;
28
+ readonly opts: Opts;
29
+ readonly globals: GlobalCliOptions;
30
+ }
31
+ /** The run result and its surrounding context, for the report phase. */
32
+ interface ReportInput<Prelude, RunResult, Presenter, Opts> {
33
+ readonly result: RunResult;
34
+ readonly prelude: Prelude;
35
+ readonly opts: Opts;
36
+ readonly presenter: Presenter | undefined;
37
+ readonly elapsedSeconds: number;
38
+ }
39
+ /**
40
+ * The invariant shape every workspace command and subcommand shares: resolve a prelude, build and
41
+ * validate a request, run it, then report to one of two audiences and record a single exit code.
42
+ *
43
+ * @remarks The optional slots carry the per-command variations — a working-tree guard and a streaming
44
+ * presenter — so the control flow itself is written once.
45
+ *
46
+ * @since 0.11.0
47
+ */
48
+ export interface CommandPipeline<Prelude, Request, RunResult, Presenter = never, Opts extends BaseCommandOptions = BaseCommandOptions> {
49
+ readonly name?: string | undefined;
50
+ readonly description?: string | undefined;
51
+ readonly positional?: {
52
+ readonly name: string;
53
+ readonly help: string;
54
+ } | undefined;
55
+ readonly jsonHelp?: string | undefined;
56
+ readonly configureArgv?: ((command: Command) => void) | undefined;
57
+ readonly prepare: CommandPrepare<Prelude>;
58
+ readonly guard?: ((input: {
59
+ readonly prelude: Prelude;
60
+ readonly opts: Opts;
61
+ }) => Promise<Result<void, AppError>>) | undefined;
62
+ readonly schema: ZodType<Request>;
63
+ readonly buildRequest: (input: BuildInput<Prelude, Opts>) => unknown;
64
+ readonly createPresenter?: ((input: BuildInput<Prelude, Opts>) => Presenter) | undefined;
65
+ readonly run: (fs: Filesystem, request: Request, presenter: Presenter | undefined) => Promise<Result<RunResult, AppError>>;
66
+ readonly presentHuman?: ((input: ReportInput<Prelude, RunResult, Presenter, Opts>) => void) | undefined;
67
+ readonly formatJson: (input: ReportInput<Prelude, RunResult, Presenter, Opts>) => string;
68
+ readonly exitCode: (result: RunResult) => number;
69
+ }
70
+ /**
71
+ * A pipeline that names itself, so it can register as a subcommand under a parent command.
72
+ *
73
+ * @since 0.11.0
74
+ */
75
+ export type NamedCommandPipeline<Prelude, Request, RunResult, Presenter = never, Opts extends BaseCommandOptions = BaseCommandOptions> = CommandPipeline<Prelude, Request, RunResult, Presenter, Opts> & {
76
+ readonly name: string;
77
+ readonly description: string;
78
+ };
79
+ /**
80
+ * Wires a pipeline onto a named Command: the shared positional, `--json`, any extra options, and the action.
81
+ *
82
+ * @since 0.11.0
83
+ */
84
+ export declare function applyCommandPipeline<Prelude, Request, RunResult, Presenter, Opts extends BaseCommandOptions>(command: Command, fs: Filesystem, pipeline: CommandPipeline<Prelude, Request, RunResult, Presenter, Opts>): Command;
85
+ /**
86
+ * Registers a pipeline as a subcommand under `parent`, taking its name and description from the pipeline.
87
+ *
88
+ * @since 0.11.0
89
+ */
90
+ export declare function registerPipelineSubcommand<Prelude, Request, RunResult, Presenter, Opts extends BaseCommandOptions>(parent: Command, fs: Filesystem, pipeline: NamedCommandPipeline<Prelude, Request, RunResult, Presenter, Opts>): void;
91
+ export {};
@@ -0,0 +1,83 @@
1
+ import process from "node:process";
2
+ import { globalCliCommanderOptionsSchema } from "#/core/cli/global-options";
3
+ import { readOptionalPositionalArg } from "#/core/cli/positional";
4
+ import { consumeCliAppError } from "#/core/cli/result-handle";
5
+ import { logger } from "#/core/logger";
6
+ import { parseWithSchema } from "#/core/schema-parse";
7
+ const DEFAULT_JSON_HELP = "Print one JSON summary on stdout (suppresses human progress)";
8
+ function readGlobalOptions(command) {
9
+ return (command.optsWithGlobals?.() ?? command.opts());
10
+ }
11
+ function makeAction(fs, pipeline) {
12
+ return async (rawArg, opts, command) => {
13
+ const globalsOutcome = parseWithSchema(globalCliCommanderOptionsSchema, readGlobalOptions(command));
14
+ if (!consumeCliAppError(globalsOutcome)) {
15
+ return;
16
+ }
17
+ const globals = globalsOutcome.value;
18
+ const prelude = await pipeline.prepare(fs, {
19
+ currentWorkingDirectory: process.cwd(),
20
+ rawArg: readOptionalPositionalArg(rawArg),
21
+ globals,
22
+ });
23
+ if (!consumeCliAppError(prelude)) {
24
+ return;
25
+ }
26
+ if (pipeline.guard) {
27
+ const guarded = await pipeline.guard({ prelude: prelude.value, opts });
28
+ if (!consumeCliAppError(guarded)) {
29
+ return;
30
+ }
31
+ }
32
+ const parsed = parseWithSchema(pipeline.schema, pipeline.buildRequest({ prelude: prelude.value, opts, globals }));
33
+ if (!consumeCliAppError(parsed)) {
34
+ return;
35
+ }
36
+ const json = !!opts.json;
37
+ const presenter = !json && pipeline.createPresenter
38
+ ? pipeline.createPresenter({ prelude: prelude.value, opts, globals })
39
+ : undefined;
40
+ const startedAt = performance.now();
41
+ const outcome = await pipeline.run(fs, parsed.value, presenter);
42
+ if (!consumeCliAppError(outcome)) {
43
+ return;
44
+ }
45
+ const elapsedSeconds = (performance.now() - startedAt) / 1000;
46
+ const report = {
47
+ result: outcome.value,
48
+ prelude: prelude.value,
49
+ opts,
50
+ presenter,
51
+ elapsedSeconds,
52
+ };
53
+ if (json) {
54
+ logger.out(pipeline.formatJson(report));
55
+ }
56
+ else {
57
+ pipeline.presentHuman?.(report);
58
+ }
59
+ process.exitCode = pipeline.exitCode(outcome.value);
60
+ };
61
+ }
62
+ /**
63
+ * Wires a pipeline onto a named Command: the shared positional, `--json`, any extra options, and the action.
64
+ *
65
+ * @since 0.11.0
66
+ */
67
+ export function applyCommandPipeline(command, fs, pipeline) {
68
+ if (pipeline.positional) {
69
+ command.argument(pipeline.positional.name, pipeline.positional.help);
70
+ }
71
+ command.option("--json", pipeline.jsonHelp ?? DEFAULT_JSON_HELP, false);
72
+ pipeline.configureArgv?.(command);
73
+ command.action(makeAction(fs, pipeline));
74
+ return command;
75
+ }
76
+ /**
77
+ * Registers a pipeline as a subcommand under `parent`, taking its name and description from the pipeline.
78
+ *
79
+ * @since 0.11.0
80
+ */
81
+ export function registerPipelineSubcommand(parent, fs, pipeline) {
82
+ applyCommandPipeline(parent.command(pipeline.name).description(pipeline.description), fs, pipeline);
83
+ }
@@ -0,0 +1,7 @@
1
+ import type { AppError } from "#/core/errors";
2
+ /**
3
+ * Formats an `AppError` as a `[CODE] message` line for CLI output.
4
+ *
5
+ * @since 0.3.16-canary.0
6
+ */
7
+ export declare function formatAppError(error: AppError): string;
@@ -0,0 +1,15 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * The validated global CLI options shared by every subcommand.
4
+ *
5
+ * @since 0.3.16-canary.0
6
+ */
7
+ export interface GlobalCliOptions {
8
+ color?: boolean | undefined;
9
+ }
10
+ /**
11
+ * Commander global opts shape validated before mirror prelude (`color` from `--no-color`).
12
+ *
13
+ * @since 0.3.16-canary.0
14
+ */
15
+ export declare const globalCliCommanderOptionsSchema: z.ZodType<GlobalCliOptions>;
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
  /**
3
3
  * Commander global opts shape validated before mirror prelude (`color` from `--no-color`).
4
4
  *
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Coerce a raw Commander positional argument to a string, or undefined when absent.
3
+ *
4
+ * @since 0.3.16-canary.0
5
+ */
6
+ export declare function readOptionalPositionalArg(candidate: unknown): string | undefined;
@@ -0,0 +1,9 @@
1
+ import { AppError } from "#/core/errors";
2
+ import type { Filesystem } from "#/core/filesystem/filesystem";
3
+ import type { Result } from "#/core/result";
4
+ /**
5
+ * Resolves the project root as a `Result`, mapping a resolution failure to an `INFRA_FAILURE` error.
6
+ *
7
+ * @since 0.11.0
8
+ */
9
+ export declare function resolveProjectRootResult(fs: Filesystem, currentWorkingDirectory: string): Result<string, AppError>;
@@ -0,0 +1,16 @@
1
+ import { AppError, messageFrom } from "#/core/errors";
2
+ import { err, ok } from "#/core/result";
3
+ import { resolveProjectRoot } from "#/core/workspace/resolver";
4
+ /**
5
+ * Resolves the project root as a `Result`, mapping a resolution failure to an `INFRA_FAILURE` error.
6
+ *
7
+ * @since 0.11.0
8
+ */
9
+ export function resolveProjectRootResult(fs, currentWorkingDirectory) {
10
+ try {
11
+ return ok(resolveProjectRoot(currentWorkingDirectory, fs).rootDir);
12
+ }
13
+ catch (caughtError) {
14
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
15
+ }
16
+ }
@@ -0,0 +1,13 @@
1
+ import type { AppError } from "#/core/errors";
2
+ import type { Result } from "#/core/result";
3
+ /**
4
+ * Narrows a `Result`, reporting a failure and setting the exit code, or logging an optional success message.
5
+ *
6
+ * @since 0.3.16-canary.0
7
+ */
8
+ export declare function consumeCliAppError<Value>(outcome: Result<Value, AppError>, options?: {
9
+ readonly successMessage?: string;
10
+ }): outcome is {
11
+ readonly ok: true;
12
+ readonly value: Value;
13
+ };
@@ -38,17 +38,4 @@ export function consumeCliAppError(outcome, options) {
38
38
  logger.out(options.successMessage);
39
39
  }
40
40
  return true;
41
- }
42
- /**
43
- * Awaits a `Result`, hands a success to `onSuccess`, and records the returned exit code on the process.
44
- *
45
- * @since 0.3.16-canary.0
46
- */
47
- export async function runCliResultAsync(outcomePromise, onSuccess) {
48
- const outcome = await outcomePromise;
49
- if (!consumeCliAppError(outcome)) {
50
- return;
51
- }
52
- const exit = await onSuccess(outcome.value);
53
- process.exitCode = exit === undefined ? 0 : exit;
54
41
  }
@@ -0,0 +1,7 @@
1
+ import type { CodefastConfig } from "#/core/config/schema";
2
+ /**
3
+ * Types a `codefast.config.*` object for editor autocomplete and type-checking; returns it unchanged.
4
+ *
5
+ * @since 0.10.0
6
+ */
7
+ export declare function defineConfig(config: CodefastConfig): CodefastConfig;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Types a `codefast.config.*` object for editor autocomplete and type-checking; returns it unchanged.
3
+ *
4
+ * @since 0.10.0
5
+ */
6
+ export function defineConfig(config) {
7
+ return config;
8
+ }
@@ -0,0 +1,18 @@
1
+ import type { CodefastConfig } from "#/core/config/schema";
2
+ import type { Filesystem } from "#/core/filesystem/filesystem";
3
+ /**
4
+ * A loaded config together with its schema warnings and the path it was read from.
5
+ *
6
+ * @since 0.3.16-canary.0
7
+ */
8
+ export type LoadConfigPayload = {
9
+ readonly config: CodefastConfig;
10
+ readonly warnings: Array<string>;
11
+ readonly configPath?: string;
12
+ };
13
+ /**
14
+ * Loads and caches the config payload for a directory, sharing one load per resolved path.
15
+ *
16
+ * @since 0.3.16-canary.0
17
+ */
18
+ export declare function loadConfigPayload(startDir: string, fs: Filesystem): Promise<LoadConfigPayload>;
@@ -1,6 +1,7 @@
1
1
  import path from "node:path";
2
2
  import jiti from "jiti";
3
3
  import { codefastConfigRootSchema } from "#/core/config/schema";
4
+ import { ancestorDirectories } from "#/core/workspace/ancestor-directories";
4
5
  function formatZodError(error, filePath) {
5
6
  const formatted = error.issues
6
7
  .map((issue) => {
@@ -22,8 +23,7 @@ const configJson = "codefast.config.json";
22
23
  const cachedLoads = new Map();
23
24
  function listConfigCandidates(startDir, fs) {
24
25
  const candidates = [];
25
- let current = path.resolve(startDir);
26
- while (true) {
26
+ for (const current of ancestorDirectories(startDir)) {
27
27
  for (const name of configJsPriority) {
28
28
  const candidate = path.join(current, name);
29
29
  if (fs.existsSync(candidate)) {
@@ -34,11 +34,6 @@ function listConfigCandidates(startDir, fs) {
34
34
  if (fs.existsSync(jsonCandidate)) {
35
35
  candidates.push(jsonCandidate);
36
36
  }
37
- const parent = path.dirname(current);
38
- if (parent === current) {
39
- break;
40
- }
41
- current = parent;
42
37
  }
43
38
  return candidates;
44
39
  }
@@ -0,0 +1,99 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * A config hook invoked with the written file paths after a command rewrites files.
4
+ *
5
+ * @since 0.3.16-canary.0
6
+ */
7
+ export type CodefastAfterWriteHook = (context: {
8
+ files: Array<string>;
9
+ }) => void | Promise<void>;
10
+ /**
11
+ * CSS export configuration for a mirrored package — a flag, or per-file overrides.
12
+ */
13
+ type MirrorCssConfig = boolean | {
14
+ enabled?: boolean | undefined;
15
+ customExports?: Record<string, string> | undefined;
16
+ forceExportFiles?: boolean | undefined;
17
+ };
18
+ /**
19
+ * Per-package mirror configuration. Setting a package to `false` skips it entirely.
20
+ */
21
+ interface MirrorPackageConfig {
22
+ /** Preserve the existing `package.json#exports` map and only add missing conditions
23
+ * (`source`, `types`, `import`); no `dist/` scan is performed. */
24
+ preserve?: boolean | undefined;
25
+ strip?: string | undefined;
26
+ /** Specifiers to leave out of the generated map, so a package's public surface is a decision
27
+ * rather than a consequence of its `dist/` layout. Matched against the specifier as it would
28
+ * appear in `exports` (after `strip`); a trailing `/*` excludes a whole subtree. The root
29
+ * export and `./package.json` are never excluded. */
30
+ exclude?: Array<string> | undefined;
31
+ exports?: Record<string, string> | undefined;
32
+ /** All three default to `true`; the mirror resolves an omitted value the same as `true`. */
33
+ source?: boolean | string | undefined;
34
+ types?: boolean | undefined;
35
+ import?: boolean | undefined;
36
+ css?: MirrorCssConfig | undefined;
37
+ }
38
+ /**
39
+ * The validated `mirror` configuration, keyed by package name.
40
+ *
41
+ * @since 0.3.16-canary.0
42
+ */
43
+ export type MirrorConfig = Record<string, false | MirrorPackageConfig>;
44
+ /**
45
+ * The validated `tag` command configuration.
46
+ *
47
+ * @since 0.3.16-canary.0
48
+ */
49
+ export interface CodefastTagConfig {
50
+ skipPackages?: Array<string> | undefined;
51
+ onAfterWrite?: CodefastAfterWriteHook | undefined;
52
+ }
53
+ /**
54
+ * The validated `arrange` command configuration.
55
+ *
56
+ * @since 0.3.16-canary.0
57
+ */
58
+ export interface CodefastArrangeConfig {
59
+ onAfterWrite?: CodefastAfterWriteHook | undefined;
60
+ }
61
+ /** An audit's per-command defaults: entries to ignore, as bare tokens or `repo/relative/path:token`. */
62
+ interface CodefastAuditAllowlistConfig {
63
+ allowlist?: Array<string> | undefined;
64
+ }
65
+ /** Per-audit defaults grouped under `audit`; the scan always starts at the repo root. */
66
+ interface CodefastAuditConfig {
67
+ rtl?: {
68
+ target?: string | undefined;
69
+ allowlist?: Array<string> | undefined;
70
+ } | undefined;
71
+ links?: CodefastAuditAllowlistConfig | undefined;
72
+ comments?: CodefastAuditAllowlistConfig | undefined;
73
+ imports?: CodefastAuditAllowlistConfig | undefined;
74
+ displayNames?: CodefastAuditAllowlistConfig | undefined;
75
+ }
76
+ /**
77
+ * The validated root `codefast.config` shape.
78
+ *
79
+ * @since 0.3.16-canary.0
80
+ */
81
+ export interface CodefastConfig {
82
+ mirror?: MirrorConfig | undefined;
83
+ tag?: CodefastTagConfig | undefined;
84
+ arrange?: CodefastArrangeConfig | undefined;
85
+ audit?: CodefastAuditConfig | undefined;
86
+ }
87
+ /**
88
+ * Zod validator for the `mirror` configuration record; its output is a {@link MirrorConfig}.
89
+ *
90
+ * @since 0.3.16-canary.0
91
+ */
92
+ export declare const mirrorConfigSchema: z.ZodType<MirrorConfig>;
93
+ /**
94
+ * Zod validator for a raw `codefast.config` object; its output is a {@link CodefastConfig}.
95
+ *
96
+ * @since 0.3.16-canary.0
97
+ */
98
+ export declare const codefastConfigRootSchema: z.ZodType<CodefastConfig>;
99
+ export {};