@dzhechkov/p-replicator 1.5.6 → 1.5.8

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 (34) hide show
  1. package/LICENSE +21 -0
  2. package/README/eng/01_quickstart.md +244 -0
  3. package/README/eng/02_user_guide.md +634 -0
  4. package/README/eng/03_admin_guide.md +333 -0
  5. package/README/eng/04_api_reference.md +302 -0
  6. package/README/eng/05_architecture.md +370 -0
  7. package/README/eng/06_troubleshooting.md +353 -0
  8. package/README/eng/07_changelog.md +134 -0
  9. package/README/eng/README.md +60 -0
  10. package/README/ru/01_quickstart.md +244 -0
  11. package/README/ru/02_user_guide.md +633 -0
  12. package/README/ru/03_admin_guide.md +337 -0
  13. package/README/ru/04_api_reference.md +333 -0
  14. package/README/ru/05_architecture.md +372 -0
  15. package/README/ru/06_troubleshooting.md +355 -0
  16. package/README/ru/07_changelog.md +146 -0
  17. package/README/ru/README.md +60 -0
  18. package/README/ru/html/build.js +553 -0
  19. package/README/ru/html/index.html +1312 -0
  20. package/README/ru/html/script.js +496 -0
  21. package/README/ru/html/style.css +804 -0
  22. package/bin/cli.js +0 -0
  23. package/package.json +10 -10
  24. package/src/cli.js +7 -1
  25. package/src/commands/init.js +4 -1
  26. package/templates/.claude/agents/replicate-coordinator.md +23 -21
  27. package/templates/.claude/commands/replicate.md +4 -2
  28. package/templates/.claude/rules/replicate-pipeline.md +16 -0
  29. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md +15 -0
  30. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/04-generate-p1.md +20 -0
  31. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/README.md +11 -0
  32. package/templates/.claude/skills/goap-research-ed25519/SKILL.md +3 -0
  33. package/templates/.claude/skills/problem-solver-enhanced/SKILL.md +3 -0
  34. package/templates/.claude/skills/reverse-engineering-unicorn/SKILL.md +3 -0
@@ -0,0 +1,370 @@
1
+ # 05. Architecture
2
+
3
+ Internal design of `p-replicator` — how it installs, upgrades, coexists
4
+ with user customizations.
5
+
6
+ ## Two-tier model: Pre-shipped vs Project-generated
7
+
8
+ The fundamental architectural split:
9
+
10
+ | Tier | Created by | Lives in | Updated |
11
+ |---|---|---|---|
12
+ | **Pre-shipped** | `npx p-replicator init` | `.claude/{skills,commands,agents,rules,hooks}/` + `settings.json` | On each package upgrade |
13
+ | **Project-generated** | `/replicate` Phase 3 (LLM execution) | Various: `CLAUDE.md`, `.claude/agents/planner.md`, `docs/`, etc. | Only on regeneration |
14
+
15
+ This is **the main fix** of v1.4.0 — previously `/replicate` Phase 3 tried
16
+ to generate ALL artifacts (including generic commands like `/run`,
17
+ `/feature`), which led to flaky outputs (LLM compression, missed templates).
18
+ Post-v1.4.0, generic commands are pre-shipped, Phase 3 generates ONLY
19
+ project-specific artifacts.
20
+
21
+ ---
22
+
23
+ ## SSOT: `utils.COMPONENTS`
24
+
25
+ Single source of truth for what's shipped and what's generated:
26
+
27
+ ```javascript
28
+ const COMPONENTS = {
29
+ // Pre-shipped (6 groups, install via npx init):
30
+ skills: { kind: 'pre-shipped', src: '.claude/skills', items: { /* 10 */ } },
31
+ commands: { kind: 'pre-shipped', src: '.claude/commands', items: { /* 11 */ } },
32
+ agents: { kind: 'pre-shipped', src: '.claude/agents', items: { /* 4 */ } },
33
+ rules: { kind: 'pre-shipped', src: '.claude/rules', items: { /* 5 */ } },
34
+ settings: { kind: 'pre-shipped', isFile: true, src: '.claude/settings.json' },
35
+ hooks: { kind: 'pre-shipped', src: '.claude/hooks', items: { /* 6 */ } },
36
+
37
+ // Project-generated (3 groups, created by /replicate Phase 3):
38
+ projectAgents: { kind: 'project-generated', items: { /* full paths */ } },
39
+ projectRules: { kind: 'project-generated', items: { /* full paths */ } },
40
+ projectFiles: { kind: 'project-generated', items: { /* full paths */ } },
41
+ };
42
+ ```
43
+
44
+ **Consumers:**
45
+ - `init.js` / `update.js` iterate only `kind === 'pre-shipped'` for install
46
+ - `doctor.js` checks existence of pre-shipped artifacts
47
+ - `list.js` outputs metadata
48
+ - `verify.js` checks BOTH groups (pre-shipped strict, project-generated hints)
49
+ - `cli.js` showHelp dynamically counts items for display
50
+
51
+ **Any future edit to items automatically updates all 5 surfaces** —
52
+ eliminating drift issues that existed pre-v1.3.1.
53
+
54
+ ---
55
+
56
+ ## Path derivation: `getItemRelativePath()`
57
+
58
+ A single helper centralizes path derivation across all groups:
59
+
60
+ ```javascript
61
+ function getItemRelativePath(comp, itemKey) {
62
+ if (comp.isFile) return comp.src; // settings.json
63
+ if (comp.kind === 'project-generated') return itemKey; // full paths
64
+ if (comp.src === '.claude/skills') return path.join(comp.src, itemKey, 'SKILL.md');
65
+ if (comp.src === '.claude/hooks') return path.join(comp.src, itemKey + '.cjs');
66
+ return path.join(comp.src, itemKey + '.md'); // commands/rules/agents
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Cross-platform hooks (v1.4.1)
73
+
74
+ **Design principle:** zero shell dependency.
75
+
76
+ All 6 hook scripts are pure Node, using `execFileSync('git', [...])`
77
+ instead of shell pipes. This works equivalently on:
78
+ - Windows cmd.exe (no `2>/dev/null`, no `2>nul` — neither needed)
79
+ - Bash / zsh / Git Bash on Windows
80
+ - PowerShell
81
+
82
+ **Pattern for autocommit script:**
83
+
84
+ ```javascript
85
+ const fs = require('node:fs');
86
+ const path = require('node:path');
87
+ const { execFileSync } = require('node:child_process');
88
+
89
+ const TARGET = path.resolve(process.cwd(), '.claude', 'feature-roadmap.json');
90
+ const SILENT = { stdio: 'ignore' };
91
+ const git = (args) => execFileSync('git', args, SILENT);
92
+
93
+ try {
94
+ if (!fs.existsSync(TARGET)) process.exit(0);
95
+ try { git(['rev-parse', '--git-dir']); } catch { process.exit(0); }
96
+ git(['add', '--', TARGET]);
97
+ let hasDiff = false;
98
+ try { git(['diff', '--cached', '--quiet', '--', TARGET]); }
99
+ catch { hasDiff = true; }
100
+ if (hasDiff) git(['commit', '--only', '--', TARGET, '-m', '...']);
101
+ } catch { process.exit(0); }
102
+ ```
103
+
104
+ **Defensive properties:**
105
+ - `if (!fs.existsSync) exit 0` — no file, nothing to commit
106
+ - `try { rev-parse } catch { exit 0 }` — no git repo, skip
107
+ - `try { diff } catch { hasDiff = true }` — `git diff --quiet` exits 1 if diff
108
+ - Outer `try/catch` ensures exit 0 on any error (best-effort)
109
+
110
+ ---
111
+
112
+ ## Sync-templates: MERGE mode (v1.4.1)
113
+
114
+ **File:** `scripts/sync-templates.js` — runs as `prepublishOnly` hook.
115
+
116
+ **Goal:** copy `.claude/` from source repo into `templates/.claude/` (which
117
+ ends up in the npm tarball).
118
+
119
+ **Pre-v1.4.1 (BUG):** `cleanDir(target)` + `copyRecursive(source, target)` —
120
+ cleared target before copy. Deleted files present in `templates/` but absent
121
+ in source. This **silently deleted all v1.4.0 pre-shipped commands** during
122
+ `npm publish --dry-run`.
123
+
124
+ **Post-v1.4.1 (FIX):** `ensureDir(target)` + `copyRecursive(source, target)` —
125
+ copies/overwrites source files but does NOT delete target-only ones.
126
+ Pre-shipped files survive; source files overwrite with correct content.
127
+
128
+ **Idempotent:** running twice consecutively → identical result.
129
+
130
+ ---
131
+
132
+ ## Settings.json merge (v1.4.2)
133
+
134
+ `init --force` and `update` use `mergeSettingsJson(existing, template)` to
135
+ preserve user customizations.
136
+
137
+ ### Algorithm
138
+
139
+ ```
140
+ mergeSettingsJson(existing, template):
141
+ if !existing: return template (fresh install)
142
+ if !template: return existing (defensive)
143
+
144
+ merged = {...existing}
145
+
146
+ # Top level: template only fills what user lacks
147
+ for each (key, value) in template:
148
+ if key not in merged: merged[key] = value
149
+
150
+ # Hooks: deep merge per event type
151
+ if template.hooks:
152
+ merged.hooks = mergeHookEvents(existing.hooks, template.hooks)
153
+
154
+ return merged
155
+
156
+ mergeHookEvents(existing, template):
157
+ for each eventType in template:
158
+ if !existing[eventType]: existing[eventType] = template[eventType]
159
+ else: mergeHookMatchers(existing[eventType], template[eventType])
160
+
161
+ mergeHookMatchers(existing[], template[]):
162
+ for each tplEntry in template:
163
+ target = existing.find(e => e.matcher === tplEntry.matcher)
164
+ if !target: existing.push(tplEntry)
165
+ else:
166
+ existingCmds = Set(target.hooks.map(h => h.command))
167
+ for each tplHook in tplEntry.hooks:
168
+ if !existingCmds.has(tplHook.command):
169
+ target.hooks.push(tplHook) # de-dup by command string
170
+ ```
171
+
172
+ ### Identity model
173
+
174
+ Hooks are compared by `command` string. Implications:
175
+
176
+ - User-added hook (absent from template): **preserved**
177
+ - User-modified default (changed command): treated as user-added → **preserved**
178
+ (old default removed via orphan detection if it was in shippedDefaults)
179
+ - Identical command in template and user: **de-duped** (single copy)
180
+ - New hook in template: **added** to user's settings
181
+
182
+ ### Override
183
+
184
+ `--reset-settings` flag disables merge — full overwrite. For when user wants
185
+ clean slate.
186
+
187
+ ---
188
+
189
+ ## Orphan detection (v1.4.3)
190
+
191
+ **Problem with merge-only logic:** if a new package version removes a hook,
192
+ the old hook lingers forever in user's settings (looks user-added from
193
+ merge perspective).
194
+
195
+ **Solution:** `manifest.shippedDefaults` baseline.
196
+
197
+ ### Algorithm
198
+
199
+ ```
200
+ init/update upgrade flow:
201
+ 1. previousManifest = read .p-replicator.json BEFORE overwrite
202
+ 2. oldTpl = previousManifest.shippedDefaults['settings.json']
203
+ 3. newTpl = read templates/.claude/settings.json (current)
204
+ 4. existing = read user's .claude/settings.json
205
+ 5. cleaned = removeOrphanHooks(existing, oldTpl, newTpl)
206
+ 6. merged = mergeSettingsJson(cleaned, newTpl)
207
+ 7. write merged to .claude/settings.json
208
+ 8. write new manifest with shippedDefaults = newTpl (for next upgrade)
209
+
210
+ removeOrphanHooks(existing, oldTpl, newTpl):
211
+ if !oldTpl: return existing (first upgrade, no baseline yet)
212
+ oldCmds = extractCommands(oldTpl)
213
+ newCmds = extractCommands(newTpl)
214
+ orphans = oldCmds.filter(c => !newCmds.has(c))
215
+ return existing with orphan commands filtered out
216
+ ```
217
+
218
+ ### Properties
219
+
220
+ - **User-added** (never in `oldTpl`) → preserved
221
+ - **Removed default** (was in `oldTpl`, gone from `newTpl`, present in user's) → removed
222
+ - **Unchanged default** (in all three) → kept
223
+ - **Renamed/modified default** (cmd-string changed) → old orphaned, new added via merge
224
+
225
+ ### Backward compat
226
+
227
+ If manifest has no `shippedDefaults` (pre-1.4.3 install) — orphan detection
228
+ skipped on first upgrade. Manifest gets populated for future upgrades.
229
+
230
+ ---
231
+
232
+ ## Statusline architecture (v1.5.0)
233
+
234
+ **Goal:** single-script multi-line dashboard.
235
+
236
+ ```
237
+ ┌─ statusline.cjs (entry, ~330 LOC) ─────────────────────────┐
238
+ │ │
239
+ │ 1. main() │
240
+ │ ├── parseManifest() ───────► .p-replicator.json │
241
+ │ ├── parseState() ──────────► .claude/.p-replicator-state.json (with stale check) │
242
+ │ ├── parseRoadmap() ────────► .claude/feature-roadmap.json │
243
+ │ ├── parseSparcDocs() ──────► docs/PRD.md, ..., ADR.md │
244
+ │ ├── parseValidationScore() ► docs/validation-report.md (regex) │
245
+ │ ├── parseAdrs() ───────────► docs/ADR.md OR docs/adr/ OR docs/ddd/adr/ │
246
+ │ ├── parsePlans() ──────────► docs/plans/*.md │
247
+ │ ├── parseInsights() ───────► .claude/insights/index.md │
248
+ │ ├── parseToolkit() ────────► filesystem walks │
249
+ │ ├── parseSettingsStatus() ─► deep-equals current vs shippedDefaults │
250
+ │ ├── parseMcpServers() ─────► .mcp.json │
251
+ │ ├── parseKeysarium() ──────► .keysarium.json existence │
252
+ │ ├── parseDomain() ─────────► CLAUDE.md keyword grep │
253
+ │ ├── parseLastHarvest() ────► TOOLKIT_HARVEST.md mtime │
254
+ │ └── parseLastTest() ───────► .claude/.last-test.json (optional) │
255
+ │ │
256
+ │ 2. lines = [ │
257
+ │ buildHeader(manifest), │
258
+ │ buildPipeline(state), │
259
+ │ buildRoadmap(roadmap, domain), │
260
+ │ buildDocs(sparc, validation, plans, adrs, lastHarvest), │
261
+ │ buildToolkit(toolkit, expected), │
262
+ │ buildStatus(insights, lastTest, mcpServers, settingsStatus, keysarium), │
263
+ │ ] │
264
+ │ │
265
+ │ 3. process.stdout.write(lines.join('\n') + '\n') │
266
+ │ │
267
+ └─────────────────────────────────────────────────────────────┘
268
+ ```
269
+
270
+ **Defensive design:** every `parse*` function wrapped in `safeRun()` with
271
+ fallback. One parse error → fallback value, other sections work.
272
+
273
+ **State-file flow:**
274
+
275
+ ```
276
+ command (e.g., /run) ──Bash──► node .claude/hooks/state-update.cjs --command /run --phase loop --progress 0.4
277
+
278
+
279
+ .claude/.p-replicator-state.json (atomic write)
280
+
281
+
282
+ Claude Code prompt ────────► node .claude/hooks/statusline.cjs
283
+
284
+
285
+ reads state, computes heuristics, renders 6 lines
286
+ ```
287
+
288
+ **Stale check:** state older than 30 minutes → ignored (Pipeline section
289
+ shows `idle`).
290
+
291
+ ---
292
+
293
+ ## Test infrastructure
294
+
295
+ **Suite:** 105 tests, 36 suites, ~25 sec runtime.
296
+
297
+ | Layer | File | Coverage |
298
+ |---|---|---|
299
+ | **Unit** | `tests/unit/utils.test.js` (54 tests) | Pure functions: createManifest, mergeSettingsJson, removeOrphanHooks, getItemRelativePath, parseToolkit logic |
300
+ | **E2E** | `tests/e2e/lifecycle.test.js` (48 tests) | Full CLI lifecycle, hooks installation, settings merge edge cases, statusline output, --feature-branches docs |
301
+ | **Snapshot** | `tests/snapshot/templates.test.js` (3 tests) | SHA-256 baseline of all 115 files in `templates/` |
302
+
303
+ **Meta-tests:** verify consistency between documents:
304
+ - `replicate-pipeline.md` mentions every pre-shipped command (no orphan in rule)
305
+ - `replicate.md` Phase 3 doesn't claim "Generate `<pre-shipped>.md`" (no spec drift)
306
+
307
+ **Snapshot baseline** regenerated via `npm run snapshot:baseline` after
308
+ intentional template changes.
309
+
310
+ ---
311
+
312
+ ## Module composition: `view()` syntax (Claude Code-specific)
313
+
314
+ Skills use `view()` for cross-skill loading at runtime:
315
+
316
+ ```markdown
317
+ view() .claude/skills/explore/SKILL.md
318
+ view() .claude/skills/explore/references/questioning-techniques.md
319
+ ```
320
+
321
+ Claude Code resolves these references dynamically: when executing a skill,
322
+ the LLM reads referenced files at the moment of use. This lets skill A
323
+ delegate to skill B without duplicating content.
324
+
325
+ **Limitation:** only Claude Code supports this runtime mechanism. For
326
+ other platforms (Codex, OpenCode), skill content must be **inlined**
327
+ (compiled into command markdown) at install time. See
328
+ `MULTIPLATFORM_ROADMAP.md`.
329
+
330
+ ---
331
+
332
+ ## Pipeline: `/replicate` phases
333
+
334
+ ```
335
+ INPUT (idea or company name)
336
+
337
+
338
+ Phase 0: PRODUCT DISCOVERY (optional)
339
+ │ skill: reverse-engineering-unicorn
340
+ │ output: docs/00_product_discovery.md
341
+
342
+ Phase 1: PLANNING
343
+ │ skill: sparc-prd-mini (internally: explore + research + solve + 5 SPARC phases)
344
+ │ output: docs/PRD.md, Architecture.md, Pseudocode.md, ... (11 docs)
345
+
346
+ Phase 2: VALIDATION (5-agent swarm)
347
+ │ skill: requirements-validator
348
+ │ output: docs/validation-report.md, docs/test-scenarios.md (BDD)
349
+ │ verdict: 🟢 READY / 🟡 CAVEATS / 🔴 NEEDS WORK (max 3 retries)
350
+
351
+ Phase 3: TOOLKIT GENERATION (project-specific only)
352
+ │ skill: cc-toolkit-generator-enhanced (9 modules)
353
+ │ output: project agents (planner, code-reviewer, architect),
354
+ │ project rules (security, coding-style, testing),
355
+ │ project skills (project-context, coding-standards),
356
+ │ CLAUDE.md, feature-roadmap.json, DEVELOPMENT_GUIDE.md
357
+
358
+ Phase 4: FINALIZE
359
+ │ output: docker-compose.yml, Dockerfile, .gitignore
360
+ │ action: git commit
361
+
362
+ DONE — project ready for /start or /run
363
+ ```
364
+
365
+ ---
366
+
367
+ ## Next
368
+
369
+ - [06_troubleshooting.md](./06_troubleshooting.md) — common issues
370
+ - [07_changelog.md](./07_changelog.md) — version history