@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,94 @@
1
+ import { useRef, useEffect } from 'react';
2
+ import 'node:crypto';
3
+ import 'node:fs/promises';
4
+ import { readHashManifest, computeNamespacePrefixes } from '../../core/hashManifest/hashManifest.mjs';
5
+ import 'node:path';
6
+ import 'picocolors';
7
+ import { buildPlan } from '../../core/buildPlan/buildPlan.mjs';
8
+ import { resolveScope } from '../../core/scope/scope.mjs';
9
+
10
+ function usePlanStep({ targets, scope, originCwd, force, dispatch, onPlansReady, }) {
11
+ const startedRef = useRef(false);
12
+ useEffect(() => {
13
+ if (!scope || startedRef.current)
14
+ return;
15
+ startedRef.current = true;
16
+ let cancelled = false;
17
+ (async () => {
18
+ const results = [];
19
+ const warnings = [];
20
+ for (const target of targets) {
21
+ if (cancelled)
22
+ return;
23
+ dispatch({
24
+ type: 'plan-step',
25
+ step: { packageName: target.name, status: 'running' },
26
+ });
27
+ try {
28
+ if (!target.hashesPresent) {
29
+ dispatch({
30
+ type: 'plan-step',
31
+ step: {
32
+ packageName: target.name,
33
+ status: 'failed',
34
+ error: 'dist/claude-hashes.json missing',
35
+ },
36
+ });
37
+ continue;
38
+ }
39
+ const manifest = await readHashManifest(target.packageRoot);
40
+ const scopeResolution = resolveScope(scope, originCwd);
41
+ const plan = await buildPlan({
42
+ sourceHashes: manifest.files,
43
+ targetRoot: scopeResolution.targetRoot,
44
+ namespacePrefixes: computeNamespacePrefixes(manifest),
45
+ force,
46
+ });
47
+ results.push({ target, scope: scopeResolution, plan });
48
+ for (const action of plan.actions) {
49
+ if (action.kind === 'warn-diverged' || action.kind === 'warn-orphan') {
50
+ warnings.push({
51
+ packageName: target.name,
52
+ kind: action.kind,
53
+ relPath: action.relPath,
54
+ description: action.kind === 'warn-diverged'
55
+ ? 'local differs from source (user edit or version change)'
56
+ : 'exists locally but not in manifest',
57
+ });
58
+ }
59
+ }
60
+ dispatch({
61
+ type: 'plan-step',
62
+ step: { packageName: target.name, status: 'done' },
63
+ });
64
+ }
65
+ catch (error) {
66
+ dispatch({
67
+ type: 'plan-step',
68
+ step: {
69
+ packageName: target.name,
70
+ status: 'failed',
71
+ error: error instanceof Error ? error.message : String(error),
72
+ },
73
+ });
74
+ }
75
+ }
76
+ if (cancelled)
77
+ return;
78
+ dispatch({ type: 'plans-ready', plans: results });
79
+ onPlansReady(results, warnings);
80
+ })().catch((error) => {
81
+ if (!cancelled) {
82
+ dispatch({
83
+ type: 'fail',
84
+ error: error instanceof Error ? error : new Error(String(error)),
85
+ });
86
+ }
87
+ });
88
+ return () => {
89
+ cancelled = true;
90
+ };
91
+ }, [targets, scope, originCwd, force, dispatch, onPlansReady]);
92
+ }
93
+
94
+ export { usePlanStep };
@@ -0,0 +1,18 @@
1
+ import type { ConsumerPackage } from '../../commands/runCli/type.js';
2
+ import type { Scope } from '../../core/index.js';
3
+ import type { InjectEvent } from '../types/index.js';
4
+ interface UseResolveStepOptions {
5
+ readonly targets: readonly ConsumerPackage[];
6
+ readonly flags: {
7
+ readonly scope?: string;
8
+ };
9
+ readonly dispatch: (event: InjectEvent) => void;
10
+ readonly onScopeResolved: (scope: Scope) => void;
11
+ }
12
+ /**
13
+ * Ink path is guaranteed TTY by `renderOrFallback`, so interactive
14
+ * scope selection is always safe. Non-TTY invocations go through
15
+ * `renderPlain` + `resolveScopeFlag` which exits 2 on missing scope.
16
+ */
17
+ export declare function useResolveStep({ targets, flags, dispatch, onScopeResolved, }: UseResolveStepOptions): void;
18
+ export {};
@@ -0,0 +1,21 @@
1
+ import { useEffect } from 'react';
2
+
3
+ function useResolveStep({ targets, flags, dispatch, onScopeResolved, }) {
4
+ useEffect(() => {
5
+ if (flags.scope === 'user' || flags.scope === 'project') {
6
+ const resolved = flags.scope;
7
+ dispatch({ type: 'scope-selected', scope: resolved });
8
+ dispatch({ type: 'planning-started', targets, scope: resolved });
9
+ onScopeResolved(resolved);
10
+ return;
11
+ }
12
+ const pending = (scope) => {
13
+ dispatch({ type: 'scope-selected', scope });
14
+ dispatch({ type: 'planning-started', targets, scope });
15
+ onScopeResolved(scope);
16
+ };
17
+ dispatch({ type: 'scope-needed', pending });
18
+ }, [targets, flags.scope, dispatch, onScopeResolved]);
19
+ }
20
+
21
+ export { useResolveStep };
@@ -0,0 +1 @@
1
+ export declare function useTerminalWidth(): number;
@@ -0,0 +1,2 @@
1
+ export { renderInjectApp } from './InjectApp/index.js';
2
+ export type { Phase, InjectEvent, RenderInput, TargetPlan, Warning, ApplyProgress, PlanStepState, } from './types/index.js';
@@ -0,0 +1,16 @@
1
+ import { renderInjectApp } from './InjectApp/utils/renderInjectApp.mjs';
2
+ import 'react/jsx-runtime';
3
+ import 'react';
4
+ import 'ink';
5
+ import 'ink-select-input';
6
+ import 'ink-spinner';
7
+ import 'node:fs/promises';
8
+ import 'node:path';
9
+ import 'picocolors';
10
+ import 'node:crypto';
11
+ import 'node:os';
12
+ import 'node:fs';
13
+
14
+
15
+
16
+ export { renderInjectApp };
@@ -0,0 +1,12 @@
1
+ export declare const colors: {
2
+ readonly primary: "cyan";
3
+ readonly success: "green";
4
+ readonly warn: "yellow";
5
+ readonly danger: "red";
6
+ readonly muted: "gray";
7
+ readonly accent: "magenta";
8
+ readonly info: "blue";
9
+ readonly dim: "gray";
10
+ };
11
+ export declare const gradientStops: readonly ["#22d3ee", "#a78bfa", "#f59e0b"];
12
+ export type ColorName = (typeof colors)[keyof typeof colors];
@@ -0,0 +1,9 @@
1
+ const colors = {
2
+ primary: 'cyan',
3
+ success: 'green',
4
+ warn: 'yellow',
5
+ danger: 'red',
6
+ muted: 'gray',
7
+ accent: 'magenta'};
8
+
9
+ export { colors };
@@ -0,0 +1,29 @@
1
+ export declare const icons: {
2
+ readonly bulletDone: "●";
3
+ readonly bulletActive: "◐";
4
+ readonly bulletPending: "○";
5
+ readonly triangleRight: "▸";
6
+ readonly check: "✓";
7
+ readonly cross: "✗";
8
+ readonly warning: "⚠";
9
+ readonly question: "?";
10
+ readonly plus: "+";
11
+ readonly equals: "=";
12
+ readonly minus: "−";
13
+ readonly tilde: "~";
14
+ readonly blockFull: "█";
15
+ readonly blockEmpty: "░";
16
+ readonly dash: "─";
17
+ readonly divider: "───";
18
+ readonly boxTopLeft: "╭";
19
+ readonly boxTopRight: "╮";
20
+ readonly boxBottomLeft: "╰";
21
+ readonly boxBottomRight: "╯";
22
+ readonly boxHorizontal: "─";
23
+ readonly boxVertical: "│";
24
+ readonly boxDoubleTopLeft: "┌";
25
+ readonly boxDoubleTopRight: "┐";
26
+ readonly boxDoubleBottomLeft: "└";
27
+ readonly boxDoubleBottomRight: "┘";
28
+ };
29
+ export type IconName = keyof typeof icons;
@@ -0,0 +1,17 @@
1
+ const icons = {
2
+ bulletDone: '●',
3
+ bulletActive: '◐',
4
+ bulletPending: '○',
5
+ triangleRight: '▸',
6
+ check: '✓',
7
+ cross: '✗',
8
+ warning: '⚠',
9
+ question: '?',
10
+ plus: '+',
11
+ equals: '=',
12
+ minus: '−',
13
+ blockFull: '█',
14
+ blockEmpty: '░',
15
+ divider: '───'};
16
+
17
+ export { icons };
@@ -0,0 +1,20 @@
1
+ export declare const spacing: {
2
+ readonly xs: 0;
3
+ readonly sm: 1;
4
+ readonly md: 2;
5
+ readonly lg: 3;
6
+ readonly xl: 4;
7
+ };
8
+ export declare const widths: {
9
+ readonly statusBadge: 10;
10
+ readonly pathColumn: 60;
11
+ readonly progressBarDefault: 28;
12
+ readonly targetCardCount: 18;
13
+ readonly minTerminalWidth: 60;
14
+ readonly idealTerminalWidth: 120;
15
+ };
16
+ export declare const limits: {
17
+ readonly maxWarningsBeforeCollapse: 10;
18
+ readonly maxPlanRowsBeforeTruncate: 40;
19
+ readonly planTruncatedReveal: 15;
20
+ };
@@ -0,0 +1,9 @@
1
+ const widths = {
2
+ progressBarDefault: 28};
3
+ const limits = {
4
+ maxWarningsBeforeCollapse: 10,
5
+ maxPlanRowsBeforeTruncate: 40,
6
+ planTruncatedReveal: 15,
7
+ };
8
+
9
+ export { limits, widths };
@@ -0,0 +1,45 @@
1
+ import type { ConsumerPackage } from '../../commands/runCli/type.js';
2
+ import type { InjectReport, Scope } from '../../core/index.js';
3
+ import type { PlanStepState, TargetPlan, Warning } from './target.js';
4
+ export type InjectEvent = {
5
+ readonly type: 'scope-needed';
6
+ readonly pending: (scope: Scope) => void;
7
+ } | {
8
+ readonly type: 'scope-selected';
9
+ readonly scope: Scope;
10
+ } | {
11
+ readonly type: 'planning-started';
12
+ readonly targets: readonly ConsumerPackage[];
13
+ readonly scope: Scope;
14
+ } | {
15
+ readonly type: 'plan-step';
16
+ readonly step: PlanStepState;
17
+ } | {
18
+ readonly type: 'plans-ready';
19
+ readonly plans: readonly TargetPlan[];
20
+ } | {
21
+ readonly type: 'force-confirm-required';
22
+ readonly warnings: readonly Warning[];
23
+ readonly pending: (ok: boolean) => void;
24
+ } | {
25
+ readonly type: 'force-answer';
26
+ readonly ok: boolean;
27
+ } | {
28
+ readonly type: 'apply-start';
29
+ readonly total: number;
30
+ } | {
31
+ readonly type: 'apply-progress';
32
+ readonly done: number;
33
+ readonly current?: string;
34
+ } | {
35
+ readonly type: 'done';
36
+ readonly reports: readonly InjectReport[];
37
+ readonly exitCode: 0 | 1 | 2;
38
+ readonly dryRun: boolean;
39
+ } | {
40
+ readonly type: 'fail';
41
+ readonly error: Error;
42
+ } | {
43
+ readonly type: 'focus-target';
44
+ readonly index: number;
45
+ };
@@ -0,0 +1,4 @@
1
+ export type { Phase } from './phase.js';
2
+ export type { InjectEvent } from './event.js';
3
+ export type { RenderInput } from './render.js';
4
+ export type { ApplyProgress, PlanStepState, TargetPlan, Warning, } from './target.js';
@@ -0,0 +1,44 @@
1
+ import type { ConsumerPackage } from '../../commands/runCli/type.js';
2
+ import type { InjectReport, Scope } from '../../core/index.js';
3
+ import type { ApplyProgress, PlanStepState, TargetPlan, Warning } from './target.js';
4
+ export type Phase = {
5
+ readonly kind: 'booting';
6
+ } | {
7
+ readonly kind: 'resolving';
8
+ readonly targets: readonly ConsumerPackage[];
9
+ } | {
10
+ readonly kind: 'scope-select';
11
+ readonly targets: readonly ConsumerPackage[];
12
+ readonly pending: (scope: Scope) => void;
13
+ } | {
14
+ readonly kind: 'planning';
15
+ readonly targets: readonly ConsumerPackage[];
16
+ readonly scope: Scope;
17
+ readonly progress: ReadonlyMap<string, PlanStepState>;
18
+ } | {
19
+ readonly kind: 'diff-review';
20
+ readonly plans: readonly TargetPlan[];
21
+ readonly focusedIndex: number;
22
+ readonly scope: Scope;
23
+ } | {
24
+ readonly kind: 'force-confirm';
25
+ readonly plans: readonly TargetPlan[];
26
+ readonly warnings: readonly Warning[];
27
+ readonly pending: (ok: boolean) => void;
28
+ readonly scope: Scope;
29
+ } | {
30
+ readonly kind: 'applying';
31
+ readonly plans: readonly TargetPlan[];
32
+ readonly progress: ApplyProgress;
33
+ readonly scope: Scope;
34
+ } | {
35
+ readonly kind: 'summary';
36
+ readonly reports: readonly InjectReport[];
37
+ readonly plans: readonly TargetPlan[];
38
+ readonly exitCode: 0 | 1 | 2;
39
+ readonly scope: Scope;
40
+ readonly dryRun: boolean;
41
+ } | {
42
+ readonly kind: 'error';
43
+ readonly error: Error;
44
+ };
@@ -0,0 +1,6 @@
1
+ import type { ConsumerPackage, DefaultFlags } from '../../commands/runCli/type.js';
2
+ export interface RenderInput {
3
+ readonly targets: readonly ConsumerPackage[];
4
+ readonly flags: DefaultFlags;
5
+ readonly originCwd: string;
6
+ }
@@ -0,0 +1,25 @@
1
+ import type { InjectPlan } from '../../core/buildPlan/index.js';
2
+ import type { ScopeResolution } from '../../core/index.js';
3
+ import type { ConsumerPackage } from '../../commands/runCli/type.js';
4
+ export interface PlanStepState {
5
+ readonly packageName: string;
6
+ readonly status: 'pending' | 'running' | 'done' | 'failed';
7
+ readonly error?: string;
8
+ }
9
+ export interface TargetPlan {
10
+ readonly target: ConsumerPackage;
11
+ readonly scope: ScopeResolution;
12
+ readonly plan: InjectPlan;
13
+ }
14
+ export interface Warning {
15
+ readonly packageName: string;
16
+ readonly kind: 'warn-diverged' | 'warn-orphan';
17
+ readonly relPath: string;
18
+ readonly description: string;
19
+ }
20
+ export interface ApplyProgress {
21
+ readonly total: number;
22
+ readonly done: number;
23
+ readonly current?: string;
24
+ readonly startedAt: number;
25
+ }
@@ -2,4 +2,4 @@
2
2
  * Current package version from package.json
3
3
  * Automatically synchronized during build process
4
4
  */
5
- export declare const VERSION = "0.2.0";
5
+ export declare const VERSION = "0.3.1";
@@ -1,3 +1,3 @@
1
- const VERSION = '0.2.0';
1
+ const VERSION = '0.3.1';
2
2
 
3
3
  export { VERSION };
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: claude-docs-asset-wiring
3
+ description: "Wire a consumer package's docs/claude assets into the @slats/claude-assets-sync engine. Adds package.json.claude.assetPath, points scripts.build:hashes at claude-build-hashes, declares the engine as a dependency, updates CLAUDE.md, and runs the dispatcher smoke test. Idempotent — asks before clobbering."
4
+ user-invocable: true
5
+ disable-model-invocation: true
6
+ argument-hint: <target-package-path>
7
+ ---
8
+
9
+ # claude-docs-asset-wiring
10
+
11
+ Wire a consumer package's `docs/claude/**` into `@slats/claude-assets-sync`
12
+ so end users can inject those assets via the engine's `inject-claude-settings`
13
+ bin. Reference consumer: `packages/canard/schema-form`.
14
+
15
+ The engine is single-dispatcher. Consumers do NOT ship their own bin stubs
16
+ — they declare `claude.assetPath` in `package.json` and let the engine's
17
+ `claude-build-hashes` bin regenerate `dist/claude-hashes.json` during
18
+ build. `src/core/**` never reads `package.json`; only the engine's `bin/`
19
+ layer resolves a single explicitly-named target.
20
+
21
+ **Outcome**
22
+
23
+ ```bash
24
+ npx -p @slats/claude-assets-sync inject-claude-settings \
25
+ --package=<PACKAGE_NAME> \
26
+ --scope=user|project [--dry-run] [--force]
27
+ ```
28
+
29
+ ## Role
30
+
31
+ You are a monorepo wiring specialist. Execute the 6 steps below as a
32
+ single, idempotent procedure. On any conflicting existing value — ask
33
+ the user before overwriting. Never clobber silently.
34
+
35
+ ## Knowledge Resources
36
+
37
+ Consult these files as needed during execution. Do NOT preload everything;
38
+ load on demand.
39
+
40
+ - `knowledge/reference-files.md` — what the consumer should (and should not) own
41
+ - `knowledge/package-json-patches.md` — every required `package.json` edit, with guard conditions
42
+ - `knowledge/claude-md-template.md` — the `## Claude Docs Injector` section to inject into the target `CLAUDE.md`
43
+ - `knowledge/smoke-tests.md` — E2E 8-path matrix via the engine dispatcher
44
+ - `knowledge/dependency-cruiser.md` — optional CI-time isolation rule
45
+ - `knowledge/gotchas.md` — invariants and pitfalls
46
+
47
+ ## Inputs
48
+
49
+ Resolve these before starting. If any is missing, stop and ask.
50
+
51
+ | Variable | Source |
52
+ |----------------|-----------------------------------------------------------------------------------------------------------|
53
+ | `TARGET_PATH` | Skill argument (e.g. `packages/lerx/promise-modal`). If absent, ask the user. |
54
+ | `PACKAGE_NAME` | `name` field of `${TARGET_PATH}/package.json`. |
55
+ | `SHORTCUT` | Root `package.json` `scripts` entry whose value equals `yarn workspace ${PACKAGE_NAME}`; else unset. |
56
+
57
+ `SHORTCUT` is a convenience only. When unset, fall back to full workspace
58
+ syntax: `yarn workspace ${PACKAGE_NAME} <subcommand>`.
59
+
60
+ ## Pre-Flight
61
+
62
+ Stop and report on any failure. Do not attempt to fix silently.
63
+
64
+ - [ ] `${TARGET_PATH}/docs/claude/skills/<name>/SKILL.md` and `knowledge/*.md` exist — the docs to be injected.
65
+ - [ ] `${TARGET_PATH}/package.json` has `"type": "module"` and `"sideEffects": false`.
66
+ - [ ] Build pipeline uses `rollup -c && yarn build:types` where `build:types` runs `node ../../aileron/script/build/buildTypes.mjs`.
67
+ - [ ] `git status` in `${TARGET_PATH}` is clean. Unrelated changes present → confirm with user before proceeding.
68
+
69
+ ## Steps
70
+
71
+ Execute in order. Each step is idempotent; on conflict, ask rather than overwrite.
72
+
73
+ ### Step 1 — Patch `${TARGET_PATH}/package.json`
74
+
75
+ See `knowledge/package-json-patches.md` for the complete patch list:
76
+
77
+ - `claude.assetPath` — set to `docs/claude` (or the consumer's chosen path).
78
+ - `scripts.build` — ensure the chain ends with `&& yarn build:hashes`.
79
+ - `scripts.build:hashes` — set to `claude-build-hashes` (the engine's bin).
80
+ - `scripts.prepublishOnly` — `yarn build` if not already present.
81
+ - `devDependencies."@slats/claude-assets-sync"` — add (NOT `dependencies`, NOT `peerDependencies`). The engine is CLI-only and must not leak into end-user production installs.
82
+ - `files` — ensure `"dist"`, `"docs"`, `"README.md"` are listed. Never include `"bin"` or `"scripts"`.
83
+
84
+ Do NOT add any `bin` entry. Do NOT add `./bin/*` or `./docs/*` to `exports`.
85
+ Do NOT create `bin/` or `scripts/` directories in the consumer.
86
+
87
+ ### Step 2 — Patch `${TARGET_PATH}/CLAUDE.md`
88
+
89
+ If `CLAUDE.md` exists, append or replace the `## Claude Docs Injector`
90
+ section from `knowledge/claude-md-template.md`, substituting
91
+ `${PACKAGE_NAME}`. Skip if `CLAUDE.md` does not exist (do not create one).
92
+
93
+ ### Step 3 — (Optional) Dependency-cruiser isolation gate
94
+
95
+ Skip unless `${TARGET_PATH}/.dependency-cruiser.cjs` already exists or the
96
+ user explicitly asks. See `knowledge/dependency-cruiser.md` for the single
97
+ remaining forbidden rule (`src/**` → `docs/**`) and the `depcheck` script.
98
+
99
+ ### Step 4 — Install and build
100
+
101
+ ```bash
102
+ yarn install
103
+ yarn ${SHORTCUT:-workspace ${PACKAGE_NAME}} build
104
+ ```
105
+
106
+ Expected: `rollup` → `buildTypes` → `claude-build-hashes` succeed, and
107
+ `${TARGET_PATH}/dist/claude-hashes.json` is written.
108
+
109
+ ### Step 5 — E2E smoke via engine dispatcher
110
+
111
+ Run from `/tmp/...`, never from the monorepo root or `${TARGET_PATH}/` —
112
+ `--scope=project` walks `cwd` upward looking for an existing `.claude`,
113
+ which would mutate the real repo's. See `knowledge/smoke-tests.md` for
114
+ the full 8-path matrix, expected exit codes, and rationale.
115
+
116
+ ### Step 6 — Report
117
+
118
+ Summarize:
119
+
120
+ - Files patched vs. skipped (with reason for each skip).
121
+ - Manifest file count from `dist/claude-hashes.json`.
122
+ - Smoke-test exit codes (all 8).
123
+ - Recommendation: commit this change on its own, separate from other work.
124
+
125
+ ## Report Template
126
+
127
+ ```markdown
128
+ ## claude-docs-asset-wiring — ${PACKAGE_NAME}
129
+
130
+ **Files patched**
131
+ - package.json — patched: [claude.assetPath, scripts.build, scripts.build:hashes, dependencies, files]
132
+ - CLAUDE.md — section added | skipped (no CLAUDE.md)
133
+ - .dependency-cruiser.cjs — updated | skipped (not present)
134
+
135
+ **Manifest**
136
+ - dist/claude-hashes.json: <N> files
137
+
138
+ **Smoke tests**
139
+ | # | command | expected | actual |
140
+ |---|-------------------------------------------------------------|----------|--------|
141
+ | 1 | --package=${PACKAGE_NAME} --scope=project --dry-run | 0 | <n> |
142
+ | 2 | --package=${PACKAGE_NAME} --scope=project | 0 | <n> |
143
+ | 3 | --package=${PACKAGE_NAME} --scope=project (up-to-date) | 0 | <n> |
144
+ | 4 | CI=true --package=${PACKAGE_NAME} --scope=project (tampered)| 2 | <n> |
145
+ | 5 | CI=true --package=${PACKAGE_NAME} --scope=project --force | 0 | <n> |
146
+ | 6 | CI=true --package=${PACKAGE_NAME} (missing --scope) | 2 | <n> |
147
+ | 7 | (missing --package) | 2 | <n> |
148
+ | 8 | --package=@does/not-exist | 2 | <n> |
149
+
150
+ **Next**: commit on its own — do not bundle with unrelated changes.
151
+ ```
152
+
153
+ ## Termination Conditions
154
+
155
+ - **Pre-Flight fails** → stop, report the failing check. Do not proceed.
156
+ - **Conflict during patch** → stop, show the diff, ask user whether to overwrite.
157
+ - **Build fails at Step 4** → stop, report error. Do not run smoke tests on a broken build.
158
+ - **Smoke test mismatch** → stop, report the failing path with captured exit code.
159
+ - **All steps pass** → emit the report from the template above.
@@ -0,0 +1,78 @@
1
+ # `CLAUDE.md` — `## Claude Docs Injector` section
2
+
3
+ Reference: `packages/canard/schema-form/CLAUDE.md`.
4
+
5
+ Append the section below to `${TARGET_PATH}/CLAUDE.md` if the file
6
+ exists. Substitute the sample package name in the chosen template
7
+ with `${PACKAGE_NAME}` — four occurrences. Skip the entire step if
8
+ `CLAUDE.md` does not exist (do not create one).
9
+
10
+ The template is intentionally terse: CLI usage + essential isolation
11
+ warnings. Architectural rationale lives in `knowledge/gotchas.md` —
12
+ do not duplicate it into every consumer's `CLAUDE.md`.
13
+
14
+ ---
15
+
16
+ ## Template (Korean — used by all consumers except `@winglet/style-utils`)
17
+
18
+ ````markdown
19
+ ## Claude Docs Injector
20
+
21
+ `docs/claude/**` 자산을 사용자 `.claude/` 에 주입. 엔진: `@slats/claude-assets-sync` (bin: `inject-claude-settings`). 엔진은 `devDependencies` 에만 있으므로 항상 `npx -p @slats/claude-assets-sync ...` 로 호출합니다.
22
+
23
+ ```bash
24
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=user
25
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=project
26
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=user --dry-run
27
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=user --force
28
+ ```
29
+
30
+ ### Isolation Guardrails
31
+
32
+ - `src/**` 는 `docs/**` 와 `@slats/claude-assets-sync` 어느 것도 import 금지.
33
+ - **절대 `exports` 에 `./docs/*` 를 추가하지 말 것.**
34
+ ````
35
+
36
+ ---
37
+
38
+ ## Template (English — `@winglet/style-utils` convention)
39
+
40
+ ````markdown
41
+ ## Claude Docs Injector
42
+
43
+ Inject `docs/claude/**` into the user's `.claude/`. Engine: `@slats/claude-assets-sync` (bin: `inject-claude-settings`). The engine is declared only in `devDependencies`, so always invoke via `npx -p @slats/claude-assets-sync ...`.
44
+
45
+ ```bash
46
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=user
47
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=project
48
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=user --dry-run
49
+ npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=user --force
50
+ ```
51
+
52
+ ### Isolation Guardrails
53
+
54
+ - `src/**` MUST NOT import from `docs/**` or `@slats/claude-assets-sync`.
55
+ - **Never add `./docs/*` to `exports`.**
56
+ ````
57
+
58
+ ---
59
+
60
+ ## Substitution Rules
61
+
62
+ - Replace the sample package name in the chosen template with
63
+ `${PACKAGE_NAME}` — four occurrences.
64
+ - Preserve the Isolation Guardrails bullets verbatim — these are
65
+ the sharp invariants that must stay consistent across consumers.
66
+
67
+ ---
68
+
69
+ ## Placement & Skip Conditions
70
+
71
+ - Append to end of `CLAUDE.md`. Ensure one blank line before the
72
+ injected section.
73
+ - `${TARGET_PATH}/CLAUDE.md` does not exist → skip, report
74
+ "skipped (no CLAUDE.md)".
75
+ - Section already present with identical content → skip, report
76
+ "unchanged".
77
+ - Section present with different content → ask user, do not
78
+ clobber.