@slats/claude-assets-sync 0.1.3 → 0.2.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 (228) hide show
  1. package/README.md +111 -587
  2. package/bin/claude-sync.mjs +24 -0
  3. package/dist/@aileron/declare/index.d.ts +4 -4
  4. package/dist/claude-hashes.json +20 -0
  5. package/dist/commands/index.d.ts +1 -112
  6. package/dist/commands/runCli/index.d.ts +2 -0
  7. package/dist/commands/runCli/runCli.cjs +31 -0
  8. package/dist/commands/runCli/runCli.d.ts +10 -0
  9. package/dist/commands/runCli/runCli.mjs +29 -0
  10. package/dist/commands/runCli/type.d.ts +28 -0
  11. package/dist/commands/runCli/utils/injectOne.cjs +48 -0
  12. package/dist/commands/runCli/utils/injectOne.d.ts +3 -0
  13. package/dist/commands/runCli/utils/injectOne.mjs +46 -0
  14. package/dist/commands/runCli/utils/resolveScopeFlag.cjs +28 -0
  15. package/dist/commands/runCli/utils/resolveScopeFlag.d.ts +2 -0
  16. package/dist/commands/runCli/utils/resolveScopeFlag.mjs +26 -0
  17. package/dist/commands/runCli/utils/runInject.cjs +36 -0
  18. package/dist/commands/runCli/utils/runInject.d.ts +2 -0
  19. package/dist/commands/runCli/utils/runInject.mjs +34 -0
  20. package/dist/core/buildPlan/buildPlan.cjs +42 -0
  21. package/dist/core/buildPlan/buildPlan.d.ts +2 -0
  22. package/dist/core/buildPlan/buildPlan.mjs +40 -0
  23. package/dist/core/buildPlan/index.d.ts +2 -0
  24. package/dist/core/buildPlan/type.d.ts +32 -0
  25. package/dist/core/buildPlan/utils/toPosix.cjs +9 -0
  26. package/dist/core/buildPlan/utils/toPosix.d.ts +1 -0
  27. package/dist/core/buildPlan/utils/toPosix.mjs +7 -0
  28. package/dist/core/buildPlan/utils/walkFiles.cjs +25 -0
  29. package/dist/core/buildPlan/utils/walkFiles.d.ts +1 -0
  30. package/dist/core/buildPlan/utils/walkFiles.mjs +23 -0
  31. package/dist/core/hash/hash.cjs +30 -0
  32. package/dist/core/hash/hash.d.ts +4 -0
  33. package/dist/core/hash/hash.mjs +26 -0
  34. package/dist/core/hash/index.d.ts +1 -0
  35. package/dist/core/hashManifest/hashManifest.cjs +27 -0
  36. package/dist/core/hashManifest/hashManifest.d.ts +17 -0
  37. package/dist/core/hashManifest/hashManifest.mjs +23 -0
  38. package/dist/core/hashManifest/index.d.ts +1 -0
  39. package/dist/core/index.d.ts +5 -0
  40. package/dist/core/injectDocs/index.d.ts +2 -0
  41. package/dist/core/injectDocs/injectDocs.cjs +43 -0
  42. package/dist/core/injectDocs/injectDocs.d.ts +2 -0
  43. package/dist/core/injectDocs/injectDocs.mjs +41 -0
  44. package/dist/core/injectDocs/type.d.ts +30 -0
  45. package/dist/core/injectDocs/utils/applyAction.cjs +21 -0
  46. package/dist/core/injectDocs/utils/applyAction.d.ts +2 -0
  47. package/dist/core/injectDocs/utils/applyAction.mjs +19 -0
  48. package/dist/core/injectDocs/utils/emitCiForceList.cjs +10 -0
  49. package/dist/core/injectDocs/utils/emitCiForceList.d.ts +2 -0
  50. package/dist/core/injectDocs/utils/emitCiForceList.mjs +8 -0
  51. package/dist/core/injectDocs/utils/printPlan.cjs +20 -0
  52. package/dist/core/injectDocs/utils/printPlan.d.ts +2 -0
  53. package/dist/core/injectDocs/utils/printPlan.mjs +18 -0
  54. package/dist/core/injectDocs/utils/summarize.cjs +27 -0
  55. package/dist/core/injectDocs/utils/summarize.d.ts +3 -0
  56. package/dist/core/injectDocs/utils/summarize.mjs +25 -0
  57. package/dist/core/scope/index.d.ts +1 -0
  58. package/dist/core/scope/scope.cjs +46 -0
  59. package/dist/core/scope/scope.d.ts +16 -0
  60. package/dist/core/scope/scope.mjs +41 -0
  61. package/dist/core/scope/utils/isDirectory.cjs +14 -0
  62. package/dist/core/scope/utils/isDirectory.d.ts +1 -0
  63. package/dist/core/scope/utils/isDirectory.mjs +12 -0
  64. package/dist/index.cjs +15 -9
  65. package/dist/index.d.ts +3 -5
  66. package/dist/index.mjs +7 -3
  67. package/dist/prompts/confirmForce.cjs +27 -0
  68. package/dist/prompts/confirmForce.d.ts +1 -0
  69. package/dist/prompts/confirmForce.mjs +25 -0
  70. package/dist/prompts/index.d.ts +2 -0
  71. package/dist/prompts/selectScope.cjs +30 -0
  72. package/dist/prompts/selectScope.d.ts +2 -0
  73. package/dist/prompts/selectScope.mjs +28 -0
  74. package/dist/utils/heartbeat.cjs +25 -0
  75. package/dist/utils/heartbeat.d.ts +16 -0
  76. package/dist/utils/heartbeat.mjs +23 -0
  77. package/dist/utils/logger.cjs +7 -0
  78. package/dist/utils/logger.d.ts +8 -0
  79. package/dist/utils/logger.mjs +7 -0
  80. package/dist/utils/types.d.ts +1 -252
  81. package/dist/utils/version.cjs +2 -14
  82. package/dist/utils/version.d.ts +3 -53
  83. package/dist/utils/version.mjs +2 -13
  84. package/docs/bundle-size-decision.md +36 -0
  85. package/docs/claude/skills/claude-sync-applier/SKILL.md +195 -0
  86. package/docs/claude/skills/claude-sync-applier/knowledge/claude-md-template.md +77 -0
  87. package/docs/claude/skills/claude-sync-applier/knowledge/dependency-cruiser.md +126 -0
  88. package/docs/claude/skills/claude-sync-applier/knowledge/gotchas.md +139 -0
  89. package/docs/claude/skills/claude-sync-applier/knowledge/package-json-patches.md +130 -0
  90. package/docs/claude/skills/claude-sync-applier/knowledge/reference-files.md +120 -0
  91. package/docs/claude/skills/claude-sync-applier/knowledge/smoke-tests.md +102 -0
  92. package/docs/consumer-integration.md +153 -0
  93. package/package.json +25 -17
  94. package/scripts/build-hashes.mjs +30 -0
  95. package/scripts/buildHashes.d.mts +15 -0
  96. package/scripts/buildHashes.mjs +82 -0
  97. package/scripts/claude-build-hashes.mjs +42 -0
  98. package/scripts/inject-version.js +112 -0
  99. package/dist/cli.cjs +0 -8
  100. package/dist/cli.d.ts +0 -1
  101. package/dist/cli.mjs +0 -7
  102. package/dist/commands/add.cjs +0 -80
  103. package/dist/commands/add.d.ts +0 -8
  104. package/dist/commands/add.mjs +0 -78
  105. package/dist/commands/list.cjs +0 -94
  106. package/dist/commands/list.d.ts +0 -15
  107. package/dist/commands/list.mjs +0 -91
  108. package/dist/commands/migrate.cjs +0 -9
  109. package/dist/commands/migrate.d.ts +0 -6
  110. package/dist/commands/migrate.mjs +0 -7
  111. package/dist/commands/remove.cjs +0 -127
  112. package/dist/commands/remove.d.ts +0 -6
  113. package/dist/commands/remove.mjs +0 -105
  114. package/dist/commands/status.cjs +0 -193
  115. package/dist/commands/status.d.ts +0 -6
  116. package/dist/commands/status.mjs +0 -171
  117. package/dist/commands/sync.cjs +0 -28
  118. package/dist/commands/sync.d.ts +0 -6
  119. package/dist/commands/sync.mjs +0 -26
  120. package/dist/commands/types.d.ts +0 -89
  121. package/dist/commands/update.cjs +0 -209
  122. package/dist/commands/update.d.ts +0 -29
  123. package/dist/commands/update.mjs +0 -206
  124. package/dist/components/add/AddCommand.cjs +0 -103
  125. package/dist/components/add/AddCommand.d.ts +0 -14
  126. package/dist/components/add/AddCommand.mjs +0 -101
  127. package/dist/components/add/BulkAddView.cjs +0 -165
  128. package/dist/components/add/BulkAddView.d.ts +0 -11
  129. package/dist/components/add/BulkAddView.mjs +0 -163
  130. package/dist/components/add/index.d.ts +0 -2
  131. package/dist/components/index.d.ts +0 -2
  132. package/dist/components/list/EditableTreeItem.d.ts +0 -13
  133. package/dist/components/list/ListCommand.cjs +0 -651
  134. package/dist/components/list/ListCommand.d.ts +0 -5
  135. package/dist/components/list/ListCommand.mjs +0 -649
  136. package/dist/components/list/SyncedPackageTree.d.ts +0 -14
  137. package/dist/components/list/index.d.ts +0 -10
  138. package/dist/components/list/types.d.ts +0 -14
  139. package/dist/components/primitives/Box.d.ts +0 -4
  140. package/dist/components/primitives/Spinner.d.ts +0 -6
  141. package/dist/components/primitives/Text.d.ts +0 -4
  142. package/dist/components/primitives/index.d.ts +0 -3
  143. package/dist/components/remove/RemoveConfirm.cjs +0 -18
  144. package/dist/components/remove/RemoveConfirm.d.ts +0 -11
  145. package/dist/components/remove/RemoveConfirm.mjs +0 -16
  146. package/dist/components/shared/Confirm.cjs +0 -30
  147. package/dist/components/shared/Confirm.d.ts +0 -8
  148. package/dist/components/shared/Confirm.mjs +0 -28
  149. package/dist/components/shared/MenuItem.cjs +0 -18
  150. package/dist/components/shared/MenuItem.d.ts +0 -7
  151. package/dist/components/shared/MenuItem.mjs +0 -16
  152. package/dist/components/shared/ProgressBar.d.ts +0 -7
  153. package/dist/components/shared/StepRunner.cjs +0 -58
  154. package/dist/components/shared/StepRunner.d.ts +0 -15
  155. package/dist/components/shared/StepRunner.mjs +0 -56
  156. package/dist/components/shared/Table.cjs +0 -19
  157. package/dist/components/shared/Table.d.ts +0 -8
  158. package/dist/components/shared/Table.mjs +0 -17
  159. package/dist/components/shared/index.d.ts +0 -6
  160. package/dist/components/status/PackageStatusCard.d.ts +0 -10
  161. package/dist/components/status/StatusDisplay.cjs +0 -26
  162. package/dist/components/status/StatusDisplay.d.ts +0 -23
  163. package/dist/components/status/StatusDisplay.mjs +0 -24
  164. package/dist/components/status/StatusTreeNode.cjs +0 -40
  165. package/dist/components/status/StatusTreeNode.d.ts +0 -15
  166. package/dist/components/status/StatusTreeNode.mjs +0 -38
  167. package/dist/components/status/index.d.ts +0 -6
  168. package/dist/components/tree/AssetTreeNode.cjs +0 -54
  169. package/dist/components/tree/AssetTreeNode.d.ts +0 -12
  170. package/dist/components/tree/AssetTreeNode.mjs +0 -52
  171. package/dist/components/tree/TreeSelect.cjs +0 -129
  172. package/dist/components/tree/TreeSelect.d.ts +0 -12
  173. package/dist/components/tree/TreeSelect.mjs +0 -127
  174. package/dist/components/tree/index.d.ts +0 -4
  175. package/dist/core/assetStructure.cjs +0 -30
  176. package/dist/core/assetStructure.d.ts +0 -36
  177. package/dist/core/assetStructure.mjs +0 -27
  178. package/dist/core/cli.cjs +0 -106
  179. package/dist/core/cli.d.ts +0 -9
  180. package/dist/core/cli.mjs +0 -103
  181. package/dist/core/constants.cjs +0 -28
  182. package/dist/core/constants.d.ts +0 -94
  183. package/dist/core/constants.mjs +0 -21
  184. package/dist/core/filesystem.cjs +0 -98
  185. package/dist/core/filesystem.d.ts +0 -94
  186. package/dist/core/filesystem.mjs +0 -88
  187. package/dist/core/github.cjs +0 -115
  188. package/dist/core/github.d.ts +0 -61
  189. package/dist/core/github.mjs +0 -107
  190. package/dist/core/io.cjs +0 -46
  191. package/dist/core/io.d.ts +0 -40
  192. package/dist/core/io.mjs +0 -39
  193. package/dist/core/listOperations.cjs +0 -228
  194. package/dist/core/listOperations.d.ts +0 -43
  195. package/dist/core/listOperations.mjs +0 -205
  196. package/dist/core/localSource.cjs +0 -126
  197. package/dist/core/localSource.d.ts +0 -33
  198. package/dist/core/localSource.mjs +0 -120
  199. package/dist/core/migration.cjs +0 -201
  200. package/dist/core/migration.d.ts +0 -57
  201. package/dist/core/migration.mjs +0 -198
  202. package/dist/core/packageScanner.cjs +0 -360
  203. package/dist/core/packageScanner.d.ts +0 -22
  204. package/dist/core/packageScanner.mjs +0 -356
  205. package/dist/core/sync.cjs +0 -400
  206. package/dist/core/sync.d.ts +0 -21
  207. package/dist/core/sync.mjs +0 -397
  208. package/dist/core/syncMeta.cjs +0 -242
  209. package/dist/core/syncMeta.d.ts +0 -75
  210. package/dist/core/syncMeta.mjs +0 -229
  211. package/dist/utils/dependencies.cjs +0 -57
  212. package/dist/utils/dependencies.d.ts +0 -10
  213. package/dist/utils/dependencies.mjs +0 -34
  214. package/dist/utils/nameTransform.cjs +0 -13
  215. package/dist/utils/nameTransform.d.ts +0 -65
  216. package/dist/utils/nameTransform.mjs +0 -11
  217. package/dist/utils/package.cjs +0 -170
  218. package/dist/utils/package.d.ts +0 -105
  219. package/dist/utils/package.mjs +0 -157
  220. package/dist/utils/packageName.cjs +0 -24
  221. package/dist/utils/packageName.d.ts +0 -32
  222. package/dist/utils/packageName.mjs +0 -21
  223. package/dist/utils/paths.cjs +0 -18
  224. package/dist/utils/paths.d.ts +0 -55
  225. package/dist/utils/paths.mjs +0 -15
  226. package/dist/version.cjs +0 -5
  227. package/dist/version.d.ts +0 -5
  228. package/dist/version.mjs +0 -3
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from '@slats/claude-assets-sync';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
8
+ const pkg = JSON.parse(
9
+ await readFile(resolve(packageRoot, 'package.json'), 'utf-8'),
10
+ );
11
+
12
+ if (typeof pkg.claude?.assetPath === 'string') {
13
+ runCli(process.argv, {
14
+ packageRoot,
15
+ packageName: pkg.name,
16
+ packageVersion: pkg.version,
17
+ assetPath: pkg.claude.assetPath,
18
+ }).catch((err) => {
19
+ process.stderr.write(
20
+ `[${pkg.name}] claude-sync failed: ${err instanceof Error ? err.message : String(err)}\n`,
21
+ );
22
+ process.exit(1);
23
+ });
24
+ }
@@ -1,4 +1,4 @@
1
- export * from './function';
2
- export * from './object';
3
- export * from './utility';
4
- export * from './unit';
1
+ export * from './function.js';
2
+ export * from './object.js';
3
+ export * from './utility.js';
4
+ export * from './unit.js';
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "package": {
4
+ "name": "@slats/claude-assets-sync",
5
+ "version": "0.2.0"
6
+ },
7
+ "generatedAt": "2026-04-24T04:25:43.386Z",
8
+ "algorithm": "sha256",
9
+ "assetRoot": "docs/claude",
10
+ "files": {
11
+ "skills/claude-sync-applier/SKILL.md": "1c846b7ff7b127217a3201028ec4e1476857e5a5bb38b92d863b92a16ac4c7d0",
12
+ "skills/claude-sync-applier/knowledge/claude-md-template.md": "966fcc668b0e8f43ae83a6111ba1887d5504182e0b138e19937abb1fb43b3318",
13
+ "skills/claude-sync-applier/knowledge/dependency-cruiser.md": "058de112be3c03999846a66d066be540f72f2b1c40f5a1d04a82d36236a3c562",
14
+ "skills/claude-sync-applier/knowledge/gotchas.md": "310ffb416cbcaaf4b9162d0e6004dead6a8d658ff693ffe9e8580a8b83f7b6ea",
15
+ "skills/claude-sync-applier/knowledge/package-json-patches.md": "3ef1c39800e541e6390575a5296a8a247772b58c126c30149cd1efa61ead5dcc",
16
+ "skills/claude-sync-applier/knowledge/reference-files.md": "d0d42df1f90b17d8a35e914bfd16fe381890d71e0ea6a767d1e5e14874f2b95f",
17
+ "skills/claude-sync-applier/knowledge/smoke-tests.md": "76c396e2c7d410920139c894fc52d74e9914ea59d0e41dc30ebfe106e99c4be3"
18
+ },
19
+ "previousVersions": {}
20
+ }
@@ -1,112 +1 @@
1
- /**
2
- * Command registry and exports
3
- */
4
- export * from './types';
5
- export { runSyncCommand } from './sync';
6
- export { runListCommand, registerListCommand } from './list';
7
- export { runRemoveCommand } from './remove';
8
- export { runStatusCommand } from './status';
9
- export { runMigrateCommand } from './migrate';
10
- export { runAddCommand } from './add';
11
- export { runUpdateCommand } from './update';
12
- export type { UpdateCommandOptions } from './update';
13
- /**
14
- * Command metadata for CLI help and documentation
15
- */
16
- export declare const COMMANDS: {
17
- readonly sync: {
18
- readonly name: "sync";
19
- readonly description: "Sync Claude assets from npm packages";
20
- readonly options: readonly [{
21
- readonly flag: "-p, --package <name>";
22
- readonly description: "Package name to sync";
23
- }, {
24
- readonly flag: "-f, --force";
25
- readonly description: "Force sync even if version matches";
26
- }, {
27
- readonly flag: "--dry-run";
28
- readonly description: "Preview changes without writing files";
29
- }, {
30
- readonly flag: "-l, --local";
31
- readonly description: "Read from local workspace";
32
- }, {
33
- readonly flag: "-r, --ref <ref>";
34
- readonly description: "Git ref to fetch from";
35
- }, {
36
- readonly flag: "--no-flat";
37
- readonly description: "Use legacy nested structure";
38
- }];
39
- };
40
- readonly add: {
41
- readonly name: "add";
42
- readonly description: "Add a package with interactive asset selection";
43
- readonly options: readonly [{
44
- readonly flag: "-p, --package <name>";
45
- readonly description: "Package name to add";
46
- }, {
47
- readonly flag: "-l, --local";
48
- readonly description: "Read from local workspace";
49
- }, {
50
- readonly flag: "-r, --ref <ref>";
51
- readonly description: "Git ref to fetch from";
52
- }];
53
- };
54
- readonly list: {
55
- readonly name: "list";
56
- readonly description: "List all synced packages";
57
- readonly options: readonly [{
58
- readonly flag: "--json";
59
- readonly description: "Output as JSON";
60
- }];
61
- };
62
- readonly remove: {
63
- readonly name: "remove";
64
- readonly description: "Remove a synced package";
65
- readonly options: readonly [{
66
- readonly flag: "-p, --package <name>";
67
- readonly description: "Package name to remove";
68
- }, {
69
- readonly flag: "-y, --yes";
70
- readonly description: "Skip confirmation prompt";
71
- }, {
72
- readonly flag: "--dry-run";
73
- readonly description: "Preview changes without removing files";
74
- }];
75
- };
76
- readonly status: {
77
- readonly name: "status";
78
- readonly description: "Show sync status of all packages";
79
- readonly options: readonly [{
80
- readonly flag: "--no-remote";
81
- readonly description: "Skip remote version check";
82
- }];
83
- };
84
- readonly migrate: {
85
- readonly name: "migrate";
86
- readonly description: "Migrate from legacy to flat structure";
87
- readonly options: readonly [{
88
- readonly flag: "--dry-run";
89
- readonly description: "Preview migration without making changes";
90
- }];
91
- };
92
- readonly update: {
93
- readonly name: "update";
94
- readonly description: "Update package metadata in .sync-meta.json";
95
- readonly options: readonly [{
96
- readonly flag: "-p, --package <name>";
97
- readonly description: "Package name to update (default: all)";
98
- }, {
99
- readonly flag: "-l, --local";
100
- readonly description: "Read from local workspace";
101
- }, {
102
- readonly flag: "-r, --ref <ref>";
103
- readonly description: "Git ref to fetch from";
104
- }, {
105
- readonly flag: "--dry-run";
106
- readonly description: "Preview changes without writing";
107
- }, {
108
- readonly flag: "--sync";
109
- readonly description: "Re-sync files after updating metadata";
110
- }];
111
- };
112
- };
1
+ export { runCli, type DefaultFlags, type RunCliOptions, } from './runCli/index.js';
@@ -0,0 +1,2 @@
1
+ export { runCli } from './runCli.js';
2
+ export type { DefaultFlags, RunCliOptions } from './type.js';
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var commander = require('commander');
4
+ var logger = require('../../utils/logger.cjs');
5
+ var version = require('../../utils/version.cjs');
6
+ var runInject = require('./utils/runInject.cjs');
7
+
8
+ async function runCli(argv = process.argv, options) {
9
+ const cmd = new commander.Command();
10
+ cmd
11
+ .name('claude-sync')
12
+ .description("Inject this package's assets into the target .claude directory")
13
+ .version(options.version ?? version.VERSION)
14
+ .option('--scope <scope>', 'Target scope: user (~/.claude) | project (nearest ancestor .claude or <cwd>/.claude)')
15
+ .option('--dry-run', 'Preview without writing', false)
16
+ .option('--force', 'Overwrite user modifications', false)
17
+ .option('--root <path>', 'Override scope resolution cwd (default: cwd)')
18
+ .action(async (flags) => {
19
+ await runInject.runInject(flags, options);
20
+ });
21
+ try {
22
+ await cmd.parseAsync([...argv]);
23
+ }
24
+ catch (err) {
25
+ const msg = err instanceof Error ? err.message : String(err);
26
+ logger.logger.error(msg);
27
+ process.exit(1);
28
+ }
29
+ }
30
+
31
+ exports.runCli = runCli;
@@ -0,0 +1,10 @@
1
+ import type { RunCliOptions } from './type.js';
2
+ /**
3
+ * CLI entry for `@slats/claude-assets-sync`.
4
+ *
5
+ * The caller passes its own package metadata (`packageRoot`, `packageName`,
6
+ * `packageVersion`, `assetPath`) so the library never walks the filesystem
7
+ * looking for consumers. Consumer bin stubs read their own `package.json`
8
+ * and forward the resolved values here.
9
+ */
10
+ export declare function runCli(argv: readonly string[] | undefined, options: RunCliOptions): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { Command } from 'commander';
2
+ import { logger } from '../../utils/logger.mjs';
3
+ import { VERSION } from '../../utils/version.mjs';
4
+ import { runInject } from './utils/runInject.mjs';
5
+
6
+ async function runCli(argv = process.argv, options) {
7
+ const cmd = new Command();
8
+ cmd
9
+ .name('claude-sync')
10
+ .description("Inject this package's assets into the target .claude directory")
11
+ .version(options.version ?? VERSION)
12
+ .option('--scope <scope>', 'Target scope: user (~/.claude) | project (nearest ancestor .claude or <cwd>/.claude)')
13
+ .option('--dry-run', 'Preview without writing', false)
14
+ .option('--force', 'Overwrite user modifications', false)
15
+ .option('--root <path>', 'Override scope resolution cwd (default: cwd)')
16
+ .action(async (flags) => {
17
+ await runInject(flags, options);
18
+ });
19
+ try {
20
+ await cmd.parseAsync([...argv]);
21
+ }
22
+ catch (err) {
23
+ const msg = err instanceof Error ? err.message : String(err);
24
+ logger.error(msg);
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ export { runCli };
@@ -0,0 +1,28 @@
1
+ export interface RunCliOptions {
2
+ version?: string;
3
+ /** Absolute filesystem path to the consumer package root. */
4
+ packageRoot: string;
5
+ /** Consumer package name used in logs and error messages. */
6
+ packageName: string;
7
+ /** Consumer package version used in logs. */
8
+ packageVersion: string;
9
+ /** Asset directory path relative to `packageRoot`. */
10
+ assetPath: string;
11
+ }
12
+ export interface DefaultFlags {
13
+ scope?: string;
14
+ dryRun?: boolean;
15
+ force?: boolean;
16
+ root?: string;
17
+ }
18
+ /**
19
+ * Resolved consumer metadata passed to the injection pipeline.
20
+ * The caller owns the definition; the library does not read `package.json`.
21
+ */
22
+ export interface ConsumerPackage {
23
+ name: string;
24
+ version: string;
25
+ packageRoot: string;
26
+ assetRoot: string;
27
+ hashesPresent: boolean;
28
+ }
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ require('node:crypto');
4
+ require('node:fs/promises');
5
+ require('node:path');
6
+ var injectDocs = require('../../../core/injectDocs/injectDocs.cjs');
7
+ require('node:os');
8
+ require('node:fs');
9
+ require('@inquirer/prompts');
10
+ require('picocolors');
11
+ var confirmForce = require('../../../prompts/confirmForce.cjs');
12
+ var heartbeat = require('../../../utils/heartbeat.cjs');
13
+ var logger = require('../../../utils/logger.cjs');
14
+
15
+ async function injectOne(target, scope, flags, originCwd) {
16
+ if (!target.hashesPresent) {
17
+ logger.logger.warn(`${target.name}: dist/claude-hashes.json missing — build the package (e.g. yarn build) to regenerate the hash manifest first.`);
18
+ return;
19
+ }
20
+ logger.logger.heading(`${target.name}@${target.version}`);
21
+ const stopHeartbeat = heartbeat.startHeartbeat({
22
+ label: `injecting ${target.name}`,
23
+ });
24
+ try {
25
+ const report = await injectDocs.injectDocs({
26
+ packageName: target.name,
27
+ packageVersion: target.version,
28
+ packageRoot: target.packageRoot,
29
+ assetRoot: target.assetRoot,
30
+ scope,
31
+ originCwd,
32
+ dryRun: flags.dryRun ?? false,
33
+ force: flags.force ?? false,
34
+ confirmForce: async (plan) => {
35
+ const diverged = plan.actions.filter((a) => a.kind === 'warn-diverged');
36
+ const orphans = plan.actions.filter((a) => a.kind === 'warn-orphan');
37
+ return confirmForce.confirmForceAsync(diverged.length, orphans.length, [...diverged, ...orphans].map((a) => a.relPath).slice(0, 3));
38
+ },
39
+ });
40
+ if (report.exitCode !== 0)
41
+ process.exit(report.exitCode);
42
+ }
43
+ finally {
44
+ stopHeartbeat();
45
+ }
46
+ }
47
+
48
+ exports.injectOne = injectOne;
@@ -0,0 +1,3 @@
1
+ import { type Scope } from '../../../core/index.js';
2
+ import type { ConsumerPackage, DefaultFlags } from '../type.js';
3
+ export declare function injectOne(target: ConsumerPackage, scope: Scope, flags: DefaultFlags, originCwd: string): Promise<void>;
@@ -0,0 +1,46 @@
1
+ import 'node:crypto';
2
+ import 'node:fs/promises';
3
+ import 'node:path';
4
+ import { injectDocs } from '../../../core/injectDocs/injectDocs.mjs';
5
+ import 'node:os';
6
+ import 'node:fs';
7
+ import '@inquirer/prompts';
8
+ import 'picocolors';
9
+ import { confirmForceAsync } from '../../../prompts/confirmForce.mjs';
10
+ import { startHeartbeat } from '../../../utils/heartbeat.mjs';
11
+ import { logger } from '../../../utils/logger.mjs';
12
+
13
+ async function injectOne(target, scope, flags, originCwd) {
14
+ if (!target.hashesPresent) {
15
+ logger.warn(`${target.name}: dist/claude-hashes.json missing — build the package (e.g. yarn build) to regenerate the hash manifest first.`);
16
+ return;
17
+ }
18
+ logger.heading(`${target.name}@${target.version}`);
19
+ const stopHeartbeat = startHeartbeat({
20
+ label: `injecting ${target.name}`,
21
+ });
22
+ try {
23
+ const report = await injectDocs({
24
+ packageName: target.name,
25
+ packageVersion: target.version,
26
+ packageRoot: target.packageRoot,
27
+ assetRoot: target.assetRoot,
28
+ scope,
29
+ originCwd,
30
+ dryRun: flags.dryRun ?? false,
31
+ force: flags.force ?? false,
32
+ confirmForce: async (plan) => {
33
+ const diverged = plan.actions.filter((a) => a.kind === 'warn-diverged');
34
+ const orphans = plan.actions.filter((a) => a.kind === 'warn-orphan');
35
+ return confirmForceAsync(diverged.length, orphans.length, [...diverged, ...orphans].map((a) => a.relPath).slice(0, 3));
36
+ },
37
+ });
38
+ if (report.exitCode !== 0)
39
+ process.exit(report.exitCode);
40
+ }
41
+ finally {
42
+ stopHeartbeat();
43
+ }
44
+ }
45
+
46
+ export { injectOne };
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ require('node:crypto');
4
+ require('node:fs/promises');
5
+ require('node:path');
6
+ var logger = require('../../../utils/logger.cjs');
7
+ var scope = require('../../../core/scope/scope.cjs');
8
+ var selectScope = require('../../../prompts/selectScope.cjs');
9
+ require('@inquirer/prompts');
10
+ require('picocolors');
11
+
12
+ async function resolveScopeFlag(flag) {
13
+ if (flag) {
14
+ if (!scope.isValidScope(flag)) {
15
+ logger.logger.error(`Invalid --scope: ${flag}. Expected user | project.`);
16
+ process.exit(2);
17
+ }
18
+ return flag;
19
+ }
20
+ if (!scope.isInteractive()) {
21
+ logger.logger.error('--scope is required in non-interactive environments.');
22
+ logger.logger.error(' Pass --scope=user | --scope=project.');
23
+ process.exit(2);
24
+ }
25
+ return selectScope.selectScopeAsync();
26
+ }
27
+
28
+ exports.resolveScopeFlag = resolveScopeFlag;
@@ -0,0 +1,2 @@
1
+ import { type Scope } from '../../../core/index.js';
2
+ export declare function resolveScopeFlag(flag: string | undefined): Promise<Scope>;
@@ -0,0 +1,26 @@
1
+ import 'node:crypto';
2
+ import 'node:fs/promises';
3
+ import 'node:path';
4
+ import { logger } from '../../../utils/logger.mjs';
5
+ import { isValidScope, isInteractive } from '../../../core/scope/scope.mjs';
6
+ import { selectScopeAsync } from '../../../prompts/selectScope.mjs';
7
+ import '@inquirer/prompts';
8
+ import 'picocolors';
9
+
10
+ async function resolveScopeFlag(flag) {
11
+ if (flag) {
12
+ if (!isValidScope(flag)) {
13
+ logger.error(`Invalid --scope: ${flag}. Expected user | project.`);
14
+ process.exit(2);
15
+ }
16
+ return flag;
17
+ }
18
+ if (!isInteractive()) {
19
+ logger.error('--scope is required in non-interactive environments.');
20
+ logger.error(' Pass --scope=user | --scope=project.');
21
+ process.exit(2);
22
+ }
23
+ return selectScopeAsync();
24
+ }
25
+
26
+ export { resolveScopeFlag };
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var promises = require('node:fs/promises');
4
+ var node_path = require('node:path');
5
+ var logger = require('../../../utils/logger.cjs');
6
+ var injectOne = require('./injectOne.cjs');
7
+ var resolveScopeFlag = require('./resolveScopeFlag.cjs');
8
+
9
+ async function runInject(flags, options) {
10
+ if (!options.packageRoot ||
11
+ !options.packageName ||
12
+ !options.packageVersion ||
13
+ !options.assetPath) {
14
+ logger.logger.error('runCli requires { packageRoot, packageName, packageVersion, assetPath }.');
15
+ process.exit(2);
16
+ }
17
+ if (!node_path.isAbsolute(options.packageRoot)) {
18
+ logger.logger.error(`packageRoot must be an absolute path; received: ${options.packageRoot}`);
19
+ process.exit(2);
20
+ }
21
+ const assetRoot = node_path.resolve(options.packageRoot, options.assetPath);
22
+ const hashesPath = node_path.join(options.packageRoot, 'dist', 'claude-hashes.json');
23
+ const hashesPresent = await promises.stat(hashesPath).then(() => true, () => false);
24
+ const target = {
25
+ name: options.packageName,
26
+ version: options.packageVersion,
27
+ packageRoot: options.packageRoot,
28
+ assetRoot,
29
+ hashesPresent,
30
+ };
31
+ const originCwd = flags.root ?? process.cwd();
32
+ const scope = await resolveScopeFlag.resolveScopeFlag(flags.scope);
33
+ await injectOne.injectOne(target, scope, flags, originCwd);
34
+ }
35
+
36
+ exports.runInject = runInject;
@@ -0,0 +1,2 @@
1
+ import type { DefaultFlags, RunCliOptions } from '../type.js';
2
+ export declare function runInject(flags: DefaultFlags, options: RunCliOptions): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { isAbsolute, resolve, join } from 'node:path';
3
+ import { logger } from '../../../utils/logger.mjs';
4
+ import { injectOne } from './injectOne.mjs';
5
+ import { resolveScopeFlag } from './resolveScopeFlag.mjs';
6
+
7
+ async function runInject(flags, options) {
8
+ if (!options.packageRoot ||
9
+ !options.packageName ||
10
+ !options.packageVersion ||
11
+ !options.assetPath) {
12
+ logger.error('runCli requires { packageRoot, packageName, packageVersion, assetPath }.');
13
+ process.exit(2);
14
+ }
15
+ if (!isAbsolute(options.packageRoot)) {
16
+ logger.error(`packageRoot must be an absolute path; received: ${options.packageRoot}`);
17
+ process.exit(2);
18
+ }
19
+ const assetRoot = resolve(options.packageRoot, options.assetPath);
20
+ const hashesPath = join(options.packageRoot, 'dist', 'claude-hashes.json');
21
+ const hashesPresent = await stat(hashesPath).then(() => true, () => false);
22
+ const target = {
23
+ name: options.packageName,
24
+ version: options.packageVersion,
25
+ packageRoot: options.packageRoot,
26
+ assetRoot,
27
+ hashesPresent,
28
+ };
29
+ const originCwd = flags.root ?? process.cwd();
30
+ const scope = await resolveScopeFlag(flags.scope);
31
+ await injectOne(target, scope, flags, originCwd);
32
+ }
33
+
34
+ export { runInject };
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ var node_path = require('node:path');
4
+ var hash = require('../hash/hash.cjs');
5
+ var toPosix = require('./utils/toPosix.cjs');
6
+ var walkFiles = require('./utils/walkFiles.cjs');
7
+
8
+ async function buildPlan(input) {
9
+ const { sourceHashes, targetRoot, namespacePrefixes, force } = input;
10
+ const actions = [];
11
+ let requiresForce = false;
12
+ for (const [relPath, srcHash] of Object.entries(sourceHashes)) {
13
+ const dstAbs = node_path.join(targetRoot, relPath);
14
+ const dstHash = await hash.hashFile(dstAbs);
15
+ if (dstHash === null)
16
+ actions.push({ kind: 'copy', relPath, dstAbs });
17
+ else if (hash.hashEquals(dstHash, srcHash))
18
+ actions.push({ kind: 'skip-uptodate', relPath, dstAbs });
19
+ else {
20
+ actions.push({ kind: 'warn-diverged', relPath, dstAbs });
21
+ requiresForce = true;
22
+ }
23
+ }
24
+ const known = new Set(Object.keys(sourceHashes));
25
+ for (const prefix of namespacePrefixes) {
26
+ const prefixRoot = node_path.join(targetRoot, prefix);
27
+ for await (const abs of walkFiles.walkFiles(prefixRoot)) {
28
+ const relPath = toPosix.toPosix(node_path.relative(targetRoot, abs));
29
+ if (known.has(relPath))
30
+ continue;
31
+ if (force)
32
+ actions.push({ kind: 'delete', relPath, dstAbs: abs });
33
+ else {
34
+ actions.push({ kind: 'warn-orphan', relPath, dstAbs: abs });
35
+ requiresForce = true;
36
+ }
37
+ }
38
+ }
39
+ return { actions, requiresForce };
40
+ }
41
+
42
+ exports.buildPlan = buildPlan;
@@ -0,0 +1,2 @@
1
+ import type { InjectPlan, PlanInput } from './type.js';
2
+ export declare function buildPlan(input: PlanInput): Promise<InjectPlan>;
@@ -0,0 +1,40 @@
1
+ import { join, relative } from 'node:path';
2
+ import { hashFile, hashEquals } from '../hash/hash.mjs';
3
+ import { toPosix } from './utils/toPosix.mjs';
4
+ import { walkFiles } from './utils/walkFiles.mjs';
5
+
6
+ async function buildPlan(input) {
7
+ const { sourceHashes, targetRoot, namespacePrefixes, force } = input;
8
+ const actions = [];
9
+ let requiresForce = false;
10
+ for (const [relPath, srcHash] of Object.entries(sourceHashes)) {
11
+ const dstAbs = join(targetRoot, relPath);
12
+ const dstHash = await hashFile(dstAbs);
13
+ if (dstHash === null)
14
+ actions.push({ kind: 'copy', relPath, dstAbs });
15
+ else if (hashEquals(dstHash, srcHash))
16
+ actions.push({ kind: 'skip-uptodate', relPath, dstAbs });
17
+ else {
18
+ actions.push({ kind: 'warn-diverged', relPath, dstAbs });
19
+ requiresForce = true;
20
+ }
21
+ }
22
+ const known = new Set(Object.keys(sourceHashes));
23
+ for (const prefix of namespacePrefixes) {
24
+ const prefixRoot = join(targetRoot, prefix);
25
+ for await (const abs of walkFiles(prefixRoot)) {
26
+ const relPath = toPosix(relative(targetRoot, abs));
27
+ if (known.has(relPath))
28
+ continue;
29
+ if (force)
30
+ actions.push({ kind: 'delete', relPath, dstAbs: abs });
31
+ else {
32
+ actions.push({ kind: 'warn-orphan', relPath, dstAbs: abs });
33
+ requiresForce = true;
34
+ }
35
+ }
36
+ }
37
+ return { actions, requiresForce };
38
+ }
39
+
40
+ export { buildPlan };
@@ -0,0 +1,2 @@
1
+ export { buildPlan } from './buildPlan.js';
2
+ export type { Action, InjectPlan, PlanInput } from './type.js';
@@ -0,0 +1,32 @@
1
+ import type { Sha256Hex } from '../hash/index.js';
2
+ export type Action = {
3
+ kind: 'copy';
4
+ relPath: string;
5
+ dstAbs: string;
6
+ } | {
7
+ kind: 'skip-uptodate';
8
+ relPath: string;
9
+ dstAbs: string;
10
+ } | {
11
+ kind: 'warn-diverged';
12
+ relPath: string;
13
+ dstAbs: string;
14
+ } | {
15
+ kind: 'warn-orphan';
16
+ relPath: string;
17
+ dstAbs: string;
18
+ } | {
19
+ kind: 'delete';
20
+ relPath: string;
21
+ dstAbs: string;
22
+ };
23
+ export interface InjectPlan {
24
+ actions: Action[];
25
+ requiresForce: boolean;
26
+ }
27
+ export interface PlanInput {
28
+ sourceHashes: Record<string, Sha256Hex>;
29
+ targetRoot: string;
30
+ namespacePrefixes: string[];
31
+ force: boolean;
32
+ }
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ var node_path = require('node:path');
4
+
5
+ function toPosix(p) {
6
+ return node_path.sep === '/' ? p : p.split(node_path.sep).join('/');
7
+ }
8
+
9
+ exports.toPosix = toPosix;
@@ -0,0 +1 @@
1
+ export declare function toPosix(p: string): string;
@@ -0,0 +1,7 @@
1
+ import { sep } from 'node:path';
2
+
3
+ function toPosix(p) {
4
+ return sep === '/' ? p : p.split(sep).join('/');
5
+ }
6
+
7
+ export { toPosix };