@slats/claude-assets-sync 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +47 -63
  2. package/bin/inject-claude-settings.mjs +4 -0
  3. package/dist/claude-hashes.json +9 -9
  4. package/dist/commands/index.d.ts +1 -1
  5. package/dist/commands/runCli/index.d.ts +1 -1
  6. package/dist/commands/runCli/runCli.d.ts +10 -6
  7. package/dist/commands/runCli/runCli.mjs +33 -6
  8. package/dist/commands/runCli/type.d.ts +4 -12
  9. package/dist/commands/runCli/utils/classifyTarget.d.ts +19 -0
  10. package/dist/commands/runCli/utils/classifyTarget.mjs +46 -0
  11. package/dist/commands/runCli/utils/renderOrFallback.d.ts +6 -0
  12. package/dist/commands/runCli/utils/renderOrFallback.mjs +12 -0
  13. package/dist/commands/runCli/utils/renderPlain.d.ts +11 -0
  14. package/dist/commands/runCli/utils/renderPlain.mjs +89 -0
  15. package/dist/commands/runCli/utils/resolvePackage.d.ts +16 -0
  16. package/dist/commands/runCli/utils/resolvePackage.mjs +74 -0
  17. package/dist/commands/runCli/utils/resolveScopeAlias.d.ts +2 -0
  18. package/dist/commands/runCli/utils/resolveScopeAlias.mjs +67 -0
  19. package/dist/commands/runCli/utils/resolveScopeFlag.d.ts +9 -1
  20. package/dist/commands/runCli/utils/resolveScopeFlag.mjs +5 -11
  21. package/dist/commands/runCli/utils/resolveTargets.d.ts +15 -0
  22. package/dist/commands/runCli/utils/resolveTargets.mjs +38 -0
  23. package/dist/commands/runCli/utils/toConsumerPackages.d.ts +9 -0
  24. package/dist/commands/runCli/utils/toConsumerPackages.mjs +26 -0
  25. package/dist/core/index.d.ts +2 -2
  26. package/dist/core/injectDocs/index.d.ts +3 -2
  27. package/dist/core/injectDocs/type.d.ts +0 -19
  28. package/dist/core/injectDocs/utils/applyAction.mjs +1 -1
  29. package/dist/core/scope/index.d.ts +1 -1
  30. package/dist/core/scope/scope.d.ts +0 -1
  31. package/dist/core/scope/scope.mjs +1 -4
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.mjs +2 -2
  34. package/dist/ui/InjectApp/InjectApp.d.ts +2 -0
  35. package/dist/ui/InjectApp/InjectApp.mjs +82 -0
  36. package/dist/ui/InjectApp/index.d.ts +2 -0
  37. package/dist/ui/InjectApp/utils/eventSelectors.d.ts +5 -0
  38. package/dist/ui/InjectApp/utils/eventSelectors.mjs +24 -0
  39. package/dist/ui/InjectApp/utils/phaseReducer.d.ts +2 -0
  40. package/dist/ui/InjectApp/utils/phaseReducer.mjs +130 -0
  41. package/dist/ui/InjectApp/utils/renderInjectApp.d.ts +2 -0
  42. package/dist/ui/InjectApp/utils/renderInjectApp.mjs +19 -0
  43. package/dist/ui/InjectApp/utils/type.d.ts +5 -0
  44. package/dist/ui/components/ActionRow.d.ts +7 -0
  45. package/dist/ui/components/ActionRow.mjs +45 -0
  46. package/dist/ui/components/Banner.d.ts +7 -0
  47. package/dist/ui/components/Banner.mjs +9 -0
  48. package/dist/ui/components/ConfirmForce.d.ts +8 -0
  49. package/dist/ui/components/ConfirmForce.mjs +35 -0
  50. package/dist/ui/components/ErrorPanel.d.ts +6 -0
  51. package/dist/ui/components/ErrorPanel.mjs +14 -0
  52. package/dist/ui/components/Footer.d.ts +8 -0
  53. package/dist/ui/components/Footer.mjs +27 -0
  54. package/dist/ui/components/PlanTable.d.ts +8 -0
  55. package/dist/ui/components/PlanTable.mjs +15 -0
  56. package/dist/ui/components/ProgressBar.d.ts +10 -0
  57. package/dist/ui/components/ProgressBar.mjs +28 -0
  58. package/dist/ui/components/ScopePicker.d.ts +7 -0
  59. package/dist/ui/components/ScopePicker.mjs +26 -0
  60. package/dist/ui/components/Spinner.d.ts +8 -0
  61. package/dist/ui/components/Spinner.mjs +10 -0
  62. package/dist/ui/components/StatusBadge.d.ts +8 -0
  63. package/dist/ui/components/StepTracker.d.ts +9 -0
  64. package/dist/ui/components/StepTracker.mjs +43 -0
  65. package/dist/ui/components/Summary.d.ts +9 -0
  66. package/dist/ui/components/Summary.mjs +30 -0
  67. package/dist/ui/components/TargetCard.d.ts +11 -0
  68. package/dist/ui/components/TargetCard.mjs +29 -0
  69. package/dist/ui/hooks/useApplyStep.d.ts +12 -0
  70. package/dist/ui/hooks/useApplyStep.mjs +30 -0
  71. package/dist/ui/hooks/useExitApp.d.ts +8 -0
  72. package/dist/ui/hooks/useExitApp.mjs +19 -0
  73. package/dist/ui/hooks/useForceConfirmStep.d.ts +9 -0
  74. package/dist/ui/hooks/useForceConfirmStep.mjs +24 -0
  75. package/dist/ui/hooks/useInjectSession.d.ts +10 -0
  76. package/dist/ui/hooks/useInjectSession.mjs +63 -0
  77. package/dist/ui/hooks/useInterval.d.ts +1 -0
  78. package/dist/ui/hooks/usePhase.d.ts +2 -0
  79. package/dist/ui/hooks/usePhase.mjs +9 -0
  80. package/dist/ui/hooks/usePlanStep.d.ts +13 -0
  81. package/dist/ui/hooks/usePlanStep.mjs +94 -0
  82. package/dist/ui/hooks/useResolveStep.d.ts +18 -0
  83. package/dist/ui/hooks/useResolveStep.mjs +21 -0
  84. package/dist/ui/hooks/useTerminalWidth.d.ts +1 -0
  85. package/dist/ui/index.d.ts +2 -0
  86. package/dist/ui/index.mjs +16 -0
  87. package/dist/ui/theme/colors.d.ts +12 -0
  88. package/dist/ui/theme/colors.mjs +9 -0
  89. package/dist/ui/theme/icons.d.ts +29 -0
  90. package/dist/ui/theme/icons.mjs +17 -0
  91. package/dist/ui/theme/layout.d.ts +20 -0
  92. package/dist/ui/theme/layout.mjs +9 -0
  93. package/dist/ui/types/event.d.ts +45 -0
  94. package/dist/ui/types/index.d.ts +4 -0
  95. package/dist/ui/types/phase.d.ts +44 -0
  96. package/dist/ui/types/render.d.ts +6 -0
  97. package/dist/ui/types/target.d.ts +25 -0
  98. package/dist/utils/version.d.ts +1 -1
  99. package/dist/utils/version.mjs +1 -1
  100. package/docs/claude/skills/claude-docs-asset-wiring/SKILL.md +159 -0
  101. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/claude-md-template.md +78 -0
  102. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/dependency-cruiser.md +54 -0
  103. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/gotchas.md +125 -0
  104. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/package-json-patches.md +150 -0
  105. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/reference-files.md +37 -0
  106. package/docs/claude/skills/claude-docs-asset-wiring/knowledge/smoke-tests.md +111 -0
  107. package/docs/consumer-integration.md +43 -101
  108. package/package.json +13 -8
  109. package/scripts/dev-ui-fixtures.ts +288 -0
  110. package/scripts/dev-ui.tsx +289 -0
  111. package/bin/claude-sync.mjs +0 -24
  112. package/dist/commands/runCli/runCli.cjs +0 -31
  113. package/dist/commands/runCli/utils/injectOne.cjs +0 -48
  114. package/dist/commands/runCli/utils/injectOne.d.ts +0 -3
  115. package/dist/commands/runCli/utils/injectOne.mjs +0 -46
  116. package/dist/commands/runCli/utils/resolveScopeFlag.cjs +0 -28
  117. package/dist/commands/runCli/utils/runInject.cjs +0 -36
  118. package/dist/commands/runCli/utils/runInject.d.ts +0 -2
  119. package/dist/commands/runCli/utils/runInject.mjs +0 -34
  120. package/dist/core/buildPlan/buildPlan.cjs +0 -42
  121. package/dist/core/buildPlan/utils/toPosix.cjs +0 -9
  122. package/dist/core/buildPlan/utils/walkFiles.cjs +0 -25
  123. package/dist/core/hash/hash.cjs +0 -30
  124. package/dist/core/hashManifest/hashManifest.cjs +0 -27
  125. package/dist/core/injectDocs/injectDocs.cjs +0 -43
  126. package/dist/core/injectDocs/injectDocs.d.ts +0 -2
  127. package/dist/core/injectDocs/injectDocs.mjs +0 -41
  128. package/dist/core/injectDocs/utils/applyAction.cjs +0 -21
  129. package/dist/core/injectDocs/utils/emitCiForceList.cjs +0 -10
  130. package/dist/core/injectDocs/utils/emitCiForceList.d.ts +0 -2
  131. package/dist/core/injectDocs/utils/emitCiForceList.mjs +0 -8
  132. package/dist/core/injectDocs/utils/printPlan.cjs +0 -20
  133. package/dist/core/injectDocs/utils/printPlan.d.ts +0 -2
  134. package/dist/core/injectDocs/utils/printPlan.mjs +0 -18
  135. package/dist/core/injectDocs/utils/summarize.cjs +0 -27
  136. package/dist/core/scope/scope.cjs +0 -46
  137. package/dist/core/scope/utils/isDirectory.cjs +0 -14
  138. package/dist/index.cjs +0 -20
  139. package/dist/prompts/confirmForce.cjs +0 -27
  140. package/dist/prompts/confirmForce.d.ts +0 -1
  141. package/dist/prompts/confirmForce.mjs +0 -25
  142. package/dist/prompts/index.d.ts +0 -2
  143. package/dist/prompts/selectScope.cjs +0 -30
  144. package/dist/prompts/selectScope.d.ts +0 -2
  145. package/dist/prompts/selectScope.mjs +0 -28
  146. package/dist/utils/asyncPool.cjs +0 -26
  147. package/dist/utils/heartbeat.cjs +0 -25
  148. package/dist/utils/heartbeat.d.ts +0 -16
  149. package/dist/utils/heartbeat.mjs +0 -23
  150. package/dist/utils/logger.cjs +0 -74
  151. package/dist/utils/version.cjs +0 -5
  152. package/docs/claude/skills/claude-sync-applier/SKILL.md +0 -195
  153. package/docs/claude/skills/claude-sync-applier/knowledge/claude-md-template.md +0 -77
  154. package/docs/claude/skills/claude-sync-applier/knowledge/dependency-cruiser.md +0 -126
  155. package/docs/claude/skills/claude-sync-applier/knowledge/gotchas.md +0 -139
  156. package/docs/claude/skills/claude-sync-applier/knowledge/package-json-patches.md +0 -130
  157. package/docs/claude/skills/claude-sync-applier/knowledge/reference-files.md +0 -120
  158. package/docs/claude/skills/claude-sync-applier/knowledge/smoke-tests.md +0 -102
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env node
2
+ import { render, Box, Text, useApp, useInput } from 'ink';
3
+ import React, { useEffect, useState } from 'react';
4
+
5
+ import { Banner } from '../src/ui/components/Banner.js';
6
+ import { ConfirmForce } from '../src/ui/components/ConfirmForce.js';
7
+ import { ErrorPanel } from '../src/ui/components/ErrorPanel.js';
8
+ import { Footer } from '../src/ui/components/Footer.js';
9
+ import { ProgressBar } from '../src/ui/components/ProgressBar.js';
10
+ import { ScopePicker } from '../src/ui/components/ScopePicker.js';
11
+ import { Spinner } from '../src/ui/components/Spinner.js';
12
+ import { StepTracker } from '../src/ui/components/StepTracker.js';
13
+ import { Summary } from '../src/ui/components/Summary.js';
14
+ import { TargetCard } from '../src/ui/components/TargetCard.js';
15
+ import { colors } from '../src/ui/theme/colors.js';
16
+ import { icons } from '../src/ui/theme/icons.js';
17
+ import type { Phase } from '../src/ui/types/index.js';
18
+
19
+ import { buildPhase, PHASES, type PhaseKey } from './dev-ui-fixtures.js';
20
+
21
+ const VERSION = '0.3.0-dev';
22
+
23
+ interface CliArgs {
24
+ mode: 'usage' | 'phase' | 'tour';
25
+ phase?: PhaseKey;
26
+ tourMs?: number;
27
+ }
28
+
29
+ function parseArgs(argv: readonly string[]): CliArgs {
30
+ if (argv.includes('--tour')) {
31
+ const msArg = argv.find((a) => a.startsWith('--ms='));
32
+ const tourMs = msArg ? Number(msArg.slice(5)) : 2500;
33
+ return { mode: 'tour', tourMs };
34
+ }
35
+ const phaseArg = argv.find((a) => a.startsWith('--phase='));
36
+ if (phaseArg) {
37
+ const phaseKey = phaseArg.slice(8);
38
+ if (!PHASES.includes(phaseKey as PhaseKey)) {
39
+ console.error(
40
+ `Unknown phase: ${phaseKey}. Available: ${PHASES.join(', ')}`,
41
+ );
42
+ process.exit(2);
43
+ }
44
+ return { mode: 'phase', phase: phaseKey as PhaseKey };
45
+ }
46
+ return { mode: 'usage' };
47
+ }
48
+
49
+ function Usage(): React.ReactElement {
50
+ return (
51
+ <Box flexDirection="column">
52
+ <Text bold color={colors.primary}>
53
+ {icons.triangleRight} claude-assets-sync — dev UI runner
54
+ </Text>
55
+ <Box marginLeft={2} marginTop={1} flexDirection="column">
56
+ <Text color={colors.muted}>Preview individual Ink screens or tour them all.</Text>
57
+ <Box marginTop={1} flexDirection="column">
58
+ <Text>
59
+ <Text color={colors.success} bold>yarn dev:ui</Text>
60
+ <Text color={colors.muted}>{' --phase=<name> '}</Text>
61
+ <Text dimColor>single phase preview</Text>
62
+ </Text>
63
+ <Text>
64
+ <Text color={colors.success} bold>yarn dev:ui</Text>
65
+ <Text color={colors.muted}>{' --tour [--ms=2500] '}</Text>
66
+ <Text dimColor>cycle through all phases</Text>
67
+ </Text>
68
+ <Text>
69
+ <Text color={colors.success} bold>yarn dev:cli</Text>
70
+ <Text color={colors.muted}>{' <args> '}</Text>
71
+ <Text dimColor>run the actual CLI against real packages</Text>
72
+ </Text>
73
+ </Box>
74
+ <Box marginTop={1} flexDirection="column">
75
+ <Text bold>Available phases:</Text>
76
+ {PHASES.map((p) => (
77
+ <Text key={p} color={colors.muted}>
78
+ {' '}·{' '}
79
+ <Text color={colors.accent}>{p}</Text>
80
+ </Text>
81
+ ))}
82
+ </Box>
83
+ <Box marginTop={1} flexDirection="column">
84
+ <Text bold>Examples:</Text>
85
+ <Text color={colors.muted}>
86
+ {' '}yarn dev:ui --phase=diff-review
87
+ </Text>
88
+ <Text color={colors.muted}>
89
+ {' '}yarn dev:ui --phase=applying
90
+ </Text>
91
+ <Text color={colors.muted}>
92
+ {' '}yarn dev:ui --tour --ms=1800
93
+ </Text>
94
+ <Text color={colors.muted}>
95
+ {' '}yarn dev:cli --package @canard/schema-form --scope=project --dry-run
96
+ </Text>
97
+ </Box>
98
+ </Box>
99
+ </Box>
100
+ );
101
+ }
102
+
103
+ interface FixtureViewProps {
104
+ readonly phase: Phase;
105
+ readonly targetCount: number;
106
+ }
107
+
108
+ function FixtureView({ phase, targetCount }: FixtureViewProps): React.ReactElement {
109
+ return (
110
+ <Box flexDirection="column">
111
+ <Banner version={VERSION} scope="user" />
112
+ <Box marginTop={1}>
113
+ <StepTracker phase={phase} targetCount={targetCount} scope="user" />
114
+ </Box>
115
+ <Box flexDirection="column" marginTop={1}>
116
+ {renderPhaseBody(phase)}
117
+ </Box>
118
+ <Footer phase={phase} version={VERSION} />
119
+ </Box>
120
+ );
121
+ }
122
+
123
+ function renderPhaseBody(phase: Phase): React.ReactNode {
124
+ switch (phase.kind) {
125
+ case 'booting':
126
+ case 'resolving':
127
+ return <Spinner label="resolving targets…" />;
128
+ case 'scope-select':
129
+ return <ScopePicker onSelect={phase.pending} />;
130
+ case 'planning':
131
+ return (
132
+ <Box flexDirection="column">
133
+ <Spinner label="building plans…" />
134
+ <Box flexDirection="column" marginLeft={2} marginTop={1}>
135
+ {[...phase.progress.values()].map((step) => (
136
+ <Box key={step.packageName}>
137
+ <Text
138
+ color={
139
+ step.status === 'done'
140
+ ? colors.success
141
+ : step.status === 'running'
142
+ ? colors.warn
143
+ : step.status === 'failed'
144
+ ? colors.danger
145
+ : colors.muted
146
+ }
147
+ bold={step.status === 'running'}
148
+ >
149
+ {step.status === 'done'
150
+ ? icons.check
151
+ : step.status === 'failed'
152
+ ? icons.cross
153
+ : step.status === 'running'
154
+ ? icons.bulletActive
155
+ : icons.bulletPending}{' '}
156
+ </Text>
157
+ <Text>{step.packageName}</Text>
158
+ </Box>
159
+ ))}
160
+ </Box>
161
+ </Box>
162
+ );
163
+ case 'diff-review':
164
+ return (
165
+ <Box flexDirection="column">
166
+ {phase.plans.map((tp, idx) => (
167
+ <TargetCard
168
+ key={tp.target.name}
169
+ target={tp.target}
170
+ plan={tp.plan}
171
+ expanded
172
+ highlighted={idx === phase.focusedIndex}
173
+ />
174
+ ))}
175
+ </Box>
176
+ );
177
+ case 'force-confirm':
178
+ return <ConfirmForce warnings={phase.warnings} onAnswer={phase.pending} />;
179
+ case 'applying': {
180
+ const elapsedMs = Math.max(Date.now() - phase.progress.startedAt, 1);
181
+ const rate = phase.progress.done / elapsedMs;
182
+ const remaining = phase.progress.total - phase.progress.done;
183
+ const eta = rate > 0 ? remaining / rate / 1000 : undefined;
184
+ return (
185
+ <Box flexDirection="column">
186
+ <ProgressBar
187
+ done={phase.progress.done}
188
+ total={phase.progress.total}
189
+ etaSeconds={eta}
190
+ label={phase.progress.current}
191
+ />
192
+ <Box flexDirection="column" marginLeft={2} marginTop={1}>
193
+ {phase.plans.map((tp) => (
194
+ <TargetCard
195
+ key={tp.target.name}
196
+ target={tp.target}
197
+ plan={tp.plan}
198
+ expanded={false}
199
+ />
200
+ ))}
201
+ </Box>
202
+ </Box>
203
+ );
204
+ }
205
+ case 'summary':
206
+ return (
207
+ <Box flexDirection="column">
208
+ {phase.plans.map((tp) => (
209
+ <TargetCard
210
+ key={tp.target.name}
211
+ target={tp.target}
212
+ plan={tp.plan}
213
+ expanded={false}
214
+ />
215
+ ))}
216
+ <Summary
217
+ reports={phase.reports}
218
+ exitCode={phase.exitCode}
219
+ dryRun={phase.dryRun}
220
+ />
221
+ </Box>
222
+ );
223
+ case 'error':
224
+ return <ErrorPanel error={phase.error} />;
225
+ default: {
226
+ const _exhaustive: never = phase;
227
+ void _exhaustive;
228
+ return null;
229
+ }
230
+ }
231
+ }
232
+
233
+ function PhaseApp({ phaseKey }: { phaseKey: PhaseKey }): React.ReactElement {
234
+ const { exit } = useApp();
235
+ const phase = buildPhase(phaseKey);
236
+ useInput((input) => {
237
+ if (input === 'q' || input === '') exit();
238
+ });
239
+ return <FixtureView phase={phase} targetCount={3} />;
240
+ }
241
+
242
+ function TourApp({ intervalMs }: { intervalMs: number }): React.ReactElement {
243
+ const { exit } = useApp();
244
+ const [idx, setIdx] = useState(0);
245
+ useEffect(() => {
246
+ const handle = setInterval(() => {
247
+ setIdx((current) => {
248
+ if (current + 1 >= PHASES.length) {
249
+ setTimeout(() => exit(), 300);
250
+ return current;
251
+ }
252
+ return current + 1;
253
+ });
254
+ }, intervalMs);
255
+ return () => clearInterval(handle);
256
+ }, [intervalMs, exit]);
257
+ useInput((input) => {
258
+ if (input === 'q' || input === '') exit();
259
+ if (input === ' ')
260
+ setIdx((current) =>
261
+ current + 1 >= PHASES.length ? current : current + 1,
262
+ );
263
+ });
264
+ const phaseKey = PHASES[idx];
265
+ const phase = buildPhase(phaseKey);
266
+ return (
267
+ <Box flexDirection="column">
268
+ <Box>
269
+ <Text color={colors.accent} bold>
270
+ [tour {idx + 1}/{PHASES.length}]
271
+ </Text>
272
+ <Text color={colors.muted} dimColor>
273
+ {' '}
274
+ {phaseKey} · space:next · q/esc:exit
275
+ </Text>
276
+ </Box>
277
+ <FixtureView phase={phase} targetCount={3} />
278
+ </Box>
279
+ );
280
+ }
281
+
282
+ const args = parseArgs(process.argv.slice(2));
283
+ if (args.mode === 'usage') {
284
+ render(<Usage />);
285
+ } else if (args.mode === 'phase') {
286
+ render(<PhaseApp phaseKey={args.phase!} />);
287
+ } else if (args.mode === 'tour') {
288
+ render(<TourApp intervalMs={args.tourMs ?? 2500} />);
289
+ }
@@ -1,24 +0,0 @@
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,31 +0,0 @@
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;
@@ -1,48 +0,0 @@
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;
@@ -1,3 +0,0 @@
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>;
@@ -1,46 +0,0 @@
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 };
@@ -1,28 +0,0 @@
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;
@@ -1,36 +0,0 @@
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;
@@ -1,2 +0,0 @@
1
- import type { DefaultFlags, RunCliOptions } from '../type.js';
2
- export declare function runInject(flags: DefaultFlags, options: RunCliOptions): Promise<void>;
@@ -1,34 +0,0 @@
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 };
@@ -1,42 +0,0 @@
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;
@@ -1,9 +0,0 @@
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;
@@ -1,25 +0,0 @@
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;
@@ -1,30 +0,0 @@
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;