@dzhechkov/p-replicator 1.2.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bin/cli.js +0 -0
- package/package.json +10 -3
- package/src/cli.js +23 -6
- package/src/commands/doctor.js +46 -29
- package/src/commands/init.js +61 -8
- package/src/commands/list.js +5 -26
- package/src/commands/update.js +73 -7
- package/src/commands/verify.js +111 -0
- package/src/utils.js +275 -4
- package/templates/.claude/commands/deploy.md +100 -0
- package/templates/.claude/commands/docs.md +79 -0
- package/templates/.claude/commands/feature.md +134 -0
- package/templates/.claude/commands/go.md +115 -0
- package/templates/.claude/commands/myinsights.md +72 -0
- package/templates/.claude/commands/next.md +110 -0
- package/templates/.claude/commands/plan.md +88 -0
- package/templates/.claude/commands/replicate.md +103 -17
- package/templates/.claude/commands/run.md +151 -0
- package/templates/.claude/commands/start.md +88 -0
- package/templates/.claude/hooks/autocommit-insights.cjs +39 -0
- package/templates/.claude/hooks/autocommit-plans.cjs +39 -0
- package/templates/.claude/hooks/autocommit-roadmap.cjs +44 -0
- package/templates/.claude/hooks/session-insights.cjs +28 -0
- package/templates/.claude/hooks/state-update.cjs +79 -0
- package/templates/.claude/hooks/statusline.cjs +399 -0
- package/templates/.claude/rules/feature-lifecycle.md +145 -0
- package/templates/.claude/rules/git-workflow.md +74 -0
- package/templates/.claude/rules/insights-capture.md +77 -0
- package/templates/.claude/rules/replicate-pipeline.md +97 -20
- package/templates/.claude/settings.json +44 -0
- package/templates/.claude/skills/brutal-honesty-review/SKILL.md +43 -0
- package/templates/.claude/skills/brutal-honesty-review/scripts/assess-code.sh +0 -0
- package/templates/.claude/skills/brutal-honesty-review/scripts/assess-tests.sh +0 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/SKILL.md +8 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md +46 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/04-generate-p1.md +9 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/05-generate-p2p3.md +11 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/06-package-deliver.md +46 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/security-patterns-library.md +196 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/automation-commands.md +15 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-agents.md +39 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle.md +8 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py +0 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/goap_planner.py +0 -0
- package/templates/.claude/skills/requirements-validator/SKILL.md +25 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const {
|
|
5
|
+
green, red, yellow, cyan, bold, dim,
|
|
6
|
+
info, success, error: logError,
|
|
7
|
+
readManifest, fileExists,
|
|
8
|
+
COMPONENTS, getItemRelativePath,
|
|
9
|
+
} = require('../utils');
|
|
10
|
+
|
|
11
|
+
function run(options) {
|
|
12
|
+
const { targetDir } = options;
|
|
13
|
+
|
|
14
|
+
const manifest = readManifest(targetDir);
|
|
15
|
+
if (!manifest) {
|
|
16
|
+
logError('P-Replicator is not installed in this directory.');
|
|
17
|
+
info(`Run ${cyan('npx @dzhechkov/p-replicator init')} first.`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let issues = 0;
|
|
22
|
+
let warnings = 0;
|
|
23
|
+
|
|
24
|
+
function pass(msg) { console.log(` ${green('✓')} ${msg}`); }
|
|
25
|
+
function fail(msg) { console.log(` ${red('✗')} ${msg}`); issues++; }
|
|
26
|
+
function hint(msg) { console.log(` ${yellow('!')} ${msg}`); warnings++; }
|
|
27
|
+
|
|
28
|
+
console.log(bold('P-Replicator — Verify state'));
|
|
29
|
+
console.log(dim(`Manifest: v${manifest.version}, installed ${manifest.installedAt}`));
|
|
30
|
+
console.log('');
|
|
31
|
+
|
|
32
|
+
// ── Section 1: Pre-shipped (init contract — MUST exist) ─────────────────
|
|
33
|
+
console.log(bold('Pre-shipped (from p-replicator init):'));
|
|
34
|
+
console.log('');
|
|
35
|
+
|
|
36
|
+
const preShippedGroups = Object.entries(COMPONENTS)
|
|
37
|
+
.filter(([, c]) => c.kind === 'pre-shipped');
|
|
38
|
+
|
|
39
|
+
for (const [groupKey, comp] of preShippedGroups) {
|
|
40
|
+
for (const [itemKey, desc] of Object.entries(comp.items)) {
|
|
41
|
+
const rel = getItemRelativePath(comp, itemKey);
|
|
42
|
+
const full = path.join(targetDir, rel);
|
|
43
|
+
// Display labels: commands as /name, others as group: name
|
|
44
|
+
const label = groupKey === 'commands'
|
|
45
|
+
? `/${itemKey}`
|
|
46
|
+
: `${groupKey}: ${itemKey}`;
|
|
47
|
+
if (fileExists(full)) {
|
|
48
|
+
pass(`${label} ${dim('— ' + desc)}`);
|
|
49
|
+
} else {
|
|
50
|
+
fail(`${label} — missing (${rel})`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log('');
|
|
56
|
+
|
|
57
|
+
// ── Section 2: Post-/replicate (project-generated — advisory) ────────────
|
|
58
|
+
// Detect: was /replicate run? Heuristic: CLAUDE.md OR feature-roadmap.json present.
|
|
59
|
+
const replicateRan =
|
|
60
|
+
fileExists(path.join(targetDir, 'CLAUDE.md')) ||
|
|
61
|
+
fileExists(path.join(targetDir, '.claude', 'feature-roadmap.json'));
|
|
62
|
+
|
|
63
|
+
const projectGroups = Object.entries(COMPONENTS)
|
|
64
|
+
.filter(([, c]) => c.kind === 'project-generated');
|
|
65
|
+
|
|
66
|
+
if (replicateRan) {
|
|
67
|
+
console.log(bold('Post-/replicate (generated by Phase 3):'));
|
|
68
|
+
console.log('');
|
|
69
|
+
for (const [, comp] of projectGroups) {
|
|
70
|
+
for (const [itemKey, desc] of Object.entries(comp.items)) {
|
|
71
|
+
const rel = getItemRelativePath(comp, itemKey);
|
|
72
|
+
const full = path.join(targetDir, rel);
|
|
73
|
+
if (fileExists(full)) {
|
|
74
|
+
pass(`${rel} ${dim('— ' + desc)}`);
|
|
75
|
+
} else {
|
|
76
|
+
hint(`${rel} ${dim('— ' + desc)} (not found)`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
console.log(bold('Post-/replicate:'));
|
|
82
|
+
console.log(dim(' No /replicate output detected (CLAUDE.md and feature-roadmap.json both absent).'));
|
|
83
|
+
console.log(dim(' Run /replicate in Claude Code to generate project-specific artifacts.'));
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log(dim(` Expected after /replicate (${projectGroups.reduce((n, [, c]) => n + Object.keys(c.items).length, 0)} artifacts across ${projectGroups.length} groups):`));
|
|
86
|
+
for (const [groupKey, comp] of projectGroups) {
|
|
87
|
+
console.log(dim(` ${groupKey}: ${Object.keys(comp.items).length} items`));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log('');
|
|
92
|
+
|
|
93
|
+
// ── Summary ─────────────────────────────────────────────────────────────
|
|
94
|
+
console.log(bold('─'.repeat(60)));
|
|
95
|
+
if (issues === 0 && warnings === 0) {
|
|
96
|
+
success(bold('All artifacts verified.'));
|
|
97
|
+
} else if (issues === 0) {
|
|
98
|
+
success(`Pre-shipped contract OK (${yellow(warnings + ' post-replicate hint(s)')}).`);
|
|
99
|
+
} else {
|
|
100
|
+
logError(`${red(issues + ' issue(s)')} in pre-shipped contract, ${yellow(warnings + ' post-replicate hint(s)')}.`);
|
|
101
|
+
console.log('');
|
|
102
|
+
info(`Repair pre-shipped: ${cyan('npx @dzhechkov/p-replicator init --force')}`);
|
|
103
|
+
info(`Regenerate post-pipeline: run ${cyan('/replicate')} in Claude Code`);
|
|
104
|
+
}
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
process.exitCode = issues > 0 ? 1 : 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = run;
|
|
111
|
+
module.exports.run = run;
|
package/src/utils.js
CHANGED
|
@@ -207,13 +207,21 @@ function writeManifest(targetDir, data) {
|
|
|
207
207
|
writeJSON(path.join(targetDir, MANIFEST_FILE), data);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
function createManifest(version, components, files) {
|
|
211
|
-
|
|
210
|
+
function createManifest(version, components, files, shippedDefaults) {
|
|
211
|
+
const manifest = {
|
|
212
212
|
version: version,
|
|
213
213
|
installedAt: new Date().toISOString(),
|
|
214
214
|
components: components,
|
|
215
215
|
files: files,
|
|
216
216
|
};
|
|
217
|
+
// shippedDefaults (v1.4.3+): snapshot of files we shipped this install. Used
|
|
218
|
+
// by next upgrade to detect orphan hooks that have been removed from the
|
|
219
|
+
// current template. Currently tracks settings.json only (the file most
|
|
220
|
+
// affected by user customization vs template drift).
|
|
221
|
+
if (shippedDefaults && Object.keys(shippedDefaults).length > 0) {
|
|
222
|
+
manifest.shippedDefaults = shippedDefaults;
|
|
223
|
+
}
|
|
224
|
+
return manifest;
|
|
217
225
|
}
|
|
218
226
|
|
|
219
227
|
// ===========================================================================
|
|
@@ -231,29 +239,282 @@ function getTemplatesDir() {
|
|
|
231
239
|
// needed since this is a complete package).
|
|
232
240
|
// ===========================================================================
|
|
233
241
|
|
|
242
|
+
// items maps are the SINGLE SOURCE OF TRUTH for component names + descriptions.
|
|
243
|
+
// Consumed by: doctor.js (existence checks), list.js (display), cli.js (help counts),
|
|
244
|
+
// verify.js (post-/replicate state check), and is the canonical contract for what
|
|
245
|
+
// the package ships AND what /replicate is expected to generate.
|
|
246
|
+
//
|
|
247
|
+
// `kind: 'pre-shipped'` — installed by `npx p-replicator init` (must always exist).
|
|
248
|
+
// `kind: 'project-generated'` — created by `/replicate` Phase 3; items keys are full
|
|
249
|
+
// relative paths (e.g., '.claude/agents/planner.md').
|
|
234
250
|
const COMPONENTS = {
|
|
235
251
|
skills: {
|
|
236
252
|
src: '.claude/skills',
|
|
253
|
+
kind: 'pre-shipped',
|
|
237
254
|
label: 'Skills (10 skill packs)',
|
|
238
255
|
group: 'core',
|
|
256
|
+
items: {
|
|
257
|
+
'explore': 'Socratic task clarification',
|
|
258
|
+
'sparc-prd-mini': 'SPARC documentation generator (11 docs)',
|
|
259
|
+
'goap-research-ed25519': 'Verified research with Ed25519 anti-hallucination',
|
|
260
|
+
'problem-solver-enhanced': 'First principles + TRIZ (9 modules)',
|
|
261
|
+
'requirements-validator': 'INVEST/SMART validation + BDD scenarios',
|
|
262
|
+
'brutal-honesty-review': 'Unvarnished technical criticism',
|
|
263
|
+
'cc-toolkit-generator-enhanced': 'Modular toolkit generator (9 modules, ~165K chars)',
|
|
264
|
+
'reverse-engineering-unicorn': 'Company reverse engineering + playbook',
|
|
265
|
+
'pipeline-forge': 'Meta-skill: build AI pipelines from patterns',
|
|
266
|
+
'knowledge-extractor': 'Extract reusable knowledge from projects',
|
|
267
|
+
},
|
|
239
268
|
},
|
|
240
269
|
commands: {
|
|
241
270
|
src: '.claude/commands',
|
|
242
|
-
|
|
271
|
+
kind: 'pre-shipped',
|
|
272
|
+
label: 'Commands (orchestration + workflow)',
|
|
243
273
|
group: 'core',
|
|
274
|
+
items: {
|
|
275
|
+
'replicate': 'Full pipeline: idea → validated docs → toolkit',
|
|
276
|
+
'harvest': 'Knowledge extraction from projects',
|
|
277
|
+
'start': 'Bootstrap project from SPARC docs (monorepo + Docker)',
|
|
278
|
+
'plan': 'Lightweight planning to docs/plans/ (auto-commit)',
|
|
279
|
+
'feature': 'Full SPARC-mini lifecycle (PLAN → VALIDATE → IMPLEMENT → REVIEW)',
|
|
280
|
+
'go': 'Intelligent pipeline router (delegates to /plan or /feature)',
|
|
281
|
+
'run': 'Autonomous build loop: /next → /go → repeat',
|
|
282
|
+
'next': 'Pick next feature from .claude/feature-roadmap.json',
|
|
283
|
+
'docs': 'Bilingual documentation generator (RU/EN)',
|
|
284
|
+
'deploy': 'Deployment workflow (dev / staging / prod)',
|
|
285
|
+
'myinsights': 'Capture and recall development insights',
|
|
286
|
+
},
|
|
244
287
|
},
|
|
245
288
|
agents: {
|
|
246
289
|
src: '.claude/agents',
|
|
290
|
+
kind: 'pre-shipped',
|
|
247
291
|
label: 'Agents (4 orchestrators)',
|
|
248
292
|
group: 'core',
|
|
293
|
+
items: {
|
|
294
|
+
'replicate-coordinator': 'Pipeline orchestration (Phases 0-4)',
|
|
295
|
+
'product-discoverer': 'Market research (Phase 0)',
|
|
296
|
+
'doc-validator': 'Documentation validation swarm (Phase 2)',
|
|
297
|
+
'harvest-coordinator': 'Knowledge extraction swarm',
|
|
298
|
+
},
|
|
249
299
|
},
|
|
250
300
|
rules: {
|
|
251
301
|
src: '.claude/rules',
|
|
252
|
-
|
|
302
|
+
kind: 'pre-shipped',
|
|
303
|
+
label: 'Rules (pipeline + workflow constraints)',
|
|
304
|
+
group: 'core',
|
|
305
|
+
items: {
|
|
306
|
+
'replicate-pipeline': 'Phase sequence, output paths, git discipline, modular skill loading',
|
|
307
|
+
'skill-interface-protocol': 'view() contract, module interface, maturity tagging, composition rules',
|
|
308
|
+
'git-workflow': 'Commit/push discipline, branch strategy, semantic messages',
|
|
309
|
+
'insights-capture': 'When and how to capture development insights to knowledge base',
|
|
310
|
+
'feature-lifecycle': '/feature phases (PLAN → VALIDATE → IMPLEMENT → REVIEW), checkpoints, scoring',
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
settings: {
|
|
314
|
+
src: '.claude/settings.json',
|
|
315
|
+
kind: 'pre-shipped',
|
|
316
|
+
label: 'Hooks config (settings.json)',
|
|
253
317
|
group: 'core',
|
|
318
|
+
isFile: true,
|
|
319
|
+
items: {
|
|
320
|
+
'settings.json': 'SessionStart insight injection + Stop auto-commit (roadmap, insights, plans)',
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
hooks: {
|
|
324
|
+
src: '.claude/hooks',
|
|
325
|
+
kind: 'pre-shipped',
|
|
326
|
+
label: 'Hook scripts (cross-platform Node)',
|
|
327
|
+
group: 'core',
|
|
328
|
+
items: {
|
|
329
|
+
'session-insights': 'Inject 3 most recent insights into Claude session context',
|
|
330
|
+
'autocommit-roadmap': 'Auto-commit .claude/feature-roadmap.json on Stop hook',
|
|
331
|
+
'autocommit-insights': 'Auto-commit .claude/insights/ on Stop hook',
|
|
332
|
+
'autocommit-plans': 'Auto-commit docs/plans/ on Stop hook',
|
|
333
|
+
'statusline': 'Multi-line dashboard (pipeline, roadmap, toolkit) for Claude Code statusLine',
|
|
334
|
+
'state-update': 'Argv-driven helper for pipeline commands to publish current command + phase + progress',
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
// ─── Project-generated groups (created by /replicate Phase 3) ───────────
|
|
338
|
+
// items keys are FULL relative paths (e.g., '.claude/agents/planner.md').
|
|
339
|
+
// Used by verify.js to report post-/replicate state; doctor.js does NOT
|
|
340
|
+
// assert their presence (advisory hints only).
|
|
341
|
+
projectAgents: {
|
|
342
|
+
kind: 'project-generated',
|
|
343
|
+
label: 'Project-specific agents (Phase 3 generated from SPARC)',
|
|
344
|
+
group: 'project',
|
|
345
|
+
items: {
|
|
346
|
+
'.claude/agents/planner.md': 'Feature planning with algorithm templates from Pseudocode.md',
|
|
347
|
+
'.claude/agents/code-reviewer.md': 'Quality review with edge cases from Refinement.md',
|
|
348
|
+
'.claude/agents/architect.md': 'System design from Architecture.md + Solution_Strategy.md',
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
projectRules: {
|
|
352
|
+
kind: 'project-generated',
|
|
353
|
+
label: 'Project-specific rules (Phase 3 generated from NFRs/tech stack)',
|
|
354
|
+
group: 'project',
|
|
355
|
+
items: {
|
|
356
|
+
'.claude/rules/security.md': 'NFRs from Specification.md',
|
|
357
|
+
'.claude/rules/coding-style.md': 'Conventions from Architecture.md tech stack',
|
|
358
|
+
'.claude/rules/testing.md': 'Test strategy from Refinement.md',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
projectFiles: {
|
|
362
|
+
kind: 'project-generated',
|
|
363
|
+
label: 'Project files (Phase 3 generated)',
|
|
364
|
+
group: 'project',
|
|
365
|
+
items: {
|
|
366
|
+
'CLAUDE.md': 'Project context (root)',
|
|
367
|
+
'.claude/feature-roadmap.json': 'Feature list (used by /run, /next)',
|
|
368
|
+
'DEVELOPMENT_GUIDE.md': 'Step-by-step dev lifecycle',
|
|
369
|
+
'docker-compose.yml': 'Container orchestration scaffold',
|
|
370
|
+
},
|
|
254
371
|
},
|
|
255
372
|
};
|
|
256
373
|
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// Path derivation: maps a component + item key to its on-disk relative path.
|
|
376
|
+
// Centralizes the "where do we find item X of group Y" logic so doctor/verify/list
|
|
377
|
+
// don't each re-implement it.
|
|
378
|
+
// ---------------------------------------------------------------------------
|
|
379
|
+
|
|
380
|
+
// ---------------------------------------------------------------------------
|
|
381
|
+
// settings.json merge (v1.4.2): preserve user customizations on `init --force`.
|
|
382
|
+
// Algorithm: deep-merge top-level fields (template fills only what user lacks),
|
|
383
|
+
// per-event-type merge for hooks, per-matcher merge for hook arrays, de-dup by
|
|
384
|
+
// command string. Use `--reset-settings` flag for explicit overwrite.
|
|
385
|
+
// ---------------------------------------------------------------------------
|
|
386
|
+
|
|
387
|
+
function mergeSettingsJson(existing, template) {
|
|
388
|
+
if (!existing) return template;
|
|
389
|
+
if (!template) return existing;
|
|
390
|
+
|
|
391
|
+
const merged = { ...existing };
|
|
392
|
+
|
|
393
|
+
// Top-level: add template fields that user doesn't have. Don't overwrite.
|
|
394
|
+
for (const [key, value] of Object.entries(template)) {
|
|
395
|
+
if (!(key in merged)) merged[key] = value;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Special: hooks need structural merge.
|
|
399
|
+
if (template.hooks) {
|
|
400
|
+
merged.hooks = mergeHookEvents(existing.hooks || {}, template.hooks);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return merged;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function mergeHookEvents(existing, template) {
|
|
407
|
+
const merged = { ...existing };
|
|
408
|
+
for (const eventType of Object.keys(template)) {
|
|
409
|
+
if (!merged[eventType]) {
|
|
410
|
+
merged[eventType] = template[eventType];
|
|
411
|
+
} else {
|
|
412
|
+
merged[eventType] = mergeHookMatchers(merged[eventType], template[eventType]);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return merged;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ---------------------------------------------------------------------------
|
|
419
|
+
// removeOrphanHooks (v1.4.3): orphan detection on upgrade.
|
|
420
|
+
// "Orphan" = a hook command that WAS shipped by the package previously
|
|
421
|
+
// (in oldTemplate from manifest.shippedDefaults) but is NO LONGER in the
|
|
422
|
+
// current template. Such hooks should be removed from user's settings on
|
|
423
|
+
// upgrade — otherwise they linger forever, calling broken/missing scripts.
|
|
424
|
+
//
|
|
425
|
+
// Identity model: hooks are compared by their `command` string. User-modified
|
|
426
|
+
// commands have a different string and are treated as user-added (preserved).
|
|
427
|
+
// User-added commands (never in oldTemplate) are also preserved.
|
|
428
|
+
// ---------------------------------------------------------------------------
|
|
429
|
+
|
|
430
|
+
function extractCommands(hooksRoot) {
|
|
431
|
+
const cmds = new Set();
|
|
432
|
+
if (!hooksRoot || !hooksRoot.hooks) return cmds;
|
|
433
|
+
for (const eventEntries of Object.values(hooksRoot.hooks)) {
|
|
434
|
+
if (!Array.isArray(eventEntries)) continue;
|
|
435
|
+
for (const matcher of eventEntries) {
|
|
436
|
+
for (const h of (matcher.hooks || [])) {
|
|
437
|
+
if (h && typeof h.command === 'string') cmds.add(h.command);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return cmds;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function removeOrphanHooks(existing, oldTemplate, newTemplate) {
|
|
445
|
+
// First-upgrade case: no baseline → can't detect orphans. Pass-through.
|
|
446
|
+
if (!oldTemplate || !existing) return existing;
|
|
447
|
+
|
|
448
|
+
const oldCmds = extractCommands(oldTemplate);
|
|
449
|
+
const newCmds = extractCommands(newTemplate);
|
|
450
|
+
|
|
451
|
+
// Orphans: shipped previously, no longer shipped.
|
|
452
|
+
const orphanCmds = new Set();
|
|
453
|
+
for (const cmd of oldCmds) {
|
|
454
|
+
if (!newCmds.has(cmd)) orphanCmds.add(cmd);
|
|
455
|
+
}
|
|
456
|
+
if (orphanCmds.size === 0) return existing;
|
|
457
|
+
|
|
458
|
+
// Deep-clone existing while filtering out orphan commands.
|
|
459
|
+
const cleaned = { ...existing };
|
|
460
|
+
if (existing.hooks) {
|
|
461
|
+
cleaned.hooks = {};
|
|
462
|
+
for (const [eventType, entries] of Object.entries(existing.hooks)) {
|
|
463
|
+
if (!Array.isArray(entries)) {
|
|
464
|
+
cleaned.hooks[eventType] = entries;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
cleaned.hooks[eventType] = entries.map((matcher) => ({
|
|
468
|
+
...matcher,
|
|
469
|
+
hooks: (matcher.hooks || []).filter(
|
|
470
|
+
(h) => !(h && typeof h.command === 'string' && orphanCmds.has(h.command))
|
|
471
|
+
),
|
|
472
|
+
}));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return cleaned;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function mergeHookMatchers(existing, template) {
|
|
479
|
+
// Clone the existing array; we'll mutate per-entry hook arrays via reference.
|
|
480
|
+
const result = existing.map((m) => ({ ...m, hooks: [...(m.hooks || [])] }));
|
|
481
|
+
for (const tplEntry of template) {
|
|
482
|
+
const target = result.find((e) => e.matcher === tplEntry.matcher);
|
|
483
|
+
if (!target) {
|
|
484
|
+
// New matcher — keep it as-is
|
|
485
|
+
result.push({ ...tplEntry, hooks: [...(tplEntry.hooks || [])] });
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
// Same matcher — append template hooks not already present (compare by command)
|
|
489
|
+
const existingCmds = new Set(target.hooks.map((h) => h.command));
|
|
490
|
+
for (const tplHook of tplEntry.hooks || []) {
|
|
491
|
+
if (!existingCmds.has(tplHook.command)) {
|
|
492
|
+
target.hooks.push(tplHook);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return result;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function getItemRelativePath(comp, itemKey) {
|
|
500
|
+
// Single-file components (settings.json)
|
|
501
|
+
if (comp.isFile) return comp.src;
|
|
502
|
+
|
|
503
|
+
// Project-generated: items keys ARE full relative paths
|
|
504
|
+
if (comp.kind === 'project-generated') return itemKey;
|
|
505
|
+
|
|
506
|
+
// Pre-shipped multi-file groups
|
|
507
|
+
if (comp.src === '.claude/skills') {
|
|
508
|
+
return path.join(comp.src, itemKey, 'SKILL.md');
|
|
509
|
+
}
|
|
510
|
+
// Hook scripts have .cjs extension
|
|
511
|
+
if (comp.src === '.claude/hooks') {
|
|
512
|
+
return path.join(comp.src, itemKey + '.cjs');
|
|
513
|
+
}
|
|
514
|
+
// commands / rules / agents are plain .md
|
|
515
|
+
return path.join(comp.src, itemKey + '.md');
|
|
516
|
+
}
|
|
517
|
+
|
|
257
518
|
// ===========================================================================
|
|
258
519
|
// Exports
|
|
259
520
|
// ===========================================================================
|
|
@@ -277,4 +538,14 @@ module.exports = {
|
|
|
277
538
|
|
|
278
539
|
// Components
|
|
279
540
|
COMPONENTS,
|
|
541
|
+
getItemRelativePath,
|
|
542
|
+
|
|
543
|
+
// Settings merge (v1.4.2)
|
|
544
|
+
mergeSettingsJson,
|
|
545
|
+
mergeHookEvents,
|
|
546
|
+
mergeHookMatchers,
|
|
547
|
+
|
|
548
|
+
// Orphan detection (v1.4.3)
|
|
549
|
+
removeOrphanHooks,
|
|
550
|
+
extractCommands,
|
|
280
551
|
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Guide deployment to dev/staging/prod environments. Reads pre-deployment checklist from docs/Completion.md, runs gating checks per environment tier, executes deployment, and verifies post-deploy health.
|
|
3
|
+
argument-hint: '<dev | staging | prod>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /deploy $ARGUMENTS
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Structured deployment workflow with environment-specific gates.
|
|
11
|
+
|
|
12
|
+
## Environment Tiers
|
|
13
|
+
|
|
14
|
+
| Tier | Confirmation | Checks | Auto-rollback |
|
|
15
|
+
|------|--------------|--------|---------------|
|
|
16
|
+
| `dev` | None — auto | Tests pass, build succeeds | No |
|
|
17
|
+
| `staging` | Implicit (after gate checks) | Tests + lint + smoke + health | Yes |
|
|
18
|
+
| `prod` | Explicit `yes` typed | All staging + manual review | Yes |
|
|
19
|
+
|
|
20
|
+
## Process
|
|
21
|
+
|
|
22
|
+
### Step 1: Determine Target
|
|
23
|
+
|
|
24
|
+
Parse `$ARGUMENTS`: `dev` (default) | `staging` | `prod`. Halt on invalid.
|
|
25
|
+
|
|
26
|
+
### Step 2: Read Pre-Deploy Checklist
|
|
27
|
+
|
|
28
|
+
From `docs/Completion.md`: env vars, external services, migrations, smoke tests, rollback procedure.
|
|
29
|
+
|
|
30
|
+
### Step 3: Gate Checks (per tier)
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
ALL TIERS:
|
|
34
|
+
✓ git status clean
|
|
35
|
+
✓ on main/master
|
|
36
|
+
✓ tests passing: npm test
|
|
37
|
+
✓ build succeeds: npm run build
|
|
38
|
+
✓ lint clean
|
|
39
|
+
|
|
40
|
+
STAGING + PROD:
|
|
41
|
+
✓ all .env.<tier> vars set
|
|
42
|
+
✓ external services reachable (DB, Redis)
|
|
43
|
+
✓ docker images tagged with current commit SHA
|
|
44
|
+
|
|
45
|
+
PROD ONLY:
|
|
46
|
+
✓ staging deploy was successful in last 24h
|
|
47
|
+
✓ no open critical issues
|
|
48
|
+
✓ on-call notified
|
|
49
|
+
✓ rollback plan reviewed
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If any gate fails → halt with specific remediation.
|
|
53
|
+
|
|
54
|
+
### Step 4: Execute Deployment
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
docker build -t <project>:<commit-sha> .
|
|
58
|
+
docker tag <project>:<commit-sha> <registry>/<project>:<tier>
|
|
59
|
+
docker push <registry>/<project>:<tier>
|
|
60
|
+
docker compose -f docker-compose.<tier>.yml up -d
|
|
61
|
+
<migration-command>
|
|
62
|
+
until curl -f https://<tier-host>/health; do sleep 2; done
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Step 5: Smoke Tests
|
|
66
|
+
|
|
67
|
+
Run smoke test suite from `docs/Completion.md`.
|
|
68
|
+
|
|
69
|
+
### Step 6: Confirmation (prod only)
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
🚨 PROD DEPLOYMENT — confirm
|
|
73
|
+
Tag: <commit-sha>
|
|
74
|
+
Migrations: <list>
|
|
75
|
+
Downtime: <duration>
|
|
76
|
+
Rollback: <procedure>
|
|
77
|
+
Type 'yes' to proceed.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 7: Deploy + Monitor (5-15 min)
|
|
81
|
+
|
|
82
|
+
For prod: progressive rollout (canary → full) if infra supports.
|
|
83
|
+
Monitor: error rate, p95/p99 latency, health endpoint.
|
|
84
|
+
|
|
85
|
+
### Step 8: Report
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
✅ Deploy complete
|
|
89
|
+
Tier: <tier>, Commit: <sha>
|
|
90
|
+
Migrations: <N>, Smoke: <pass/fail>, Health: <status>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Rollback
|
|
94
|
+
|
|
95
|
+
`/deploy <tier> --rollback`: re-deploy previous successful tag, run reverse migrations from Completion.md.
|
|
96
|
+
|
|
97
|
+
## Related
|
|
98
|
+
|
|
99
|
+
- `docs/Completion.md` — pre-deploy checklist source
|
|
100
|
+
- `.claude/rules/git-workflow.md` — branch + commit discipline
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate bilingual project documentation (Russian + English). Creates `README/ru/` and `README/eng/` with admin guide, user guide, API docs, and quick start. Modes: default (both languages), `eng`/`ru` (single), `update` (refresh existing).
|
|
3
|
+
argument-hint: '[eng | ru | update]'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /docs $ARGUMENTS
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Generate user-facing and admin-facing documentation from project artifacts.
|
|
11
|
+
Bilingual by default (Russian + English).
|
|
12
|
+
|
|
13
|
+
## Modes
|
|
14
|
+
|
|
15
|
+
| `$ARGUMENTS` | Languages | Mode |
|
|
16
|
+
|--------------|-----------|------|
|
|
17
|
+
| (empty) | RU + EN | Create or replace |
|
|
18
|
+
| `ru` | RU only | Create or replace |
|
|
19
|
+
| `eng` | EN only | Create or replace |
|
|
20
|
+
| `update` | Existing | Update only changed sections |
|
|
21
|
+
|
|
22
|
+
## Process
|
|
23
|
+
|
|
24
|
+
### Step 1: Gather Context
|
|
25
|
+
|
|
26
|
+
Read these sources:
|
|
27
|
+
|
|
28
|
+
| Source | Used for |
|
|
29
|
+
|--------|----------|
|
|
30
|
+
| `docs/PRD.md` | Product overview, user personas |
|
|
31
|
+
| `docs/Architecture.md` | System design, deployment |
|
|
32
|
+
| `docs/Specification.md` | Feature list, API surface |
|
|
33
|
+
| `CLAUDE.md` | Project context |
|
|
34
|
+
| `.claude/insights/index.md` | Known gotchas, FAQs |
|
|
35
|
+
| Source code | API signatures (top-level routes) |
|
|
36
|
+
| `package.json` | Tech stack, scripts, dependencies |
|
|
37
|
+
|
|
38
|
+
### Step 2: Generate Per-Language Files
|
|
39
|
+
|
|
40
|
+
For each target language, write into `README/<lang>/`:
|
|
41
|
+
|
|
42
|
+
| File | Content |
|
|
43
|
+
|------|---------|
|
|
44
|
+
| `01_quickstart.md` | Install + run in 5 commands |
|
|
45
|
+
| `02_user_guide.md` | End-user workflows |
|
|
46
|
+
| `03_admin_guide.md` | Deployment, monitoring, backup, secrets |
|
|
47
|
+
| `04_api_reference.md` | API endpoints with examples |
|
|
48
|
+
| `05_architecture.md` | High-level architecture (auto from Architecture.md) |
|
|
49
|
+
| `06_troubleshooting.md` | From insights |
|
|
50
|
+
| `07_changelog.md` | From git log |
|
|
51
|
+
| `README.md` | TOC linking to the above |
|
|
52
|
+
|
|
53
|
+
### Step 3: Cross-Language Consistency
|
|
54
|
+
|
|
55
|
+
Ensure RU + EN cover identical sections (same numbering, same TOC).
|
|
56
|
+
|
|
57
|
+
### Step 4: Generate Top-Level Index
|
|
58
|
+
|
|
59
|
+
Update root `README.md`:
|
|
60
|
+
```markdown
|
|
61
|
+
## Documentation
|
|
62
|
+
- 🇷🇺 [Документация на русском](./README/ru/README.md)
|
|
63
|
+
- 🇬🇧 [English documentation](./README/eng/README.md)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Step 5: Validate + Commit
|
|
67
|
+
|
|
68
|
+
- All internal links resolve
|
|
69
|
+
- All code blocks have language tags
|
|
70
|
+
- Commit: `docs: generate bilingual documentation (RU + EN)`
|
|
71
|
+
|
|
72
|
+
## Update Mode
|
|
73
|
+
|
|
74
|
+
`/docs update` only regenerates files where source has changed since last run.
|
|
75
|
+
|
|
76
|
+
## Related
|
|
77
|
+
|
|
78
|
+
- `/harvest` — extract reusable patterns (different goal)
|
|
79
|
+
- `/myinsights` — fed into troubleshooting section
|