@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,69 @@
1
+ 'use strict';
2
+
3
+ var node_fs = require('node:fs');
4
+ var promises = require('node:fs/promises');
5
+ var node_path = require('node:path');
6
+ var logger = require('../../../utils/logger.cjs');
7
+ var resolvePackage = require('./resolvePackage.cjs');
8
+
9
+ async function resolveScopeAlias(scope, rootCwd) {
10
+ const packagesRoot = findPackagesRoot(rootCwd);
11
+ if (!packagesRoot) {
12
+ logger.logger.error(`cannot locate a monorepo root with a "packages/" directory starting from "${rootCwd}". Scope alias "@${scope}" requires a workspace root.`);
13
+ process.exit(2);
14
+ }
15
+ const scopeDir = node_path.join(packagesRoot, 'packages', scope);
16
+ let entries;
17
+ try {
18
+ entries = await promises.readdir(scopeDir);
19
+ }
20
+ catch {
21
+ logger.logger.error(`scope alias "@${scope}" has no matching directory at ${scopeDir}.`);
22
+ process.exit(2);
23
+ }
24
+ const matchedNames = [];
25
+ const expectedPrefix = `@${scope}/`;
26
+ for (const entry of entries) {
27
+ const pkgJsonPath = node_path.join(scopeDir, entry, 'package.json');
28
+ if (!node_fs.existsSync(pkgJsonPath))
29
+ continue;
30
+ let parsed;
31
+ try {
32
+ const raw = await promises.readFile(pkgJsonPath, 'utf-8');
33
+ parsed = JSON.parse(raw);
34
+ }
35
+ catch {
36
+ continue;
37
+ }
38
+ if (typeof parsed.name === 'string' &&
39
+ parsed.name.startsWith(expectedPrefix) &&
40
+ parsed.name.length > expectedPrefix.length) {
41
+ matchedNames.push(parsed.name);
42
+ }
43
+ }
44
+ if (matchedNames.length === 0) {
45
+ logger.logger.warn(`scope alias "@${scope}" matched no workspace packages under ${scopeDir}.`);
46
+ return [];
47
+ }
48
+ const resolved = [];
49
+ for (const name of matchedNames) {
50
+ const meta = await resolvePackage.resolvePackage(name, { skipMissingAsset: true });
51
+ if (meta)
52
+ resolved.push(meta);
53
+ }
54
+ return resolved;
55
+ }
56
+ function findPackagesRoot(start) {
57
+ let cur = node_path.resolve(start);
58
+ while (true) {
59
+ if (node_fs.existsSync(node_path.join(cur, 'package.json')) && node_fs.existsSync(node_path.join(cur, 'packages'))) {
60
+ return cur;
61
+ }
62
+ const parent = node_path.dirname(cur);
63
+ if (parent === cur)
64
+ return null;
65
+ cur = parent;
66
+ }
67
+ }
68
+
69
+ exports.resolveScopeAlias = resolveScopeAlias;
@@ -0,0 +1,2 @@
1
+ import { type ResolvedMetadata } from './resolvePackage.js';
2
+ export declare function resolveScopeAlias(scope: string, rootCwd: string): Promise<ResolvedMetadata[]>;
@@ -0,0 +1,67 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, readFile } from 'node:fs/promises';
3
+ import { join, resolve, dirname } from 'node:path';
4
+ import { logger } from '../../../utils/logger.mjs';
5
+ import { resolvePackage } from './resolvePackage.mjs';
6
+
7
+ async function resolveScopeAlias(scope, rootCwd) {
8
+ const packagesRoot = findPackagesRoot(rootCwd);
9
+ if (!packagesRoot) {
10
+ logger.error(`cannot locate a monorepo root with a "packages/" directory starting from "${rootCwd}". Scope alias "@${scope}" requires a workspace root.`);
11
+ process.exit(2);
12
+ }
13
+ const scopeDir = join(packagesRoot, 'packages', scope);
14
+ let entries;
15
+ try {
16
+ entries = await readdir(scopeDir);
17
+ }
18
+ catch {
19
+ logger.error(`scope alias "@${scope}" has no matching directory at ${scopeDir}.`);
20
+ process.exit(2);
21
+ }
22
+ const matchedNames = [];
23
+ const expectedPrefix = `@${scope}/`;
24
+ for (const entry of entries) {
25
+ const pkgJsonPath = join(scopeDir, entry, 'package.json');
26
+ if (!existsSync(pkgJsonPath))
27
+ continue;
28
+ let parsed;
29
+ try {
30
+ const raw = await readFile(pkgJsonPath, 'utf-8');
31
+ parsed = JSON.parse(raw);
32
+ }
33
+ catch {
34
+ continue;
35
+ }
36
+ if (typeof parsed.name === 'string' &&
37
+ parsed.name.startsWith(expectedPrefix) &&
38
+ parsed.name.length > expectedPrefix.length) {
39
+ matchedNames.push(parsed.name);
40
+ }
41
+ }
42
+ if (matchedNames.length === 0) {
43
+ logger.warn(`scope alias "@${scope}" matched no workspace packages under ${scopeDir}.`);
44
+ return [];
45
+ }
46
+ const resolved = [];
47
+ for (const name of matchedNames) {
48
+ const meta = await resolvePackage(name, { skipMissingAsset: true });
49
+ if (meta)
50
+ resolved.push(meta);
51
+ }
52
+ return resolved;
53
+ }
54
+ function findPackagesRoot(start) {
55
+ let cur = resolve(start);
56
+ while (true) {
57
+ if (existsSync(join(cur, 'package.json')) && existsSync(join(cur, 'packages'))) {
58
+ return cur;
59
+ }
60
+ const parent = dirname(cur);
61
+ if (parent === cur)
62
+ return null;
63
+ cur = parent;
64
+ }
65
+ }
66
+
67
+ export { resolveScopeAlias };
@@ -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,40 @@
1
+ 'use strict';
2
+
3
+ var logger = require('../../../utils/logger.cjs');
4
+ var classifyTarget = require('./classifyTarget.cjs');
5
+ var resolvePackage = require('./resolvePackage.cjs');
6
+ var resolveScopeAlias = require('./resolveScopeAlias.cjs');
7
+
8
+ async function resolveTargets(targets, rootCwd) {
9
+ if (targets.length === 0)
10
+ return [];
11
+ const isSingleTarget = targets.length === 1;
12
+ const seen = new Set();
13
+ const results = [];
14
+ for (const target of targets) {
15
+ const classification = classifyTarget.classifyTarget(target);
16
+ if (classification.kind === 'invalid') {
17
+ logger.logger.error(classification.reason);
18
+ process.exit(2);
19
+ }
20
+ let candidates;
21
+ if (classification.kind === 'scope') {
22
+ candidates = await resolveScopeAlias.resolveScopeAlias(classification.scope, rootCwd);
23
+ }
24
+ else {
25
+ const meta = await resolvePackage.resolvePackage(classification.name, {
26
+ skipMissingAsset: !isSingleTarget,
27
+ });
28
+ candidates = meta ? [meta] : [];
29
+ }
30
+ for (const meta of candidates) {
31
+ if (!seen.has(meta.packageName)) {
32
+ seen.add(meta.packageName);
33
+ results.push(meta);
34
+ }
35
+ }
36
+ }
37
+ return results;
38
+ }
39
+
40
+ exports.resolveTargets = resolveTargets;
@@ -0,0 +1,15 @@
1
+ import { type ResolvedMetadata } from './resolvePackage.js';
2
+ /**
3
+ * Classify each `--package` value, resolve them all, and dedupe the
4
+ * result by `packageName`.
5
+ *
6
+ * - `@<scope>` values enumerate through `resolveScopeAlias` (soft skip
7
+ * when a workspace package lacks `claude.assetPath`).
8
+ * - `@<scope>/<name>` and `<name>` values go through `resolvePackage`.
9
+ * When there is a single `--package` value, the call is strict
10
+ * (asset-missing → exit 2); otherwise asset-missing is a soft skip
11
+ * so the rest of the batch can proceed.
12
+ *
13
+ * Invalid `--package` values exit with code 2 before any filesystem IO.
14
+ */
15
+ export declare function resolveTargets(targets: readonly string[], rootCwd: string): Promise<ResolvedMetadata[]>;
@@ -0,0 +1,38 @@
1
+ import { logger } from '../../../utils/logger.mjs';
2
+ import { classifyTarget } from './classifyTarget.mjs';
3
+ import { resolvePackage } from './resolvePackage.mjs';
4
+ import { resolveScopeAlias } from './resolveScopeAlias.mjs';
5
+
6
+ async function resolveTargets(targets, rootCwd) {
7
+ if (targets.length === 0)
8
+ return [];
9
+ const isSingleTarget = targets.length === 1;
10
+ const seen = new Set();
11
+ const results = [];
12
+ for (const target of targets) {
13
+ const classification = classifyTarget(target);
14
+ if (classification.kind === 'invalid') {
15
+ logger.error(classification.reason);
16
+ process.exit(2);
17
+ }
18
+ let candidates;
19
+ if (classification.kind === 'scope') {
20
+ candidates = await resolveScopeAlias(classification.scope, rootCwd);
21
+ }
22
+ else {
23
+ const meta = await resolvePackage(classification.name, {
24
+ skipMissingAsset: !isSingleTarget,
25
+ });
26
+ candidates = meta ? [meta] : [];
27
+ }
28
+ for (const meta of candidates) {
29
+ if (!seen.has(meta.packageName)) {
30
+ seen.add(meta.packageName);
31
+ results.push(meta);
32
+ }
33
+ }
34
+ }
35
+ return results;
36
+ }
37
+
38
+ export { resolveTargets };
@@ -0,0 +1,52 @@
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, metadataList) {
10
+ if (metadataList.length === 0)
11
+ return;
12
+ for (const metadata of metadataList) {
13
+ if (!node_path.isAbsolute(metadata.packageRoot)) {
14
+ logger.logger.error(`packageRoot must be an absolute path; received: ${metadata.packageRoot}`);
15
+ process.exit(2);
16
+ }
17
+ }
18
+ const originCwd = flags.root ?? process.cwd();
19
+ const scope = await resolveScopeFlag.resolveScopeFlag(flags.scope);
20
+ const fatalOnError = metadataList.length === 1;
21
+ let failureCount = 0;
22
+ for (const metadata of metadataList) {
23
+ const assetRoot = node_path.resolve(metadata.packageRoot, metadata.assetPath);
24
+ const hashesPath = node_path.join(metadata.packageRoot, 'dist', 'claude-hashes.json');
25
+ const hashesPresent = await promises.stat(hashesPath).then(() => true, () => false);
26
+ const target = {
27
+ name: metadata.packageName,
28
+ version: metadata.packageVersion,
29
+ packageRoot: metadata.packageRoot,
30
+ assetRoot,
31
+ hashesPresent,
32
+ };
33
+ let exitCode;
34
+ try {
35
+ exitCode = await injectOne.injectOne(target, scope, flags, originCwd);
36
+ }
37
+ catch (err) {
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ logger.logger.error(`${target.name}: ${msg}`);
40
+ exitCode = 1;
41
+ }
42
+ if (exitCode !== 0) {
43
+ if (fatalOnError)
44
+ process.exit(exitCode);
45
+ failureCount += 1;
46
+ }
47
+ }
48
+ if (failureCount > 0)
49
+ process.exit(1);
50
+ }
51
+
52
+ exports.runInject = runInject;
@@ -0,0 +1,3 @@
1
+ import type { DefaultFlags } from '../type.js';
2
+ import type { ResolvedMetadata } from './resolvePackage.js';
3
+ export declare function runInject(flags: DefaultFlags, metadataList: readonly ResolvedMetadata[]): Promise<void>;
@@ -0,0 +1,50 @@
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, metadataList) {
8
+ if (metadataList.length === 0)
9
+ return;
10
+ for (const metadata of metadataList) {
11
+ if (!isAbsolute(metadata.packageRoot)) {
12
+ logger.error(`packageRoot must be an absolute path; received: ${metadata.packageRoot}`);
13
+ process.exit(2);
14
+ }
15
+ }
16
+ const originCwd = flags.root ?? process.cwd();
17
+ const scope = await resolveScopeFlag(flags.scope);
18
+ const fatalOnError = metadataList.length === 1;
19
+ let failureCount = 0;
20
+ for (const metadata of metadataList) {
21
+ const assetRoot = resolve(metadata.packageRoot, metadata.assetPath);
22
+ const hashesPath = join(metadata.packageRoot, 'dist', 'claude-hashes.json');
23
+ const hashesPresent = await stat(hashesPath).then(() => true, () => false);
24
+ const target = {
25
+ name: metadata.packageName,
26
+ version: metadata.packageVersion,
27
+ packageRoot: metadata.packageRoot,
28
+ assetRoot,
29
+ hashesPresent,
30
+ };
31
+ let exitCode;
32
+ try {
33
+ exitCode = await injectOne(target, scope, flags, originCwd);
34
+ }
35
+ catch (err) {
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ logger.error(`${target.name}: ${msg}`);
38
+ exitCode = 1;
39
+ }
40
+ if (exitCode !== 0) {
41
+ if (fatalOnError)
42
+ process.exit(exitCode);
43
+ failureCount += 1;
44
+ }
45
+ }
46
+ if (failureCount > 0)
47
+ process.exit(1);
48
+ }
49
+
50
+ 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 };
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ var promises = require('node:fs/promises');
4
+ var node_path = require('node:path');
5
+
6
+ async function* walkFiles(root) {
7
+ let entries;
8
+ try {
9
+ entries = await promises.readdir(root, { withFileTypes: true });
10
+ }
11
+ catch (err) {
12
+ if (err.code === 'ENOENT')
13
+ return;
14
+ throw err;
15
+ }
16
+ for (const entry of entries) {
17
+ const abs = node_path.join(root, entry.name);
18
+ if (entry.isDirectory())
19
+ yield* walkFiles(abs);
20
+ else if (entry.isFile())
21
+ yield abs;
22
+ }
23
+ }
24
+
25
+ exports.walkFiles = walkFiles;
@@ -0,0 +1 @@
1
+ export declare function walkFiles(root: string): AsyncGenerator<string>;
@@ -0,0 +1,23 @@
1
+ import { readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+
4
+ async function* walkFiles(root) {
5
+ let entries;
6
+ try {
7
+ entries = await readdir(root, { withFileTypes: true });
8
+ }
9
+ catch (err) {
10
+ if (err.code === 'ENOENT')
11
+ return;
12
+ throw err;
13
+ }
14
+ for (const entry of entries) {
15
+ const abs = join(root, entry.name);
16
+ if (entry.isDirectory())
17
+ yield* walkFiles(abs);
18
+ else if (entry.isFile())
19
+ yield abs;
20
+ }
21
+ }
22
+
23
+ export { walkFiles };
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ var node_crypto = require('node:crypto');
4
+ var promises = require('node:fs/promises');
5
+
6
+ function hashContent(buffer) {
7
+ return node_crypto.createHash('sha256').update(buffer).digest('hex');
8
+ }
9
+ async function hashFile(absPath) {
10
+ try {
11
+ const buf = await promises.readFile(absPath);
12
+ return hashContent(buf);
13
+ }
14
+ catch (err) {
15
+ if (err.code === 'ENOENT')
16
+ return null;
17
+ throw err;
18
+ }
19
+ }
20
+ function hashEquals(a, b) {
21
+ if (a === null || b === null)
22
+ return false;
23
+ if (a.length !== b.length)
24
+ return false;
25
+ return a.toLowerCase() === b.toLowerCase();
26
+ }
27
+
28
+ exports.hashContent = hashContent;
29
+ exports.hashEquals = hashEquals;
30
+ exports.hashFile = hashFile;
@@ -0,0 +1,4 @@
1
+ export type Sha256Hex = string;
2
+ export declare function hashContent(buffer: Buffer | string): Sha256Hex;
3
+ export declare function hashFile(absPath: string): Promise<Sha256Hex | null>;
4
+ export declare function hashEquals(a: Sha256Hex | null, b: Sha256Hex | null): boolean;
@@ -0,0 +1,26 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+
4
+ function hashContent(buffer) {
5
+ return createHash('sha256').update(buffer).digest('hex');
6
+ }
7
+ async function hashFile(absPath) {
8
+ try {
9
+ const buf = await readFile(absPath);
10
+ return hashContent(buf);
11
+ }
12
+ catch (err) {
13
+ if (err.code === 'ENOENT')
14
+ return null;
15
+ throw err;
16
+ }
17
+ }
18
+ function hashEquals(a, b) {
19
+ if (a === null || b === null)
20
+ return false;
21
+ if (a.length !== b.length)
22
+ return false;
23
+ return a.toLowerCase() === b.toLowerCase();
24
+ }
25
+
26
+ export { hashContent, hashEquals, hashFile };