@dzhechkov/p-replicator 1.0.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 (92) hide show
  1. package/README.md +314 -0
  2. package/bin/cli.js +4 -0
  3. package/package.json +62 -0
  4. package/src/cli.js +160 -0
  5. package/src/commands/doctor.js +151 -0
  6. package/src/commands/init.js +155 -0
  7. package/src/commands/list.js +133 -0
  8. package/src/commands/remove.js +111 -0
  9. package/src/commands/update.js +102 -0
  10. package/src/utils.js +280 -0
  11. package/templates/.claude/agents/doc-validator.md +92 -0
  12. package/templates/.claude/agents/harvest-coordinator.md +91 -0
  13. package/templates/.claude/agents/product-discoverer.md +57 -0
  14. package/templates/.claude/agents/replicate-coordinator.md +98 -0
  15. package/templates/.claude/commands/harvest.md +106 -0
  16. package/templates/.claude/commands/replicate.md +389 -0
  17. package/templates/.claude/rules/replicate-pipeline.md +92 -0
  18. package/templates/.claude/skills/brutal-honesty-review/README.md +218 -0
  19. package/templates/.claude/skills/brutal-honesty-review/SKILL.md +225 -0
  20. package/templates/.claude/skills/brutal-honesty-review/resources/assessment-rubrics.md +295 -0
  21. package/templates/.claude/skills/brutal-honesty-review/resources/review-template.md +102 -0
  22. package/templates/.claude/skills/brutal-honesty-review/scripts/assess-code.sh +179 -0
  23. package/templates/.claude/skills/brutal-honesty-review/scripts/assess-tests.sh +223 -0
  24. package/templates/.claude/skills/cc-toolkit-generator-enhanced/SKILL.md +374 -0
  25. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/claude-md-strategy.md +178 -0
  26. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/enhanced-recommendations.md +416 -0
  27. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/extended-mapping.md +370 -0
  28. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/automation-commands.md +733 -0
  29. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-agents.md +416 -0
  30. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-hooks-commands.md +524 -0
  31. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-skills.md +350 -0
  32. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/enhanced-claude-md.md +235 -0
  33. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle-ent.md +400 -0
  34. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle.md +325 -0
  35. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-suggestions.md +423 -0
  36. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/insights-system.md +349 -0
  37. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/mcp.md +274 -0
  38. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/start-command.md +283 -0
  39. package/templates/.claude/skills/explore/SKILL.md +215 -0
  40. package/templates/.claude/skills/explore/references/questioning-techniques.md +151 -0
  41. package/templates/.claude/skills/explore/references/task-brief-templates.md +355 -0
  42. package/templates/.claude/skills/goap-research-ed25519/SKILL.md +415 -0
  43. package/templates/.claude/skills/goap-research-ed25519/references/ed25519-verification.md +658 -0
  44. package/templates/.claude/skills/goap-research-ed25519/references/research-actions.md +544 -0
  45. package/templates/.claude/skills/goap-research-ed25519/references/source-evaluation.md +560 -0
  46. package/templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py +662 -0
  47. package/templates/.claude/skills/goap-research-ed25519/scripts/goap_planner.py +720 -0
  48. package/templates/.claude/skills/knowledge-extractor/SKILL.md +412 -0
  49. package/templates/.claude/skills/knowledge-extractor/examples/rate-limiting-extraction.md +259 -0
  50. package/templates/.claude/skills/knowledge-extractor/modules/01-agent-review.md +192 -0
  51. package/templates/.claude/skills/knowledge-extractor/modules/02-classify.md +122 -0
  52. package/templates/.claude/skills/knowledge-extractor/modules/03-decontextualize.md +156 -0
  53. package/templates/.claude/skills/knowledge-extractor/modules/04-integrate.md +178 -0
  54. package/templates/.claude/skills/knowledge-extractor/references/artifact-categories.md +342 -0
  55. package/templates/.claude/skills/knowledge-extractor/references/decontextualization-guide.md +247 -0
  56. package/templates/.claude/skills/knowledge-extractor/references/maturity-model.md +153 -0
  57. package/templates/.claude/skills/knowledge-extractor/templates/artifact-card.md +60 -0
  58. package/templates/.claude/skills/knowledge-extractor/templates/harvest-report.md +70 -0
  59. package/templates/.claude/skills/knowledge-extractor/templates/toolkit-harvest.md +38 -0
  60. package/templates/.claude/skills/pipeline-forge/SKILL.md +523 -0
  61. package/templates/.claude/skills/pipeline-forge/examples/replicate-analysis.md +291 -0
  62. package/templates/.claude/skills/pipeline-forge/references/patterns-catalog.md +408 -0
  63. package/templates/.claude/skills/pipeline-forge/references/quality-gates.md +268 -0
  64. package/templates/.claude/skills/pipeline-forge/references/skill-anatomy.md +292 -0
  65. package/templates/.claude/skills/pipeline-forge/templates/agent-template.md +60 -0
  66. package/templates/.claude/skills/pipeline-forge/templates/command-template.md +80 -0
  67. package/templates/.claude/skills/pipeline-forge/templates/pipeline-template.md +137 -0
  68. package/templates/.claude/skills/pipeline-forge/templates/skill-template.md +132 -0
  69. package/templates/.claude/skills/problem-solver-enhanced/SKILL.md +562 -0
  70. package/templates/.claude/skills/requirements-validator/SKILL.md +121 -0
  71. package/templates/.claude/skills/requirements-validator/assets/templates/bdd-feature-template.feature +69 -0
  72. package/templates/.claude/skills/requirements-validator/references/bdd-patterns.md +184 -0
  73. package/templates/.claude/skills/requirements-validator/references/invest-criteria.md +121 -0
  74. package/templates/.claude/skills/requirements-validator/references/scoring-system.md +134 -0
  75. package/templates/.claude/skills/requirements-validator/references/smart-criteria.md +130 -0
  76. package/templates/.claude/skills/reverse-engineering-unicorn/SKILL.md +194 -0
  77. package/templates/.claude/skills/reverse-engineering-unicorn/examples/noom-cjm-example.md +100 -0
  78. package/templates/.claude/skills/reverse-engineering-unicorn/examples/noom-module1-example.md +88 -0
  79. package/templates/.claude/skills/reverse-engineering-unicorn/modules/01-intelligence.md +328 -0
  80. package/templates/.claude/skills/reverse-engineering-unicorn/modules/02-product-customers.md +221 -0
  81. package/templates/.claude/skills/reverse-engineering-unicorn/modules/025-cjm-prototype.md +206 -0
  82. package/templates/.claude/skills/reverse-engineering-unicorn/modules/03-market-competition.md +402 -0
  83. package/templates/.claude/skills/reverse-engineering-unicorn/modules/04-business-finance.md +287 -0
  84. package/templates/.claude/skills/reverse-engineering-unicorn/modules/05-growth-engine.md +290 -0
  85. package/templates/.claude/skills/reverse-engineering-unicorn/modules/06-playbook-synthesis.md +286 -0
  86. package/templates/.claude/skills/reverse-engineering-unicorn/references/blue-ocean-canvas.md +39 -0
  87. package/templates/.claude/skills/reverse-engineering-unicorn/references/industry-benchmarks.md +67 -0
  88. package/templates/.claude/skills/reverse-engineering-unicorn/references/jtbd-canvas.md +48 -0
  89. package/templates/.claude/skills/sparc-prd-mini/SKILL.md +955 -0
  90. package/templates/.claude/skills/sparc-prd-mini/references/sparc-methodology.md +360 -0
  91. package/templates/.claude/skills/sparc-prd-mini/templates/CLAUDE.md +91 -0
  92. package/templates/.claude/skills/sparc-prd-mini/templates/prd.md +336 -0
@@ -0,0 +1,155 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const {
6
+ green, cyan, bold, dim,
7
+ info, success, warn, error: logError, step,
8
+ copyDirRecursive, fileExists, readJSON,
9
+ createManifest, writeManifest, getTemplatesDir, getRelativePaths,
10
+ COMPONENTS, MANIFEST_FILE,
11
+ } = require('../utils');
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Keysarium integration detection
15
+ // ---------------------------------------------------------------------------
16
+
17
+ const KEYSARIUM_MANIFEST = '.keysarium.json';
18
+
19
+ function detectKeysarium(targetDir) {
20
+ const manifestPath = path.join(targetDir, KEYSARIUM_MANIFEST);
21
+ if (!fileExists(manifestPath)) return null;
22
+ return readJSON(manifestPath);
23
+ }
24
+
25
+ function showKeysariumIntegration(keysariumManifest) {
26
+ console.log('');
27
+ console.log(cyan(' \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510'));
28
+ console.log(cyan(' \u2502') + bold(' @dzhechkov/keysarium detected!') + ' ' + cyan('\u2502'));
29
+ console.log(cyan(' \u2502') + ` Version: ${dim(keysariumManifest.version)}` + ' '.repeat(39 - keysariumManifest.version.length) + cyan('\u2502'));
30
+ console.log(cyan(' \u2502') + ' PU skills will integrate with Keysarium setup. ' + cyan('\u2502'));
31
+ console.log(cyan(' \u2502') + ' Shared directories: .claude/commands, rules, agents ' + cyan('\u2502'));
32
+ console.log(cyan(' \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518'));
33
+ console.log('');
34
+ }
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Helpers
38
+ // ---------------------------------------------------------------------------
39
+
40
+ function installComponent(key, comp, templatesDir, targetDir) {
41
+ const src = path.join(templatesDir, comp.src);
42
+ const dest = path.join(targetDir, comp.src);
43
+
44
+ if (!fileExists(src)) {
45
+ warn(`Template source not found: ${comp.src} \u2014 skipping.`);
46
+ return [];
47
+ }
48
+
49
+ copyDirRecursive(src, dest);
50
+ return getRelativePaths(dest).map((rel) => path.join(comp.src, rel));
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Main command
55
+ // ---------------------------------------------------------------------------
56
+
57
+ function run(options) {
58
+ const { force, dryRun, targetDir } = options;
59
+ const manifestPath = path.join(targetDir, MANIFEST_FILE);
60
+
61
+ // ── a) Check for existing installation ──────────────────────────────────
62
+ if (fileExists(manifestPath)) {
63
+ if (!force) {
64
+ warn('P-Replicator is already installed in this directory.');
65
+ info(`Run ${cyan('npx @dzhechkov/p-replicator update')} to update, or use ${bold('--force')} to overwrite.`);
66
+ process.exit(1);
67
+ }
68
+ warn('Existing installation found \u2014 overwriting (--force).');
69
+ }
70
+
71
+ // ── b) Detect keysarium integration ─────────────────────────────────────
72
+ const keysariumManifest = detectKeysarium(targetDir);
73
+ if (keysariumManifest) {
74
+ showKeysariumIntegration(keysariumManifest);
75
+ }
76
+
77
+ // ── c) Show plan ────────────────────────────────────────────────────────
78
+ const componentKeys = Object.keys(COMPONENTS);
79
+ const templatesDir = getTemplatesDir();
80
+
81
+ console.log('');
82
+ info(bold('Installation plan:'));
83
+ console.log('');
84
+
85
+ for (const key of componentKeys) {
86
+ const comp = COMPONENTS[key];
87
+ console.log(` ${green('+')} ${comp.label}`);
88
+ }
89
+
90
+ console.log('');
91
+
92
+ if (dryRun) {
93
+ warn('Dry run \u2014 no files were written.');
94
+ process.exit(0);
95
+ }
96
+
97
+ // ── d) Install components ───────────────────────────────────────────────
98
+ const totalComponents = componentKeys.length;
99
+ const installedFiles = [];
100
+
101
+ for (let i = 0; i < totalComponents; i++) {
102
+ const key = componentKeys[i];
103
+ const comp = COMPONENTS[key];
104
+ step(i + 1, totalComponents, `Installing ${comp.label}...`);
105
+
106
+ const files = installComponent(key, comp, templatesDir, targetDir);
107
+ installedFiles.push(...files);
108
+ }
109
+
110
+ // ── e) Write manifest ──────────────────────────────────────────────────
111
+ const pkgPath = path.resolve(__dirname, '../../package.json');
112
+ const pkg = readJSON(pkgPath);
113
+ const version = pkg ? pkg.version : '0.0.0';
114
+
115
+ const manifest = createManifest(version, componentKeys, installedFiles.sort());
116
+ writeManifest(targetDir, manifest);
117
+ info(`Created ${MANIFEST_FILE} manifest`);
118
+
119
+ // ── f) Success summary ─────────────────────────────────────────────────
120
+ console.log('');
121
+ success(bold('P-Replicator installed!'));
122
+ console.log('');
123
+
124
+ console.log(bold('Installed components:'));
125
+ for (const key of componentKeys) {
126
+ const comp = COMPONENTS[key];
127
+ console.log(` ${green('\u2713')} ${comp.label}`);
128
+ }
129
+
130
+ console.log('');
131
+ console.log(` ${dim('Total files:')} ${installedFiles.length}`);
132
+ console.log('');
133
+
134
+ console.log(bold('Next steps:'));
135
+ console.log(` 1. Open ${cyan('Claude Code')} in this directory`);
136
+ console.log(` 2. Run ${cyan('/replicate "Your product idea"')} for the full pipeline`);
137
+ console.log(` 3. Follow 4-5 phases with interactive checkpoints`);
138
+ console.log('');
139
+ console.log(bold('Available commands after /replicate:'));
140
+ console.log(` ${cyan('/replicate')} ${dim('\u2014 Full pipeline: idea \u2192 validated docs \u2192 toolkit')}`);
141
+ console.log(` ${cyan('/harvest')} ${dim('\u2014 Extract reusable knowledge from projects')}`);
142
+ console.log('');
143
+
144
+ if (keysariumManifest) {
145
+ console.log(bold('Integration:'));
146
+ console.log(' PU commands are available alongside your Keysarium pipeline.');
147
+ console.log(` Run ${cyan('npx @dzhechkov/keysarium list')} to see all components.`);
148
+ console.log('');
149
+ }
150
+
151
+ process.exit(0);
152
+ }
153
+
154
+ module.exports = run;
155
+ module.exports.run = run;
@@ -0,0 +1,133 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const {
6
+ green, cyan, bold, dim, yellow,
7
+ info, warn,
8
+ readManifest, fileExists,
9
+ MANIFEST_FILE,
10
+ } = require('../utils');
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Skill details for rich listing
14
+ // ---------------------------------------------------------------------------
15
+
16
+ const SKILL_DETAILS = {
17
+ 'explore': 'Socratic task clarification',
18
+ 'sparc-prd-mini': 'SPARC documentation generator (11 docs)',
19
+ 'goap-research-ed25519': 'Verified research with Ed25519 anti-hallucination',
20
+ 'problem-solver-enhanced': 'First principles + TRIZ (9 modules)',
21
+ 'requirements-validator': 'INVEST/SMART validation + BDD scenarios',
22
+ 'brutal-honesty-review': 'Unvarnished technical criticism',
23
+ 'cc-toolkit-generator-enhanced': 'Claude Code toolkit generator',
24
+ 'reverse-engineering-unicorn': 'Company reverse engineering + playbook',
25
+ 'pipeline-forge': 'Meta-skill: build AI pipelines from patterns',
26
+ 'knowledge-extractor': 'Extract reusable knowledge from projects',
27
+ };
28
+
29
+ const COMMAND_DETAILS = {
30
+ 'replicate': 'Full pipeline: idea \u2192 validated docs \u2192 toolkit',
31
+ 'harvest': 'Knowledge extraction from projects',
32
+ };
33
+
34
+ const AGENT_DETAILS = {
35
+ 'replicate-coordinator': 'Pipeline orchestration (Phases 0-4)',
36
+ 'product-discoverer': 'Market research (Phase 0)',
37
+ 'doc-validator': 'Documentation validation swarm (Phase 2)',
38
+ 'harvest-coordinator': 'Knowledge extraction swarm',
39
+ };
40
+
41
+ function run(options) {
42
+ const { targetDir } = options;
43
+
44
+ const manifest = readManifest(targetDir);
45
+ if (!manifest) {
46
+ warn('P-Replicator is not installed in this directory.');
47
+ info(`Run ${cyan('npx @dzhechkov/p-replicator init')} to install.`);
48
+ process.exit(1);
49
+ }
50
+
51
+ console.log(bold('P-Replicator') + dim(` v${manifest.version}`));
52
+ console.log(dim(`Installed: ${manifest.installedAt}`));
53
+ console.log('');
54
+
55
+ // ── Skills ──────────────────────────────────────────────────────────────
56
+ const skillsDir = path.join(targetDir, '.claude', 'skills');
57
+ console.log(bold('Skills:'));
58
+ if (fileExists(skillsDir)) {
59
+ const skills = fs.readdirSync(skillsDir).filter((d) => {
60
+ return fs.statSync(path.join(skillsDir, d)).isDirectory();
61
+ });
62
+ for (const skill of skills.sort()) {
63
+ const desc = SKILL_DETAILS[skill] || '';
64
+ const hasSkillMd = fileExists(path.join(skillsDir, skill, 'SKILL.md'));
65
+ const status = hasSkillMd ? green('\u2713') : yellow('?');
66
+ console.log(` ${status} ${skill}` + (desc ? dim(` \u2014 ${desc}`) : ''));
67
+ }
68
+ console.log(dim(` Total: ${skills.length} skills`));
69
+ } else {
70
+ console.log(dim(' No skills directory found.'));
71
+ }
72
+ console.log('');
73
+
74
+ // ── Commands ────────────────────────────────────────────────────────────
75
+ const commandsDir = path.join(targetDir, '.claude', 'commands');
76
+ console.log(bold('Commands:'));
77
+ if (fileExists(commandsDir)) {
78
+ const commands = fs.readdirSync(commandsDir)
79
+ .filter((f) => f.endsWith('.md'))
80
+ .map((f) => f.replace('.md', ''));
81
+ for (const cmd of commands.sort()) {
82
+ const desc = COMMAND_DETAILS[cmd] || '';
83
+ console.log(` ${green('\u2713')} /${cmd}` + (desc ? dim(` \u2014 ${desc}`) : ''));
84
+ }
85
+ console.log(dim(` Total: ${commands.length} commands`));
86
+ } else {
87
+ console.log(dim(' No commands directory found.'));
88
+ }
89
+ console.log('');
90
+
91
+ // ── Agents ──────────────────────────────────────────────────────────────
92
+ const agentsDir = path.join(targetDir, '.claude', 'agents');
93
+ console.log(bold('Agents:'));
94
+ if (fileExists(agentsDir)) {
95
+ const agents = fs.readdirSync(agentsDir)
96
+ .filter((f) => f.endsWith('.md'))
97
+ .map((f) => f.replace('.md', ''));
98
+ for (const agent of agents.sort()) {
99
+ const desc = AGENT_DETAILS[agent] || '';
100
+ console.log(` ${green('\u2713')} ${agent}` + (desc ? dim(` \u2014 ${desc}`) : ''));
101
+ }
102
+ console.log(dim(` Total: ${agents.length} agents`));
103
+ } else {
104
+ console.log(dim(' No agents directory found.'));
105
+ }
106
+ console.log('');
107
+
108
+ // ── Rules ───────────────────────────────────────────────────────────────
109
+ const rulesDir = path.join(targetDir, '.claude', 'rules');
110
+ console.log(bold('Rules:'));
111
+ if (fileExists(rulesDir)) {
112
+ const rules = fs.readdirSync(rulesDir)
113
+ .filter((f) => f.endsWith('.md'))
114
+ .map((f) => f.replace('.md', ''));
115
+ for (const rule of rules.sort()) {
116
+ console.log(` ${green('\u2713')} ${rule}`);
117
+ }
118
+ console.log(dim(` Total: ${rules.length} rules`));
119
+ } else {
120
+ console.log(dim(' No rules directory found.'));
121
+ }
122
+ console.log('');
123
+
124
+ // ── File count ──────────────────────────────────────────────────────────
125
+ const totalFiles = (manifest.files || []).length;
126
+ console.log(dim(`Total tracked files: ${totalFiles}`));
127
+ console.log('');
128
+
129
+ process.exit(0);
130
+ }
131
+
132
+ module.exports = run;
133
+ module.exports.run = run;
@@ -0,0 +1,111 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const {
6
+ green, red, cyan, bold, dim,
7
+ info, success, warn, error: logError,
8
+ readManifest, fileExists,
9
+ MANIFEST_FILE,
10
+ } = require('../utils');
11
+
12
+ function run(options) {
13
+ const { force, dryRun, targetDir } = options;
14
+
15
+ // ── a) Check for existing installation ──────────────────────────────────
16
+ const manifest = readManifest(targetDir);
17
+ if (!manifest) {
18
+ logError('P-Replicator is not installed in this directory.');
19
+ info('Nothing to remove.');
20
+ process.exit(1);
21
+ }
22
+
23
+ info(`Found installation v${bold(manifest.version)} (${manifest.installedAt})`);
24
+ console.log('');
25
+
26
+ // ── b) List files to remove ─────────────────────────────────────────────
27
+ const files = manifest.files || [];
28
+ const existingFiles = files.filter((f) => fileExists(path.join(targetDir, f)));
29
+
30
+ console.log(bold('Files to remove:'));
31
+ for (const f of existingFiles) {
32
+ console.log(` ${red('\u2717')} ${f}`);
33
+ }
34
+ console.log('');
35
+ console.log(` ${dim('Total:')} ${existingFiles.length} files`);
36
+ console.log('');
37
+
38
+ if (existingFiles.length === 0) {
39
+ warn('No files found to remove (already cleaned up?).');
40
+ // Still remove manifest
41
+ const manifestPath = path.join(targetDir, MANIFEST_FILE);
42
+ if (fileExists(manifestPath)) {
43
+ fs.unlinkSync(manifestPath);
44
+ info(`Removed ${MANIFEST_FILE}`);
45
+ }
46
+ process.exit(0);
47
+ }
48
+
49
+ if (dryRun) {
50
+ warn('Dry run \u2014 no files were removed.');
51
+ process.exit(0);
52
+ }
53
+
54
+ // ── c) Remove files ────────────────────────────────────────────────────
55
+ let removed = 0;
56
+ for (const f of existingFiles) {
57
+ const fullPath = path.join(targetDir, f);
58
+ try {
59
+ fs.unlinkSync(fullPath);
60
+ removed++;
61
+ } catch (err) {
62
+ warn(`Could not remove: ${f} (${err.message})`);
63
+ }
64
+ }
65
+
66
+ // ── d) Clean up empty directories ──────────────────────────────────────
67
+ const dirs = new Set();
68
+ for (const f of existingFiles) {
69
+ let dir = path.dirname(f);
70
+ while (dir && dir !== '.') {
71
+ dirs.add(dir);
72
+ dir = path.dirname(dir);
73
+ }
74
+ }
75
+
76
+ // Sort deepest first for safe removal
77
+ const sortedDirs = [...dirs].sort((a, b) => b.split(path.sep).length - a.split(path.sep).length);
78
+ for (const dir of sortedDirs) {
79
+ const fullDir = path.join(targetDir, dir);
80
+ try {
81
+ const entries = fs.readdirSync(fullDir);
82
+ if (entries.length === 0) {
83
+ fs.rmdirSync(fullDir);
84
+ }
85
+ } catch {
86
+ // Directory doesn't exist or not empty — skip
87
+ }
88
+ }
89
+
90
+ // ── e) Remove manifest ─────────────────────────────────────────────────
91
+ const manifestPath = path.join(targetDir, MANIFEST_FILE);
92
+ if (fileExists(manifestPath)) {
93
+ fs.unlinkSync(manifestPath);
94
+ }
95
+
96
+ console.log('');
97
+ success(`Removed ${removed} files.`);
98
+ console.log('');
99
+ console.log(bold('Note:'));
100
+ console.log(' Project-specific files were NOT removed:');
101
+ console.log(` ${dim('\u2022')} docs/ (SPARC documentation)`);
102
+ console.log(` ${dim('\u2022')} CLAUDE.md, DEVELOPMENT_GUIDE.md`);
103
+ console.log(` ${dim('\u2022')} Generated commands (/start, /feature, /plan, etc.)`);
104
+ console.log(` ${dim('\u2022')} docker-compose.yml, Dockerfile`);
105
+ console.log('');
106
+
107
+ process.exit(0);
108
+ }
109
+
110
+ module.exports = run;
111
+ module.exports.run = run;
@@ -0,0 +1,102 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const {
5
+ green, yellow, cyan, bold, dim,
6
+ info, success, warn, error: logError, step,
7
+ copyDirRecursive, fileExists, readJSON,
8
+ diffFiles, getRelativePaths,
9
+ readManifest, writeManifest, createManifest, getTemplatesDir,
10
+ COMPONENTS, MANIFEST_FILE,
11
+ } = require('../utils');
12
+
13
+ function run(options) {
14
+ const { force, dryRun, targetDir } = options;
15
+
16
+ // ── a) Check for existing installation ──────────────────────────────────
17
+ const manifest = readManifest(targetDir);
18
+ if (!manifest) {
19
+ logError('P-Replicator is not installed in this directory.');
20
+ info(`Run ${cyan('npx @dzhechkov/p-replicator init')} first.`);
21
+ process.exit(1);
22
+ }
23
+
24
+ const pkgPath = path.resolve(__dirname, '../../package.json');
25
+ const pkg = readJSON(pkgPath);
26
+ const newVersion = pkg ? pkg.version : '0.0.0';
27
+
28
+ info(`Installed version: ${bold(manifest.version)}`);
29
+ info(`Package version: ${bold(newVersion)}`);
30
+ console.log('');
31
+
32
+ // ── b) Diff files ───────────────────────────────────────────────────────
33
+ const templatesDir = getTemplatesDir();
34
+ const templateClaude = path.join(templatesDir, '.claude');
35
+ const projectClaude = path.join(targetDir, '.claude');
36
+
37
+ if (!fileExists(templateClaude)) {
38
+ logError('Template .claude/ directory not found in package.');
39
+ process.exit(1);
40
+ }
41
+
42
+ const { added, modified, unchanged } = diffFiles(templateClaude, projectClaude);
43
+
44
+ console.log(bold('Changes detected:'));
45
+ console.log(` ${green('+')} ${added.length} new files`);
46
+ console.log(` ${yellow('~')} ${modified.length} modified files`);
47
+ console.log(` ${dim('=')} ${unchanged.length} unchanged files`);
48
+ console.log('');
49
+
50
+ if (added.length === 0 && modified.length === 0) {
51
+ success('Already up to date!');
52
+ process.exit(0);
53
+ }
54
+
55
+ // ── c) Show details ────────────────────────────────────────────────────
56
+ if (added.length > 0) {
57
+ console.log(green('New files:'));
58
+ for (const f of added) {
59
+ console.log(` ${green('+')} .claude/${f}`);
60
+ }
61
+ console.log('');
62
+ }
63
+
64
+ if (modified.length > 0) {
65
+ console.log(yellow('Modified files:'));
66
+ for (const f of modified) {
67
+ console.log(` ${yellow('~')} .claude/${f}`);
68
+ }
69
+ console.log('');
70
+ }
71
+
72
+ if (dryRun) {
73
+ warn('Dry run \u2014 no files were written.');
74
+ process.exit(0);
75
+ }
76
+
77
+ // ── d) Apply updates ───────────────────────────────────────────────────
78
+ const filesToUpdate = [...added, ...modified];
79
+ let updated = 0;
80
+
81
+ for (const rel of filesToUpdate) {
82
+ const src = path.join(templateClaude, rel);
83
+ const dest = path.join(projectClaude, rel);
84
+ copyDirRecursive(src, dest);
85
+ updated++;
86
+ }
87
+
88
+ // ── e) Update manifest ─────────────────────────────────────────────────
89
+ const allFiles = getRelativePaths(projectClaude).map((f) => '.claude/' + f);
90
+ const componentKeys = Object.keys(COMPONENTS);
91
+ const newManifest = createManifest(newVersion, componentKeys, allFiles.sort());
92
+ writeManifest(targetDir, newManifest);
93
+
94
+ console.log('');
95
+ success(`Updated ${updated} files to version ${bold(newVersion)}`);
96
+ console.log('');
97
+
98
+ process.exit(0);
99
+ }
100
+
101
+ module.exports = run;
102
+ module.exports.run = run;