@slats/claude-assets-sync 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +111 -587
  2. package/bin/claude-sync.mjs +24 -0
  3. package/dist/claude-hashes.json +20 -0
  4. package/dist/commands/index.d.ts +1 -112
  5. package/dist/commands/runCli/index.d.ts +2 -0
  6. package/dist/commands/runCli/runCli.cjs +31 -0
  7. package/dist/commands/runCli/runCli.d.ts +10 -0
  8. package/dist/commands/runCli/runCli.mjs +29 -0
  9. package/dist/commands/runCli/type.d.ts +28 -0
  10. package/dist/commands/runCli/utils/injectOne.cjs +48 -0
  11. package/dist/commands/runCli/utils/injectOne.d.ts +3 -0
  12. package/dist/commands/runCli/utils/injectOne.mjs +46 -0
  13. package/dist/commands/runCli/utils/resolveScopeFlag.cjs +28 -0
  14. package/dist/commands/runCli/utils/resolveScopeFlag.d.ts +2 -0
  15. package/dist/commands/runCli/utils/resolveScopeFlag.mjs +26 -0
  16. package/dist/commands/runCli/utils/runInject.cjs +36 -0
  17. package/dist/commands/runCli/utils/runInject.d.ts +2 -0
  18. package/dist/commands/runCli/utils/runInject.mjs +34 -0
  19. package/dist/core/buildPlan/buildPlan.cjs +42 -0
  20. package/dist/core/buildPlan/buildPlan.d.ts +2 -0
  21. package/dist/core/buildPlan/buildPlan.mjs +40 -0
  22. package/dist/core/buildPlan/index.d.ts +2 -0
  23. package/dist/core/buildPlan/type.d.ts +32 -0
  24. package/dist/core/buildPlan/utils/toPosix.cjs +9 -0
  25. package/dist/core/buildPlan/utils/toPosix.d.ts +1 -0
  26. package/dist/core/buildPlan/utils/toPosix.mjs +7 -0
  27. package/dist/core/buildPlan/utils/walkFiles.cjs +25 -0
  28. package/dist/core/buildPlan/utils/walkFiles.d.ts +1 -0
  29. package/dist/core/buildPlan/utils/walkFiles.mjs +23 -0
  30. package/dist/core/hash/hash.cjs +30 -0
  31. package/dist/core/hash/hash.d.ts +4 -0
  32. package/dist/core/hash/hash.mjs +26 -0
  33. package/dist/core/hash/index.d.ts +1 -0
  34. package/dist/core/hashManifest/hashManifest.cjs +27 -0
  35. package/dist/core/hashManifest/hashManifest.d.ts +17 -0
  36. package/dist/core/hashManifest/hashManifest.mjs +23 -0
  37. package/dist/core/hashManifest/index.d.ts +1 -0
  38. package/dist/core/index.d.ts +5 -0
  39. package/dist/core/injectDocs/index.d.ts +2 -0
  40. package/dist/core/injectDocs/injectDocs.cjs +43 -0
  41. package/dist/core/injectDocs/injectDocs.d.ts +2 -0
  42. package/dist/core/injectDocs/injectDocs.mjs +41 -0
  43. package/dist/core/injectDocs/type.d.ts +30 -0
  44. package/dist/core/injectDocs/utils/applyAction.cjs +21 -0
  45. package/dist/core/injectDocs/utils/applyAction.d.ts +2 -0
  46. package/dist/core/injectDocs/utils/applyAction.mjs +19 -0
  47. package/dist/core/injectDocs/utils/emitCiForceList.cjs +10 -0
  48. package/dist/core/injectDocs/utils/emitCiForceList.d.ts +2 -0
  49. package/dist/core/injectDocs/utils/emitCiForceList.mjs +8 -0
  50. package/dist/core/injectDocs/utils/printPlan.cjs +20 -0
  51. package/dist/core/injectDocs/utils/printPlan.d.ts +2 -0
  52. package/dist/core/injectDocs/utils/printPlan.mjs +18 -0
  53. package/dist/core/injectDocs/utils/summarize.cjs +27 -0
  54. package/dist/core/injectDocs/utils/summarize.d.ts +3 -0
  55. package/dist/core/injectDocs/utils/summarize.mjs +25 -0
  56. package/dist/core/scope/index.d.ts +1 -0
  57. package/dist/core/scope/scope.cjs +46 -0
  58. package/dist/core/scope/scope.d.ts +16 -0
  59. package/dist/core/scope/scope.mjs +41 -0
  60. package/dist/core/scope/utils/isDirectory.cjs +14 -0
  61. package/dist/core/scope/utils/isDirectory.d.ts +1 -0
  62. package/dist/core/scope/utils/isDirectory.mjs +12 -0
  63. package/dist/index.cjs +15 -9
  64. package/dist/index.d.ts +3 -5
  65. package/dist/index.mjs +7 -3
  66. package/dist/prompts/confirmForce.cjs +27 -0
  67. package/dist/prompts/confirmForce.d.ts +1 -0
  68. package/dist/prompts/confirmForce.mjs +25 -0
  69. package/dist/prompts/index.d.ts +2 -0
  70. package/dist/prompts/selectScope.cjs +30 -0
  71. package/dist/prompts/selectScope.d.ts +2 -0
  72. package/dist/prompts/selectScope.mjs +28 -0
  73. package/dist/utils/heartbeat.cjs +25 -0
  74. package/dist/utils/heartbeat.d.ts +16 -0
  75. package/dist/utils/heartbeat.mjs +23 -0
  76. package/dist/utils/logger.cjs +7 -0
  77. package/dist/utils/logger.d.ts +8 -0
  78. package/dist/utils/logger.mjs +7 -0
  79. package/dist/utils/types.d.ts +1 -252
  80. package/dist/utils/version.cjs +2 -14
  81. package/dist/utils/version.d.ts +3 -53
  82. package/dist/utils/version.mjs +2 -13
  83. package/docs/bundle-size-decision.md +36 -0
  84. package/docs/claude/skills/claude-sync-applier/SKILL.md +195 -0
  85. package/docs/claude/skills/claude-sync-applier/knowledge/claude-md-template.md +77 -0
  86. package/docs/claude/skills/claude-sync-applier/knowledge/dependency-cruiser.md +126 -0
  87. package/docs/claude/skills/claude-sync-applier/knowledge/gotchas.md +139 -0
  88. package/docs/claude/skills/claude-sync-applier/knowledge/package-json-patches.md +130 -0
  89. package/docs/claude/skills/claude-sync-applier/knowledge/reference-files.md +120 -0
  90. package/docs/claude/skills/claude-sync-applier/knowledge/smoke-tests.md +102 -0
  91. package/docs/consumer-integration.md +153 -0
  92. package/package.json +24 -16
  93. package/scripts/build-hashes.mjs +30 -0
  94. package/scripts/buildHashes.d.mts +15 -0
  95. package/scripts/buildHashes.mjs +82 -0
  96. package/scripts/claude-build-hashes.mjs +42 -0
  97. package/scripts/inject-version.js +112 -0
  98. package/dist/cli.cjs +0 -8
  99. package/dist/cli.d.ts +0 -1
  100. package/dist/cli.mjs +0 -7
  101. package/dist/commands/add.cjs +0 -80
  102. package/dist/commands/add.d.ts +0 -8
  103. package/dist/commands/add.mjs +0 -78
  104. package/dist/commands/list.cjs +0 -94
  105. package/dist/commands/list.d.ts +0 -15
  106. package/dist/commands/list.mjs +0 -91
  107. package/dist/commands/migrate.cjs +0 -9
  108. package/dist/commands/migrate.d.ts +0 -6
  109. package/dist/commands/migrate.mjs +0 -7
  110. package/dist/commands/remove.cjs +0 -127
  111. package/dist/commands/remove.d.ts +0 -6
  112. package/dist/commands/remove.mjs +0 -105
  113. package/dist/commands/status.cjs +0 -193
  114. package/dist/commands/status.d.ts +0 -6
  115. package/dist/commands/status.mjs +0 -171
  116. package/dist/commands/sync.cjs +0 -28
  117. package/dist/commands/sync.d.ts +0 -6
  118. package/dist/commands/sync.mjs +0 -26
  119. package/dist/commands/types.d.ts +0 -89
  120. package/dist/commands/update.cjs +0 -209
  121. package/dist/commands/update.d.ts +0 -29
  122. package/dist/commands/update.mjs +0 -206
  123. package/dist/components/add/AddCommand.cjs +0 -103
  124. package/dist/components/add/AddCommand.d.ts +0 -14
  125. package/dist/components/add/AddCommand.mjs +0 -101
  126. package/dist/components/add/BulkAddView.cjs +0 -165
  127. package/dist/components/add/BulkAddView.d.ts +0 -11
  128. package/dist/components/add/BulkAddView.mjs +0 -163
  129. package/dist/components/add/index.d.ts +0 -2
  130. package/dist/components/index.d.ts +0 -2
  131. package/dist/components/list/EditableTreeItem.d.ts +0 -13
  132. package/dist/components/list/ListCommand.cjs +0 -651
  133. package/dist/components/list/ListCommand.d.ts +0 -5
  134. package/dist/components/list/ListCommand.mjs +0 -649
  135. package/dist/components/list/SyncedPackageTree.d.ts +0 -14
  136. package/dist/components/list/index.d.ts +0 -10
  137. package/dist/components/list/types.d.ts +0 -14
  138. package/dist/components/primitives/Box.d.ts +0 -4
  139. package/dist/components/primitives/Spinner.d.ts +0 -6
  140. package/dist/components/primitives/Text.d.ts +0 -4
  141. package/dist/components/primitives/index.d.ts +0 -3
  142. package/dist/components/remove/RemoveConfirm.cjs +0 -18
  143. package/dist/components/remove/RemoveConfirm.d.ts +0 -11
  144. package/dist/components/remove/RemoveConfirm.mjs +0 -16
  145. package/dist/components/shared/Confirm.cjs +0 -30
  146. package/dist/components/shared/Confirm.d.ts +0 -8
  147. package/dist/components/shared/Confirm.mjs +0 -28
  148. package/dist/components/shared/MenuItem.cjs +0 -18
  149. package/dist/components/shared/MenuItem.d.ts +0 -7
  150. package/dist/components/shared/MenuItem.mjs +0 -16
  151. package/dist/components/shared/ProgressBar.d.ts +0 -7
  152. package/dist/components/shared/StepRunner.cjs +0 -58
  153. package/dist/components/shared/StepRunner.d.ts +0 -15
  154. package/dist/components/shared/StepRunner.mjs +0 -56
  155. package/dist/components/shared/Table.cjs +0 -19
  156. package/dist/components/shared/Table.d.ts +0 -8
  157. package/dist/components/shared/Table.mjs +0 -17
  158. package/dist/components/shared/index.d.ts +0 -6
  159. package/dist/components/status/PackageStatusCard.d.ts +0 -10
  160. package/dist/components/status/StatusDisplay.cjs +0 -26
  161. package/dist/components/status/StatusDisplay.d.ts +0 -23
  162. package/dist/components/status/StatusDisplay.mjs +0 -24
  163. package/dist/components/status/StatusTreeNode.cjs +0 -40
  164. package/dist/components/status/StatusTreeNode.d.ts +0 -15
  165. package/dist/components/status/StatusTreeNode.mjs +0 -38
  166. package/dist/components/status/index.d.ts +0 -6
  167. package/dist/components/tree/AssetTreeNode.cjs +0 -54
  168. package/dist/components/tree/AssetTreeNode.d.ts +0 -12
  169. package/dist/components/tree/AssetTreeNode.mjs +0 -52
  170. package/dist/components/tree/TreeSelect.cjs +0 -129
  171. package/dist/components/tree/TreeSelect.d.ts +0 -12
  172. package/dist/components/tree/TreeSelect.mjs +0 -127
  173. package/dist/components/tree/index.d.ts +0 -4
  174. package/dist/core/assetStructure.cjs +0 -30
  175. package/dist/core/assetStructure.d.ts +0 -36
  176. package/dist/core/assetStructure.mjs +0 -27
  177. package/dist/core/cli.cjs +0 -106
  178. package/dist/core/cli.d.ts +0 -9
  179. package/dist/core/cli.mjs +0 -103
  180. package/dist/core/constants.cjs +0 -28
  181. package/dist/core/constants.d.ts +0 -94
  182. package/dist/core/constants.mjs +0 -21
  183. package/dist/core/filesystem.cjs +0 -98
  184. package/dist/core/filesystem.d.ts +0 -94
  185. package/dist/core/filesystem.mjs +0 -88
  186. package/dist/core/github.cjs +0 -115
  187. package/dist/core/github.d.ts +0 -61
  188. package/dist/core/github.mjs +0 -107
  189. package/dist/core/io.cjs +0 -46
  190. package/dist/core/io.d.ts +0 -40
  191. package/dist/core/io.mjs +0 -39
  192. package/dist/core/listOperations.cjs +0 -228
  193. package/dist/core/listOperations.d.ts +0 -43
  194. package/dist/core/listOperations.mjs +0 -205
  195. package/dist/core/localSource.cjs +0 -126
  196. package/dist/core/localSource.d.ts +0 -33
  197. package/dist/core/localSource.mjs +0 -120
  198. package/dist/core/migration.cjs +0 -201
  199. package/dist/core/migration.d.ts +0 -57
  200. package/dist/core/migration.mjs +0 -198
  201. package/dist/core/packageScanner.cjs +0 -360
  202. package/dist/core/packageScanner.d.ts +0 -22
  203. package/dist/core/packageScanner.mjs +0 -356
  204. package/dist/core/sync.cjs +0 -400
  205. package/dist/core/sync.d.ts +0 -21
  206. package/dist/core/sync.mjs +0 -397
  207. package/dist/core/syncMeta.cjs +0 -242
  208. package/dist/core/syncMeta.d.ts +0 -75
  209. package/dist/core/syncMeta.mjs +0 -229
  210. package/dist/utils/dependencies.cjs +0 -57
  211. package/dist/utils/dependencies.d.ts +0 -10
  212. package/dist/utils/dependencies.mjs +0 -34
  213. package/dist/utils/nameTransform.cjs +0 -13
  214. package/dist/utils/nameTransform.d.ts +0 -65
  215. package/dist/utils/nameTransform.mjs +0 -11
  216. package/dist/utils/package.cjs +0 -170
  217. package/dist/utils/package.d.ts +0 -105
  218. package/dist/utils/package.mjs +0 -157
  219. package/dist/utils/packageName.cjs +0 -24
  220. package/dist/utils/packageName.d.ts +0 -32
  221. package/dist/utils/packageName.mjs +0 -21
  222. package/dist/utils/paths.cjs +0 -18
  223. package/dist/utils/paths.d.ts +0 -55
  224. package/dist/utils/paths.mjs +0 -15
  225. package/dist/version.cjs +0 -5
  226. package/dist/version.d.ts +0 -5
  227. package/dist/version.mjs +0 -3
@@ -0,0 +1,195 @@
1
+ ---
2
+ name: claude-sync-applier
3
+ description: "Wire the claude-sync CLI onto a consumer package in this monorepo. Copies verbatim bin/claude-sync.mjs and scripts/build-hashes.mjs stubs, patches package.json, updates CLAUDE.md, runs E2E smoke tests, and verifies bundle isolation. Idempotent — asks before clobbering."
4
+ user-invocable: true
5
+ disable-model-invocation: true
6
+ argument-hint: <target-package-path>
7
+ ---
8
+
9
+ # claude-sync-applier
10
+
11
+ Replicate the `claude-sync` bin setup on a target consumer package. The engine
12
+ is `@slats/claude-assets-sync`; the reference consumer is `packages/canard/schema-form`.
13
+
14
+ The bin stub reads its own `package.json` via `import.meta.url` and hands the
15
+ engine `{ packageRoot, packageName, packageVersion, assetPath }`. Each invocation
16
+ targets exactly one consumer — it does not discover other packages.
17
+
18
+ **Outcome**
19
+
20
+ ```bash
21
+ npx <PACKAGE_NAME> claude-sync --scope=user|project [--dry-run] [--force] [--root=<cwd>]
22
+ ```
23
+
24
+ ## Role
25
+
26
+ You are a monorepo wiring specialist. Execute the 10 steps below as a single,
27
+ idempotent procedure. On any conflicting existing value — ask the user before
28
+ overwriting. Never clobber silently.
29
+
30
+ ## Knowledge Resources
31
+
32
+ Consult these files as needed during execution. Do NOT preload everything;
33
+ load on demand.
34
+
35
+ - `knowledge/reference-files.md` — source stubs (`bin/claude-sync.mjs`, `scripts/build-hashes.mjs`) with expected contents and rationale
36
+ - `knowledge/package-json-patches.md` — every required `package.json` edit, with guard conditions
37
+ - `knowledge/claude-md-template.md` — the `## Claude Docs Injector` section to inject into the target `CLAUDE.md`
38
+ - `knowledge/dependency-cruiser.md` — optional Step 4: three forbidden rules + config shape for static isolation
39
+ - `knowledge/smoke-tests.md` — E2E 6-path matrix with expected exit codes and why
40
+ - `knowledge/gotchas.md` — invariants, isolation guardrails, pitfalls
41
+
42
+ ## Inputs
43
+
44
+ Resolve these before starting. If any is missing, stop and ask.
45
+
46
+ | Variable | Source |
47
+ |-------------------|------------------------------------------------------------------------------------------------------|
48
+ | `TARGET_PATH` | Skill argument (e.g. `packages/lerx/promise-modal`). If absent, ask the user. |
49
+ | `PACKAGE_NAME` | `name` field of `${TARGET_PATH}/package.json`. |
50
+ | `SHORTCUT` | Root `package.json` `scripts` entry whose value equals `yarn workspace ${PACKAGE_NAME}`; else unset. |
51
+
52
+ `SHORTCUT` is a convenience only. When unset, fall back to full workspace
53
+ syntax: `yarn workspace ${PACKAGE_NAME} <subcommand>`.
54
+
55
+ ## Pre-Flight
56
+
57
+ Stop and report on any failure. Do not attempt to fix silently.
58
+
59
+ - [ ] `${TARGET_PATH}/docs/claude/skills/<name>/SKILL.md` and `knowledge/*.md` exist — the docs to be injected.
60
+ - [ ] `${TARGET_PATH}/package.json` has `"type": "module"` and `"sideEffects": false`.
61
+ - [ ] Build pipeline uses `rollup -c && yarn build:types` where `build:types` runs `node ../../aileron/script/build/buildTypes.mjs`.
62
+ - [ ] `git status` in `${TARGET_PATH}` is clean. Unrelated changes present → confirm with user before proceeding.
63
+
64
+ ## Steps
65
+
66
+ Execute in order. Each step is idempotent; on conflict, ask rather than overwrite.
67
+
68
+ ### Step 1 — Create `${TARGET_PATH}/bin/claude-sync.mjs`
69
+
70
+ Copy verbatim from the reference consumer. See `knowledge/reference-files.md`
71
+ for the expected content and the source path. `chmod +x` the result.
72
+
73
+ ### Step 2 — Create `${TARGET_PATH}/scripts/build-hashes.mjs`
74
+
75
+ Copy verbatim. See `knowledge/reference-files.md`.
76
+
77
+ ### Step 3 — Patch `${TARGET_PATH}/package.json`
78
+
79
+ See `knowledge/package-json-patches.md` for the complete patch list:
80
+
81
+ - `bin` entry
82
+ - `files` append
83
+ - `scripts.build` append (guarded)
84
+ - `scripts.build:hashes`
85
+ - `scripts.prepublishOnly`
86
+ - `dependencies."@slats/claude-assets-sync"` (NOT devDependencies)
87
+ - `claude.assetPath` default
88
+
89
+ Do NOT add `./bin/*` to `exports` — ever.
90
+
91
+ ### Step 4 — (Optional) dependency-cruiser isolation gate
92
+
93
+ Skip unless `${TARGET_PATH}/.dependency-cruiser.cjs` already exists or the user
94
+ explicitly asks. Legacy `.dependency-cruiser.js` → out of scope; flag to user.
95
+
96
+ When applicable, see `knowledge/dependency-cruiser.md` for the three forbidden
97
+ rules, `no-orphans` adjustment, `includeOnly` expansion, and `depcheck` script.
98
+
99
+ ### Step 5 — Patch `${TARGET_PATH}/CLAUDE.md`
100
+
101
+ If `CLAUDE.md` exists, append the `## Claude Docs Injector` section from
102
+ `knowledge/claude-md-template.md`, substituting `@canard/schema-form` →
103
+ `${PACKAGE_NAME}`. Keep the Isolation Guardrails subsection. Skip if
104
+ `CLAUDE.md` does not exist.
105
+
106
+ ### Step 6 — Install and build
107
+
108
+ ```bash
109
+ yarn install
110
+ yarn ${SHORTCUT:-workspace ${PACKAGE_NAME}} build
111
+ ```
112
+
113
+ Expected: `rollup` → `buildTypes` → `build:hashes` succeed, and
114
+ `${TARGET_PATH}/dist/claude-hashes.json` is written.
115
+
116
+ ### Step 7 — E2E smoke tests (6 paths)
117
+
118
+ Run from `/tmp/...`, never from the monorepo root or `${TARGET_PATH}/` —
119
+ `--scope=project` walks cwd upward looking for an existing `.claude`, and would
120
+ mutate the real repo's. See `knowledge/smoke-tests.md` for the full 6-path
121
+ matrix, expected exit codes, and rationale.
122
+
123
+ Split into two bash calls (paths 1–3, then 4–6). cwd resets between calls; the
124
+ `[ -d ... ] && find -delete` prefix keeps it idempotent. Never use `rm -rf` or
125
+ unquoted `*` globs.
126
+
127
+ ### Step 8 — Bundle isolation grep (must be empty)
128
+
129
+ ```bash
130
+ grep -rE "@slats/claude-assets-sync|docs/claude|claude-sync" \
131
+ ${TARGET_PATH}/dist/index.mjs ${TARGET_PATH}/dist/index.cjs
132
+ ```
133
+
134
+ Pass = exit code 1 (no matches). Any match → stop; CLI has leaked into the
135
+ library bundle. See `knowledge/gotchas.md` for the three-layer isolation model.
136
+
137
+ ### Step 9 — depcheck (only if Step 4 ran)
138
+
139
+ ```bash
140
+ yarn ${SHORTCUT:-workspace ${PACKAGE_NAME}} depcheck
141
+ ```
142
+
143
+ Zero errors. Pre-existing `no-orphans` warnings are acceptable.
144
+
145
+ ### Step 10 — Report
146
+
147
+ Summarize:
148
+
149
+ - Files written vs. skipped (with reason for each skip)
150
+ - Manifest file count from `dist/claude-hashes.json`
151
+ - Smoke-test exit codes (all 6)
152
+ - Grep result (expected: no matches)
153
+ - depcheck result (or "static isolation not enforced" if Step 4 skipped)
154
+ - Recommendation: commit this change on its own, separate from other work
155
+
156
+ ## Report Template
157
+
158
+ ```markdown
159
+ ## apply-claude-sync — ${PACKAGE_NAME}
160
+
161
+ **Files**
162
+ - bin/claude-sync.mjs — created | unchanged | asked-user
163
+ - scripts/build-hashes.mjs — created | unchanged | asked-user
164
+ - package.json — patched: [bin, files, scripts.build, …]
165
+ - CLAUDE.md — section added | skipped (no CLAUDE.md)
166
+ - .dependency-cruiser.cjs — updated | skipped (not present)
167
+
168
+ **Manifest**
169
+ - dist/claude-hashes.json: <N> files
170
+
171
+ **Smoke tests**
172
+ | # | command | expected | actual |
173
+ |---|-------------------------------------------------|----------|--------|
174
+ | 1 | --scope=project --dry-run | 0 | <n> |
175
+ | 2 | --scope=project | 0 | <n> |
176
+ | 3 | --scope=project (up-to-date) | 0 | <n> |
177
+ | 4 | CI=true --scope=project (tampered) | 2 | <n> |
178
+ | 5 | CI=true --scope=project --force | 0 | <n> |
179
+ | 6 | CI=true (missing --scope) | 2 | <n> |
180
+
181
+ **Isolation**
182
+ - grep on dist/index.{mjs,cjs}: no matches ✓
183
+ - depcheck: <result | "static isolation not enforced">
184
+
185
+ **Next**: commit on its own — do not bundle with unrelated changes.
186
+ ```
187
+
188
+ ## Termination Conditions
189
+
190
+ - **Pre-Flight fails** → stop, report the failing check. Do not proceed.
191
+ - **Conflict during patch** → stop, show the diff, ask user whether to overwrite.
192
+ - **Build fails at Step 6** → stop, report error. Do not run smoke tests on a broken build.
193
+ - **Smoke test mismatch** → stop, report the failing path with captured exit code.
194
+ - **Bundle grep finds matches** → stop, report which file leaked. Isolation is broken.
195
+ - **All steps pass** → emit the report from the template above.
@@ -0,0 +1,77 @@
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 exists.
6
+ Substitute `@canard/schema-form` → `${PACKAGE_NAME}`. Skip the entire step if
7
+ `CLAUDE.md` does not exist (do not create one).
8
+
9
+ The template is intentionally terse: CLI usage + essential isolation warnings.
10
+ Architectural rationale (three-layer isolation model, silent no-op design,
11
+ stub mechanics) lives in this skill's `knowledge/gotchas.md` — do not
12
+ duplicate it into every consumer's `CLAUDE.md`.
13
+
14
+ ---
15
+
16
+ ## Template
17
+
18
+ ````markdown
19
+ ## Claude Docs Injector
20
+
21
+ Thin CLI stub that injects `docs/claude/` assets into the user's `.claude`
22
+ directory. Engine: `@slats/claude-assets-sync`.
23
+
24
+ ```bash
25
+ npx claude-sync --scope=user # ~/.claude
26
+ npx claude-sync --scope=project # nearest existing .claude walking up from cwd
27
+ npx claude-sync --scope=user --dry-run # preview
28
+ npx claude-sync --scope=user --force # overwrite local edits
29
+
30
+ npx -p @canard/schema-form claude-sync --scope=user # transitive-dep context
31
+ ```
32
+
33
+ ### Isolation Guardrails
34
+
35
+ - `src/**` MUST NOT import from `bin/**`, `docs/**`, or `@slats/claude-assets-sync`.
36
+ - **Never add `./bin/*` to `exports`.**
37
+ - `yarn depcheck` enforces the isolation in CI.
38
+ ````
39
+
40
+ ---
41
+
42
+ ## Substitution Rules
43
+
44
+ - Replace `@canard/schema-form` with `${PACKAGE_NAME}` (one occurrence, in the
45
+ `npx -p` line).
46
+ - Preserve the Isolation Guardrails bullets verbatim — these are the sharp
47
+ invariants that must stay consistent across consumers.
48
+
49
+ ---
50
+
51
+ ## Placement & Skip Conditions
52
+
53
+ - Append to end of `CLAUDE.md`. Ensure one blank line before the injected
54
+ section.
55
+ - `${TARGET_PATH}/CLAUDE.md` does not exist → skip, report "skipped (no CLAUDE.md)".
56
+ - Section already present with identical content → skip, report "unchanged".
57
+ - Section present with different content → ask user, do not clobber.
58
+
59
+ ---
60
+
61
+ ## What Was Deliberately Removed
62
+
63
+ If a previous version of this skill injected a longer template, these parts
64
+ were intentionally dropped:
65
+
66
+ - Intro paragraph explaining the stub mechanics — belongs in `gotchas.md`,
67
+ not per-package docs.
68
+ - `--scope=project` cwd-walk blockquote — the comment beside the command is
69
+ enough.
70
+ - Per-package structure list (`bin/`, `scripts/`, `docs/claude/`,
71
+ `claude.assetPath` convention) — mechanical, same across all consumers,
72
+ not useful as per-package documentation.
73
+ - Verbose Isolation Guardrails prose — reduced to three one-line rules.
74
+
75
+ The principle: per-package `CLAUDE.md` should carry only what an agent or
76
+ human needs **specific to this package**. Shared architecture belongs in the
77
+ skill's knowledge files.
@@ -0,0 +1,126 @@
1
+ # Step 4 — dependency-cruiser isolation gate (optional)
2
+
3
+ This step is **only** executed when:
4
+
5
+ - `${TARGET_PATH}/.dependency-cruiser.cjs` already exists (static isolation
6
+ was previously enforced), OR
7
+ - The user explicitly asks for it.
8
+
9
+ Do **not** introduce a new `.dependency-cruiser.cjs` into a target package that
10
+ has not already opted into static analysis — the runtime isolation (import
11
+ graph + `sideEffects: false` + no `bin` in `exports`) is sufficient on its own.
12
+
13
+ **Legacy**: `.dependency-cruiser.js` (not `.cjs`) → out of scope. Flag to user
14
+ and do not rename.
15
+
16
+ Reference: `packages/canard/schema-form/.dependency-cruiser.cjs`.
17
+
18
+ ---
19
+
20
+ ## Changes to Apply
21
+
22
+ When applicable, mirror the reference config. Four edits total:
23
+
24
+ ### 1. Append three `forbidden` rules
25
+
26
+ Append each with `severity: 'error'`:
27
+
28
+ ```js
29
+ {
30
+ name: 'src-no-bin',
31
+ severity: 'error',
32
+ comment:
33
+ 'src/ must not import from bin/. bin/ is a CLI-only entry point and must ' +
34
+ 'never leak into the library bundle.',
35
+ from: { path: '^src/' },
36
+ to: { path: '^bin/' },
37
+ },
38
+ {
39
+ name: 'src-no-docs',
40
+ severity: 'error',
41
+ comment:
42
+ 'src/ must not import from docs/. docs/claude/** contains pure markdown assets ' +
43
+ 'meant only for the inject-docs CLI, not for the library runtime.',
44
+ from: { path: '^src/' },
45
+ to: { path: '^docs/' },
46
+ },
47
+ {
48
+ name: 'src-no-claude-assets-sync',
49
+ severity: 'error',
50
+ comment:
51
+ '@slats/claude-assets-sync is a CLI-only dependency. It is allowed only ' +
52
+ 'from bin/. Importing it from src/ would leak the CLI engine into ' +
53
+ 'consumer production bundles.',
54
+ from: { path: '^src/' },
55
+ to: { path: 'node_modules/@slats/claude-assets-sync' },
56
+ },
57
+ ```
58
+
59
+ Place these alongside the existing `forbidden` rules in the reference config.
60
+ Do not duplicate if any of these rule names already exist.
61
+
62
+ ### 2. Extend `no-orphans` rule
63
+
64
+ Add `'^bin/'` to the existing `no-orphans` rule's `from.pathNot` array. `bin`
65
+ entry points are orphans by design (they're invoked as executables, not
66
+ imported).
67
+
68
+ ```js
69
+ from: {
70
+ orphan: true,
71
+ pathNot: [
72
+ '(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$',
73
+ '[.]d[.]ts$',
74
+ '(^|/)tsconfig[.]json$',
75
+ '(^|/)(?:babel|webpack)[.]config[.](?:js|cjs|mjs|ts|cts|mts|json)$',
76
+ '^bin/',
77
+ ],
78
+ },
79
+ ```
80
+
81
+ ### 3. Expand `options.includeOnly`
82
+
83
+ Change to include both `src` and `bin` so dependency-cruiser scans the bin
84
+ entry points as well:
85
+
86
+ ```js
87
+ includeOnly: ['^src', '^bin'],
88
+ ```
89
+
90
+ ### 4. Add `depcheck` script
91
+
92
+ In `${TARGET_PATH}/package.json` `scripts`:
93
+
94
+ ```json
95
+ "depcheck": "depcruise src bin --config .dependency-cruiser.cjs --no-progress"
96
+ ```
97
+
98
+ If an existing `depcheck` script points elsewhere, ask the user.
99
+
100
+ ---
101
+
102
+ ## Post-Step Verification
103
+
104
+ After Steps 1–6 complete and this Step 4 has been applied, Step 9 runs:
105
+
106
+ ```bash
107
+ yarn ${SHORTCUT:-workspace ${PACKAGE_NAME}} depcheck
108
+ ```
109
+
110
+ Must exit 0 with no errors. Pre-existing `no-orphans` warnings are acceptable.
111
+
112
+ ---
113
+
114
+ ## Why This Step Is Optional
115
+
116
+ The three-layer isolation works without static analysis:
117
+
118
+ 1. Import graph: `src/**` never references `bin/**`, `docs/**`, or
119
+ `@slats/claude-assets-sync`.
120
+ 2. `"sideEffects": false` + `"type": "module"` — dead-code elimination of any
121
+ accidental reference.
122
+ 3. No `./bin/*` in `exports` — consumer bundlers cannot deep-import into bin.
123
+
124
+ dependency-cruiser adds a fourth layer (CI-time regression detection) but is
125
+ not required for correctness. Don't force-enable it on a package that hasn't
126
+ opted in — it carries real maintenance cost.
@@ -0,0 +1,139 @@
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
+ ## Stubs are verbatim
9
+
10
+ The `bin/claude-sync.mjs` and `scripts/build-hashes.mjs` files are
11
+ **identical across all consumers** in this monorepo. No per-package
12
+ substitution. Runtime `import.meta.url` (in the bin) and `process.cwd()` (in
13
+ the build script) discover the package root; package metadata is parsed from
14
+ the adjacent `package.json`.
15
+
16
+ If you find yourself "adapting" the stub for a new consumer, stop — that's a
17
+ sign you misread the design. The engine is generic; the consumer-specific
18
+ convention is the `claude.assetPath` field inside `package.json`.
19
+
20
+ ---
21
+
22
+ ## Silent no-op on missing `claude.assetPath`
23
+
24
+ Both stubs guard with `if (typeof pkg.claude?.assetPath === 'string')`.
25
+
26
+ - Missing field → exit 0, produce no output.
27
+ - Non-string value → exit 0, produce no output.
28
+
29
+ This is the intentional opt-out path: a package can ship the bin and script
30
+ but disable the feature by removing the config field. Do not add "helpful"
31
+ error messages for this case — it would break the opt-out.
32
+
33
+ ---
34
+
35
+ ## `@slats/claude-assets-sync` must be in `dependencies`
36
+
37
+ **Not** `devDependencies`, **not** `peerDependencies`.
38
+
39
+ Isolation from the library bundle is enforced by:
40
+
41
+ 1. The import graph (`src/**` never references the engine), and
42
+ 2. Optionally, dependency-cruiser static rules.
43
+
44
+ It is **not** enforced by dependency-type. Placing the engine in
45
+ `devDependencies` would break `npx <pkg> claude-sync` when a downstream
46
+ consumer installs the package — their `npm install` omits dev deps.
47
+
48
+ ---
49
+
50
+ ## Never add `./bin/*` to `exports`
51
+
52
+ The `exports` map in `package.json` controls which subpaths a consumer's
53
+ bundler can resolve. Leaving `./bin/*` out of `exports` is what prevents a
54
+ bundler from deep-importing the CLI by accident.
55
+
56
+ Adding `./bin/claude-sync.mjs` to `exports` — even with `"default"` —
57
+ creates a path for a careless `import "@canard/schema-form/bin/claude-sync"`
58
+ to pull the CLI engine (and `@slats/claude-assets-sync`) into the library
59
+ consumer's production bundle. Three-layer isolation collapses to zero.
60
+
61
+ ---
62
+
63
+ ## Do not commit `dist/claude-hashes.json`
64
+
65
+ It is a build artifact. The `yarn build` chain regenerates it via
66
+ `build:hashes`. It should be in `.gitignore` (usually via a catch-all `dist/`
67
+ rule). If you see it in `git status`, stop — something is misconfigured.
68
+
69
+ ---
70
+
71
+ ## `yarn workspace ${PACKAGE_NAME} build` can fail with `rollup: command not found`
72
+
73
+ Yarn v4 workspace dispatch does not always propagate the workspace-local
74
+ PATH. Prefer `yarn ${SHORTCUT} build` from the monorepo root, where
75
+ `${SHORTCUT}` is the root-level script alias (e.g. `yarn schemaForm`).
76
+
77
+ If no shortcut exists, the full form `yarn workspace ${PACKAGE_NAME} build`
78
+ may still work depending on yarn version and cache state — but if it fails
79
+ with `rollup: 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 existing
87
+ `.claude` directory. The first one found is reused; if none is found, the
88
+ engine creates one at `cwd`.
89
+
90
+ Consequence: running the smoke tests from the monorepo root would reuse the
91
+ monorepo's real `.claude`, corrupting it. Always run smoke tests from
92
+ `/tmp/...` with a fresh directory.
93
+
94
+ ---
95
+
96
+ ## Bin paths are orphans on purpose
97
+
98
+ `bin/claude-sync.mjs` is an executable entry point. It is never imported from
99
+ `src/`. That makes it an orphan in dependency-cruiser's eyes.
100
+
101
+ Step 4 explicitly excludes `^bin/` from the `no-orphans` rule to silence this
102
+ warning. If you add new bin entry points, extend the `pathNot` pattern — do
103
+ not disable the rule wholesale.
104
+
105
+ ---
106
+
107
+ ## Three-layer isolation — why
108
+
109
+ 1. **Import graph** — `src/**` never references `bin/**`, `docs/**`, or
110
+ `@slats/claude-assets-sync`. Primary defense.
111
+ 2. **`sideEffects: false`** — allows the bundler to tree-shake any accidental
112
+ reference.
113
+ 3. **No `./bin/*` in `exports`** — consumer bundlers cannot reach the bin
114
+ through subpath imports.
115
+ 4. **(Optional) dependency-cruiser** — CI-time regression check that layer 1
116
+ stays intact.
117
+
118
+ Step 8 (`grep` on `dist/index.{mjs,cjs}`) is the post-build verification that
119
+ all three primary layers held. Any match → one of them is broken.
120
+
121
+ ---
122
+
123
+ ## Commit this change alone
124
+
125
+ The change set from this skill touches `bin/`, `scripts/`, `package.json`,
126
+ and possibly `CLAUDE.md` + `.dependency-cruiser.cjs`. It should land in a
127
+ single commit, with no unrelated changes interleaved.
128
+
129
+ Reasons:
130
+
131
+ - Easier to revert as a unit if an issue appears downstream.
132
+ - The CI signal (smoke tests, bundle grep) is bound to the state of these
133
+ files and nothing else.
134
+ - The change is almost entirely mechanical — reviewers can skim-verify
135
+ against the reference consumer without reviewing business logic.
136
+
137
+ If the user asks to bundle with other work, push back once: recommend a
138
+ separate commit. If they still want it bundled, proceed but note it in the
139
+ Step 10 report.
@@ -0,0 +1,130 @@
1
+ # `package.json` Patches
2
+
3
+ All edits below are **additive**. Existing non-conflicting values remain
4
+ untouched. On any conflicting existing value, stop and ask the user — do not
5
+ overwrite.
6
+
7
+ Reference: `packages/canard/schema-form/package.json`.
8
+
9
+ ---
10
+
11
+ ## 1. `bin`
12
+
13
+ ```json
14
+ "bin": {
15
+ "claude-sync": "./bin/claude-sync.mjs"
16
+ }
17
+ ```
18
+
19
+ If `bin` already exists with other entries, merge in the `claude-sync` key;
20
+ preserve siblings. If `bin.claude-sync` already points elsewhere, ask.
21
+
22
+ ---
23
+
24
+ ## 2. `files`
25
+
26
+ Append `"bin"` to the `files` array if not already present. Order within the
27
+ array is not load-bearing, but to match the reference:
28
+
29
+ ```json
30
+ "files": [
31
+ "dist",
32
+ "docs",
33
+ "bin",
34
+ "README.md"
35
+ ]
36
+ ```
37
+
38
+ If `files` is absent, create it with at least `["dist", "bin"]`, preserving
39
+ any conventions already present in sibling packages.
40
+
41
+ ---
42
+
43
+ ## 3. `scripts.build`
44
+
45
+ Append ` && yarn build:hashes` to whatever the package currently has.
46
+
47
+ **Guard against double-append.** If the existing value already ends with
48
+ `yarn build:hashes` or already contains `build:hashes`, leave it alone.
49
+
50
+ Reference value:
51
+
52
+ ```json
53
+ "build": "rollup -c && yarn build:types && yarn build:hashes"
54
+ ```
55
+
56
+ ---
57
+
58
+ ## 4. `scripts.build:hashes`
59
+
60
+ ```json
61
+ "build:hashes": "node scripts/build-hashes.mjs"
62
+ ```
63
+
64
+ If a different `build:hashes` script exists, ask.
65
+
66
+ ---
67
+
68
+ ## 5. `scripts.prepublishOnly`
69
+
70
+ ```json
71
+ "prepublishOnly": "yarn build"
72
+ ```
73
+
74
+ If the target already has a `prepublishOnly` that calls `yarn build`
75
+ (directly or transitively), leave it alone.
76
+
77
+ ---
78
+
79
+ ## 6. `dependencies."@slats/claude-assets-sync"`
80
+
81
+ **Must be in `dependencies`, never `devDependencies`.**
82
+
83
+ ```json
84
+ "dependencies": {
85
+ "@slats/claude-assets-sync": "workspace:^"
86
+ }
87
+ ```
88
+
89
+ Rationale: isolation from the library bundle is enforced by the import graph
90
+ (and optionally by dependency-cruiser), not by dependency-type. Placing it in
91
+ `devDependencies` would make `npm install` on a published package fail when a
92
+ consumer runs `npx <pkg> claude-sync`.
93
+
94
+ If the target already has it in `devDependencies`, move it. Do not duplicate.
95
+
96
+ ---
97
+
98
+ ## 7. `claude.assetPath`
99
+
100
+ Default value (used when the field is absent):
101
+
102
+ ```json
103
+ "claude": {
104
+ "assetPath": "docs/claude"
105
+ }
106
+ ```
107
+
108
+ **If `claude.assetPath` already exists with a non-default value, preserve it.**
109
+ The convention lives in the consumer, not the library.
110
+
111
+ The bin stub guards on `typeof pkg.claude?.assetPath === 'string'` — a missing
112
+ or non-string value is a silent no-op. That is the intentional opt-out path.
113
+
114
+ ---
115
+
116
+ ## Must-NOT
117
+
118
+ - **Never** add `./bin/*` (or any bin path) to the `exports` field. Leaving bin
119
+ subpaths unexported is what prevents a consumer bundler from accidentally
120
+ reaching into the CLI assets via deep imports.
121
+
122
+ ---
123
+
124
+ ## Full Reference
125
+
126
+ See `packages/canard/schema-form/package.json` for the canonical shape. The
127
+ relevant keys are `bin`, `files`, `scripts.build`, `scripts.build:hashes`,
128
+ `scripts.prepublishOnly`, `dependencies."@slats/claude-assets-sync"`, and
129
+ `claude.assetPath`. Everything else in that file is schema-form-specific and
130
+ must not be copied.