@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
package/README.md CHANGED
@@ -1,640 +1,164 @@
1
1
  # @slats/claude-assets-sync
2
2
 
3
- CLI tool to sync Claude commands and skills from npm packages to your project's `.claude/` directory.
3
+ Shared CLI engine that lets any npm package ship its own Claude Code docs (skills, rules, commands) and inject them into a user's `.claude/` directory through a thin `claude-sync` bin stub.
4
4
 
5
5
  ## Overview
6
6
 
7
- This tool allows npm package authors to distribute Claude Code commands and skills alongside their packages. When users install these packages, they can sync the Claude assets to their local `.claude/` directory for immediate use with Claude Code.
7
+ A consumer package ships a thin `bin/claude-sync.mjs` stub that reads its own `package.json` and calls `runCli(argv, { packageRoot, packageName, packageVersion, assetPath })`. End users run `npx claude-sync` (or the consumer's own bin alias) and this engine compares a per-file SHA-256 manifest against the target `.claude/`, copying only what is out of date. The library operates on exactly one consumer per invocation — the one supplied by the caller; it never walks `node_modules` or yarn workspaces.
8
8
 
9
- ## Features
9
+ No GitHub fetch, no `.sync-meta.json`, no migrations — the consumer's `dist/claude-hashes.json` is the single source of truth.
10
10
 
11
- - **Multi-package sync**: Sync multiple packages in a single command
12
- - **Version tracking**: Automatically skip re-syncing if versions match
13
- - **Flat structure support**: Modern flat file organization with prefixed filenames
14
- - **Legacy migration**: Migrate from nested to flat directory structure
15
- - **Package management**: List, remove, and inspect synced packages
16
- - **Status monitoring**: Check sync status and available updates
17
- - **Dry-run mode**: Preview changes before applying them
18
- - **GitHub & npm integration**: Fetch from GitHub API and monitor npm registry
19
-
20
- ## Installation
21
-
22
- ```bash
23
- # Using npx (recommended for one-time use)
24
- npx @slats/claude-assets-sync -p @canard/schema-form
25
-
26
- # Or install globally
27
- npm install -g @slats/claude-assets-sync
28
- ```
29
-
30
- ## Quick Start
31
-
32
- ```bash
33
- # Sync a single package
34
- npx @slats/claude-assets-sync -p @canard/schema-form
35
-
36
- # Sync multiple packages
37
- npx @slats/claude-assets-sync -p @canard/schema-form -p @lerx/promise-modal
38
-
39
- # See what would be synced
40
- npx @slats/claude-assets-sync -p @canard/schema-form --dry-run
41
-
42
- # Check sync status and available updates
43
- npx @slats/claude-assets-sync status
44
-
45
- # List all synced packages
46
- npx @slats/claude-assets-sync list
47
-
48
- # Remove a synced package
49
- npx @slats/claude-assets-sync remove -p @canard/schema-form
50
-
51
- # Migrate from legacy nested structure to flat structure
52
- npx @slats/claude-assets-sync migrate
53
- ```
54
-
55
- ## Commands
56
-
57
- ### sync (Default Command)
58
-
59
- Synchronize Claude assets from npm packages.
60
-
61
- ```bash
62
- npx @slats/claude-assets-sync [options] -p <package>
63
- ```
64
-
65
- **Options:**
66
-
67
- | Option | Description |
68
- |--------|-------------|
69
- | `-p, --package <name>` | Package name to sync (can be specified multiple times) |
70
- | `-f, --force` | Force sync even if version matches |
71
- | `--dry-run` | Preview changes without writing files |
72
- | `-l, --local` | Read packages from local workspace instead of node_modules |
73
- | `-r, --ref <ref>` | Git ref (branch, tag, or commit) to fetch from |
74
- | `--no-flat` | Use legacy nested directory structure instead of flat |
75
- | `--help` | Show help |
76
- | `--version` | Show version |
77
-
78
- **Examples:**
79
-
80
- ```bash
81
- # Sync with version check (default behavior)
82
- npx @slats/claude-assets-sync -p @canard/schema-form
83
-
84
- # Force sync, ignoring version check
85
- npx @slats/claude-assets-sync -p @canard/schema-form --force
86
-
87
- # Preview changes before syncing
88
- npx @slats/claude-assets-sync -p @canard/schema-form --dry-run
89
-
90
- # Sync from a specific git ref
91
- npx @slats/claude-assets-sync -p @canard/schema-form -r main
92
-
93
- # Sync from local workspace
94
- npx @slats/claude-assets-sync -p @canard/schema-form --local
95
-
96
- # Use legacy nested structure
97
- npx @slats/claude-assets-sync -p @canard/schema-form --no-flat
98
- ```
99
-
100
- ### add
101
-
102
- Add a package with interactive file selection.
103
-
104
- ```bash
105
- npx @slats/claude-assets-sync add -p <package> [options]
106
- ```
107
-
108
- **Options:**
109
-
110
- | Option | Description |
111
- |--------|-------------|
112
- | `-p, --package <name>` | Package name to add (required) |
113
- | `-l, --local` | Read packages from local workspace instead of node_modules |
114
- | `-r, --ref <ref>` | Git ref (branch, tag, or commit) to fetch from |
115
-
116
- **Interactive Features:**
117
-
118
- When running in a TTY environment, the add command provides an interactive tree-select UI:
119
-
120
- - **↑/↓**: Navigate items
121
- - **Space**: Toggle file/directory selection
122
- - **→/←**: Expand/collapse directories
123
- - **Enter**: Confirm selection and sync
124
- - **a**: Select all files
125
- - **n**: Deselect all files
126
- - **q**: Cancel operation
127
-
128
- **Examples:**
129
-
130
- ```bash
131
- # Add a package with interactive selection
132
- npx @slats/claude-assets-sync add -p @lerx/promise-modal
133
-
134
- # Add from local workspace
135
- npx @slats/claude-assets-sync add -p @lerx/promise-modal --local
136
-
137
- # Add from specific git branch
138
- npx @slats/claude-assets-sync add -p @lerx/promise-modal --ref master
139
- ```
140
-
141
- ### list
142
-
143
- List all synced packages with interactive tree view and edit mode.
144
-
145
- ```bash
146
- npx @slats/claude-assets-sync list [options]
147
- ```
148
-
149
- **Options:**
150
-
151
- | Option | Description |
152
- |--------|-------------|
153
- | `--json` | Output results as JSON |
154
-
155
- **Interactive Features (TTY mode):**
156
-
157
- When running in a TTY environment, the list command provides an interactive UI:
158
-
159
- **View Mode:**
160
- - Tree structure showing all synced packages and their files
161
- - **e**: Enter edit mode
162
- - **r**: Refresh view
163
- - **q**: Quit
164
-
165
- **Edit Mode:**
166
- - **d**: Mark file for deletion
167
- - **a**: Add new file to package
168
- - **Esc**: Exit edit mode
169
-
170
- **Examples:**
171
-
172
- ```bash
173
- # Interactive tree view (TTY mode)
174
- npx @slats/claude-assets-sync list
175
-
176
- # JSON output for scripting
177
- npx @slats/claude-assets-sync list --json
178
- ```
179
-
180
- **Output (TTY mode):**
181
-
182
- ```
183
- ┌─ Synced Packages ─────────────────────────────┐
184
- │ │
185
- │ ▼ @canard/schema-form@1.0.0 │
186
- │ ├─ commands/ │
187
- │ │ └─ @canard-schema-form-my-command.md │
188
- │ └─ skills/ │
189
- │ └─ @canard-schema-form-my-skill.md │
190
- │ │
191
- │ ▼ @lerx/promise-modal@0.5.0 │
192
- │ └─ skills/ │
193
- │ └─ @lerx-promise-modal-my-skill.md │
194
- │ │
195
- │ [e] Edit [r] Refresh [q] Quit │
196
- └───────────────────────────────────────────────┘
197
- ```
198
-
199
- **Output (JSON mode):**
200
-
201
- ```json
202
- {
203
- "packages": [
204
- {
205
- "name": "@canard/schema-form",
206
- "version": "1.0.0",
207
- "syncedAt": "2025-02-05T10:30:00.000Z",
208
- "assets": 2,
209
- "types": { "commands": 1, "skills": 1 }
210
- }
211
- ]
212
- }
213
- ```
214
-
215
- ### remove
216
-
217
- Remove a synced package and its assets.
218
-
219
- ```bash
220
- npx @slats/claude-assets-sync remove [options] -p <package>
221
- ```
222
-
223
- **Options:**
224
-
225
- | Option | Description |
226
- |--------|-------------|
227
- | `-p, --package <name>` | Package name to remove (required) |
228
- | `-y, --yes` | Skip confirmation prompt |
229
- | `--dry-run` | Preview changes without removing files |
230
-
231
- **Examples:**
232
-
233
- ```bash
234
- # Remove a package with confirmation prompt
235
- npx @slats/claude-assets-sync remove -p @canard/schema-form
236
-
237
- # Remove without asking for confirmation
238
- npx @slats/claude-assets-sync remove -p @canard/schema-form --yes
239
-
240
- # Preview what would be removed
241
- npx @slats/claude-assets-sync remove -p @canard/schema-form --dry-run
242
- ```
243
-
244
- ### status
245
-
246
- Show sync status of all packages with visual UI and update checking.
247
-
248
- ```bash
249
- npx @slats/claude-assets-sync status [options]
250
- ```
251
-
252
- **Options:**
253
-
254
- | Option | Description |
255
- |--------|-------------|
256
- | `--no-remote` | Skip checking remote npm registry for updates |
257
-
258
- **Features:**
259
-
260
- - Visual box UI with color-coded status indicators (TTY mode)
261
- - Shows local vs synced version comparison
262
- - Checks npm registry for latest versions
263
- - Caches remote version checks (5-minute TTL)
264
- - Includes sync timestamp for each package
265
- - Summary statistics at the bottom
266
-
267
- **Status Indicators:**
268
-
269
- - **✓** (green): Up-to-date
270
- - **⚠** (yellow): Update available
271
- - **✗** (red): Error or missing
272
-
273
- **Examples:**
274
-
275
- ```bash
276
- # Check status with remote version checks (visual UI)
277
- npx @slats/claude-assets-sync status
278
-
279
- # Check status without checking npm registry
280
- npx @slats/claude-assets-sync status --no-remote
281
- ```
282
-
283
- **Output (TTY mode):**
284
-
285
- ```
286
- ┌─ Package Status ──────────────────────────────┐
287
- │ │
288
- │ ✓ @canard/schema-form │
289
- │ Local: 1.0.0 │
290
- │ Synced: 1.0.0 │
291
- │ Status: Up to date │
292
- │ Updated: 2/5/2025, 10:30 AM │
293
- │ Assets: 2 files │
294
- │ │
295
- │ ⚠ @lerx/promise-modal │
296
- │ Local: 0.6.0 │
297
- │ Synced: 0.5.0 │
298
- │ Status: Outdated │
299
- │ Updated: 2/5/2025, 10:30 AM │
300
- │ Assets: 1 files │
301
- │ │
302
- ├─ Summary ────────────────────────────────────┤
303
- │ Total: 2 packages │
304
- │ ✓ Up-to-date: 1 ⚠ Outdated: 1 │
305
- └───────────────────────────────────────────────┘
306
- ```
307
-
308
- ### migrate
309
-
310
- Migrate synced packages from legacy nested structure to flat structure.
311
-
312
- ```bash
313
- npx @slats/claude-assets-sync migrate [options]
314
- ```
315
-
316
- **Options:**
317
-
318
- | Option | Description |
319
- |--------|-------------|
320
- | `--dry-run` | Preview migration without making changes |
321
-
322
- **Features:**
323
-
324
- - Converts nested directory structure to flat file naming
325
- - Preserves all package metadata
326
- - Creates backup of original structure
327
- - Can be run multiple times safely
328
- - Includes comprehensive dry-run preview
329
-
330
- **Examples:**
11
+ ## Install
331
12
 
332
13
  ```bash
333
- # Preview migration changes
334
- npx @slats/claude-assets-sync migrate --dry-run
335
-
336
- # Perform migration
337
- npx @slats/claude-assets-sync migrate
338
- ```
339
-
340
- ## Directory Structures
341
-
342
- ### Flat Structure (Default, Modern)
343
-
344
- The default flat structure uses prefixed filenames in shared directories:
345
-
14
+ npm install -D @slats/claude-assets-sync
15
+ # or
16
+ yarn add -D @slats/claude-assets-sync
346
17
  ```
347
- your-project/
348
- └── .claude/
349
- ├── commands/
350
- │ ├── @canard-schema-form-my-command.md
351
- │ └── @lerx-promise-modal-another-command.md
352
- └── skills/
353
- ├── @canard-schema-form-my-skill.md
354
- └── @lerx-promise-modal-another-skill.md
355
- ```
356
-
357
- **Benefits:**
358
- - Cleaner directory structure
359
- - Easier to share commands across packages
360
- - Single .sync-meta.json per asset type
361
- - Better scalability with many packages
362
-
363
- ### Nested Structure (Legacy)
364
18
 
365
- The legacy nested structure organizes by package:
19
+ ## CLI Surface
366
20
 
367
21
  ```
368
- your-project/
369
- └── .claude/
370
- ├── commands/
371
- │ └── @canard/
372
- │ └── schema-form/
373
- │ ├── my-command.md
374
- │ └── .sync-meta.json
375
- └── skills/
376
- └── @lerx/
377
- └── promise-modal/
378
- ├── my-skill.md
379
- └── .sync-meta.json
22
+ claude-sync [--scope=user|project] [--dry-run] [--force]
380
23
  ```
381
24
 
382
- **Use case:** Legacy projects or when per-package organization is preferred
25
+ Each consumer package exposes its own `claude-sync` bin entry (see [Consumer Integration](#consumer-integration-3-steps) below). When invoked, the engine operates on exactly one consumer — the one whose metadata was passed by the stub. There is no cross-package discovery.
383
26
 
384
- ## Version Management
27
+ | Flag | Meaning |
28
+ |---|---|
29
+ | `--scope=user` | `~/.claude` (applies globally) |
30
+ | `--scope=project` | nearest ancestor `.claude` directory, or `<cwd>/.claude` if none found |
31
+ | `--dry-run` | print the copy / skip / warn plan, no writes |
32
+ | `--force` | overwrite diverged files & delete orphans (interactive confirm on TTY) |
385
33
 
386
- The tool tracks synced versions to avoid unnecessary re-syncing. A unified `.sync-meta.json` file stores metadata for all packages:
34
+ **Exit codes**: `0` success / up-to-date / dry-run, `1` runtime error, `2` user / configuration error (e.g. missing `--scope` in non-TTY, invalid `assetPath`).
387
35
 
388
- ```json
389
- {
390
- "version": "0.0.1",
391
- "syncedAt": "2025-02-05T10:30:00.000Z",
392
- "packages": {
393
- "@canard-schema-form": {
394
- "originalName": "@canard/schema-form",
395
- "version": "1.0.0",
396
- "files": {
397
- "commands": [
398
- { "original": "my-command.md", "transformed": "@canard-schema-form-my-command.md" }
399
- ],
400
- "skills": [
401
- { "original": "my-skill.md", "transformed": "@canard-schema-form-my-skill.md" }
402
- ]
403
- }
404
- }
405
- }
406
- }
407
- ```
36
+ For `--scope=project` the target `.claude` directory is resolved by walking up from `process.cwd()` to the nearest existing `.claude` ancestor; the CLI logs `(auto-located)` when this happens.
408
37
 
409
- **Features:**
38
+ ## Consumer Integration (3 steps)
410
39
 
411
- - Sync is automatically skipped if package version hasn't changed
412
- - Use `--force` to override version checking and re-sync
413
- - Each sync updates the `syncedAt` timestamp
414
- - Full file mapping for cleanup and migration
40
+ ### 1. `package.json`
415
41
 
416
- ## For Package Authors
417
-
418
- To make your package compatible with `claude-assets-sync`, add a `claude` field to your `package.json`:
419
-
420
- ```json
42
+ ```jsonc
421
43
  {
422
44
  "name": "@your-scope/your-package",
423
- "version": "1.0.0",
424
- "repository": {
425
- "type": "git",
426
- "url": "https://github.com/your-org/your-repo.git",
427
- "directory": "packages/your-package"
45
+ "bin": { "claude-sync": "./bin/claude-sync.mjs" },
46
+ "files": ["dist", "docs", "dist/claude-hashes.json", "bin", "README.md"],
47
+ "scripts": {
48
+ "build": "… && yarn build:hashes",
49
+ "build:hashes": "node scripts/build-hashes.mjs"
50
+ },
51
+ "dependencies": {
52
+ "@slats/claude-assets-sync": "workspace:^"
428
53
  },
429
- "claude": {
430
- "assetPath": "docs/claude"
431
- }
54
+ "claude": { "assetPath": "docs/claude" }
432
55
  }
433
56
  ```
434
57
 
435
- ### Package Structure
58
+ Do **not** expose `./bin/*` in `exports` — that would let consumer bundlers pull CLI code into app bundles.
436
59
 
437
- Your package should have the following structure:
60
+ ### 2. `bin/claude-sync.mjs`
438
61
 
439
- ```
440
- your-package/
441
- ├── docs/
442
- │ └── claude/
443
- │ ├── commands/
444
- │ │ └── your-command.md
445
- │ └── skills/
446
- │ └── your-skill.md
447
- └── package.json
448
- ```
449
-
450
- ### Asset Guidelines
62
+ ```javascript
63
+ #!/usr/bin/env node
64
+ import { runCli } from '@slats/claude-assets-sync';
65
+ import { readFile } from 'node:fs/promises';
66
+ import { dirname, resolve } from 'node:path';
67
+ import { fileURLToPath } from 'node:url';
451
68
 
452
- - **Commands and skills**: Must be Markdown files (`.md`)
453
- - **File format**: Use standard Claude Code command/skill format
454
- - **Naming**: Use descriptive, lowercase filenames with hyphens (e.g., `my-command.md`)
455
- - **No modification**: Files are synced as-is without transformation
456
- - **Repository requirement**: Must have valid `repository.type` and `repository.url` in package.json
69
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
70
+ const pkg = JSON.parse(
71
+ await readFile(resolve(packageRoot, 'package.json'), 'utf-8'),
72
+ );
457
73
 
458
- ### Configuration
459
-
460
- The `claude.assetPath` in your package.json should point to the directory containing your `commands/` and `skills/` subdirectories:
461
-
462
- ```json
463
- {
464
- "claude": {
465
- "assetPath": "docs/claude" // Path relative to package root
466
- }
74
+ if (typeof pkg.claude?.assetPath !== 'string') {
75
+ process.stderr.write(
76
+ `[claude-sync] missing or invalid "claude.assetPath" in ${resolve(packageRoot, 'package.json')}\n`,
77
+ );
78
+ process.exit(2);
467
79
  }
468
- ```
469
-
470
- ## Environment Variables
471
-
472
- | Variable | Description | Default |
473
- |----------|-------------|---------|
474
- | `GITHUB_TOKEN` | GitHub personal access token for higher API rate limits | (unauthenticated) |
475
- | `VERBOSE` | Enable debug logging (set to any value) | (disabled) |
476
-
477
- ## Rate Limits
478
-
479
- - **Without token**: 60 requests/hour (GitHub API limit)
480
- - **With token**: 5,000 requests/hour
481
-
482
- For most use cases, the unauthenticated limit is sufficient. If syncing many packages, set a GitHub token:
483
80
 
484
- ```bash
485
- export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
486
- npx @slats/claude-assets-sync -p @package1 -p @package2 -p @package3
487
- ```
488
-
489
- ## Workflow Examples
490
-
491
- ### Initial Setup
492
-
493
- ```bash
494
- # Sync all packages from your project
495
- npx @slats/claude-assets-sync \
496
- -p @canard/schema-form \
497
- -p @lerx/promise-modal \
498
- -p @winglet/react-utils
499
-
500
- # Verify they're synced
501
- npx @slats/claude-assets-sync list
502
-
503
- # Check for any available updates
504
- npx @slats/claude-assets-sync status
505
- ```
506
-
507
- ### Regular Maintenance
508
-
509
- ```bash
510
- # Check which packages have updates available
511
- npx @slats/claude-assets-sync status
512
-
513
- # Update a specific package to latest version
514
- npx @slats/claude-assets-sync -p @canard/schema-form --force
515
-
516
- # Update all packages from a specific branch
517
- npx @slats/claude-assets-sync \
518
- -p @canard/schema-form \
519
- -p @lerx/promise-modal \
520
- --force -r develop
521
- ```
522
-
523
- ### Cleanup
524
-
525
- ```bash
526
- # Check what you'll remove before doing it
527
- npx @slats/claude-assets-sync remove -p @old-package --dry-run
528
-
529
- # Remove a package
530
- npx @slats/claude-assets-sync remove -p @old-package --yes
531
-
532
- # List remaining packages
533
- npx @slats/claude-assets-sync list
534
- ```
535
-
536
- ### CI/CD Integration
537
-
538
- ```bash
539
- #!/bin/bash
540
- # Script to sync all team packages
541
- PACKAGES=(
542
- "@canard/schema-form"
543
- "@lerx/promise-modal"
544
- "@winglet/react-utils"
545
- )
546
-
547
- for pkg in "${PACKAGES[@]}"; do
548
- npx @slats/claude-assets-sync -p "$pkg" --force
549
- done
550
-
551
- # Verify sync
552
- npx @slats/claude-assets-sync list
81
+ await runCli(process.argv, {
82
+ packageRoot,
83
+ packageName: pkg.name,
84
+ packageVersion: pkg.version,
85
+ assetPath: pkg.claude.assetPath,
86
+ }).catch((err) => {
87
+ process.stderr.write(
88
+ `[${pkg.name}] claude-sync failed: ${err instanceof Error ? err.message : String(err)}\n`,
89
+ );
90
+ process.exit(1);
91
+ });
92
+ ```
93
+
94
+ The `claude.assetPath` field in the consumer's `package.json` is a **consumer-side convention**; the library does not enforce or read it. Consumers are free to resolve `assetPath` in any way they choose and pass the result to `runCli`.
95
+
96
+ ### 3. `scripts/build-hashes.mjs`
97
+
98
+ ```javascript
99
+ #!/usr/bin/env node
100
+ import { buildHashes } from '@slats/claude-assets-sync/buildHashes';
101
+
102
+ try {
103
+ const { outPath, fileCount } = await buildHashes();
104
+ console.log(`✓ claude-hashes.json written: ${fileCount} file(s) → ${outPath}`);
105
+ } catch (err) {
106
+ console.error('❌ buildHashes failed:', err?.message ?? err);
107
+ process.exit(1);
108
+ }
553
109
  ```
554
110
 
555
- ## Troubleshooting
111
+ `buildHashes` reads the current `package.json`'s `claude.assetPath`, hashes every file beneath it (ignoring `.omc/**`, `*.log`, `.DS_Store`), and writes `dist/claude-hashes.json`.
556
112
 
557
- ### "Package is not synced"
113
+ ## Authoring `docs/claude/`
558
114
 
559
- The specified package hasn't been synced yet. List available packages:
115
+ Any tree works, but the recommended layout matches Claude Code conventions:
560
116
 
561
- ```bash
562
- npx @slats/claude-assets-sync list
563
117
  ```
564
-
565
- Then sync it:
566
-
567
- ```bash
568
- npx @slats/claude-assets-sync -p @your-package
118
+ docs/claude/
119
+ ├── skills/
120
+ │ └── <skill-name>/
121
+ │ ├── SKILL.md
122
+ │ └── knowledge/...
123
+ ├── rules/...
124
+ └── commands/...
569
125
  ```
570
126
 
571
- ### "Rate limit exceeded"
572
-
573
- You've hit GitHub's API rate limit (60 requests/hour without authentication). Solutions:
127
+ Every file under the asset root is hashed and tracked in `dist/claude-hashes.json`.
574
128
 
575
- 1. **Set GitHub token:** `export GITHUB_TOKEN=ghp_xxxxxxxxxxxx`
576
- 2. **Wait 1 hour** for rate limit to reset
577
- 3. **Use `--local` flag** if packages are in your local workspace
129
+ ## Hash-Based Sync Strategy (Option A)
578
130
 
579
- ```bash
580
- GITHUB_TOKEN=ghp_xxxxxxxxxxxx npx @slats/claude-assets-sync -p @package
581
- ```
131
+ - `dist/claude-hashes.json` (schema v1) is the sole source of truth.
132
+ - Per-file SHA-256 comparison:
133
+ - **missing locally** → copy
134
+ - **hash equal** → skip
135
+ - **hash differs** → warn + require `--force` (user edit vs. source update is indistinguishable by design)
136
+ - **file is outside the manifest but under a managed prefix (`skills/<name>/`)** → orphan; requires `--force` to delete
582
137
 
583
- ### "Repository information not found"
138
+ - `--force` on TTY opens an interactive confirm via `@inquirer/prompts.confirm`, listing up to 3 diverged/orphan paths.
139
+ - `--force` on non-TTY prints the divergent list to stderr and proceeds.
584
140
 
585
- The package's `package.json` is missing required repository configuration:
141
+ ## Programmatic API
586
142
 
587
- ```json
588
- {
589
- "repository": {
590
- "type": "git",
591
- "url": "https://github.com/your-org/your-repo.git"
592
- }
593
- }
143
+ ```ts
144
+ import {
145
+ runCli,
146
+ injectDocs,
147
+ readHashManifest,
148
+ resolveScope,
149
+ isInteractive,
150
+ isValidScope,
151
+ computeNamespacePrefixes,
152
+ } from '@slats/claude-assets-sync';
594
153
  ```
595
154
 
596
- ### Files not appearing in `.claude/`
597
-
598
- 1. **Check sync status:** `npx @slats/claude-assets-sync list`
599
- 2. **Verify package has assets:** Check that the package has a `docs/claude/commands` or `docs/claude/skills` directory
600
- 3. **Use dry-run to debug:** `npx @slats/claude-assets-sync -p @package --dry-run`
601
-
602
- ### Migrating from older versions
155
+ See `src/index.ts` and `src/DETAIL.md` for the full export surface.
603
156
 
604
- If you have a legacy nested structure:
157
+ ## Additional Docs
605
158
 
606
- ```bash
607
- # Preview migration changes
608
- npx @slats/claude-assets-sync migrate --dry-run
609
-
610
- # Perform migration
611
- npx @slats/claude-assets-sync migrate
612
- ```
613
-
614
- ## Architecture
615
-
616
- ### Command Architecture
617
-
618
- The tool uses a modular command structure:
619
-
620
- - **sync**: Core synchronization logic with GitHub API integration
621
- - **list**: Query unified metadata and display package information
622
- - **remove**: Safe package removal with confirmation prompts
623
- - **status**: Version checking with npm registry integration
624
- - **migrate**: Structure migration with dry-run support
625
-
626
- ### Data Flow
627
-
628
- ```
629
- 1. Read package.json → Extract claude.assetPath
630
- 2. Parse repository URL → GitHub owner/repo
631
- 3. Check version → Skip if unchanged (unless --force)
632
- 4. Fetch files → GitHub API (commands/ and skills/)
633
- 5. Transform paths → Apply naming conventions
634
- 6. Write files → .claude/{type}/{prefixed-name}.md (flat)
635
- 7. Update metadata → Unified .sync-meta.json
636
- ```
159
+ - `docs/consumer-integration.md` — complete consumer checklist (dep-cruiser rules, verification steps, end-user install topologies)
160
+ - `docs/bundle-size-decision.md` why `@inquirer/prompts` over ink
637
161
 
638
162
  ## License
639
163
 
640
- MIT License - see [LICENSE](./LICENSE) for details.
164
+ MIT see [LICENSE](./LICENSE).