@slats/claude-assets-sync 0.1.4 → 0.3.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 (239) hide show
  1. package/README.md +89 -581
  2. package/bin/inject-claude-settings.mjs +4 -0
  3. package/dist/claude-hashes.json +20 -0
  4. package/dist/commands/index.d.ts +1 -112
  5. package/dist/commands/runCli/index.d.ts +2 -0
  6. package/dist/commands/runCli/runCli.cjs +53 -0
  7. package/dist/commands/runCli/runCli.d.ts +14 -0
  8. package/dist/commands/runCli/runCli.mjs +51 -0
  9. package/dist/commands/runCli/type.d.ts +19 -0
  10. package/dist/commands/runCli/utils/classifyTarget.cjs +48 -0
  11. package/dist/commands/runCli/utils/classifyTarget.d.ts +19 -0
  12. package/dist/commands/runCli/utils/classifyTarget.mjs +46 -0
  13. package/dist/commands/runCli/utils/injectOne.cjs +47 -0
  14. package/dist/commands/runCli/utils/injectOne.d.ts +3 -0
  15. package/dist/commands/runCli/utils/injectOne.mjs +45 -0
  16. package/dist/commands/runCli/utils/resolvePackage.cjs +77 -0
  17. package/dist/commands/runCli/utils/resolvePackage.d.ts +16 -0
  18. package/dist/commands/runCli/utils/resolvePackage.mjs +74 -0
  19. package/dist/commands/runCli/utils/resolveScopeAlias.cjs +69 -0
  20. package/dist/commands/runCli/utils/resolveScopeAlias.d.ts +2 -0
  21. package/dist/commands/runCli/utils/resolveScopeAlias.mjs +67 -0
  22. package/dist/commands/runCli/utils/resolveScopeFlag.cjs +28 -0
  23. package/dist/commands/runCli/utils/resolveScopeFlag.d.ts +2 -0
  24. package/dist/commands/runCli/utils/resolveScopeFlag.mjs +26 -0
  25. package/dist/commands/runCli/utils/resolveTargets.cjs +40 -0
  26. package/dist/commands/runCli/utils/resolveTargets.d.ts +15 -0
  27. package/dist/commands/runCli/utils/resolveTargets.mjs +38 -0
  28. package/dist/commands/runCli/utils/runInject.cjs +52 -0
  29. package/dist/commands/runCli/utils/runInject.d.ts +3 -0
  30. package/dist/commands/runCli/utils/runInject.mjs +50 -0
  31. package/dist/core/buildPlan/buildPlan.cjs +42 -0
  32. package/dist/core/buildPlan/buildPlan.d.ts +2 -0
  33. package/dist/core/buildPlan/buildPlan.mjs +40 -0
  34. package/dist/core/buildPlan/index.d.ts +2 -0
  35. package/dist/core/buildPlan/type.d.ts +32 -0
  36. package/dist/core/buildPlan/utils/toPosix.cjs +9 -0
  37. package/dist/core/buildPlan/utils/toPosix.d.ts +1 -0
  38. package/dist/core/buildPlan/utils/toPosix.mjs +7 -0
  39. package/dist/core/buildPlan/utils/walkFiles.cjs +25 -0
  40. package/dist/core/buildPlan/utils/walkFiles.d.ts +1 -0
  41. package/dist/core/buildPlan/utils/walkFiles.mjs +23 -0
  42. package/dist/core/hash/hash.cjs +30 -0
  43. package/dist/core/hash/hash.d.ts +4 -0
  44. package/dist/core/hash/hash.mjs +26 -0
  45. package/dist/core/hash/index.d.ts +1 -0
  46. package/dist/core/hashManifest/hashManifest.cjs +27 -0
  47. package/dist/core/hashManifest/hashManifest.d.ts +17 -0
  48. package/dist/core/hashManifest/hashManifest.mjs +23 -0
  49. package/dist/core/hashManifest/index.d.ts +1 -0
  50. package/dist/core/index.d.ts +5 -0
  51. package/dist/core/injectDocs/index.d.ts +2 -0
  52. package/dist/core/injectDocs/injectDocs.cjs +43 -0
  53. package/dist/core/injectDocs/injectDocs.d.ts +2 -0
  54. package/dist/core/injectDocs/injectDocs.mjs +41 -0
  55. package/dist/core/injectDocs/type.d.ts +30 -0
  56. package/dist/core/injectDocs/utils/applyAction.cjs +21 -0
  57. package/dist/core/injectDocs/utils/applyAction.d.ts +2 -0
  58. package/dist/core/injectDocs/utils/applyAction.mjs +19 -0
  59. package/dist/core/injectDocs/utils/emitCiForceList.cjs +10 -0
  60. package/dist/core/injectDocs/utils/emitCiForceList.d.ts +2 -0
  61. package/dist/core/injectDocs/utils/emitCiForceList.mjs +8 -0
  62. package/dist/core/injectDocs/utils/printPlan.cjs +20 -0
  63. package/dist/core/injectDocs/utils/printPlan.d.ts +2 -0
  64. package/dist/core/injectDocs/utils/printPlan.mjs +18 -0
  65. package/dist/core/injectDocs/utils/summarize.cjs +27 -0
  66. package/dist/core/injectDocs/utils/summarize.d.ts +3 -0
  67. package/dist/core/injectDocs/utils/summarize.mjs +25 -0
  68. package/dist/core/scope/index.d.ts +1 -0
  69. package/dist/core/scope/scope.cjs +46 -0
  70. package/dist/core/scope/scope.d.ts +16 -0
  71. package/dist/core/scope/scope.mjs +41 -0
  72. package/dist/core/scope/utils/isDirectory.cjs +14 -0
  73. package/dist/core/scope/utils/isDirectory.d.ts +1 -0
  74. package/dist/core/scope/utils/isDirectory.mjs +12 -0
  75. package/dist/index.cjs +15 -9
  76. package/dist/index.d.ts +3 -5
  77. package/dist/index.mjs +7 -3
  78. package/dist/prompts/confirmForce.cjs +27 -0
  79. package/dist/prompts/confirmForce.d.ts +1 -0
  80. package/dist/prompts/confirmForce.mjs +25 -0
  81. package/dist/prompts/index.d.ts +2 -0
  82. package/dist/prompts/selectScope.cjs +30 -0
  83. package/dist/prompts/selectScope.d.ts +2 -0
  84. package/dist/prompts/selectScope.mjs +28 -0
  85. package/dist/utils/heartbeat.cjs +25 -0
  86. package/dist/utils/heartbeat.d.ts +16 -0
  87. package/dist/utils/heartbeat.mjs +23 -0
  88. package/dist/utils/logger.cjs +7 -0
  89. package/dist/utils/logger.d.ts +8 -0
  90. package/dist/utils/logger.mjs +7 -0
  91. package/dist/utils/types.d.ts +1 -252
  92. package/dist/utils/version.cjs +2 -14
  93. package/dist/utils/version.d.ts +3 -53
  94. package/dist/utils/version.mjs +2 -13
  95. package/docs/bundle-size-decision.md +36 -0
  96. package/docs/claude/skills/claude-docs-asset-wiring/SKILL.md +159 -0
  97. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/claude-md-template.md +86 -0
  98. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/dependency-cruiser.md +54 -0
  99. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/gotchas.md +122 -0
  100. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/package-json-patches.md +145 -0
  101. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/reference-files.md +37 -0
  102. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/smoke-tests.md +111 -0
  103. package/docs/consumer-integration.md +94 -0
  104. package/package.json +24 -16
  105. package/scripts/build-hashes.mjs +30 -0
  106. package/scripts/buildHashes.d.mts +15 -0
  107. package/scripts/buildHashes.mjs +82 -0
  108. package/scripts/claude-build-hashes.mjs +42 -0
  109. package/scripts/inject-version.js +112 -0
  110. package/dist/cli.cjs +0 -8
  111. package/dist/cli.d.ts +0 -1
  112. package/dist/cli.mjs +0 -7
  113. package/dist/commands/add.cjs +0 -80
  114. package/dist/commands/add.d.ts +0 -8
  115. package/dist/commands/add.mjs +0 -78
  116. package/dist/commands/list.cjs +0 -94
  117. package/dist/commands/list.d.ts +0 -15
  118. package/dist/commands/list.mjs +0 -91
  119. package/dist/commands/migrate.cjs +0 -9
  120. package/dist/commands/migrate.d.ts +0 -6
  121. package/dist/commands/migrate.mjs +0 -7
  122. package/dist/commands/remove.cjs +0 -127
  123. package/dist/commands/remove.d.ts +0 -6
  124. package/dist/commands/remove.mjs +0 -105
  125. package/dist/commands/status.cjs +0 -193
  126. package/dist/commands/status.d.ts +0 -6
  127. package/dist/commands/status.mjs +0 -171
  128. package/dist/commands/sync.cjs +0 -28
  129. package/dist/commands/sync.d.ts +0 -6
  130. package/dist/commands/sync.mjs +0 -26
  131. package/dist/commands/types.d.ts +0 -89
  132. package/dist/commands/update.cjs +0 -209
  133. package/dist/commands/update.d.ts +0 -29
  134. package/dist/commands/update.mjs +0 -206
  135. package/dist/components/add/AddCommand.cjs +0 -103
  136. package/dist/components/add/AddCommand.d.ts +0 -14
  137. package/dist/components/add/AddCommand.mjs +0 -101
  138. package/dist/components/add/BulkAddView.cjs +0 -165
  139. package/dist/components/add/BulkAddView.d.ts +0 -11
  140. package/dist/components/add/BulkAddView.mjs +0 -163
  141. package/dist/components/add/index.d.ts +0 -2
  142. package/dist/components/index.d.ts +0 -2
  143. package/dist/components/list/EditableTreeItem.d.ts +0 -13
  144. package/dist/components/list/ListCommand.cjs +0 -651
  145. package/dist/components/list/ListCommand.d.ts +0 -5
  146. package/dist/components/list/ListCommand.mjs +0 -649
  147. package/dist/components/list/SyncedPackageTree.d.ts +0 -14
  148. package/dist/components/list/index.d.ts +0 -10
  149. package/dist/components/list/types.d.ts +0 -14
  150. package/dist/components/primitives/Box.d.ts +0 -4
  151. package/dist/components/primitives/Spinner.d.ts +0 -6
  152. package/dist/components/primitives/Text.d.ts +0 -4
  153. package/dist/components/primitives/index.d.ts +0 -3
  154. package/dist/components/remove/RemoveConfirm.cjs +0 -18
  155. package/dist/components/remove/RemoveConfirm.d.ts +0 -11
  156. package/dist/components/remove/RemoveConfirm.mjs +0 -16
  157. package/dist/components/shared/Confirm.cjs +0 -30
  158. package/dist/components/shared/Confirm.d.ts +0 -8
  159. package/dist/components/shared/Confirm.mjs +0 -28
  160. package/dist/components/shared/MenuItem.cjs +0 -18
  161. package/dist/components/shared/MenuItem.d.ts +0 -7
  162. package/dist/components/shared/MenuItem.mjs +0 -16
  163. package/dist/components/shared/ProgressBar.d.ts +0 -7
  164. package/dist/components/shared/StepRunner.cjs +0 -58
  165. package/dist/components/shared/StepRunner.d.ts +0 -15
  166. package/dist/components/shared/StepRunner.mjs +0 -56
  167. package/dist/components/shared/Table.cjs +0 -19
  168. package/dist/components/shared/Table.d.ts +0 -8
  169. package/dist/components/shared/Table.mjs +0 -17
  170. package/dist/components/shared/index.d.ts +0 -6
  171. package/dist/components/status/PackageStatusCard.d.ts +0 -10
  172. package/dist/components/status/StatusDisplay.cjs +0 -26
  173. package/dist/components/status/StatusDisplay.d.ts +0 -23
  174. package/dist/components/status/StatusDisplay.mjs +0 -24
  175. package/dist/components/status/StatusTreeNode.cjs +0 -40
  176. package/dist/components/status/StatusTreeNode.d.ts +0 -15
  177. package/dist/components/status/StatusTreeNode.mjs +0 -38
  178. package/dist/components/status/index.d.ts +0 -6
  179. package/dist/components/tree/AssetTreeNode.cjs +0 -54
  180. package/dist/components/tree/AssetTreeNode.d.ts +0 -12
  181. package/dist/components/tree/AssetTreeNode.mjs +0 -52
  182. package/dist/components/tree/TreeSelect.cjs +0 -129
  183. package/dist/components/tree/TreeSelect.d.ts +0 -12
  184. package/dist/components/tree/TreeSelect.mjs +0 -127
  185. package/dist/components/tree/index.d.ts +0 -4
  186. package/dist/core/assetStructure.cjs +0 -30
  187. package/dist/core/assetStructure.d.ts +0 -36
  188. package/dist/core/assetStructure.mjs +0 -27
  189. package/dist/core/cli.cjs +0 -106
  190. package/dist/core/cli.d.ts +0 -9
  191. package/dist/core/cli.mjs +0 -103
  192. package/dist/core/constants.cjs +0 -28
  193. package/dist/core/constants.d.ts +0 -94
  194. package/dist/core/constants.mjs +0 -21
  195. package/dist/core/filesystem.cjs +0 -98
  196. package/dist/core/filesystem.d.ts +0 -94
  197. package/dist/core/filesystem.mjs +0 -88
  198. package/dist/core/github.cjs +0 -115
  199. package/dist/core/github.d.ts +0 -61
  200. package/dist/core/github.mjs +0 -107
  201. package/dist/core/io.cjs +0 -46
  202. package/dist/core/io.d.ts +0 -40
  203. package/dist/core/io.mjs +0 -39
  204. package/dist/core/listOperations.cjs +0 -228
  205. package/dist/core/listOperations.d.ts +0 -43
  206. package/dist/core/listOperations.mjs +0 -205
  207. package/dist/core/localSource.cjs +0 -126
  208. package/dist/core/localSource.d.ts +0 -33
  209. package/dist/core/localSource.mjs +0 -120
  210. package/dist/core/migration.cjs +0 -201
  211. package/dist/core/migration.d.ts +0 -57
  212. package/dist/core/migration.mjs +0 -198
  213. package/dist/core/packageScanner.cjs +0 -360
  214. package/dist/core/packageScanner.d.ts +0 -22
  215. package/dist/core/packageScanner.mjs +0 -356
  216. package/dist/core/sync.cjs +0 -400
  217. package/dist/core/sync.d.ts +0 -21
  218. package/dist/core/sync.mjs +0 -397
  219. package/dist/core/syncMeta.cjs +0 -242
  220. package/dist/core/syncMeta.d.ts +0 -75
  221. package/dist/core/syncMeta.mjs +0 -229
  222. package/dist/utils/dependencies.cjs +0 -57
  223. package/dist/utils/dependencies.d.ts +0 -10
  224. package/dist/utils/dependencies.mjs +0 -34
  225. package/dist/utils/nameTransform.cjs +0 -13
  226. package/dist/utils/nameTransform.d.ts +0 -65
  227. package/dist/utils/nameTransform.mjs +0 -11
  228. package/dist/utils/package.cjs +0 -170
  229. package/dist/utils/package.d.ts +0 -105
  230. package/dist/utils/package.mjs +0 -157
  231. package/dist/utils/packageName.cjs +0 -24
  232. package/dist/utils/packageName.d.ts +0 -32
  233. package/dist/utils/packageName.mjs +0 -21
  234. package/dist/utils/paths.cjs +0 -18
  235. package/dist/utils/paths.d.ts +0 -55
  236. package/dist/utils/paths.mjs +0 -15
  237. package/dist/version.cjs +0 -5
  238. package/dist/version.d.ts +0 -5
  239. package/dist/version.mjs +0 -3
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from '@slats/claude-assets-sync';
3
+
4
+ await runCli(process.argv);
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "package": {
4
+ "name": "@slats/claude-assets-sync",
5
+ "version": "0.3.0"
6
+ },
7
+ "generatedAt": "2026-04-24T14:51:13.873Z",
8
+ "algorithm": "sha256",
9
+ "assetRoot": "docs/claude",
10
+ "files": {
11
+ "skills/claude-docs-asset-wiring/SKILL.md": "1984ed9ea93be0e7b8eec8f77d57c455e670989c3948546d017343e321fe1b80",
12
+ "skills/claude-docs-asset-wiring/knowledge/claude-md-template.md": "affd92189e9d367c8717068695aca8acbadf68989a4073a8c4b1e2f4a622b72d",
13
+ "skills/claude-docs-asset-wiring/knowledge/dependency-cruiser.md": "18e994bd16242f72a4dc6cfa508493f4b63853a7a16c4910c7b7abd0368bd103",
14
+ "skills/claude-docs-asset-wiring/knowledge/gotchas.md": "9957464329cc970f6717179fad907ffad45ee4433b1d6151e20b5b3bee75b775",
15
+ "skills/claude-docs-asset-wiring/knowledge/package-json-patches.md": "426dcfdfdd5c02405c3d8a753b800fc90e1e9286d6f1c3c29320cf13e2645878",
16
+ "skills/claude-docs-asset-wiring/knowledge/reference-files.md": "3a63a095826bbfd07fae232568faf4d415dbdae0970ee4466c962ba285c3a01d",
17
+ "skills/claude-docs-asset-wiring/knowledge/smoke-tests.md": "c90fc82d46bf4b55d794c2ce463b4c1e199d13d6b1161028486fb4bbbd6a60fe"
18
+ },
19
+ "previousVersions": {}
20
+ }
@@ -1,112 +1 @@
1
- /**
2
- * Command registry and exports
3
- */
4
- export * from './types.js';
5
- export { runSyncCommand } from './sync.js';
6
- export { runListCommand, registerListCommand } from './list.js';
7
- export { runRemoveCommand } from './remove.js';
8
- export { runStatusCommand } from './status.js';
9
- export { runMigrateCommand } from './migrate.js';
10
- export { runAddCommand } from './add.js';
11
- export { runUpdateCommand } from './update.js';
12
- export type { UpdateCommandOptions } from './update.js';
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 } from './runCli/index.js';
@@ -0,0 +1,2 @@
1
+ export { runCli } from './runCli.js';
2
+ export type { DefaultFlags } from './type.js';
@@ -0,0 +1,53 @@
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 resolveTargets = require('./utils/resolveTargets.cjs');
7
+ var runInject = require('./utils/runInject.cjs');
8
+
9
+ async function runCli(argv = process.argv) {
10
+ const cmd = new commander.Command();
11
+ cmd
12
+ .name('inject-claude-settings')
13
+ .description("Inject target consumer(s)' Claude assets into the selected .claude directory")
14
+ .version(version.VERSION)
15
+ .option('--package <name...>', 'Target(s). "@<scope>" = whole npm scope; "@<scope>/<name>" or "<name>" = one package. Repeat the flag or comma-separate values.', collectPackageValues, [])
16
+ .option('--scope <scope>', 'Target scope: user (~/.claude) | project (nearest ancestor .claude or <cwd>/.claude)')
17
+ .option('--dry-run', 'Preview without writing', false)
18
+ .option('--force', 'Overwrite user modifications', false)
19
+ .option('--root <path>', 'Override scope resolution cwd (default: cwd)')
20
+ .action(async (flags) => {
21
+ const targets = flags.package ?? [];
22
+ if (targets.length === 0) {
23
+ logger.logger.error('missing required flag: --package <name> (e.g. --package=@canard/schema-form or --package=@canard)');
24
+ process.exit(2);
25
+ }
26
+ const originCwd = flags.root ?? process.cwd();
27
+ const metadataList = await resolveTargets.resolveTargets(targets, originCwd);
28
+ if (metadataList.length === 0) {
29
+ logger.logger.warn(`no packages resolved from --package target(s): ${targets.join(', ')}`);
30
+ return;
31
+ }
32
+ await runInject.runInject(flags, metadataList);
33
+ });
34
+ try {
35
+ await cmd.parseAsync([...argv]);
36
+ }
37
+ catch (err) {
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ logger.logger.error(msg);
40
+ process.exit(1);
41
+ }
42
+ }
43
+ function collectPackageValues(value, previous = []) {
44
+ return [
45
+ ...previous,
46
+ ...value
47
+ .split(',')
48
+ .map((s) => s.trim())
49
+ .filter(Boolean),
50
+ ];
51
+ }
52
+
53
+ exports.runCli = runCli;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * CLI entry for `@slats/claude-assets-sync`.
3
+ *
4
+ * The `inject-claude-settings` dispatcher parses `--package <name...>`
5
+ * from argv and classifies each value:
6
+ * - `@<scope>` — enumerate every workspace package under that scope
7
+ * - `@<scope>/<name>` — one scoped package
8
+ * - `<name>` — one unscoped package
9
+ *
10
+ * Targets are resolved via Node module resolution (`resolvePackage`)
11
+ * except for scope aliases, which are the only path allowed to walk
12
+ * the monorepo — that exception is isolated to `resolveScopeAlias.ts`.
13
+ */
14
+ export declare function runCli(argv?: readonly string[]): Promise<void>;
@@ -0,0 +1,51 @@
1
+ import { Command } from 'commander';
2
+ import { logger } from '../../utils/logger.mjs';
3
+ import { VERSION } from '../../utils/version.mjs';
4
+ import { resolveTargets } from './utils/resolveTargets.mjs';
5
+ import { runInject } from './utils/runInject.mjs';
6
+
7
+ async function runCli(argv = process.argv) {
8
+ const cmd = new Command();
9
+ cmd
10
+ .name('inject-claude-settings')
11
+ .description("Inject target consumer(s)' Claude assets into the selected .claude directory")
12
+ .version(VERSION)
13
+ .option('--package <name...>', 'Target(s). "@<scope>" = whole npm scope; "@<scope>/<name>" or "<name>" = one package. Repeat the flag or comma-separate values.', collectPackageValues, [])
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
+ const targets = flags.package ?? [];
20
+ if (targets.length === 0) {
21
+ logger.error('missing required flag: --package <name> (e.g. --package=@canard/schema-form or --package=@canard)');
22
+ process.exit(2);
23
+ }
24
+ const originCwd = flags.root ?? process.cwd();
25
+ const metadataList = await resolveTargets(targets, originCwd);
26
+ if (metadataList.length === 0) {
27
+ logger.warn(`no packages resolved from --package target(s): ${targets.join(', ')}`);
28
+ return;
29
+ }
30
+ await runInject(flags, metadataList);
31
+ });
32
+ try {
33
+ await cmd.parseAsync([...argv]);
34
+ }
35
+ catch (err) {
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ logger.error(msg);
38
+ process.exit(1);
39
+ }
40
+ }
41
+ function collectPackageValues(value, previous = []) {
42
+ return [
43
+ ...previous,
44
+ ...value
45
+ .split(',')
46
+ .map((s) => s.trim())
47
+ .filter(Boolean),
48
+ ];
49
+ }
50
+
51
+ export { runCli };
@@ -0,0 +1,19 @@
1
+ export interface DefaultFlags {
2
+ scope?: string;
3
+ dryRun?: boolean;
4
+ force?: boolean;
5
+ root?: string;
6
+ package?: string[];
7
+ }
8
+ /**
9
+ * Resolved consumer metadata passed to the injection pipeline.
10
+ * The dispatcher bin populates this by resolving a single explicitly-named
11
+ * target package — `core/**` still never reads `package.json` itself.
12
+ */
13
+ export interface ConsumerPackage {
14
+ name: string;
15
+ version: string;
16
+ packageRoot: string;
17
+ assetRoot: string;
18
+ hashesPresent: boolean;
19
+ }
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const NPM_NAME_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
4
+ function classifyTarget(target) {
5
+ if (typeof target !== 'string' || target.length === 0) {
6
+ return { kind: 'invalid', reason: 'empty --package value' };
7
+ }
8
+ if (target.startsWith('@')) {
9
+ const body = target.slice(1);
10
+ const slashIndex = body.indexOf('/');
11
+ if (slashIndex === -1) {
12
+ if (!NPM_NAME_PATTERN.test(body)) {
13
+ return {
14
+ kind: 'invalid',
15
+ reason: `invalid scope alias "${target}" — expected "@<scope>" with lowercase alphanumerics, ".", "-", or "_"`,
16
+ };
17
+ }
18
+ return { kind: 'scope', scope: body };
19
+ }
20
+ const scopePart = body.slice(0, slashIndex);
21
+ const namePart = body.slice(slashIndex + 1);
22
+ if (!NPM_NAME_PATTERN.test(scopePart) ||
23
+ namePart.length === 0 ||
24
+ namePart.includes('/') ||
25
+ !NPM_NAME_PATTERN.test(namePart)) {
26
+ return {
27
+ kind: 'invalid',
28
+ reason: `invalid scoped package "${target}" — expected "@<scope>/<name>"`,
29
+ };
30
+ }
31
+ return { kind: 'package', name: target };
32
+ }
33
+ if (target.includes('/')) {
34
+ return {
35
+ kind: 'invalid',
36
+ reason: `invalid target "${target}" — unscoped package names cannot contain "/"`,
37
+ };
38
+ }
39
+ if (!NPM_NAME_PATTERN.test(target)) {
40
+ return {
41
+ kind: 'invalid',
42
+ reason: `invalid package name "${target}" — expected lowercase alphanumerics, ".", "-", or "_"`,
43
+ };
44
+ }
45
+ return { kind: 'package', name: target };
46
+ }
47
+
48
+ exports.classifyTarget = classifyTarget;
@@ -0,0 +1,19 @@
1
+ export type ClassifiedTarget = {
2
+ kind: 'scope';
3
+ scope: string;
4
+ } | {
5
+ kind: 'package';
6
+ name: string;
7
+ } | {
8
+ kind: 'invalid';
9
+ reason: string;
10
+ };
11
+ /**
12
+ * Classify a `--package` value as a scope alias, a package name, or invalid.
13
+ *
14
+ * - `@<scope>` (no slash) — all packages under that npm scope
15
+ * - `@<scope>/<name>` — one scoped package
16
+ * - `<name>` (no `@`, no slash) — one unscoped package
17
+ * - anything else → invalid
18
+ */
19
+ export declare function classifyTarget(target: string): ClassifiedTarget;
@@ -0,0 +1,46 @@
1
+ const NPM_NAME_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
2
+ function classifyTarget(target) {
3
+ if (typeof target !== 'string' || target.length === 0) {
4
+ return { kind: 'invalid', reason: 'empty --package value' };
5
+ }
6
+ if (target.startsWith('@')) {
7
+ const body = target.slice(1);
8
+ const slashIndex = body.indexOf('/');
9
+ if (slashIndex === -1) {
10
+ if (!NPM_NAME_PATTERN.test(body)) {
11
+ return {
12
+ kind: 'invalid',
13
+ reason: `invalid scope alias "${target}" — expected "@<scope>" with lowercase alphanumerics, ".", "-", or "_"`,
14
+ };
15
+ }
16
+ return { kind: 'scope', scope: body };
17
+ }
18
+ const scopePart = body.slice(0, slashIndex);
19
+ const namePart = body.slice(slashIndex + 1);
20
+ if (!NPM_NAME_PATTERN.test(scopePart) ||
21
+ namePart.length === 0 ||
22
+ namePart.includes('/') ||
23
+ !NPM_NAME_PATTERN.test(namePart)) {
24
+ return {
25
+ kind: 'invalid',
26
+ reason: `invalid scoped package "${target}" — expected "@<scope>/<name>"`,
27
+ };
28
+ }
29
+ return { kind: 'package', name: target };
30
+ }
31
+ if (target.includes('/')) {
32
+ return {
33
+ kind: 'invalid',
34
+ reason: `invalid target "${target}" — unscoped package names cannot contain "/"`,
35
+ };
36
+ }
37
+ if (!NPM_NAME_PATTERN.test(target)) {
38
+ return {
39
+ kind: 'invalid',
40
+ reason: `invalid package name "${target}" — expected lowercase alphanumerics, ".", "-", or "_"`,
41
+ };
42
+ }
43
+ return { kind: 'package', name: target };
44
+ }
45
+
46
+ export { classifyTarget };
@@ -0,0 +1,47 @@
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 0;
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
+ return report.exitCode;
41
+ }
42
+ finally {
43
+ stopHeartbeat();
44
+ }
45
+ }
46
+
47
+ 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<number>;
@@ -0,0 +1,45 @@
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 0;
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
+ return report.exitCode;
39
+ }
40
+ finally {
41
+ stopHeartbeat();
42
+ }
43
+ }
44
+
45
+ export { injectOne };
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ var node_fs = require('node:fs');
4
+ var promises = require('node:fs/promises');
5
+ var node_module = require('node:module');
6
+ var node_path = require('node:path');
7
+ var logger = require('../../../utils/logger.cjs');
8
+
9
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
10
+ async function resolvePackage(name, options = {}) {
11
+ const pkgJsonPath = resolvePackageJsonPath(name);
12
+ if (!pkgJsonPath) {
13
+ logger.logger.error(`cannot resolve package "${name}". Install it in the current project or pass the correct name.`);
14
+ process.exit(2);
15
+ }
16
+ const packageRoot = node_path.dirname(pkgJsonPath);
17
+ const raw = await promises.readFile(pkgJsonPath, 'utf-8');
18
+ const pkg = JSON.parse(raw);
19
+ if (typeof pkg.name !== 'string' || typeof pkg.version !== 'string') {
20
+ if (options.skipMissingAsset) {
21
+ logger.logger.warn(`"${name}" package.json is missing a string "name" or "version" — skipping.`);
22
+ return null;
23
+ }
24
+ logger.logger.error(`${pkgJsonPath} must define string "name" and "version".`);
25
+ process.exit(2);
26
+ }
27
+ const assetPath = pkg.claude?.assetPath;
28
+ if (typeof assetPath !== 'string' || assetPath.length === 0) {
29
+ if (options.skipMissingAsset) {
30
+ logger.logger.warn(`"${name}" is missing "claude.assetPath" — skipping (the package does not ship Claude assets).`);
31
+ return null;
32
+ }
33
+ logger.logger.error(`"${name}" is missing "claude.assetPath" in its package.json — the package does not ship Claude assets.`);
34
+ process.exit(2);
35
+ }
36
+ return {
37
+ packageRoot,
38
+ packageName: pkg.name,
39
+ packageVersion: pkg.version,
40
+ assetPath,
41
+ };
42
+ }
43
+ function resolvePackageJsonPath(name) {
44
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('commands/runCli/utils/resolvePackage.cjs', document.baseURI).href)));
45
+ try {
46
+ return require$1.resolve(`${name}/package.json`);
47
+ }
48
+ catch (err) {
49
+ const code = err?.code;
50
+ if (code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED')
51
+ return null;
52
+ }
53
+ let mainEntry;
54
+ try {
55
+ mainEntry = require$1.resolve(name);
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ let dir = node_path.dirname(mainEntry);
61
+ while (dir && dir !== node_path.dirname(dir)) {
62
+ const candidate = node_path.resolve(dir, 'package.json');
63
+ if (node_fs.existsSync(candidate)) {
64
+ try {
65
+ const pkg = JSON.parse(node_fs.readFileSync(candidate, 'utf-8'));
66
+ if (pkg.name === name)
67
+ return candidate;
68
+ }
69
+ catch {
70
+ }
71
+ }
72
+ dir = node_path.dirname(dir);
73
+ }
74
+ return null;
75
+ }
76
+
77
+ exports.resolvePackage = resolvePackage;
@@ -0,0 +1,16 @@
1
+ export interface ResolvedMetadata {
2
+ packageRoot: string;
3
+ packageName: string;
4
+ packageVersion: string;
5
+ assetPath: string;
6
+ }
7
+ export interface ResolvePackageOptions {
8
+ /**
9
+ * When `true`, a package without `claude.assetPath` is warned and the
10
+ * function returns `null` instead of calling `process.exit`. Default
11
+ * `false` preserves the v0.3.0 strict behavior for single-target
12
+ * dispatcher calls.
13
+ */
14
+ skipMissingAsset?: boolean;
15
+ }
16
+ export declare function resolvePackage(name: string, options?: ResolvePackageOptions): Promise<ResolvedMetadata | null>;
@@ -0,0 +1,74 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { createRequire } from 'node:module';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { logger } from '../../../utils/logger.mjs';
6
+
7
+ async function resolvePackage(name, options = {}) {
8
+ const pkgJsonPath = resolvePackageJsonPath(name);
9
+ if (!pkgJsonPath) {
10
+ logger.error(`cannot resolve package "${name}". Install it in the current project or pass the correct name.`);
11
+ process.exit(2);
12
+ }
13
+ const packageRoot = dirname(pkgJsonPath);
14
+ const raw = await readFile(pkgJsonPath, 'utf-8');
15
+ const pkg = JSON.parse(raw);
16
+ if (typeof pkg.name !== 'string' || typeof pkg.version !== 'string') {
17
+ if (options.skipMissingAsset) {
18
+ logger.warn(`"${name}" package.json is missing a string "name" or "version" — skipping.`);
19
+ return null;
20
+ }
21
+ logger.error(`${pkgJsonPath} must define string "name" and "version".`);
22
+ process.exit(2);
23
+ }
24
+ const assetPath = pkg.claude?.assetPath;
25
+ if (typeof assetPath !== 'string' || assetPath.length === 0) {
26
+ if (options.skipMissingAsset) {
27
+ logger.warn(`"${name}" is missing "claude.assetPath" — skipping (the package does not ship Claude assets).`);
28
+ return null;
29
+ }
30
+ logger.error(`"${name}" is missing "claude.assetPath" in its package.json — the package does not ship Claude assets.`);
31
+ process.exit(2);
32
+ }
33
+ return {
34
+ packageRoot,
35
+ packageName: pkg.name,
36
+ packageVersion: pkg.version,
37
+ assetPath,
38
+ };
39
+ }
40
+ function resolvePackageJsonPath(name) {
41
+ const require = createRequire(import.meta.url);
42
+ try {
43
+ return require.resolve(`${name}/package.json`);
44
+ }
45
+ catch (err) {
46
+ const code = err?.code;
47
+ if (code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED')
48
+ return null;
49
+ }
50
+ let mainEntry;
51
+ try {
52
+ mainEntry = require.resolve(name);
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ let dir = dirname(mainEntry);
58
+ while (dir && dir !== dirname(dir)) {
59
+ const candidate = resolve(dir, 'package.json');
60
+ if (existsSync(candidate)) {
61
+ try {
62
+ const pkg = JSON.parse(readFileSync(candidate, 'utf-8'));
63
+ if (pkg.name === name)
64
+ return candidate;
65
+ }
66
+ catch {
67
+ }
68
+ }
69
+ dir = dirname(dir);
70
+ }
71
+ return null;
72
+ }
73
+
74
+ export { resolvePackage };