@slats/claude-assets-sync 0.3.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.
- package/README.md +9 -9
- package/dist/claude-hashes.json +7 -7
- package/dist/commands/runCli/runCli.mjs +7 -2
- package/dist/commands/runCli/type.d.ts +1 -0
- package/dist/commands/runCli/utils/renderOrFallback.d.ts +6 -0
- package/dist/commands/runCli/utils/renderOrFallback.mjs +12 -0
- package/dist/commands/runCli/utils/renderPlain.d.ts +11 -0
- package/dist/commands/runCli/utils/renderPlain.mjs +89 -0
- package/dist/commands/runCli/utils/resolveScopeFlag.d.ts +9 -1
- package/dist/commands/runCli/utils/resolveScopeFlag.mjs +5 -11
- package/dist/commands/runCli/utils/toConsumerPackages.d.ts +9 -0
- package/dist/commands/runCli/utils/toConsumerPackages.mjs +26 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/injectDocs/index.d.ts +3 -2
- package/dist/core/injectDocs/type.d.ts +0 -19
- package/dist/core/scope/index.d.ts +1 -1
- package/dist/core/scope/scope.d.ts +0 -1
- package/dist/core/scope/scope.mjs +1 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/ui/InjectApp/InjectApp.d.ts +2 -0
- package/dist/ui/InjectApp/InjectApp.mjs +82 -0
- package/dist/ui/InjectApp/index.d.ts +2 -0
- package/dist/ui/InjectApp/utils/eventSelectors.d.ts +5 -0
- package/dist/ui/InjectApp/utils/eventSelectors.mjs +24 -0
- package/dist/ui/InjectApp/utils/phaseReducer.d.ts +2 -0
- package/dist/ui/InjectApp/utils/phaseReducer.mjs +130 -0
- package/dist/ui/InjectApp/utils/renderInjectApp.d.ts +2 -0
- package/dist/ui/InjectApp/utils/renderInjectApp.mjs +19 -0
- package/dist/ui/InjectApp/utils/type.d.ts +5 -0
- package/dist/ui/components/ActionRow.d.ts +7 -0
- package/dist/ui/components/ActionRow.mjs +45 -0
- package/dist/ui/components/Banner.d.ts +7 -0
- package/dist/ui/components/Banner.mjs +9 -0
- package/dist/ui/components/ConfirmForce.d.ts +8 -0
- package/dist/ui/components/ConfirmForce.mjs +35 -0
- package/dist/ui/components/ErrorPanel.d.ts +6 -0
- package/dist/ui/components/ErrorPanel.mjs +14 -0
- package/dist/ui/components/Footer.d.ts +8 -0
- package/dist/ui/components/Footer.mjs +27 -0
- package/dist/ui/components/PlanTable.d.ts +8 -0
- package/dist/ui/components/PlanTable.mjs +15 -0
- package/dist/ui/components/ProgressBar.d.ts +10 -0
- package/dist/ui/components/ProgressBar.mjs +28 -0
- package/dist/ui/components/ScopePicker.d.ts +7 -0
- package/dist/ui/components/ScopePicker.mjs +26 -0
- package/dist/ui/components/Spinner.d.ts +8 -0
- package/dist/ui/components/Spinner.mjs +10 -0
- package/dist/ui/components/StatusBadge.d.ts +8 -0
- package/dist/ui/components/StepTracker.d.ts +9 -0
- package/dist/ui/components/StepTracker.mjs +43 -0
- package/dist/ui/components/Summary.d.ts +9 -0
- package/dist/ui/components/Summary.mjs +30 -0
- package/dist/ui/components/TargetCard.d.ts +11 -0
- package/dist/ui/components/TargetCard.mjs +29 -0
- package/dist/ui/hooks/useApplyStep.d.ts +12 -0
- package/dist/ui/hooks/useApplyStep.mjs +30 -0
- package/dist/ui/hooks/useExitApp.d.ts +8 -0
- package/dist/ui/hooks/useExitApp.mjs +19 -0
- package/dist/ui/hooks/useForceConfirmStep.d.ts +9 -0
- package/dist/ui/hooks/useForceConfirmStep.mjs +24 -0
- package/dist/ui/hooks/useInjectSession.d.ts +10 -0
- package/dist/ui/hooks/useInjectSession.mjs +63 -0
- package/dist/ui/hooks/useInterval.d.ts +1 -0
- package/dist/ui/hooks/usePhase.d.ts +2 -0
- package/dist/ui/hooks/usePhase.mjs +9 -0
- package/dist/ui/hooks/usePlanStep.d.ts +13 -0
- package/dist/ui/hooks/usePlanStep.mjs +94 -0
- package/dist/ui/hooks/useResolveStep.d.ts +18 -0
- package/dist/ui/hooks/useResolveStep.mjs +21 -0
- package/dist/ui/hooks/useTerminalWidth.d.ts +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.mjs +16 -0
- package/dist/ui/theme/colors.d.ts +12 -0
- package/dist/ui/theme/colors.mjs +9 -0
- package/dist/ui/theme/icons.d.ts +29 -0
- package/dist/ui/theme/icons.mjs +17 -0
- package/dist/ui/theme/layout.d.ts +20 -0
- package/dist/ui/theme/layout.mjs +9 -0
- package/dist/ui/types/event.d.ts +45 -0
- package/dist/ui/types/index.d.ts +4 -0
- package/dist/ui/types/phase.d.ts +44 -0
- package/dist/ui/types/render.d.ts +6 -0
- package/dist/ui/types/target.d.ts +25 -0
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.mjs +1 -1
- package/docs/claude/skills/claude-docs-asset-wiring/SKILL.md +1 -1
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/claude-md-template.md +4 -12
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/gotchas.md +17 -14
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/package-json-patches.md +18 -13
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/reference-files.md +4 -4
- package/docs/consumer-integration.md +9 -8
- package/package.json +12 -7
- package/scripts/dev-ui-fixtures.ts +288 -0
- package/scripts/dev-ui.tsx +289 -0
- package/dist/commands/runCli/runCli.cjs +0 -53
- package/dist/commands/runCli/utils/classifyTarget.cjs +0 -48
- package/dist/commands/runCli/utils/injectOne.cjs +0 -47
- package/dist/commands/runCli/utils/injectOne.d.ts +0 -3
- package/dist/commands/runCli/utils/injectOne.mjs +0 -45
- package/dist/commands/runCli/utils/resolvePackage.cjs +0 -77
- package/dist/commands/runCli/utils/resolveScopeAlias.cjs +0 -69
- package/dist/commands/runCli/utils/resolveScopeFlag.cjs +0 -28
- package/dist/commands/runCli/utils/resolveTargets.cjs +0 -40
- package/dist/commands/runCli/utils/runInject.cjs +0 -52
- package/dist/commands/runCli/utils/runInject.d.ts +0 -3
- package/dist/commands/runCli/utils/runInject.mjs +0 -50
- package/dist/core/buildPlan/buildPlan.cjs +0 -42
- package/dist/core/buildPlan/utils/toPosix.cjs +0 -9
- package/dist/core/buildPlan/utils/walkFiles.cjs +0 -25
- package/dist/core/hash/hash.cjs +0 -30
- package/dist/core/hashManifest/hashManifest.cjs +0 -27
- package/dist/core/injectDocs/injectDocs.cjs +0 -43
- package/dist/core/injectDocs/injectDocs.d.ts +0 -2
- package/dist/core/injectDocs/injectDocs.mjs +0 -41
- package/dist/core/injectDocs/utils/applyAction.cjs +0 -21
- package/dist/core/injectDocs/utils/emitCiForceList.cjs +0 -10
- package/dist/core/injectDocs/utils/emitCiForceList.d.ts +0 -2
- package/dist/core/injectDocs/utils/emitCiForceList.mjs +0 -8
- package/dist/core/injectDocs/utils/printPlan.cjs +0 -20
- package/dist/core/injectDocs/utils/printPlan.d.ts +0 -2
- package/dist/core/injectDocs/utils/printPlan.mjs +0 -18
- package/dist/core/injectDocs/utils/summarize.cjs +0 -27
- package/dist/core/scope/scope.cjs +0 -46
- package/dist/core/scope/utils/isDirectory.cjs +0 -14
- package/dist/index.cjs +0 -20
- package/dist/prompts/confirmForce.cjs +0 -27
- package/dist/prompts/confirmForce.d.ts +0 -1
- package/dist/prompts/confirmForce.mjs +0 -25
- package/dist/prompts/index.d.ts +0 -2
- package/dist/prompts/selectScope.cjs +0 -30
- package/dist/prompts/selectScope.d.ts +0 -2
- package/dist/prompts/selectScope.mjs +0 -28
- package/dist/utils/asyncPool.cjs +0 -26
- package/dist/utils/heartbeat.cjs +0 -25
- package/dist/utils/heartbeat.d.ts +0 -16
- package/dist/utils/heartbeat.mjs +0 -23
- package/dist/utils/logger.cjs +0 -74
- package/dist/utils/version.cjs +0 -5
|
@@ -4,7 +4,7 @@ Reference: `packages/canard/schema-form/CLAUDE.md`.
|
|
|
4
4
|
|
|
5
5
|
Append the section below to `${TARGET_PATH}/CLAUDE.md` if the file
|
|
6
6
|
exists. Substitute the sample package name in the chosen template
|
|
7
|
-
with `${PACKAGE_NAME}` —
|
|
7
|
+
with `${PACKAGE_NAME}` — four occurrences. Skip the entire step if
|
|
8
8
|
`CLAUDE.md` does not exist (do not create one).
|
|
9
9
|
|
|
10
10
|
The template is intentionally terse: CLI usage + essential isolation
|
|
@@ -18,17 +18,13 @@ do not duplicate it into every consumer's `CLAUDE.md`.
|
|
|
18
18
|
````markdown
|
|
19
19
|
## Claude Docs Injector
|
|
20
20
|
|
|
21
|
-
`docs/claude/**` 자산을 사용자 `.claude/` 에 주입. 엔진: `@slats/claude-assets-sync` (bin: `inject-claude-settings`).
|
|
21
|
+
`docs/claude/**` 자산을 사용자 `.claude/` 에 주입. 엔진: `@slats/claude-assets-sync` (bin: `inject-claude-settings`). 엔진은 `devDependencies` 에만 있으므로 항상 `npx -p @slats/claude-assets-sync ...` 로 호출합니다.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
# universal — 모든 PM (pnpm strict / yarn-berry PnP 포함)
|
|
25
24
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=user
|
|
26
25
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=project
|
|
27
26
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=user --dry-run
|
|
28
27
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@canard/schema-form --scope=user --force
|
|
29
|
-
|
|
30
|
-
# 간편 — npm / yarn-classic 에서만 (transitive bin hoist 기반)
|
|
31
|
-
npx inject-claude-settings --package=@canard/schema-form --scope=user
|
|
32
28
|
```
|
|
33
29
|
|
|
34
30
|
### Isolation Guardrails
|
|
@@ -44,17 +40,13 @@ npx inject-claude-settings --package=@canard/schema-form --scope=user
|
|
|
44
40
|
````markdown
|
|
45
41
|
## Claude Docs Injector
|
|
46
42
|
|
|
47
|
-
Inject `docs/claude/**` into the user's `.claude/`. Engine: `@slats/claude-assets-sync` (bin: `inject-claude-settings`).
|
|
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 ...`.
|
|
48
44
|
|
|
49
45
|
```bash
|
|
50
|
-
# universal — every PM (pnpm strict / yarn-berry PnP included)
|
|
51
46
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=user
|
|
52
47
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=project
|
|
53
48
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=user --dry-run
|
|
54
49
|
npx -p @slats/claude-assets-sync inject-claude-settings --package=@winglet/style-utils --scope=user --force
|
|
55
|
-
|
|
56
|
-
# simple — npm / yarn-classic only (relies on transitive bin hoist)
|
|
57
|
-
npx inject-claude-settings --package=@winglet/style-utils --scope=user
|
|
58
50
|
```
|
|
59
51
|
|
|
60
52
|
### Isolation Guardrails
|
|
@@ -68,7 +60,7 @@ npx inject-claude-settings --package=@winglet/style-utils --scope=user
|
|
|
68
60
|
## Substitution Rules
|
|
69
61
|
|
|
70
62
|
- Replace the sample package name in the chosen template with
|
|
71
|
-
`${PACKAGE_NAME}` —
|
|
63
|
+
`${PACKAGE_NAME}` — four occurrences.
|
|
72
64
|
- Preserve the Isolation Guardrails bullets verbatim — these are
|
|
73
65
|
the sharp invariants that must stay consistent across consumers.
|
|
74
66
|
|
|
@@ -27,22 +27,25 @@ case — it would break silently-disabled packages.
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
## `@slats/claude-assets-sync` must be in `
|
|
31
|
-
|
|
32
|
-
Not `
|
|
33
|
-
|
|
34
|
-
1.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
## `@slats/claude-assets-sync` must be in `devDependencies`
|
|
31
|
+
|
|
32
|
+
Not `dependencies`, not `peerDependencies`. Reasons:
|
|
33
|
+
|
|
34
|
+
1. The engine is CLI-only. Declaring it in `dependencies` would
|
|
35
|
+
pull `commander`, `@inquirer/prompts`, and their transitive
|
|
36
|
+
trees into every end-user's production install even though the
|
|
37
|
+
consumer's runtime never imports the engine.
|
|
38
|
+
2. The monorepo build chain still resolves `.bin/claude-build-hashes`
|
|
39
|
+
from `devDependencies` at `yarn install` time — yarn workspaces
|
|
40
|
+
link devDeps and deps identically for workspace-local builds.
|
|
41
|
+
3. End users never rely on a hoisted `inject-claude-settings` bin.
|
|
42
|
+
The canonical invocation is `npx -p @slats/claude-assets-sync
|
|
43
|
+
inject-claude-settings --package=<THIS>`, which fetches the
|
|
44
|
+
engine on demand and caches it.
|
|
45
|
+
4. Bundle isolation is enforced by the import graph (`src/**`
|
|
41
46
|
never references the engine), not by dependency-type.
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
universal form `npx -p @slats/claude-assets-sync inject-claude-settings
|
|
45
|
-
--package=<THIS>`. Every consumer's CLAUDE.md documents both paths.
|
|
48
|
+
Every consumer's CLAUDE.md documents the single `npx -p` path.
|
|
46
49
|
|
|
47
50
|
---
|
|
48
51
|
|
|
@@ -53,8 +53,9 @@ Point to the engine's bin (NOT a local stub):
|
|
|
53
53
|
|
|
54
54
|
`claude-build-hashes` reads `process.cwd()/package.json` and picks
|
|
55
55
|
up `claude.assetPath`. Works because `@slats/claude-assets-sync` is
|
|
56
|
-
in `
|
|
57
|
-
linked
|
|
56
|
+
in `devDependencies`, so `node_modules/.bin/claude-build-hashes` is
|
|
57
|
+
linked at workspace install time (yarn workspaces link devDeps and
|
|
58
|
+
deps identically for workspace-local builds).
|
|
58
59
|
|
|
59
60
|
If a different `build:hashes` script exists, ask.
|
|
60
61
|
|
|
@@ -74,30 +75,34 @@ If the target already has a `prepublishOnly` that calls `yarn build`
|
|
|
74
75
|
|
|
75
76
|
---
|
|
76
77
|
|
|
77
|
-
## 5. `
|
|
78
|
+
## 5. `devDependencies."@slats/claude-assets-sync"`
|
|
78
79
|
|
|
79
|
-
**Must be in `
|
|
80
|
+
**Must be in `devDependencies`, never `dependencies` or
|
|
80
81
|
`peerDependencies`.**
|
|
81
82
|
|
|
82
83
|
```json
|
|
83
|
-
"
|
|
84
|
+
"devDependencies": {
|
|
84
85
|
"@slats/claude-assets-sync": "workspace:^"
|
|
85
86
|
}
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
Reasons:
|
|
89
90
|
|
|
90
|
-
-
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
- The engine is CLI-only. Declaring it in `dependencies` would pull
|
|
92
|
+
`commander`, `@inquirer/prompts`, and their transitive trees into
|
|
93
|
+
every end-user's production install even though the consumer's
|
|
94
|
+
runtime never imports the engine.
|
|
95
|
+
- The monorepo build chain still resolves `.bin/claude-build-hashes`
|
|
96
|
+
from `devDependencies` at `yarn install` time — yarn workspaces
|
|
97
|
+
link devDeps and deps identically for workspace-local builds.
|
|
98
|
+
- End users invoke the engine via `npx -p @slats/claude-assets-sync
|
|
99
|
+
inject-claude-settings --package=<THIS>`, which fetches the engine
|
|
100
|
+
on demand and caches it. No transitive bin hoist is required.
|
|
96
101
|
- Bundle isolation is enforced by the import graph (`src/**` never
|
|
97
102
|
references the engine), not by dependency-type.
|
|
98
103
|
|
|
99
|
-
If the target already has it in `
|
|
100
|
-
`peerDependencies`, move it to `
|
|
104
|
+
If the target already has it in `dependencies` or
|
|
105
|
+
`peerDependencies`, move it to `devDependencies`. Do not duplicate.
|
|
101
106
|
|
|
102
107
|
---
|
|
103
108
|
|
|
@@ -24,10 +24,10 @@ Reference consumer: `packages/canard/schema-form`.
|
|
|
24
24
|
## What the engine provides
|
|
25
25
|
|
|
26
26
|
- `inject-claude-settings` bin — dispatcher. Invoked as
|
|
27
|
-
`npx -p @slats/claude-assets-sync inject-claude-settings --package=<name> --scope=<scope
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
`npx -p @slats/claude-assets-sync inject-claude-settings --package=<name> --scope=<scope>`.
|
|
28
|
+
The engine is a consumer-side `devDependency` only, so end users
|
|
29
|
+
never get a hoisted bin; the `npx -p` form pulls the engine on
|
|
30
|
+
demand and caches it.
|
|
31
31
|
- `claude-build-hashes` bin — reads `process.cwd()/package.json`,
|
|
32
32
|
picks up `claude.assetPath`, hashes every file beneath it, and
|
|
33
33
|
writes `dist/claude-hashes.json`. Run via `yarn build:hashes` in
|
|
@@ -12,7 +12,7 @@ How to make a package ship Claude Code assets through the `inject-claude-setting
|
|
|
12
12
|
"build": "… && yarn build:hashes",
|
|
13
13
|
"build:hashes": "claude-build-hashes"
|
|
14
14
|
},
|
|
15
|
-
"
|
|
15
|
+
"devDependencies": {
|
|
16
16
|
"@slats/claude-assets-sync": "workspace:^"
|
|
17
17
|
},
|
|
18
18
|
"files": ["dist", "docs", "README.md"],
|
|
@@ -22,10 +22,10 @@ How to make a package ship Claude Code assets through the `inject-claude-setting
|
|
|
22
22
|
}
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
- `@slats/claude-assets-sync` MUST be in `
|
|
25
|
+
- `@slats/claude-assets-sync` MUST be in `devDependencies`. The engine is a CLI-only tool; declaring it in `dependencies` would pull `commander`, `@inquirer/prompts`, and their transitive trees into every end-user's production install even though the consumer's runtime never imports the engine.
|
|
26
26
|
- Do **not** add any `bin` field. Bin names collide across consumers under `node_modules/.bin/` and the engine is the sole CLI surface.
|
|
27
27
|
- Do **not** expose `./bin/*` or `./docs/*` in `exports`. Exposing them would let bundlers pull CLI code or the docs tree into app bundles.
|
|
28
|
-
- Do **not** create a `bin/` or `scripts/` directory in the consumer. The engine's `claude-build-hashes` bin (resolved via `node_modules/.bin/`) handles build-time hashing.
|
|
28
|
+
- Do **not** create a `bin/` or `scripts/` directory in the consumer. The engine's `claude-build-hashes` bin (resolved via `node_modules/.bin/` from `devDependencies` at workspace install time) handles build-time hashing.
|
|
29
29
|
|
|
30
30
|
## 2. `docs/claude/` authoring
|
|
31
31
|
|
|
@@ -65,12 +65,13 @@ The legacy `src-no-bin` and `src-no-claude-assets-sync` rules are no longer load
|
|
|
65
65
|
|
|
66
66
|
## 4. End-user invocations
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
The engine is not shipped as a runtime dependency of any consumer, so end users never get a hoisted `inject-claude-settings` bin. Always invoke via `npx -p @slats/claude-assets-sync ...`; the package manager fetches and caches the engine on demand.
|
|
69
|
+
|
|
70
|
+
| Scenario | Invocation |
|
|
69
71
|
|---|---|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
| End user has **multiple consumers installed** | Call `inject-claude-settings --package=<one-name>` per target. There is no `--all`. |
|
|
72
|
+
| Single consumer target | `npx -p @slats/claude-assets-sync inject-claude-settings --package=@your-scope/your-package --scope=user` |
|
|
73
|
+
| All packages under one npm scope | `npx -p @slats/claude-assets-sync inject-claude-settings --package=@your-scope --scope=user` (scope alias — no slash) |
|
|
74
|
+
| Multiple specific targets | Repeat `--package` or comma-separate: `--package=@scope-a --package=@scope-b/pkg`. There is no `--all`. |
|
|
74
75
|
|
|
75
76
|
### Scope resolution (project)
|
|
76
77
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slats/claude-assets-sync",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Shared CLI engine that lets consumer packages inject their Claude docs (skills, rules, commands) into a user's .claude directory via a thin bin/inject-docs wrapper.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -27,14 +27,12 @@
|
|
|
27
27
|
".": {
|
|
28
28
|
"types": "./dist/index.d.ts",
|
|
29
29
|
"source": "./src/index.ts",
|
|
30
|
-
"import": "./dist/index.mjs"
|
|
31
|
-
"require": "./dist/index.cjs"
|
|
30
|
+
"import": "./dist/index.mjs"
|
|
32
31
|
},
|
|
33
32
|
"./buildHashes": {
|
|
34
33
|
"import": "./scripts/buildHashes.mjs"
|
|
35
34
|
}
|
|
36
35
|
},
|
|
37
|
-
"main": "dist/index.cjs",
|
|
38
36
|
"module": "dist/index.mjs",
|
|
39
37
|
"types": "dist/index.d.ts",
|
|
40
38
|
"bin": {
|
|
@@ -54,6 +52,8 @@
|
|
|
54
52
|
"build:publish:npm": "yarn build && yarn publish:npm",
|
|
55
53
|
"build:types": "node ../../aileron/script/build/buildTypes.mjs",
|
|
56
54
|
"dev": "node scripts/inject-version.js && tsx src/main.ts",
|
|
55
|
+
"dev:ui": "tsx scripts/dev-ui.tsx",
|
|
56
|
+
"dev:cli": "tsx bin/inject-claude-settings.mjs",
|
|
57
57
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
58
58
|
"lint": "eslint \"src/**/*.ts\"",
|
|
59
59
|
"prepublishOnly": "yarn build",
|
|
@@ -64,12 +64,17 @@
|
|
|
64
64
|
"version:patch": "yarn version patch"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@inquirer/prompts": "^8.4.2",
|
|
68
67
|
"commander": "^12.1.0",
|
|
69
|
-
"
|
|
68
|
+
"ink": "^7.0.0",
|
|
69
|
+
"ink-gradient": "^4.0.0",
|
|
70
|
+
"ink-select-input": "^6.2.0",
|
|
71
|
+
"ink-spinner": "^5.0.0",
|
|
72
|
+
"picocolors": "^1.1.1",
|
|
73
|
+
"react": "^19.2.0"
|
|
70
74
|
},
|
|
71
75
|
"devDependencies": {
|
|
72
|
-
"@
|
|
76
|
+
"@types/react": "^19.2.0",
|
|
77
|
+
"ink-testing-library": "^4.0.0"
|
|
73
78
|
},
|
|
74
79
|
"claude": {
|
|
75
80
|
"assetPath": "docs/claude"
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type { ConsumerPackage } from '../src/commands/runCli/type.js';
|
|
5
|
+
import type { InjectPlan, Action } from '../src/core/buildPlan/index.js';
|
|
6
|
+
import type { InjectReport, ScopeResolution } from '../src/core/index.js';
|
|
7
|
+
import type {
|
|
8
|
+
ApplyProgress,
|
|
9
|
+
InjectEvent,
|
|
10
|
+
Phase,
|
|
11
|
+
PlanStepState,
|
|
12
|
+
TargetPlan,
|
|
13
|
+
Warning,
|
|
14
|
+
} from '../src/ui/types/index.js';
|
|
15
|
+
|
|
16
|
+
export const PHASES = [
|
|
17
|
+
'resolving',
|
|
18
|
+
'scope-select',
|
|
19
|
+
'planning',
|
|
20
|
+
'diff-review',
|
|
21
|
+
'force-confirm',
|
|
22
|
+
'applying',
|
|
23
|
+
'summary',
|
|
24
|
+
'summary-dry',
|
|
25
|
+
'error',
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
export type PhaseKey = (typeof PHASES)[number];
|
|
29
|
+
|
|
30
|
+
const MOCK_TARGETS: ConsumerPackage[] = [
|
|
31
|
+
{
|
|
32
|
+
name: '@canard/schema-form',
|
|
33
|
+
version: '0.12.1',
|
|
34
|
+
packageRoot: '/workspace/packages/canard/schema-form',
|
|
35
|
+
assetRoot: '/workspace/packages/canard/schema-form/docs/claude',
|
|
36
|
+
hashesPresent: true,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: '@canard/schema-form-antd-plugin',
|
|
40
|
+
version: '0.12.1',
|
|
41
|
+
packageRoot: '/workspace/packages/canard/schema-form-antd-plugin',
|
|
42
|
+
assetRoot: '/workspace/packages/canard/schema-form-antd-plugin/docs/claude',
|
|
43
|
+
hashesPresent: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: '@winglet/common-utils',
|
|
47
|
+
version: '0.12.1',
|
|
48
|
+
packageRoot: '/workspace/packages/winglet/common-utils',
|
|
49
|
+
assetRoot: '/workspace/packages/winglet/common-utils/docs/claude',
|
|
50
|
+
hashesPresent: true,
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const scopeFixture: ScopeResolution = {
|
|
55
|
+
scope: 'user',
|
|
56
|
+
targetRoot: join(homedir(), '.claude'),
|
|
57
|
+
description: '~/.claude (user)',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function makeActions(
|
|
61
|
+
baseDstRoot: string,
|
|
62
|
+
options: {
|
|
63
|
+
copy?: number;
|
|
64
|
+
skip?: number;
|
|
65
|
+
diverged?: number;
|
|
66
|
+
orphan?: number;
|
|
67
|
+
del?: number;
|
|
68
|
+
},
|
|
69
|
+
): Action[] {
|
|
70
|
+
const actions: Action[] = [];
|
|
71
|
+
let fileIdx = 0;
|
|
72
|
+
for (let i = 0; i < (options.copy ?? 0); i += 1) {
|
|
73
|
+
fileIdx += 1;
|
|
74
|
+
actions.push({
|
|
75
|
+
kind: 'copy',
|
|
76
|
+
relPath: `skills/expert/doc-${fileIdx}.md`,
|
|
77
|
+
dstAbs: `${baseDstRoot}/skills/expert/doc-${fileIdx}.md`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
for (let i = 0; i < (options.skip ?? 0); i += 1) {
|
|
81
|
+
fileIdx += 1;
|
|
82
|
+
actions.push({
|
|
83
|
+
kind: 'skip-uptodate',
|
|
84
|
+
relPath: `skills/expert/existing-${fileIdx}.md`,
|
|
85
|
+
dstAbs: `${baseDstRoot}/skills/expert/existing-${fileIdx}.md`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
for (let i = 0; i < (options.diverged ?? 0); i += 1) {
|
|
89
|
+
fileIdx += 1;
|
|
90
|
+
actions.push({
|
|
91
|
+
kind: 'warn-diverged',
|
|
92
|
+
relPath: `skills/expert/edited-${fileIdx}.md`,
|
|
93
|
+
dstAbs: `${baseDstRoot}/skills/expert/edited-${fileIdx}.md`,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
for (let i = 0; i < (options.orphan ?? 0); i += 1) {
|
|
97
|
+
fileIdx += 1;
|
|
98
|
+
actions.push({
|
|
99
|
+
kind: 'warn-orphan',
|
|
100
|
+
relPath: `skills/expert/ghost-${fileIdx}.md`,
|
|
101
|
+
dstAbs: `${baseDstRoot}/skills/expert/ghost-${fileIdx}.md`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
for (let i = 0; i < (options.del ?? 0); i += 1) {
|
|
105
|
+
fileIdx += 1;
|
|
106
|
+
actions.push({
|
|
107
|
+
kind: 'delete',
|
|
108
|
+
relPath: `skills/expert/stale-${fileIdx}.md`,
|
|
109
|
+
dstAbs: `${baseDstRoot}/skills/expert/stale-${fileIdx}.md`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return actions;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function makeTargetPlan(
|
|
116
|
+
target: ConsumerPackage,
|
|
117
|
+
actions: Action[],
|
|
118
|
+
requiresForce = false,
|
|
119
|
+
): TargetPlan {
|
|
120
|
+
const plan: InjectPlan = { actions, requiresForce };
|
|
121
|
+
return { target, scope: scopeFixture, plan };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const TP_CLEAN = makeTargetPlan(
|
|
125
|
+
MOCK_TARGETS[0],
|
|
126
|
+
makeActions(scopeFixture.targetRoot, { copy: 4, skip: 2 }),
|
|
127
|
+
false,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const TP_WARN = makeTargetPlan(
|
|
131
|
+
MOCK_TARGETS[1],
|
|
132
|
+
makeActions(scopeFixture.targetRoot, {
|
|
133
|
+
copy: 2,
|
|
134
|
+
skip: 1,
|
|
135
|
+
diverged: 1,
|
|
136
|
+
orphan: 1,
|
|
137
|
+
}),
|
|
138
|
+
true,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const TP_THIRD = makeTargetPlan(
|
|
142
|
+
MOCK_TARGETS[2],
|
|
143
|
+
makeActions(scopeFixture.targetRoot, { copy: 3, skip: 5 }),
|
|
144
|
+
false,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const PLAN_SET: readonly TargetPlan[] = [TP_CLEAN, TP_WARN, TP_THIRD];
|
|
148
|
+
|
|
149
|
+
const MOCK_WARNINGS: Warning[] = [
|
|
150
|
+
{
|
|
151
|
+
packageName: MOCK_TARGETS[1].name,
|
|
152
|
+
kind: 'warn-diverged',
|
|
153
|
+
relPath: 'skills/expert/edited-4.md',
|
|
154
|
+
description: 'local differs from source',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
packageName: MOCK_TARGETS[1].name,
|
|
158
|
+
kind: 'warn-orphan',
|
|
159
|
+
relPath: 'skills/expert/ghost-5.md',
|
|
160
|
+
description: 'exists locally but not in manifest',
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
const MOCK_REPORTS: InjectReport[] = PLAN_SET.map((tp) => {
|
|
165
|
+
const report: InjectReport = {
|
|
166
|
+
created: [],
|
|
167
|
+
updated: [],
|
|
168
|
+
skipped: [],
|
|
169
|
+
warnings: [],
|
|
170
|
+
deleted: [],
|
|
171
|
+
exitCode: 0,
|
|
172
|
+
};
|
|
173
|
+
for (const action of tp.plan.actions) {
|
|
174
|
+
if (action.kind === 'copy') report.created.push(action.relPath);
|
|
175
|
+
else if (action.kind === 'skip-uptodate') report.skipped.push(action.relPath);
|
|
176
|
+
else if (action.kind === 'warn-diverged')
|
|
177
|
+
report.warnings.push({ relPath: action.relPath, reason: 'diverged' });
|
|
178
|
+
else if (action.kind === 'warn-orphan')
|
|
179
|
+
report.warnings.push({ relPath: action.relPath, reason: 'orphan' });
|
|
180
|
+
else if (action.kind === 'delete') report.deleted.push(action.relPath);
|
|
181
|
+
}
|
|
182
|
+
return report;
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const MOCK_APPLY_PROGRESS: ApplyProgress = {
|
|
186
|
+
total: 18,
|
|
187
|
+
done: 7,
|
|
188
|
+
current: 'skills/expert/doc-8.md',
|
|
189
|
+
startedAt: Date.now() - 2500,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
function makePlanningProgress(): ReadonlyMap<string, PlanStepState> {
|
|
193
|
+
return new Map([
|
|
194
|
+
[
|
|
195
|
+
MOCK_TARGETS[0].name,
|
|
196
|
+
{ packageName: MOCK_TARGETS[0].name, status: 'done' },
|
|
197
|
+
],
|
|
198
|
+
[
|
|
199
|
+
MOCK_TARGETS[1].name,
|
|
200
|
+
{ packageName: MOCK_TARGETS[1].name, status: 'running' },
|
|
201
|
+
],
|
|
202
|
+
[
|
|
203
|
+
MOCK_TARGETS[2].name,
|
|
204
|
+
{ packageName: MOCK_TARGETS[2].name, status: 'pending' },
|
|
205
|
+
],
|
|
206
|
+
]);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function buildPhase(kind: PhaseKey): Phase {
|
|
210
|
+
switch (kind) {
|
|
211
|
+
case 'resolving':
|
|
212
|
+
return { kind: 'resolving', targets: MOCK_TARGETS };
|
|
213
|
+
case 'scope-select':
|
|
214
|
+
return {
|
|
215
|
+
kind: 'scope-select',
|
|
216
|
+
targets: MOCK_TARGETS,
|
|
217
|
+
pending: () => {
|
|
218
|
+
/* noop */
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
case 'planning':
|
|
222
|
+
return {
|
|
223
|
+
kind: 'planning',
|
|
224
|
+
targets: MOCK_TARGETS,
|
|
225
|
+
scope: 'user',
|
|
226
|
+
progress: makePlanningProgress(),
|
|
227
|
+
};
|
|
228
|
+
case 'diff-review':
|
|
229
|
+
return {
|
|
230
|
+
kind: 'diff-review',
|
|
231
|
+
plans: PLAN_SET,
|
|
232
|
+
focusedIndex: 0,
|
|
233
|
+
scope: 'user',
|
|
234
|
+
};
|
|
235
|
+
case 'force-confirm':
|
|
236
|
+
return {
|
|
237
|
+
kind: 'force-confirm',
|
|
238
|
+
plans: PLAN_SET,
|
|
239
|
+
warnings: MOCK_WARNINGS,
|
|
240
|
+
pending: () => {
|
|
241
|
+
/* noop */
|
|
242
|
+
},
|
|
243
|
+
scope: 'user',
|
|
244
|
+
};
|
|
245
|
+
case 'applying':
|
|
246
|
+
return {
|
|
247
|
+
kind: 'applying',
|
|
248
|
+
plans: PLAN_SET,
|
|
249
|
+
progress: MOCK_APPLY_PROGRESS,
|
|
250
|
+
scope: 'user',
|
|
251
|
+
};
|
|
252
|
+
case 'summary':
|
|
253
|
+
return {
|
|
254
|
+
kind: 'summary',
|
|
255
|
+
reports: MOCK_REPORTS,
|
|
256
|
+
plans: PLAN_SET,
|
|
257
|
+
exitCode: 0,
|
|
258
|
+
scope: 'user',
|
|
259
|
+
dryRun: false,
|
|
260
|
+
};
|
|
261
|
+
case 'summary-dry':
|
|
262
|
+
return {
|
|
263
|
+
kind: 'summary',
|
|
264
|
+
reports: MOCK_REPORTS,
|
|
265
|
+
plans: PLAN_SET,
|
|
266
|
+
exitCode: 0,
|
|
267
|
+
scope: 'user',
|
|
268
|
+
dryRun: true,
|
|
269
|
+
};
|
|
270
|
+
case 'error':
|
|
271
|
+
return {
|
|
272
|
+
kind: 'error',
|
|
273
|
+
error: new Error(
|
|
274
|
+
'Sample fatal: dist/claude-hashes.json missing at /workspace/packages/canard/schema-form',
|
|
275
|
+
),
|
|
276
|
+
};
|
|
277
|
+
default: {
|
|
278
|
+
const _exhaustive: never = kind;
|
|
279
|
+
void _exhaustive;
|
|
280
|
+
throw new Error('unknown phase');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function fixtureEvents(kind: PhaseKey): InjectEvent[] {
|
|
286
|
+
void kind;
|
|
287
|
+
return [];
|
|
288
|
+
}
|