@codefast/cli 0.7.0 → 0.8.1

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 (222) hide show
  1. package/README.md +152 -37
  2. package/dist/arrange/analyze.js +3 -2
  3. package/dist/arrange/cli-schema.js +7 -2
  4. package/dist/arrange/command.js +3 -2
  5. package/dist/arrange/domain/analyze-service.js +3 -2
  6. package/dist/arrange/domain/ast/ast-node.js +35 -2
  7. package/dist/arrange/domain/ast/collectors-cn.js +9 -2
  8. package/dist/arrange/domain/ast/collectors-jsx.js +3 -2
  9. package/dist/arrange/domain/ast/collectors-tv.js +11 -2
  10. package/dist/arrange/domain/ast/helpers.js +5 -2
  11. package/dist/arrange/domain/ast/simplify-targets.js +1 -2
  12. package/dist/arrange/domain/ast/targets.js +7 -2
  13. package/dist/arrange/domain/constants.js +1 -2
  14. package/dist/arrange/domain/grouping-service.js +15 -2
  15. package/dist/arrange/domain/grouping.js +3 -2
  16. package/dist/arrange/domain/imports.js +3 -2
  17. package/dist/arrange/domain/source-text-formatters.js +9 -2
  18. package/dist/arrange/domain/tailwind-token.js +3 -2
  19. package/dist/arrange/domain/token-classifier.js +5 -2
  20. package/dist/arrange/domain/types.js +1 -2
  21. package/dist/arrange/output.js +9 -2
  22. package/dist/arrange/process-file.js +3 -2
  23. package/dist/arrange/resolve-target.js +3 -2
  24. package/dist/arrange/scan-target.js +3 -2
  25. package/dist/arrange/simplify-process-file.js +3 -2
  26. package/dist/arrange/simplify-sync.js +3 -2
  27. package/dist/arrange/source-parse.js +3 -2
  28. package/dist/arrange/suggest.js +3 -2
  29. package/dist/arrange/sync.js +3 -2
  30. package/dist/arrange/typescript-ast-translator.js +3 -2
  31. package/dist/arrange/workspace.js +3 -2
  32. package/dist/audit/cli-schema.js +14 -4
  33. package/dist/audit/command.js +45 -6
  34. package/dist/audit/domain/audit-file.js +4 -5
  35. package/dist/audit/domain/comment-content.js +1 -2
  36. package/dist/audit/domain/comment-dividers.js +1 -2
  37. package/dist/audit/domain/link-references.js +1 -2
  38. package/dist/audit/domain/mappings.js +10 -9
  39. package/dist/audit/domain/markdown-links.js +1 -2
  40. package/dist/audit/domain/react-imports.js +91 -0
  41. package/dist/audit/domain/since-versions.js +85 -0
  42. package/dist/audit/domain/tokenize.js +7 -6
  43. package/dist/audit/domain/tsdoc-syntax.js +1 -2
  44. package/dist/audit/domain/types.js +1 -2
  45. package/dist/audit/output.js +45 -5
  46. package/dist/audit/prepare.js +33 -3
  47. package/dist/audit/run-comments.js +26 -2
  48. package/dist/audit/run-links.js +1 -2
  49. package/dist/audit/run-react.js +55 -0
  50. package/dist/audit/run.js +2 -3
  51. package/dist/bin.js +1 -2
  52. package/dist/cli.js +5 -2
  53. package/dist/core/cli/format-error.js +3 -2
  54. package/dist/core/cli/global-options.js +1 -2
  55. package/dist/core/cli/positional.js +1 -2
  56. package/dist/core/cli/result-handle.js +5 -20
  57. package/dist/core/config/loader.js +3 -2
  58. package/dist/core/config/schema.js +27 -9
  59. package/dist/core/config/warnings.js +3 -2
  60. package/dist/core/config.js +3 -2
  61. package/dist/core/errors.js +3 -2
  62. package/dist/core/exit-codes.js +5 -2
  63. package/dist/core/filesystem/node.js +3 -2
  64. package/dist/core/filesystem/port.js +1 -2
  65. package/dist/core/glob.js +1 -2
  66. package/dist/core/logger.js +3 -2
  67. package/dist/core/result.js +5 -2
  68. package/dist/core/schema-parse.js +3 -2
  69. package/dist/core/source-text-edit.js +9 -2
  70. package/dist/core/verbose-diagnostics.js +3 -2
  71. package/dist/core/workspace/markdown-walk.js +1 -2
  72. package/dist/core/workspace/package-version.js +24 -0
  73. package/dist/core/workspace/resolver.js +3 -2
  74. package/dist/core/workspace/skip-directories.js +3 -2
  75. package/dist/core/workspace/source-walk.js +1 -2
  76. package/dist/core/workspace/typescript-walk.js +3 -2
  77. package/dist/mirror/cli-result.js +5 -2
  78. package/dist/mirror/cli-schema.js +3 -2
  79. package/dist/mirror/command.js +3 -2
  80. package/dist/mirror/dist-filesystem-impl.js +3 -2
  81. package/dist/mirror/domain/constants.js +11 -2
  82. package/dist/mirror/domain/dirent-guard.js +1 -2
  83. package/dist/mirror/domain/dist-filesystem.js +1 -2
  84. package/dist/mirror/domain/errors.js +5 -2
  85. package/dist/mirror/domain/exports.js +5 -2
  86. package/dist/mirror/domain/package-display-name.js +1 -2
  87. package/dist/mirror/domain/path-normalizer.js +3 -2
  88. package/dist/mirror/domain/types.js +1 -2
  89. package/dist/mirror/output.js +3 -2
  90. package/dist/mirror/package-path.js +5 -2
  91. package/dist/mirror/prepare.js +3 -2
  92. package/dist/mirror/supplement-exports.js +3 -2
  93. package/dist/mirror/sync-reporter.js +1 -2
  94. package/dist/mirror/sync-types.js +1 -2
  95. package/dist/mirror/sync-workspace-package.js +3 -2
  96. package/dist/mirror/sync.js +3 -2
  97. package/dist/mirror/write-exports.js +1 -2
  98. package/dist/pack-slim/cli-result.js +23 -0
  99. package/dist/pack-slim/cli-schema.js +11 -0
  100. package/dist/pack-slim/command.js +79 -0
  101. package/dist/pack-slim/domain/transform.js +95 -0
  102. package/dist/pack-slim/domain/types.js +2 -0
  103. package/dist/pack-slim/output.js +53 -0
  104. package/dist/pack-slim/sync.js +151 -0
  105. package/dist/pack-slim/working-tree.js +45 -0
  106. package/dist/tag/cli-result.js +3 -2
  107. package/dist/tag/cli-schema.js +3 -2
  108. package/dist/tag/command.js +3 -2
  109. package/dist/tag/domain/types.js +1 -2
  110. package/dist/tag/output.js +5 -2
  111. package/dist/tag/prepare.js +3 -2
  112. package/dist/tag/resolve-target-path.js +3 -2
  113. package/dist/tag/since-writer.js +3 -2
  114. package/dist/tag/sync.js +3 -2
  115. package/dist/tag/target-candidates.js +3 -2
  116. package/dist/tag/target-runner.js +3 -2
  117. package/dist/tag/version-resolver.js +8 -23
  118. package/package.json +9 -16
  119. package/dist/arrange/analyze.js.map +0 -1
  120. package/dist/arrange/cli-schema.js.map +0 -1
  121. package/dist/arrange/command.js.map +0 -1
  122. package/dist/arrange/domain/analyze-service.js.map +0 -1
  123. package/dist/arrange/domain/ast/ast-node.js.map +0 -1
  124. package/dist/arrange/domain/ast/collectors-cn.js.map +0 -1
  125. package/dist/arrange/domain/ast/collectors-jsx.js.map +0 -1
  126. package/dist/arrange/domain/ast/collectors-tv.js.map +0 -1
  127. package/dist/arrange/domain/ast/helpers.js.map +0 -1
  128. package/dist/arrange/domain/ast/simplify-targets.js.map +0 -1
  129. package/dist/arrange/domain/ast/targets.js.map +0 -1
  130. package/dist/arrange/domain/constants.js.map +0 -1
  131. package/dist/arrange/domain/grouping-service.js.map +0 -1
  132. package/dist/arrange/domain/grouping.js.map +0 -1
  133. package/dist/arrange/domain/imports.js.map +0 -1
  134. package/dist/arrange/domain/source-text-formatters.js.map +0 -1
  135. package/dist/arrange/domain/tailwind-token.js.map +0 -1
  136. package/dist/arrange/domain/token-classifier.js.map +0 -1
  137. package/dist/arrange/domain/types.js.map +0 -1
  138. package/dist/arrange/output.js.map +0 -1
  139. package/dist/arrange/process-file.js.map +0 -1
  140. package/dist/arrange/resolve-target.js.map +0 -1
  141. package/dist/arrange/scan-target.js.map +0 -1
  142. package/dist/arrange/simplify-process-file.js.map +0 -1
  143. package/dist/arrange/simplify-sync.js.map +0 -1
  144. package/dist/arrange/source-parse.js.map +0 -1
  145. package/dist/arrange/suggest.js.map +0 -1
  146. package/dist/arrange/sync.js.map +0 -1
  147. package/dist/arrange/typescript-ast-translator.js.map +0 -1
  148. package/dist/arrange/workspace.js.map +0 -1
  149. package/dist/audit/cli-schema.js.map +0 -1
  150. package/dist/audit/command.js.map +0 -1
  151. package/dist/audit/domain/audit-file.js.map +0 -1
  152. package/dist/audit/domain/comment-content.js.map +0 -1
  153. package/dist/audit/domain/comment-dividers.js.map +0 -1
  154. package/dist/audit/domain/link-references.js.map +0 -1
  155. package/dist/audit/domain/mappings.js.map +0 -1
  156. package/dist/audit/domain/markdown-links.js.map +0 -1
  157. package/dist/audit/domain/tokenize.js.map +0 -1
  158. package/dist/audit/domain/tsdoc-syntax.js.map +0 -1
  159. package/dist/audit/domain/types.js.map +0 -1
  160. package/dist/audit/output.js.map +0 -1
  161. package/dist/audit/prepare.js.map +0 -1
  162. package/dist/audit/run-comments.js.map +0 -1
  163. package/dist/audit/run-links.js.map +0 -1
  164. package/dist/audit/run.js.map +0 -1
  165. package/dist/bin.js.map +0 -1
  166. package/dist/cli.js.map +0 -1
  167. package/dist/core/cli/format-error.js.map +0 -1
  168. package/dist/core/cli/global-options.js.map +0 -1
  169. package/dist/core/cli/positional.js.map +0 -1
  170. package/dist/core/cli/result-handle.js.map +0 -1
  171. package/dist/core/config/loader.js.map +0 -1
  172. package/dist/core/config/schema.js.map +0 -1
  173. package/dist/core/config/warnings.js.map +0 -1
  174. package/dist/core/config.js.map +0 -1
  175. package/dist/core/errors.js.map +0 -1
  176. package/dist/core/exit-codes.js.map +0 -1
  177. package/dist/core/filesystem/node.js.map +0 -1
  178. package/dist/core/filesystem/port.js.map +0 -1
  179. package/dist/core/glob.js.map +0 -1
  180. package/dist/core/logger.js.map +0 -1
  181. package/dist/core/result.js.map +0 -1
  182. package/dist/core/schema-parse.js.map +0 -1
  183. package/dist/core/source-text-edit.js.map +0 -1
  184. package/dist/core/verbose-diagnostics.js.map +0 -1
  185. package/dist/core/workspace/markdown-walk.js.map +0 -1
  186. package/dist/core/workspace/resolver.js.map +0 -1
  187. package/dist/core/workspace/skip-directories.js.map +0 -1
  188. package/dist/core/workspace/source-walk.js.map +0 -1
  189. package/dist/core/workspace/typescript-walk.js.map +0 -1
  190. package/dist/mirror/cli-result.js.map +0 -1
  191. package/dist/mirror/cli-schema.js.map +0 -1
  192. package/dist/mirror/command.js.map +0 -1
  193. package/dist/mirror/dist-filesystem-impl.js.map +0 -1
  194. package/dist/mirror/domain/constants.js.map +0 -1
  195. package/dist/mirror/domain/dirent-guard.js.map +0 -1
  196. package/dist/mirror/domain/dist-filesystem.js.map +0 -1
  197. package/dist/mirror/domain/errors.js.map +0 -1
  198. package/dist/mirror/domain/exports.js.map +0 -1
  199. package/dist/mirror/domain/package-display-name.js.map +0 -1
  200. package/dist/mirror/domain/path-normalizer.js.map +0 -1
  201. package/dist/mirror/domain/types.js.map +0 -1
  202. package/dist/mirror/output.js.map +0 -1
  203. package/dist/mirror/package-path.js.map +0 -1
  204. package/dist/mirror/prepare.js.map +0 -1
  205. package/dist/mirror/supplement-exports.js.map +0 -1
  206. package/dist/mirror/sync-reporter.js.map +0 -1
  207. package/dist/mirror/sync-types.js.map +0 -1
  208. package/dist/mirror/sync-workspace-package.js.map +0 -1
  209. package/dist/mirror/sync.js.map +0 -1
  210. package/dist/mirror/write-exports.js.map +0 -1
  211. package/dist/tag/cli-result.js.map +0 -1
  212. package/dist/tag/cli-schema.js.map +0 -1
  213. package/dist/tag/command.js.map +0 -1
  214. package/dist/tag/domain/types.js.map +0 -1
  215. package/dist/tag/output.js.map +0 -1
  216. package/dist/tag/prepare.js.map +0 -1
  217. package/dist/tag/resolve-target-path.js.map +0 -1
  218. package/dist/tag/since-writer.js.map +0 -1
  219. package/dist/tag/sync.js.map +0 -1
  220. package/dist/tag/target-candidates.js.map +0 -1
  221. package/dist/tag/target-runner.js.map +0 -1
  222. package/dist/tag/version-resolver.js.map +0 -1
@@ -3,6 +3,8 @@ import { AppError } from "#/core/errors";
3
3
  import { err, ok } from "#/core/result";
4
4
  import { normalizePath } from "#/mirror/domain/path-normalizer";
5
5
  /**
6
+ * Resolves the optional positional package argument to a root-relative path, or `undefined` when absent.
7
+ *
6
8
  * @since 0.3.16-canary.0
7
9
  */
8
10
  export function resolveMirrorPackageFromCliArg(fs, args) {
@@ -22,6 +24,8 @@ export function resolveMirrorPackageFromCliArg(fs, args) {
22
24
  return ok(normalized);
23
25
  }
24
26
  /**
27
+ * Resolves a package filter to a root-relative path, rejecting anything outside the monorepo root.
28
+ *
25
29
  * @since 0.3.16-canary.0
26
30
  */
27
31
  export function resolvePackageFilterUnderRoot(fs, rootDir, packageFilter) {
@@ -36,5 +40,4 @@ export function resolvePackageFilterUnderRoot(fs, rootDir, packageFilter) {
36
40
  return err(new AppError("VALIDATION_ERROR", `Package path must be a subdirectory under monorepo root: ${rootDir}`));
37
41
  }
38
42
  return ok(normalized);
39
- }
40
- //# sourceMappingURL=package-path.js.map
43
+ }
@@ -5,6 +5,8 @@ import { err, ok } from "#/core/result";
5
5
  import { findRepoRoot } from "#/core/workspace/resolver";
6
6
  import { resolveMirrorPackageFromCliArg } from "#/mirror/package-path";
7
7
  /**
8
+ * Resolves the repo root, config, and package filter into the prelude a mirror run starts from.
9
+ *
8
10
  * @since 0.3.16-canary.0
9
11
  */
10
12
  export async function prepareMirrorSync(fs, args) {
@@ -33,5 +35,4 @@ export async function prepareMirrorSync(fs, args) {
33
35
  config: loadedOutcome.value.config,
34
36
  packageFilter: filterOutcome.value,
35
37
  });
36
- }
37
- //# sourceMappingURL=prepare.js.map
38
+ }
@@ -105,6 +105,8 @@ function buildSupplementedEntry(specifier, existing, modulePath, distDir, fs, op
105
105
  return result;
106
106
  }
107
107
  /**
108
+ * Adds missing conditions to a package's existing exports map and returns the specifiers it touched.
109
+ *
108
110
  * @since 0.3.16-canary.0
109
111
  */
110
112
  export async function supplementExportsInPackageJson(fs, packageJsonPath, packageDir, options, write = true) {
@@ -153,5 +155,4 @@ export function buildSourcePathResolver(fs, packageDir) {
153
155
  const tsxPath = path.join(srcDir, `${modulePath}.tsx`);
154
156
  return fs.existsSync(tsxPath) ? `./src/${modulePath}.tsx` : `./src/${modulePath}.ts`;
155
157
  };
156
- }
157
- //# sourceMappingURL=supplement-exports.js.map
158
+ }
@@ -121,5 +121,4 @@ export class MirrorSyncReporter {
121
121
  }
122
122
  return `${openSequence}${text}${ANSI.reset}`;
123
123
  }
124
- }
125
- //# sourceMappingURL=sync-reporter.js.map
124
+ }
@@ -1,2 +1 @@
1
- export {};
2
- //# sourceMappingURL=sync-types.js.map
1
+ export {};
@@ -7,6 +7,8 @@ import { resolvePackageDisplayName } from "#/mirror/domain/package-display-name"
7
7
  import { buildSourcePathResolver, supplementExportsInPackageJson } from "#/mirror/supplement-exports";
8
8
  import { writePackageJsonExportsAtomic } from "#/mirror/write-exports";
9
9
  /**
10
+ * Regenerates one package's `package.json#exports` from its `dist/` and returns the package's stats.
11
+ *
10
12
  * @since 0.3.16-canary.0
11
13
  */
12
14
  export async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr, config, write = true) {
@@ -114,5 +116,4 @@ export async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr
114
116
  pkgStats.error = messageFrom(caughtError);
115
117
  }
116
118
  return pkgStats;
117
- }
118
- //# sourceMappingURL=sync-workspace-package.js.map
119
+ }
@@ -7,6 +7,8 @@ import { normalizePath } from "#/mirror/domain/path-normalizer";
7
7
  import { resolvePackageFilterUnderRoot } from "#/mirror/package-path";
8
8
  import { syncExportsForWorkspacePackage } from "#/mirror/sync-workspace-package";
9
9
  /**
10
+ * Runs the mirror sync across the targeted packages and returns the aggregate stats.
11
+ *
10
12
  * @since 0.3.16-canary.0
11
13
  */
12
14
  export async function runMirrorSync(fs, input) {
@@ -86,5 +88,4 @@ function mirrorTargetsFromWorkspaceLayout(rootDir, layoutOutcome) {
86
88
  .filter((relativePath) => relativePath.length > 0);
87
89
  relPaths.sort((left, right) => left.localeCompare(right));
88
90
  return { relPaths, multiSource };
89
- }
90
- //# sourceMappingURL=sync.js.map
91
+ }
@@ -141,5 +141,4 @@ export async function writePackageJsonExportsAtomic(fs, packageJsonPath, mergeIn
141
141
  throw new MirrorError(MirrorErrorCode.PACKAGE_WRITE, `Failed to atomically update ${packageJsonPath}: ${messageFrom(caughtRenameError)}`, caughtRenameError instanceof Error ? { cause: caughtRenameError } : undefined);
142
142
  }
143
143
  return { prunedKeys };
144
- }
145
- //# sourceMappingURL=write-exports.js.map
144
+ }
@@ -0,0 +1,23 @@
1
+ import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#/core/exit-codes";
2
+ /**
3
+ * Maps a pack-slim run's stats to the process exit code.
4
+ *
5
+ * @since 0.8.1
6
+ */
7
+ export function exitCodeForPackSlimResult(stats) {
8
+ return stats.packagesErrored > 0 ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
9
+ }
10
+ /**
11
+ * Serializes a pack-slim run's stats as the single-line JSON summary printed under `--json`.
12
+ *
13
+ * @since 0.8.1
14
+ */
15
+ export function formatPackSlimJsonOutput(stats, elapsedSeconds, write = true) {
16
+ return JSON.stringify({
17
+ schemaVersion: 1,
18
+ ok: stats.packagesErrored === 0,
19
+ write,
20
+ elapsedSeconds,
21
+ stats,
22
+ });
23
+ }
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Zod schema validating the serializable inputs of a pack-slim run.
4
+ *
5
+ * @since 0.8.1
6
+ */
7
+ export const packSlimRunRequestSchema = z.object({
8
+ rootDir: z.string().min(1),
9
+ packageFilter: z.string().optional(),
10
+ write: z.boolean().optional(),
11
+ });
@@ -0,0 +1,79 @@
1
+ import process from "node:process";
2
+ import { Command } from "commander";
3
+ import { globalCliCommanderOptionsSchema } from "#/core/cli/global-options";
4
+ import { readOptionalPositionalArg } from "#/core/cli/positional";
5
+ import { consumeCliAppError } from "#/core/cli/result-handle";
6
+ import { AppError, messageFrom } from "#/core/errors";
7
+ import { nodeFilesystem } from "#/core/filesystem/node";
8
+ import { logger } from "#/core/logger";
9
+ import { err } from "#/core/result";
10
+ import { parseWithSchema } from "#/core/schema-parse";
11
+ import { findRepoRoot } from "#/core/workspace/resolver";
12
+ import { exitCodeForPackSlimResult, formatPackSlimJsonOutput } from "#/pack-slim/cli-result";
13
+ import { packSlimRunRequestSchema } from "#/pack-slim/cli-schema";
14
+ import { PackSlimProgressPresenter } from "#/pack-slim/output";
15
+ import { runPackSlim } from "#/pack-slim/sync";
16
+ import { ensureWorkingTreeClean } from "#/pack-slim/working-tree";
17
+ /**
18
+ * Creates the `pack-slim` subcommand, which strips the source lane from published packages before publish.
19
+ *
20
+ * @since 0.8.1
21
+ */
22
+ export function createPackSlimCommand() {
23
+ const cmd = new Command("pack-slim")
24
+ .description("Strip src, source conditions, and dist source maps from published packages before publish")
25
+ .argument("[package]", "Optional package path relative to repo root (e.g. packages/ui)")
26
+ .option("--dry-run", "Report what would change without touching any file", false)
27
+ .option("--force", "Run even if the git working tree has uncommitted tracked changes", false)
28
+ .option("--json", "Print one JSON summary on stdout (suppresses human progress)", false)
29
+ .action(async (packageArg, opts, command) => {
30
+ const globalsOptionCarrier = command.optsWithGlobals?.() ??
31
+ command.opts();
32
+ const globalOptionsOutcome = parseWithSchema(globalCliCommanderOptionsSchema, globalsOptionCarrier);
33
+ if (!consumeCliAppError(globalOptionsOutcome)) {
34
+ return;
35
+ }
36
+ let rootDir;
37
+ try {
38
+ rootDir = findRepoRoot(process.cwd(), nodeFilesystem);
39
+ }
40
+ catch (caughtError) {
41
+ consumeCliAppError(err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError)));
42
+ return;
43
+ }
44
+ const write = !opts.dryRun;
45
+ // A destructive slim must never land on a developer's uncommitted work; --dry-run writes nothing, so it is exempt.
46
+ if (write && !opts.force) {
47
+ const cleanCheck = ensureWorkingTreeClean(rootDir);
48
+ if (!consumeCliAppError(cleanCheck)) {
49
+ return;
50
+ }
51
+ }
52
+ const parsed = parseWithSchema(packSlimRunRequestSchema, {
53
+ rootDir,
54
+ packageFilter: readOptionalPositionalArg(packageArg),
55
+ write,
56
+ });
57
+ if (!consumeCliAppError(parsed)) {
58
+ return;
59
+ }
60
+ const json = !!opts.json;
61
+ const presenter = new PackSlimProgressPresenter();
62
+ if (!json) {
63
+ presenter.configure({ dryRun: !write });
64
+ }
65
+ const startTime = performance.now();
66
+ const outcome = await runPackSlim(nodeFilesystem, {
67
+ ...parsed.value,
68
+ listener: json ? undefined : presenter,
69
+ });
70
+ if (!consumeCliAppError(outcome)) {
71
+ return;
72
+ }
73
+ if (json) {
74
+ logger.out(formatPackSlimJsonOutput(outcome.value, (performance.now() - startTime) / 1000, write));
75
+ }
76
+ process.exitCode = exitCodeForPackSlimResult(outcome.value);
77
+ });
78
+ return cmd;
79
+ }
@@ -0,0 +1,95 @@
1
+ /** Pure transforms that strip a package's source lane from a publish artifact. */
2
+ /**
3
+ * The emitted-file extensions that may carry a `sourceMappingURL` directive.
4
+ */
5
+ const MAP_ANNOTATED_EXTENSIONS = new Set([".js", ".mjs", ".cjs", ".d.ts", ".d.mts", ".d.cts"]);
6
+ /**
7
+ * Whether a dist entry is a source-map sidecar (`*.map`).
8
+ *
9
+ * @since 0.8.1
10
+ */
11
+ export function isSourceMapFile(fileName) {
12
+ return fileName.endsWith(".map");
13
+ }
14
+ /**
15
+ * Whether a dist entry is an emitted file that may carry a `sourceMappingURL` directive.
16
+ *
17
+ * @since 0.8.1
18
+ */
19
+ export function isMapAnnotatedFile(fileName) {
20
+ for (const extension of MAP_ANNOTATED_EXTENSIONS) {
21
+ if (fileName.endsWith(extension)) {
22
+ return true;
23
+ }
24
+ }
25
+ return false;
26
+ }
27
+ /**
28
+ * Produces a publish manifest with `src` dropped from `files` and every `source` export/import condition removed.
29
+ *
30
+ * @remarks Operates on a structural clone, so the caller's manifest is left intact. A consumer never enables the
31
+ * `source` condition and resolves `#/` through `types`/`default` to `dist`, so dropping the source lane and the shipped
32
+ * sources it points at leaves the published surface whole.
33
+ *
34
+ * @since 0.8.1
35
+ */
36
+ export function slimPublishManifest(manifest) {
37
+ const draft = structuredClone(manifest);
38
+ const filesSrcRemoved = removeSrcFromFiles(draft);
39
+ const exportsSourceRemoved = deleteSourceConditions(draft.exports);
40
+ const importsSourceRemoved = deleteSourceConditions(draft.imports);
41
+ const changed = filesSrcRemoved || exportsSourceRemoved > 0 || importsSourceRemoved > 0;
42
+ return {
43
+ manifest: draft,
44
+ report: { filesSrcRemoved, exportsSourceRemoved, importsSourceRemoved, changed },
45
+ };
46
+ }
47
+ /**
48
+ * Strips every `sourceMappingURL` directive line from an emitted file's text.
49
+ *
50
+ * @since 0.8.1
51
+ */
52
+ export function stripSourceMappingComment(text) {
53
+ const lines = text.split("\n");
54
+ const kept = lines.filter((line) => !/^\s*\/\/# sourceMappingURL=/.test(line));
55
+ if (kept.length === lines.length) {
56
+ return { text, stripped: false };
57
+ }
58
+ return { text: kept.join("\n"), stripped: true };
59
+ }
60
+ function removeSrcFromFiles(manifest) {
61
+ const files = manifest.files;
62
+ if (!Array.isArray(files)) {
63
+ return false;
64
+ }
65
+ const next = files.filter((entry) => entry !== "src");
66
+ if (next.length === files.length) {
67
+ return false;
68
+ }
69
+ manifest.files = next;
70
+ return true;
71
+ }
72
+ // Walks a conditions tree deleting every `source` key. A subpath key always starts with ".", so only real
73
+ // condition objects match, and a source-only entry never occurs here, so no node is left empty.
74
+ function deleteSourceConditions(node) {
75
+ if (Array.isArray(node)) {
76
+ let removed = 0;
77
+ for (const item of node) {
78
+ removed += deleteSourceConditions(item);
79
+ }
80
+ return removed;
81
+ }
82
+ if (node === null || typeof node !== "object") {
83
+ return 0;
84
+ }
85
+ const record = node;
86
+ let removed = 0;
87
+ if ("source" in record) {
88
+ delete record.source;
89
+ removed += 1;
90
+ }
91
+ for (const key of Object.keys(record)) {
92
+ removed += deleteSourceConditions(record[key]);
93
+ }
94
+ return removed;
95
+ }
@@ -0,0 +1,2 @@
1
+ /** Stats and progress types for a pack-slim run. */
2
+ export {};
@@ -0,0 +1,53 @@
1
+ import { logger } from "#/core/logger";
2
+ /**
3
+ * A progress listener that renders pack-slim run events as human-readable CLI lines.
4
+ *
5
+ * @since 0.8.1
6
+ */
7
+ export class PackSlimProgressPresenter {
8
+ dryRun = false;
9
+ configure(options) {
10
+ this.dryRun = options.dryRun;
11
+ }
12
+ onBanner() {
13
+ logger.out(this.dryRun ? "pack-slim (dry run) — no files will change" : "pack-slim — stripping source lane");
14
+ }
15
+ onPackageComplete(stats, ordinal, total) {
16
+ const position = `[${ordinal}/${total}]`;
17
+ if (stats.skipped) {
18
+ logger.out(`${position} skip ${stats.name} (${stats.skipReason})`);
19
+ return;
20
+ }
21
+ if (stats.error !== null) {
22
+ logger.err(`${position} error ${stats.name}: ${stats.error}`);
23
+ return;
24
+ }
25
+ if (!stats.changed) {
26
+ logger.out(`${position} ok ${stats.name} (already slim)`);
27
+ return;
28
+ }
29
+ const verb = this.dryRun ? "would drop" : "dropped";
30
+ const parts = [];
31
+ if (stats.filesSrcRemoved) {
32
+ parts.push("files:src");
33
+ }
34
+ if (stats.exportsSourceRemoved > 0) {
35
+ parts.push(`exports:source×${stats.exportsSourceRemoved}`);
36
+ }
37
+ if (stats.importsSourceRemoved > 0) {
38
+ parts.push(`imports:source×${stats.importsSourceRemoved}`);
39
+ }
40
+ if (stats.mapFilesDeleted > 0) {
41
+ parts.push(`maps×${stats.mapFilesDeleted}`);
42
+ }
43
+ if (stats.sourceCommentsStripped > 0) {
44
+ parts.push(`sourceMappingURL×${stats.sourceCommentsStripped}`);
45
+ }
46
+ logger.out(`${position} ok ${stats.name} — ${verb} ${parts.join(", ")}`);
47
+ }
48
+ onComplete(stats, elapsedSeconds) {
49
+ logger.out(`pack-slim done in ${elapsedSeconds.toFixed(2)}s — ${stats.packagesChanged} changed, ` +
50
+ `${stats.packagesSkipped} skipped, ${stats.totalMapFilesDeleted} maps ${this.dryRun ? "to drop" : "dropped"}` +
51
+ (stats.packagesErrored > 0 ? `, ${stats.packagesErrored} errored` : ""));
52
+ }
53
+ }
@@ -0,0 +1,151 @@
1
+ import path from "node:path";
2
+ import { AppError, messageFrom } from "#/core/errors";
3
+ import { err, ok } from "#/core/result";
4
+ import { listWorkspacePackageDirectories } from "#/core/workspace/resolver";
5
+ import { DIST_DIR, PACKAGE_JSON } from "#/mirror/domain/constants";
6
+ import { isMapAnnotatedFile, isSourceMapFile, slimPublishManifest, stripSourceMappingComment, } from "#/pack-slim/domain/transform";
7
+ /**
8
+ * Strips the source lane from every published package's build output and returns the aggregate stats.
9
+ *
10
+ * @remarks Meant to run on an ephemeral CI checkout right before `changeset publish`: it rewrites `package.json`, drops
11
+ * `dist` source maps, and clears their now-dangling `sourceMappingURL` directives, so the tarball ships only `dist`
12
+ * runtime and types. Private packages are skipped because `changeset publish` never publishes them.
13
+ *
14
+ * @since 0.8.1
15
+ */
16
+ export async function runPackSlim(fs, input) {
17
+ const write = input.write ?? true;
18
+ const { listener } = input;
19
+ listener?.onBanner?.();
20
+ const startTime = performance.now();
21
+ try {
22
+ const targets = await resolveTargets(fs, input.rootDir, input.packageFilter);
23
+ const stats = {
24
+ packagesFound: targets.length,
25
+ packagesProcessed: 0,
26
+ packagesSkipped: 0,
27
+ packagesErrored: 0,
28
+ packagesChanged: 0,
29
+ totalMapFilesDeleted: 0,
30
+ packageDetails: [],
31
+ };
32
+ let ordinal = 1;
33
+ for (const packageDir of targets) {
34
+ const pkgStats = await slimWorkspacePackage(fs, packageDir, write);
35
+ stats.packageDetails.push(pkgStats);
36
+ accumulate(stats, pkgStats);
37
+ listener?.onPackageComplete?.(pkgStats, ordinal, targets.length);
38
+ ordinal += 1;
39
+ }
40
+ listener?.onComplete?.(stats, (performance.now() - startTime) / 1000);
41
+ return ok(stats);
42
+ }
43
+ catch (caughtError) {
44
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
45
+ }
46
+ }
47
+ async function resolveTargets(fs, rootDir, packageFilter) {
48
+ if (packageFilter !== undefined) {
49
+ const packageDir = path.resolve(rootDir, packageFilter);
50
+ if (!fs.existsSync(path.join(packageDir, PACKAGE_JSON))) {
51
+ throw new Error(`No package.json under "${packageFilter}"`);
52
+ }
53
+ return [packageDir];
54
+ }
55
+ const layout = await listWorkspacePackageDirectories(rootDir, fs, false);
56
+ return [...layout.packageDirectoryPathsAbsolute].sort((left, right) => left.localeCompare(right));
57
+ }
58
+ async function slimWorkspacePackage(fs, packageDir, write) {
59
+ const packageJsonPath = path.join(packageDir, PACKAGE_JSON);
60
+ const pkgStats = {
61
+ name: path.basename(packageDir),
62
+ path: packageDir,
63
+ skipped: false,
64
+ skipReason: "",
65
+ error: null,
66
+ filesSrcRemoved: false,
67
+ exportsSourceRemoved: 0,
68
+ importsSourceRemoved: 0,
69
+ mapFilesDeleted: 0,
70
+ sourceCommentsStripped: 0,
71
+ changed: false,
72
+ };
73
+ if (!fs.existsSync(packageJsonPath)) {
74
+ pkgStats.skipped = true;
75
+ pkgStats.skipReason = "package.json not found";
76
+ return pkgStats;
77
+ }
78
+ try {
79
+ const raw = await fs.readFile(packageJsonPath, "utf8");
80
+ const parsed = JSON.parse(raw);
81
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
82
+ throw new SyntaxError("package.json root must be a JSON object");
83
+ }
84
+ const manifest = parsed;
85
+ if (typeof manifest.name === "string") {
86
+ pkgStats.name = manifest.name;
87
+ }
88
+ if (manifest.private === true) {
89
+ pkgStats.skipped = true;
90
+ pkgStats.skipReason = "private package";
91
+ return pkgStats;
92
+ }
93
+ const { manifest: slimmed, report } = slimPublishManifest(manifest);
94
+ pkgStats.filesSrcRemoved = report.filesSrcRemoved;
95
+ pkgStats.exportsSourceRemoved = report.exportsSourceRemoved;
96
+ pkgStats.importsSourceRemoved = report.importsSourceRemoved;
97
+ if (report.changed && write) {
98
+ await fs.writeFile(packageJsonPath, `${JSON.stringify(slimmed, null, 2)}\n`, "utf8");
99
+ }
100
+ await pruneDist(fs, path.join(packageDir, DIST_DIR), write, pkgStats);
101
+ pkgStats.changed = report.changed || pkgStats.mapFilesDeleted > 0 || pkgStats.sourceCommentsStripped > 0;
102
+ }
103
+ catch (caughtError) {
104
+ pkgStats.error = messageFrom(caughtError);
105
+ }
106
+ return pkgStats;
107
+ }
108
+ async function pruneDist(fs, distDir, write, pkgStats) {
109
+ if (!fs.existsSync(distDir)) {
110
+ return;
111
+ }
112
+ const entries = (await fs.readdir(distDir, { recursive: true, withFileTypes: true }));
113
+ for (const entry of entries) {
114
+ if (!entry.isFile()) {
115
+ continue;
116
+ }
117
+ const filePath = path.join(entry.parentPath, entry.name);
118
+ if (isSourceMapFile(entry.name)) {
119
+ if (write) {
120
+ await fs.unlink(filePath);
121
+ }
122
+ pkgStats.mapFilesDeleted += 1;
123
+ continue;
124
+ }
125
+ if (isMapAnnotatedFile(entry.name)) {
126
+ const contents = await fs.readFile(filePath, "utf8");
127
+ const { text, stripped } = stripSourceMappingComment(contents);
128
+ if (stripped) {
129
+ if (write) {
130
+ await fs.writeFile(filePath, text, "utf8");
131
+ }
132
+ pkgStats.sourceCommentsStripped += 1;
133
+ }
134
+ }
135
+ }
136
+ }
137
+ function accumulate(stats, pkgStats) {
138
+ if (pkgStats.skipped) {
139
+ stats.packagesSkipped += 1;
140
+ return;
141
+ }
142
+ if (pkgStats.error !== null) {
143
+ stats.packagesErrored += 1;
144
+ return;
145
+ }
146
+ stats.packagesProcessed += 1;
147
+ stats.totalMapFilesDeleted += pkgStats.mapFilesDeleted;
148
+ if (pkgStats.changed) {
149
+ stats.packagesChanged += 1;
150
+ }
151
+ }
@@ -0,0 +1,45 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { AppError, messageFrom } from "#/core/errors";
3
+ import { err, ok } from "#/core/result";
4
+ /**
5
+ * Whether git's tracked-only porcelain output reports any uncommitted change.
6
+ *
7
+ * @remarks The output is read with `--untracked-files=no`, so untracked and gitignored paths (like the freshly built
8
+ * `dist`) never appear — any non-blank line is a staged or unstaged change to a tracked file.
9
+ *
10
+ * @since 0.8.1
11
+ */
12
+ export function hasUncommittedTrackedChanges(porcelainOutput) {
13
+ return porcelainOutput.split("\n").some((line) => line.trim().length > 0);
14
+ }
15
+ /**
16
+ * Reads git's porcelain status for tracked files only, under the given root.
17
+ */
18
+ function readTrackedWorkingTreeStatus(rootDir) {
19
+ return execFileSync("git", ["status", "--porcelain", "--untracked-files=no"], {
20
+ cwd: rootDir,
21
+ encoding: "utf8",
22
+ });
23
+ }
24
+ /**
25
+ * Refuses when the git working tree carries uncommitted tracked changes, so a destructive slim never lands on real work.
26
+ *
27
+ * @remarks pack-slim rewrites tracked `package.json` files and deletes build output; its result must never be committed.
28
+ * A caller passing `--force` skips this, and `--dry-run` never reaches it because it writes nothing.
29
+ *
30
+ * @since 0.8.1
31
+ */
32
+ export function ensureWorkingTreeClean(rootDir) {
33
+ let porcelain;
34
+ try {
35
+ porcelain = readTrackedWorkingTreeStatus(rootDir);
36
+ }
37
+ catch (caughtError) {
38
+ return err(new AppError("INFRA_FAILURE", `Could not check the git working tree: ${messageFrom(caughtError)}. Pass --force to skip this check.`, caughtError));
39
+ }
40
+ if (hasUncommittedTrackedChanges(porcelain)) {
41
+ return err(new AppError("VALIDATION_ERROR", "pack-slim refuses to run: the git working tree has uncommitted tracked changes. " +
42
+ "Commit or stash them, use --dry-run to preview, or pass --force to override."));
43
+ }
44
+ return ok(undefined);
45
+ }
@@ -1,5 +1,7 @@
1
1
  import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#/core/exit-codes";
2
2
  /**
3
+ * Maps a tag run's result to the process exit code.
4
+ *
3
5
  * @since 0.3.16-canary.0
4
6
  */
5
7
  export function exitCodeForTagSyncResult(result) {
@@ -8,5 +10,4 @@ export function exitCodeForTagSyncResult(result) {
8
10
  }
9
11
  const hasRunErrors = result.targetResults.some((targetResult) => targetResult.runError !== null);
10
12
  return hasRunErrors || result.hookError !== null ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
11
- }
12
- //# sourceMappingURL=cli-result.js.map
13
+ }
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  /**
3
+ * Zod schema validating a `TagSyncRunRequest`.
4
+ *
3
5
  * @since 0.3.16-canary.0
4
6
  */
5
7
  export const tagSyncRunRequestSchema = z.object({
@@ -9,5 +11,4 @@ export const tagSyncRunRequestSchema = z.object({
9
11
  targetPath: z.string().optional(),
10
12
  skipPackages: z.array(z.string()).optional(),
11
13
  config: z.unknown().optional(),
12
- });
13
- //# sourceMappingURL=cli-schema.js.map
14
+ });
@@ -11,6 +11,8 @@ import { presentTagSyncResult, TagSyncProgressPresenter } from "#/tag/output";
11
11
  import { prepareTagSync } from "#/tag/prepare";
12
12
  import { runTagSync } from "#/tag/sync";
13
13
  /**
14
+ * Creates the `tag` subcommand, which stamps `@since` tags on exported declarations.
15
+ *
14
16
  * @since 0.3.16-canary.0
15
17
  */
16
18
  export function createTagCommand() {
@@ -65,5 +67,4 @@ function formatTagSyncJsonOutput(result, rootDir) {
65
67
  cwd: rootDir,
66
68
  result,
67
69
  });
68
- }
69
- //# sourceMappingURL=command.js.map
70
+ }
@@ -1,2 +1 @@
1
- export {};
2
- //# sourceMappingURL=types.js.map
1
+ export {};
@@ -2,6 +2,8 @@ import { CLI_EXIT_GENERAL_ERROR } from "#/core/exit-codes";
2
2
  import { logger } from "#/core/logger";
3
3
  import { exitCodeForTagSyncResult } from "#/tag/cli-result";
4
4
  /**
5
+ * A progress listener that prints a line as each tag target starts and completes.
6
+ *
5
7
  * @since 0.3.16-canary.0
6
8
  */
7
9
  export class TagSyncProgressPresenter {
@@ -27,6 +29,8 @@ const colors = {
27
29
  yellow: "\x1b[33m",
28
30
  };
29
31
  /**
32
+ * Prints a tag run's target table, warnings, and summary, and returns the exit code.
33
+ *
30
34
  * @since 0.3.16-canary.0
31
35
  */
32
36
  export function presentTagSyncResult(result, rootDir) {
@@ -97,5 +101,4 @@ function formatSummary(result) {
97
101
  lines.push(`[tag] Skipped: ${result.skippedPackages.length} package(s)`);
98
102
  }
99
103
  return lines.join("\n");
100
- }
101
- //# sourceMappingURL=output.js.map
104
+ }
@@ -3,6 +3,8 @@ import { ok } from "#/core/result";
3
3
  import { findRepoRoot } from "#/core/workspace/resolver";
4
4
  import { resolveProvidedTagTargetPath } from "#/tag/resolve-target-path";
5
5
  /**
6
+ * Resolves the repo root, config, and optional target path into the prelude a tag run starts from.
7
+ *
6
8
  * @since 0.3.16-canary.0
7
9
  */
8
10
  export async function prepareTagSync(fs, args) {
@@ -26,5 +28,4 @@ export async function prepareTagSync(fs, args) {
26
28
  config: loadedOutcome.value.config,
27
29
  resolvedTargetPath,
28
30
  });
29
- }
30
- //# sourceMappingURL=prepare.js.map
31
+ }