@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.
- package/README.md +47 -63
- package/bin/inject-claude-settings.mjs +4 -0
- package/dist/claude-hashes.json +9 -9
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/runCli/index.d.ts +1 -1
- package/dist/commands/runCli/runCli.d.ts +10 -6
- package/dist/commands/runCli/runCli.mjs +33 -6
- package/dist/commands/runCli/type.d.ts +4 -12
- package/dist/commands/runCli/utils/classifyTarget.d.ts +19 -0
- package/dist/commands/runCli/utils/classifyTarget.mjs +46 -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/resolvePackage.d.ts +16 -0
- package/dist/commands/runCli/utils/resolvePackage.mjs +74 -0
- package/dist/commands/runCli/utils/resolveScopeAlias.d.ts +2 -0
- package/dist/commands/runCli/utils/resolveScopeAlias.mjs +67 -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/resolveTargets.d.ts +15 -0
- package/dist/commands/runCli/utils/resolveTargets.mjs +38 -0
- 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/injectDocs/utils/applyAction.mjs +1 -1
- 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 +2 -2
- 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 +159 -0
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/claude-md-template.md +78 -0
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/dependency-cruiser.md +54 -0
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/gotchas.md +125 -0
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/package-json-patches.md +150 -0
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/reference-files.md +37 -0
- package/docs/claude/skills/claude-docs-asset-wiring/knowledge/smoke-tests.md +111 -0
- package/docs/consumer-integration.md +43 -101
- package/package.json +13 -8
- package/scripts/dev-ui-fixtures.ts +288 -0
- package/scripts/dev-ui.tsx +289 -0
- package/bin/claude-sync.mjs +0 -24
- package/dist/commands/runCli/runCli.cjs +0 -31
- package/dist/commands/runCli/utils/injectOne.cjs +0 -48
- package/dist/commands/runCli/utils/injectOne.d.ts +0 -3
- package/dist/commands/runCli/utils/injectOne.mjs +0 -46
- package/dist/commands/runCli/utils/resolveScopeFlag.cjs +0 -28
- package/dist/commands/runCli/utils/runInject.cjs +0 -36
- package/dist/commands/runCli/utils/runInject.d.ts +0 -2
- package/dist/commands/runCli/utils/runInject.mjs +0 -34
- 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
- package/docs/claude/skills/claude-sync-applier/SKILL.md +0 -195
- package/docs/claude/skills/claude-sync-applier/knowledge/claude-md-template.md +0 -77
- package/docs/claude/skills/claude-sync-applier/knowledge/dependency-cruiser.md +0 -126
- package/docs/claude/skills/claude-sync-applier/knowledge/gotchas.md +0 -139
- package/docs/claude/skills/claude-sync-applier/knowledge/package-json-patches.md +0 -130
- package/docs/claude/skills/claude-sync-applier/knowledge/reference-files.md +0 -120
- package/docs/claude/skills/claude-sync-applier/knowledge/smoke-tests.md +0 -102
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Dependency-Cruiser Isolation Rule (optional)
|
|
2
|
+
|
|
3
|
+
Skip this step unless `${TARGET_PATH}/.dependency-cruiser.cjs`
|
|
4
|
+
already exists or the user explicitly asks. This guardrail is a
|
|
5
|
+
CI-time check that the consumer's `src/**` never reaches the
|
|
6
|
+
Claude assets tree.
|
|
7
|
+
|
|
8
|
+
The post-v0.3.0 layout removes the bin stub entirely, so the
|
|
9
|
+
former `src-no-bin` and `src-no-claude-assets-sync` rules are no
|
|
10
|
+
longer load-bearing — the consumer no longer imports any of that
|
|
11
|
+
from anywhere. The one remaining invariant is `src/**` must not
|
|
12
|
+
import from `docs/**`.
|
|
13
|
+
|
|
14
|
+
## Rule
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
module.exports = {
|
|
18
|
+
forbidden: [
|
|
19
|
+
{
|
|
20
|
+
name: 'src-no-docs',
|
|
21
|
+
severity: 'error',
|
|
22
|
+
comment:
|
|
23
|
+
'src/ must not import from docs/. docs/claude/** contains pure markdown ' +
|
|
24
|
+
'assets meant only for the engine dispatcher, not for the library runtime.',
|
|
25
|
+
from: { path: '^src/' },
|
|
26
|
+
to: { path: '^docs/' },
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
options: {
|
|
30
|
+
doNotFollow: { path: 'node_modules' },
|
|
31
|
+
includeOnly: '^(src|docs)',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Optional script
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
"scripts": {
|
|
40
|
+
"depcheck": "depcruise src docs --config .dependency-cruiser.cjs --no-progress"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Zero errors expected. Orphan warnings on `docs/**` are
|
|
45
|
+
acceptable — the docs tree never imports anything.
|
|
46
|
+
|
|
47
|
+
## Legacy rules removed
|
|
48
|
+
|
|
49
|
+
Previous revisions of this skill had three forbidden rules
|
|
50
|
+
(`src-no-bin`, `src-no-docs`, `src-no-claude-assets-sync`), a
|
|
51
|
+
`no-orphans` adjustment excluding `^bin/`, and an `includeOnly`
|
|
52
|
+
covering `^src` and `^bin`. All of those assumed the consumer
|
|
53
|
+
owned a `bin/` directory. The new layout owns no `bin/`, so the
|
|
54
|
+
extra rules are dead. Do not reintroduce them.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Invariants and Gotchas
|
|
2
|
+
|
|
3
|
+
Hard-earned rules. Each one reflects a previous incident or a design
|
|
4
|
+
constraint of the `@slats/claude-assets-sync` engine.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## The engine is the only CLI surface
|
|
9
|
+
|
|
10
|
+
`inject-claude-settings` lives in one place: the engine package. No
|
|
11
|
+
consumer has a bin. No consumer has a `bin/` directory. No consumer
|
|
12
|
+
has a `scripts/` directory. If you find yourself "adapting" a stub
|
|
13
|
+
for a new consumer, stop — wiring does not need code; it needs two
|
|
14
|
+
fields in `package.json`.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## `claude.assetPath` is the opt-in marker
|
|
19
|
+
|
|
20
|
+
The engine's `claude-build-hashes` bin silently no-ops when
|
|
21
|
+
`claude.assetPath` is missing or not a string. The dispatcher
|
|
22
|
+
(`inject-claude-settings`) exits 2 with a clear error when a target
|
|
23
|
+
lacks the field. Both behaviors are intentional: missing = opt-out.
|
|
24
|
+
|
|
25
|
+
Do not add "helpful" error messages at build time for the opt-out
|
|
26
|
+
case — it would break silently-disabled packages.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
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/**`
|
|
46
|
+
never references the engine), not by dependency-type.
|
|
47
|
+
|
|
48
|
+
Every consumer's CLAUDE.md documents the single `npx -p` path.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Never add `./bin/*` or `./docs/*` to `exports`
|
|
53
|
+
|
|
54
|
+
The `exports` map in `package.json` controls which subpaths a
|
|
55
|
+
consumer's bundler can resolve. Keeping `./docs/*` out of
|
|
56
|
+
`exports` is what prevents a bundler from deep-importing the docs
|
|
57
|
+
tree into app bundles.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Do not commit `dist/claude-hashes.json`
|
|
62
|
+
|
|
63
|
+
It is a build artifact. The `yarn build` chain regenerates it via
|
|
64
|
+
`build:hashes`. It should be in `.gitignore` (usually via a
|
|
65
|
+
catch-all `dist/` rule). If you see it in `git status`, stop —
|
|
66
|
+
something is misconfigured.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## `yarn workspace ${PACKAGE_NAME} build` can fail with `rollup: command not found`
|
|
71
|
+
|
|
72
|
+
Yarn v4 workspace dispatch does not always propagate the
|
|
73
|
+
workspace-local PATH. Prefer `yarn ${SHORTCUT} build` from the
|
|
74
|
+
monorepo root, where `${SHORTCUT}` is the root-level script alias
|
|
75
|
+
(e.g. `yarn schemaForm`, `yarn claudeAssetsSync`).
|
|
76
|
+
|
|
77
|
+
If no shortcut exists, the full form may still work depending on
|
|
78
|
+
yarn version and cache state — but if it fails with `rollup:
|
|
79
|
+
command not found`, add a shortcut to the root `package.json`
|
|
80
|
+
rather than debugging the nested call.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## `--scope=project` walks upward
|
|
85
|
+
|
|
86
|
+
`--scope=project` walks `process.cwd()` upward looking for an
|
|
87
|
+
existing `.claude` directory. The first one found is reused; if
|
|
88
|
+
none is found, the engine creates one at `cwd`.
|
|
89
|
+
|
|
90
|
+
Consequence: running the smoke tests from the monorepo root would
|
|
91
|
+
reuse the monorepo's real `.claude`, corrupting it. Always run
|
|
92
|
+
smoke tests from `/tmp/...` with a fresh directory.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Dispatcher exception to the `src/core` purity rule
|
|
97
|
+
|
|
98
|
+
`src/core/**` never reads `package.json` or walks the filesystem.
|
|
99
|
+
The engine's `bin/inject-claude-settings.mjs` and
|
|
100
|
+
`src/commands/runCli/utils/resolvePackage.ts` are allowed to
|
|
101
|
+
`createRequire().resolve(`${name}/package.json`)` for exactly one
|
|
102
|
+
target — the one named in `--package=<name>`. The dispatcher never
|
|
103
|
+
enumerates, never walks `node_modules` for siblings. Preserve this
|
|
104
|
+
boundary: extensions like `--all` or workspace scan require
|
|
105
|
+
explicit re-architecture.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Commit this change alone
|
|
110
|
+
|
|
111
|
+
The change set from this skill touches the consumer's
|
|
112
|
+
`package.json` and possibly its `CLAUDE.md`. It should land in a
|
|
113
|
+
single commit, with no unrelated changes interleaved.
|
|
114
|
+
|
|
115
|
+
Reasons:
|
|
116
|
+
|
|
117
|
+
- Easier to revert as a unit if an issue appears downstream.
|
|
118
|
+
- The CI signal (smoke tests) is bound to the state of these files
|
|
119
|
+
and nothing else.
|
|
120
|
+
- Reviewers can skim-verify against the reference consumer without
|
|
121
|
+
reviewing business logic.
|
|
122
|
+
|
|
123
|
+
If the user asks to bundle with other work, push back once:
|
|
124
|
+
recommend a separate commit. If they still want it bundled,
|
|
125
|
+
proceed but note it in the Step 6 report.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# `package.json` Patches
|
|
2
|
+
|
|
3
|
+
All edits below are **additive**. Existing non-conflicting values
|
|
4
|
+
remain untouched. On any conflicting existing value, stop and ask the
|
|
5
|
+
user — do not overwrite.
|
|
6
|
+
|
|
7
|
+
Reference: `packages/canard/schema-form/package.json`.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. `claude.assetPath`
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
"claude": {
|
|
15
|
+
"assetPath": "docs/claude"
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Consumer-side convention — the engine does not enforce it. Relative
|
|
20
|
+
to the consumer's package root. If the field already exists with a
|
|
21
|
+
non-default value, preserve it.
|
|
22
|
+
|
|
23
|
+
A missing or non-string value is an intentional opt-out: the
|
|
24
|
+
dispatcher will exit 2 with a clear error, and `claude-build-hashes`
|
|
25
|
+
will silently no-op. Do not remove the opt-out path.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. `scripts.build`
|
|
30
|
+
|
|
31
|
+
Ensure the build chain invokes `yarn build:hashes` at the end:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "rollup -c && yarn build:types && yarn build:hashes"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Guard against double-append.** If the existing value already
|
|
40
|
+
contains `build:hashes`, leave it alone.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 3. `scripts.build:hashes`
|
|
45
|
+
|
|
46
|
+
Point to the engine's bin (NOT a local stub):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build:hashes": "claude-build-hashes"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`claude-build-hashes` reads `process.cwd()/package.json` and picks
|
|
55
|
+
up `claude.assetPath`. Works because `@slats/claude-assets-sync` is
|
|
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).
|
|
59
|
+
|
|
60
|
+
If a different `build:hashes` script exists, ask.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 4. `scripts.prepublishOnly`
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
"scripts": {
|
|
68
|
+
"prepublishOnly": "yarn build"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Guarantees `dist/claude-hashes.json` is regenerated before publish.
|
|
73
|
+
If the target already has a `prepublishOnly` that calls `yarn build`
|
|
74
|
+
(directly or transitively), leave it alone.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 5. `devDependencies."@slats/claude-assets-sync"`
|
|
79
|
+
|
|
80
|
+
**Must be in `devDependencies`, never `dependencies` or
|
|
81
|
+
`peerDependencies`.**
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"@slats/claude-assets-sync": "workspace:^"
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Reasons:
|
|
90
|
+
|
|
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.
|
|
101
|
+
- Bundle isolation is enforced by the import graph (`src/**` never
|
|
102
|
+
references the engine), not by dependency-type.
|
|
103
|
+
|
|
104
|
+
If the target already has it in `dependencies` or
|
|
105
|
+
`peerDependencies`, move it to `devDependencies`. Do not duplicate.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 6. `files`
|
|
110
|
+
|
|
111
|
+
Ship the published artifact surface. Keep `"dist"`, `"docs"`, and
|
|
112
|
+
`"README.md"` (plus whatever else the package needs). Do NOT
|
|
113
|
+
include `"bin"` or `"scripts"`:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"files": [
|
|
117
|
+
"dist",
|
|
118
|
+
"docs",
|
|
119
|
+
"README.md"
|
|
120
|
+
]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If `files` is absent, create it with at least `["dist", "docs", "README.md"]`.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 7. `bin` — MUST be ABSENT
|
|
128
|
+
|
|
129
|
+
Never add a `bin` field. Bin names collide across consumers under
|
|
130
|
+
`node_modules/.bin/` and the engine is the sole CLI surface.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 8. `exports` — never add `./bin/*` or `./docs/*`
|
|
135
|
+
|
|
136
|
+
Exports control which subpaths a consumer's bundler can resolve.
|
|
137
|
+
Keeping `./bin/*` and `./docs/*` out of `exports` is what prevents
|
|
138
|
+
consumer bundlers from pulling the CLI or the asset tree into app
|
|
139
|
+
bundles.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Full Reference
|
|
144
|
+
|
|
145
|
+
See `packages/canard/schema-form/package.json` for the canonical
|
|
146
|
+
shape. The relevant keys are `scripts.build`,
|
|
147
|
+
`scripts.build:hashes`, `scripts.prepublishOnly`,
|
|
148
|
+
`dependencies."@slats/claude-assets-sync"`, `claude.assetPath`, and
|
|
149
|
+
`files`. Everything else in that file is schema-form-specific and
|
|
150
|
+
must not be copied.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Reference Files
|
|
2
|
+
|
|
3
|
+
Consumers do **not** own any runtime files for the injector. The whole
|
|
4
|
+
CLI surface lives in `@slats/claude-assets-sync`. A consumer is wired
|
|
5
|
+
up by editing `package.json` and (optionally) `CLAUDE.md` — nothing
|
|
6
|
+
else.
|
|
7
|
+
|
|
8
|
+
Reference consumer: `packages/canard/schema-form`.
|
|
9
|
+
|
|
10
|
+
## What the consumer MUST own
|
|
11
|
+
|
|
12
|
+
- `docs/claude/**` — the assets to ship (skills / rules / commands).
|
|
13
|
+
- `package.json.claude.assetPath` — string, usually `"docs/claude"`.
|
|
14
|
+
|
|
15
|
+
## What the consumer MUST NOT own
|
|
16
|
+
|
|
17
|
+
- Any `bin/` directory or stub file. The engine owns the dispatcher.
|
|
18
|
+
- Any `scripts/build-hashes.mjs` wrapper. Use the engine's
|
|
19
|
+
`claude-build-hashes` bin directly in `scripts.build:hashes`.
|
|
20
|
+
- Any `"bin"` entry in `package.json`.
|
|
21
|
+
- `./bin/*` or `./docs/*` exposed in `exports`. Exposing them would
|
|
22
|
+
let bundlers pull CLI code or the docs tree into app bundles.
|
|
23
|
+
|
|
24
|
+
## What the engine provides
|
|
25
|
+
|
|
26
|
+
- `inject-claude-settings` bin — dispatcher. Invoked as
|
|
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
|
+
- `claude-build-hashes` bin — reads `process.cwd()/package.json`,
|
|
32
|
+
picks up `claude.assetPath`, hashes every file beneath it, and
|
|
33
|
+
writes `dist/claude-hashes.json`. Run via `yarn build:hashes` in
|
|
34
|
+
the consumer build chain.
|
|
35
|
+
- `buildHashes()` + `injectDocs()` — headless programmatic APIs.
|
|
36
|
+
|
|
37
|
+
No content mirroring across consumers. No stub drift to manage.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# E2E Smoke Tests — 8-path matrix via engine dispatcher
|
|
2
|
+
|
|
3
|
+
**Run from `/tmp/...` — never from the monorepo root or `${TARGET_PATH}/`.**
|
|
4
|
+
|
|
5
|
+
`--scope=project` walks `cwd` upward looking for an existing `.claude`
|
|
6
|
+
directory. Running from the monorepo would reuse or mutate the real
|
|
7
|
+
repo's `.claude`, which is a destructive error.
|
|
8
|
+
|
|
9
|
+
No fake `node_modules` needed — the engine uses
|
|
10
|
+
`createRequire(import.meta.url).resolve(`${PACKAGE_NAME}/package.json`)`
|
|
11
|
+
from the engine's own installed location.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
BIN="$PWD/packages/slats/claude-assets-sync/bin/inject-claude-settings.mjs"
|
|
19
|
+
DIR=/tmp/inject-smoke-${SHORTCUT:-target}
|
|
20
|
+
[ -d "$DIR" ] && find "$DIR" -mindepth 1 -delete
|
|
21
|
+
mkdir -p "$DIR" && cd "$DIR"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`[ -d ... ] && find -delete` keeps the setup idempotent. **Never** use
|
|
25
|
+
`rm -rf` or unquoted `*` globs — too easy to nuke the wrong directory.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Matrix
|
|
30
|
+
|
|
31
|
+
Execute sequentially. `EXIT=$?` after each so the value is captured
|
|
32
|
+
before the next command overwrites `$?`.
|
|
33
|
+
|
|
34
|
+
| # | Command | Expected exit | Purpose |
|
|
35
|
+
|----|--------------------------------------------------------------------------------------------------|---------------|--------------------------------------------------------------|
|
|
36
|
+
| 1 | `node "$BIN" --package=${PACKAGE_NAME} --scope=project --dry-run` | 0 | Dry run — previews actions, no writes. |
|
|
37
|
+
| 2 | `node "$BIN" --package=${PACKAGE_NAME} --scope=project` | 0 | First real install — writes `.claude/` under `$DIR`. |
|
|
38
|
+
| 3 | `node "$BIN" --package=${PACKAGE_NAME} --scope=project` | 0 | Re-run — no-op (idempotent). |
|
|
39
|
+
| 4 | (after tampering) `CI=true node "$BIN" --package=${PACKAGE_NAME} --scope=project` | **2** | CI + tampered content → refuse to overwrite. |
|
|
40
|
+
| 5 | `CI=true node "$BIN" --package=${PACKAGE_NAME} --scope=project --force` | 0 | `--force` overrides the refusal. |
|
|
41
|
+
| 6 | `CI=true node "$BIN" --package=${PACKAGE_NAME}` | **2** | Missing `--scope` in non-TTY context. |
|
|
42
|
+
| 7 | `node "$BIN"` | **2** | Missing `--package` (dispatcher-specific). |
|
|
43
|
+
| 8 | `node "$BIN" --package=@does/not-exist` | **2** | Unresolvable package (dispatcher-specific). |
|
|
44
|
+
|
|
45
|
+
### Tamper step (between path 3 and path 4)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
find .claude -name SKILL.md -exec sh -c 'echo tampered >> "$1"' _ {} \;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Appends `tampered` to every `SKILL.md` under the local `.claude/`.
|
|
52
|
+
Simulates a human edit that the CI-mode dispatcher must detect and
|
|
53
|
+
refuse to clobber.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Execution Shape
|
|
58
|
+
|
|
59
|
+
Split into **two bash calls** because `cwd` resets between Bash tool
|
|
60
|
+
invocations.
|
|
61
|
+
|
|
62
|
+
**First call** — paths 1–3:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
BIN="$PWD/packages/slats/claude-assets-sync/bin/inject-claude-settings.mjs"
|
|
66
|
+
DIR=/tmp/inject-smoke-${SHORTCUT:-target}
|
|
67
|
+
[ -d "$DIR" ] && find "$DIR" -mindepth 1 -delete
|
|
68
|
+
mkdir -p "$DIR" && cd "$DIR"
|
|
69
|
+
|
|
70
|
+
node "$BIN" --package=${PACKAGE_NAME} --scope=project --dry-run; echo "EXIT=$?"
|
|
71
|
+
node "$BIN" --package=${PACKAGE_NAME} --scope=project; echo "EXIT=$?"
|
|
72
|
+
node "$BIN" --package=${PACKAGE_NAME} --scope=project; echo "EXIT=$?"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Second call** — paths 4–8:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
DIR=/tmp/inject-smoke-${SHORTCUT:-target}
|
|
79
|
+
BIN="$PWD/packages/slats/claude-assets-sync/bin/inject-claude-settings.mjs"
|
|
80
|
+
cd "$DIR"
|
|
81
|
+
|
|
82
|
+
find .claude -name SKILL.md -exec sh -c 'echo tampered >> "$1"' _ {} \;
|
|
83
|
+
CI=true node "$BIN" --package=${PACKAGE_NAME} --scope=project; echo "EXIT=$?"
|
|
84
|
+
CI=true node "$BIN" --package=${PACKAGE_NAME} --scope=project --force; echo "EXIT=$?"
|
|
85
|
+
CI=true node "$BIN" --package=${PACKAGE_NAME}; echo "EXIT=$?"
|
|
86
|
+
node "$BIN"; echo "EXIT=$?"
|
|
87
|
+
node "$BIN" --package=@does/not-exist; echo "EXIT=$?"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Note: `$PWD` in the second call is the parent shell's cwd (monorepo
|
|
91
|
+
root), so `BIN` resolves correctly. `cd "$DIR"` then moves into the
|
|
92
|
+
smoke directory before invoking.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Failure Handling
|
|
97
|
+
|
|
98
|
+
| Observed | Meaning | Action |
|
|
99
|
+
|----------|-------------------------------------------------------------------------|--------------------------------------------------------------------|
|
|
100
|
+
| 1 ≠ 0 | Dry-run crashed. Likely an engine bug or bad `claude.assetPath`. | Stop, capture stderr, report. |
|
|
101
|
+
| 2 ≠ 0 | First write failed. Permissions, engine bug, or manifest issue. | Stop, inspect `dist/claude-hashes.json`, report. |
|
|
102
|
+
| 3 ≠ 0 | Idempotency broken — re-run should be no-op. | Stop, diff `$DIR/.claude` before/after, report. |
|
|
103
|
+
| 4 = 0 | CI mode did not refuse tampered files. Safety regression. | Stop — the engine's CI gate is broken. |
|
|
104
|
+
| 5 ≠ 0 | `--force` failed to override. Check engine. | Stop, report. |
|
|
105
|
+
| 6 = 0 | Engine defaulted a scope in non-TTY context. Should require `--scope`. | Stop, report. |
|
|
106
|
+
| 7 = 0 | Dispatcher accepted no `--package`. Violates contract. | Stop — dispatcher bug. |
|
|
107
|
+
| 8 = 0 | Dispatcher succeeded on unresolvable package. Violates contract. | Stop — dispatcher bug. |
|
|
108
|
+
|
|
109
|
+
Do not attempt to "make the tests pass" by altering expectations. The
|
|
110
|
+
matrix encodes invariants of the engine — a mismatch is a real
|
|
111
|
+
regression upstream.
|