@dzhechkov/p-replicator 1.3.0 → 1.5.3

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 (35) hide show
  1. package/README.md +1097 -160
  2. package/bin/cli.js +0 -0
  3. package/package.json +7 -2
  4. package/src/cli.js +23 -6
  5. package/src/commands/doctor.js +46 -29
  6. package/src/commands/init.js +61 -8
  7. package/src/commands/list.js +5 -26
  8. package/src/commands/update.js +73 -7
  9. package/src/commands/verify.js +111 -0
  10. package/src/utils.js +275 -4
  11. package/templates/.claude/commands/deploy.md +100 -0
  12. package/templates/.claude/commands/docs.md +79 -0
  13. package/templates/.claude/commands/feature.md +134 -0
  14. package/templates/.claude/commands/go.md +115 -0
  15. package/templates/.claude/commands/myinsights.md +72 -0
  16. package/templates/.claude/commands/next.md +110 -0
  17. package/templates/.claude/commands/plan.md +88 -0
  18. package/templates/.claude/commands/replicate.md +103 -17
  19. package/templates/.claude/commands/run.md +151 -0
  20. package/templates/.claude/commands/start.md +88 -0
  21. package/templates/.claude/hooks/autocommit-insights.cjs +39 -0
  22. package/templates/.claude/hooks/autocommit-plans.cjs +39 -0
  23. package/templates/.claude/hooks/autocommit-roadmap.cjs +44 -0
  24. package/templates/.claude/hooks/session-insights.cjs +28 -0
  25. package/templates/.claude/hooks/state-update.cjs +79 -0
  26. package/templates/.claude/hooks/statusline.cjs +399 -0
  27. package/templates/.claude/rules/feature-lifecycle.md +145 -0
  28. package/templates/.claude/rules/git-workflow.md +74 -0
  29. package/templates/.claude/rules/insights-capture.md +77 -0
  30. package/templates/.claude/rules/replicate-pipeline.md +92 -19
  31. package/templates/.claude/settings.json +44 -0
  32. package/templates/.claude/skills/brutal-honesty-review/scripts/assess-code.sh +0 -0
  33. package/templates/.claude/skills/brutal-honesty-review/scripts/assess-tests.sh +0 -0
  34. package/templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py +0 -0
  35. package/templates/.claude/skills/goap-research-ed25519/scripts/goap_planner.py +0 -0
@@ -0,0 +1,151 @@
1
+ ---
2
+ description: Autonomous build loop — picks next feature from roadmap, dispatches to /go, repeats until exhausted. Modes: `mvp` (default — only features tagged mvp), `all` (everything in `next` or `planned`). Auto-commits after each feature. Supports `--feature-branches` for per-feature git branches (teaching/demo workflow).
3
+ argument-hint: '[mvp | all] [--feature-branches] [--auto-merge]'
4
+ ---
5
+
6
+ # /run $ARGUMENTS
7
+
8
+ ## Purpose
9
+
10
+ One-command autonomous feature build. Reads `.claude/feature-roadmap.json`,
11
+ loops through features via `/next` → `/go`, marks them done, commits, and
12
+ continues until the scoped list is exhausted.
13
+
14
+ > **PROCESS COMPLIANCE — BLOCKING RULES:**
15
+ > - MUST delegate to `/next`, `/go`, `/plan`, `/feature` — NEVER spawn raw Agent tools directly
16
+ > - MUST commit after each feature (one feature = one commit cluster)
17
+ > - FORBIDDEN: bypassing /go's complexity routing
18
+ > - FORBIDDEN: batching multiple features in a single commit wave
19
+
20
+ ## Step 0: Parse Scope
21
+
22
+ | `$ARGUMENTS` | Filter applied to roadmap |
23
+ |--------------|---------------------------|
24
+ | `mvp` (default if empty) | Only features with `priority: "mvp"` and status in `next`/`planned` |
25
+ | `all` | All features with status in `next`/`planned` |
26
+
27
+ If `.claude/feature-roadmap.json` does not exist → halt with:
28
+ ```
29
+ Roadmap not found. Run /replicate first or create .claude/feature-roadmap.json manually.
30
+ ```
31
+
32
+ ## Step 1: Bootstrap Check
33
+
34
+ If `CLAUDE.md` exists but core scaffolding is missing (e.g., no `package.json`,
35
+ no `docker-compose.yml`), call `/start` once before the loop. Skip if
36
+ scaffolding already in place.
37
+
38
+ ## Step 2: Feature Loop
39
+
40
+ ```
41
+ while features_remaining_in_scope:
42
+ feature_id = /next # pick highest-priority next/planned
43
+ if not feature_id: break
44
+ /go feature_id # complexity router → /plan or /feature
45
+ verify completion (tests green, code committed)
46
+ mark roadmap entry: status = "done"
47
+ git commit -m "docs(roadmap): mark <id> as done"
48
+ git push origin HEAD
49
+ ```
50
+
51
+ Between iterations, briefly summarize progress: `Completed N of M features in scope`.
52
+
53
+ ## Step 3: Final Summary
54
+
55
+ When the loop terminates (scope exhausted or user interrupt):
56
+
57
+ ```
58
+ ═══════════════════════════════════════════════════════════════
59
+ ✅ /run complete — scope: <mvp|all>
60
+ Completed: <N> features
61
+ Total commits: <count>
62
+ Time elapsed: <duration>
63
+ Next: /docs to generate documentation, /harvest to extract knowledge
64
+ ═══════════════════════════════════════════════════════════════
65
+ ```
66
+
67
+ ## Error Recovery
68
+
69
+ If a single feature fails (test red, validation blocked), `/run`:
70
+ 1. Marks that feature as `blocked` with reason
71
+ 2. Continues to next feature in scope
72
+ 3. At the end, lists all blocked features for manual review
73
+
74
+ `/run` does NOT abort the whole loop on one feature failure — autonomous mode
75
+ is designed for unattended operation.
76
+
77
+ ## Flag: `--feature-branches` (v1.5.0)
78
+
79
+ Create a separate git branch per feature. Useful for **teaching/demo
80
+ workflows** where each feature must be a discrete unit the instructor can
81
+ checkout independently.
82
+
83
+ ### Branch naming format
84
+
85
+ ```
86
+ feature/{NNN}-{id}
87
+ ```
88
+ where `NNN` is a zero-padded 3-digit feature number from the roadmap, and
89
+ `{id}` is the feature's slug. Example: `feature/001-auth-jwt`.
90
+
91
+ ### Per-feature workflow with --feature-branches
92
+
93
+ ```
94
+ For each feature in scope:
95
+ 1. Verify on `main` branch (else fail with hint to switch)
96
+ 2. If working tree is dirty:
97
+ git stash push -u -m "auto-stash before /run feature-branches"
98
+ 3. Read roadmap entry; if feature has no `number`, assign max(numbers) + 1
99
+ and persist back to .claude/feature-roadmap.json
100
+ 4. git checkout -b feature/{NNN}-{id} # branched from main
101
+ 5. /go {feature-id} # delegate to standard pipeline
102
+ 6. git push origin feature/{NNN}-{id} --set-upstream
103
+ 7. Mark roadmap entry: status=done, branch="feature/{NNN}-{id}"
104
+ 8. git checkout main # ready for next iteration
105
+ 9. If --auto-merge ALSO passed:
106
+ git merge --no-ff feature/{NNN}-{id} -m "merge: feature/{NNN}-{id}"
107
+ ```
108
+
109
+ ### Companion flag: `--auto-merge`
110
+
111
+ Off by default. When passed alongside `--feature-branches`, each feature
112
+ branch is merged into `main` (with `--no-ff`) immediately after completion.
113
+ Without `--auto-merge`, branches are pushed but **NOT** merged — instructor
114
+ or reviewer is expected to merge via PR or manually.
115
+
116
+ ### Roadmap schema extension (post v1.5.0)
117
+
118
+ ```json
119
+ {
120
+ "id": "auth-jwt",
121
+ "number": 1,
122
+ "branch": "feature/001-auth-jwt",
123
+ "name": "JWT-based authentication",
124
+ "priority": "mvp",
125
+ "status": "done",
126
+ ...
127
+ }
128
+ ```
129
+
130
+ `number` is auto-assigned on first encounter when `--feature-branches` is
131
+ used. `branch` is populated when the feature completes successfully.
132
+
133
+ ### Use cases
134
+
135
+ - **Teaching:** instructor checks out `feature/003-payment` to demo a specific
136
+ feature. All branches are pushed, easy to fetch and explore.
137
+ - **Code review:** each feature has standalone branch for PR-based review.
138
+ - **Experimentation:** abandon a branch cleanly without disturbing main.
139
+
140
+ ### Anti-patterns
141
+
142
+ - Running `--feature-branches` while on a feature branch (not main) → fails
143
+ - Mixing `--feature-branches` with non-branch features in the same session
144
+ → mark already-merged features explicitly with `branch: "main"` to avoid retry
145
+
146
+ ## Related
147
+
148
+ - `/next` — picks next feature (called per iteration)
149
+ - `/go` — complexity router (called per feature; also accepts `--feature-branches`)
150
+ - `/plan`, `/feature` — actual implementation pipelines
151
+ - `.claude/feature-roadmap.json` — source of truth for what to build
@@ -0,0 +1,88 @@
1
+ ---
2
+ description: Bootstrap project from SPARC documentation. Generates monorepo skeleton, packages, Docker configs, database schema, core modules, and basic tests in 4 phases (Foundation → Packages parallel → Integration → Finalize). Reads `docs/` as source of truth.
3
+ argument-hint: '[--skip-tests | --skip-seed | --dry-run]'
4
+ ---
5
+
6
+ # /start $ARGUMENTS
7
+
8
+ ## Purpose
9
+
10
+ One-command project generation from SPARC documentation → working monorepo
11
+ with `docker compose up`. Reads `docs/` (NOT memory), maximizes parallelism
12
+ via `Task` tool, commits per logical change for safe error recovery.
13
+
14
+ ## Prerequisites
15
+
16
+ - SPARC documents in `docs/` (output of `/replicate` Phase 1)
17
+ - `CLAUDE.md` at project root
18
+ - Docker + Docker Compose installed
19
+ - Git initialized
20
+
21
+ ## Phases
22
+
23
+ ### Phase 1: Foundation (sequential)
24
+
25
+ 1. **Read all SPARC docs** to build full context:
26
+ - `docs/Architecture.md` → monorepo structure, Docker Compose, tech stack
27
+ - `docs/Specification.md` → data model, API endpoints, NFRs
28
+ - `docs/Pseudocode.md` → core algorithms
29
+ - `docs/Completion.md` → env config, deployment
30
+ - `docs/PRD.md` → features (for README)
31
+ - `docs/Refinement.md` → edge cases, testing strategy
32
+
33
+ 2. **Generate root configs:** `package.json` (monorepo workspaces),
34
+ `docker-compose.yml`, `.env.example`, `.gitignore`, `tsconfig.base.json`.
35
+
36
+ 3. **Git commit:** `chore: project root configuration`
37
+
38
+ ### Phase 2: Packages (PARALLEL via Task tool ⚡)
39
+
40
+ For EACH package in Architecture.md, spawn an independent Task referencing
41
+ SOURCE DOCS (not memory):
42
+
43
+ ```
44
+ ### Task <X>: packages/<name> ⚡
45
+ Read and use as source:
46
+ - docs/Specification.md → data model → ORM schema
47
+ - docs/Architecture.md → API endpoints → routes
48
+ - docs/Pseudocode.md → algorithms → service layer
49
+
50
+ Generate: src/<files>, tests/<files>, package.json, README.md
51
+ Commits: one per logical group.
52
+ ```
53
+
54
+ ### Phase 3: Integration (sequential)
55
+
56
+ 1. Verify cross-package imports
57
+ 2. `docker compose build`
58
+ 3. `docker compose up -d`
59
+ 4. Database migration (if applicable): `npx prisma migrate dev` (or equivalent)
60
+ 5. Health check: `curl localhost:<port>/health`
61
+ 6. Run tests
62
+ 7. Git commit: `chore: verify docker integration`
63
+
64
+ ### Phase 4: Finalize
65
+
66
+ 1. Generate/update `README.md` with quick start
67
+ 2. `git tag v0.1.0-scaffold`
68
+ 3. Report summary
69
+
70
+ ## Flags
71
+
72
+ - `--skip-tests` — don't generate test files (NOT recommended)
73
+ - `--skip-seed` — skip DB seeding
74
+ - `--dry-run` — show plan without executing
75
+
76
+ ## Critical Rules
77
+
78
+ 1. **Docs as source of truth** — every file references specific docs, never memory
79
+ 2. **Maximize parallelism** — independent packages run as parallel Tasks
80
+ 3. **Atomic commits** — one commit per logical change
81
+ 4. **Full integration** — Phase 3 includes build + start + health check
82
+ 5. **Project-specific** — adapt all examples to actual tech stack
83
+
84
+ ## Related
85
+
86
+ - `/replicate` — generates the SPARC docs that `/start` reads
87
+ - `/run mvp` — builds features after scaffold is up
88
+ - `/feature <name>` — implement individual features
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Stop hook — auto-commits .claude/insights/ if anything changed.
6
+ * Cross-platform: pure Node + execFileSync, no shell.
7
+ */
8
+
9
+ const fs = require('node:fs');
10
+ const path = require('node:path');
11
+ const { execFileSync } = require('node:child_process');
12
+
13
+ const TARGET_DIR = path.resolve(process.cwd(), '.claude', 'insights');
14
+ const RELATIVE = path.relative(process.cwd(), TARGET_DIR);
15
+ const SILENT = { stdio: 'ignore' };
16
+
17
+ function git(args) {
18
+ return execFileSync('git', args, SILENT);
19
+ }
20
+
21
+ try {
22
+ if (!fs.existsSync(TARGET_DIR)) process.exit(0);
23
+ try { git(['rev-parse', '--git-dir']); } catch { process.exit(0); }
24
+
25
+ git(['add', '--', RELATIVE]);
26
+
27
+ let hasDiff = false;
28
+ try {
29
+ git(['diff', '--cached', '--quiet', '--', RELATIVE]);
30
+ } catch {
31
+ hasDiff = true;
32
+ }
33
+
34
+ if (hasDiff) {
35
+ git(['commit', '--only', '--', RELATIVE, '-m', 'docs(insights): auto-capture']);
36
+ }
37
+ } catch (_err) {
38
+ process.exit(0);
39
+ }
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Stop hook — auto-commits docs/plans/ if anything changed.
6
+ * Cross-platform: pure Node + execFileSync, no shell.
7
+ */
8
+
9
+ const fs = require('node:fs');
10
+ const path = require('node:path');
11
+ const { execFileSync } = require('node:child_process');
12
+
13
+ const TARGET_DIR = path.resolve(process.cwd(), 'docs', 'plans');
14
+ const RELATIVE = path.relative(process.cwd(), TARGET_DIR);
15
+ const SILENT = { stdio: 'ignore' };
16
+
17
+ function git(args) {
18
+ return execFileSync('git', args, SILENT);
19
+ }
20
+
21
+ try {
22
+ if (!fs.existsSync(TARGET_DIR)) process.exit(0);
23
+ try { git(['rev-parse', '--git-dir']); } catch { process.exit(0); }
24
+
25
+ git(['add', '--', RELATIVE]);
26
+
27
+ let hasDiff = false;
28
+ try {
29
+ git(['diff', '--cached', '--quiet', '--', RELATIVE]);
30
+ } catch {
31
+ hasDiff = true;
32
+ }
33
+
34
+ if (hasDiff) {
35
+ git(['commit', '--only', '--', RELATIVE, '-m', 'docs(plan): auto-save']);
36
+ }
37
+ } catch (_err) {
38
+ process.exit(0);
39
+ }
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Stop hook — auto-commits .claude/feature-roadmap.json if it changed.
6
+ * Cross-platform: uses execFileSync('git', [...]) so no shell quoting/redirect issues.
7
+ */
8
+
9
+ const fs = require('node:fs');
10
+ const path = require('node:path');
11
+ const { execFileSync } = require('node:child_process');
12
+
13
+ const TARGET = path.resolve(process.cwd(), '.claude', 'feature-roadmap.json');
14
+ const RELATIVE = path.relative(process.cwd(), TARGET);
15
+ const SILENT = { stdio: 'ignore' };
16
+
17
+ function git(args) {
18
+ return execFileSync('git', args, SILENT);
19
+ }
20
+
21
+ try {
22
+ // Skip if file doesn't exist or we're not in a git repo.
23
+ if (!fs.existsSync(TARGET)) process.exit(0);
24
+ try { git(['rev-parse', '--git-dir']); } catch { process.exit(0); }
25
+
26
+ // Stage only the target file.
27
+ git(['add', '--', RELATIVE]);
28
+
29
+ // Check whether anything is staged for THIS path.
30
+ // `git diff --cached --quiet -- <path>` exits 0 = no diff, 1 = diff exists.
31
+ let hasDiff = false;
32
+ try {
33
+ git(['diff', '--cached', '--quiet', '--', RELATIVE]);
34
+ } catch {
35
+ hasDiff = true;
36
+ }
37
+
38
+ if (hasDiff) {
39
+ git(['commit', '--only', '--', RELATIVE, '-m', 'docs(roadmap): auto-update']);
40
+ }
41
+ } catch (_err) {
42
+ // Best-effort — never break Claude session on commit failures.
43
+ process.exit(0);
44
+ }
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * SessionStart hook — injects up to 3 most recent insights from
6
+ * .claude/insights/index.md into Claude's initial session context (via stdout).
7
+ *
8
+ * Cross-platform: pure Node, no shell pipes. Silent on missing index.
9
+ */
10
+
11
+ const fs = require('node:fs');
12
+ const path = require('node:path');
13
+
14
+ const INDEX = path.resolve(process.cwd(), '.claude', 'insights', 'index.md');
15
+
16
+ try {
17
+ if (!fs.existsSync(INDEX)) process.exit(0);
18
+ const text = fs.readFileSync(INDEX, 'utf8');
19
+ // Each insight starts with "## " heading (per insights-capture.md convention).
20
+ const sections = text.split(/^## /m).filter(Boolean);
21
+ const recent = sections.slice(-3).map((s) => '## ' + s.trim()).join('\n\n');
22
+ if (recent.length > 0) {
23
+ process.stdout.write('## Recent project insights\n\n' + recent + '\n');
24
+ }
25
+ } catch (_err) {
26
+ // Hook is advisory — never block the session on errors here.
27
+ process.exit(0);
28
+ }
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * state-update.cjs (v1.5.0) — write `.claude/.p-replicator-state.json`.
6
+ *
7
+ * Used by pipeline commands (/run, /go, /feature, /replicate) to publish
8
+ * current command + phase + progress for the statusline to display.
9
+ *
10
+ * Usage:
11
+ * node .claude/hooks/state-update.cjs \
12
+ * --command /feature \
13
+ * --phase VALIDATE \
14
+ * --index 2 \
15
+ * --total 4 \
16
+ * --progress 0.5 \
17
+ * [--last-command /replicate] \
18
+ * [--last-feature auth-jwt]
19
+ *
20
+ * Or pass JSON in one arg:
21
+ * node .claude/hooks/state-update.cjs --json '{"currentCommand":"/run", ...}'
22
+ *
23
+ * Idempotent: overwrites the state file each call. Always exits 0 (best-effort).
24
+ */
25
+
26
+ const fs = require('node:fs');
27
+ const path = require('node:path');
28
+
29
+ const STATE_FILE = path.resolve(process.cwd(), '.claude', '.p-replicator-state.json');
30
+
31
+ function parseArgs(argv) {
32
+ const out = {};
33
+ for (let i = 2; i < argv.length; i++) {
34
+ const a = argv[i];
35
+ if (!a.startsWith('--')) continue;
36
+ const key = a.slice(2);
37
+ const next = argv[i + 1];
38
+ if (next && !next.startsWith('--')) {
39
+ out[key] = next;
40
+ i++;
41
+ } else {
42
+ out[key] = true;
43
+ }
44
+ }
45
+ return out;
46
+ }
47
+
48
+ function main() {
49
+ try {
50
+ const args = parseArgs(process.argv);
51
+
52
+ let state;
53
+ if (args.json) {
54
+ try { state = JSON.parse(args.json); }
55
+ catch { state = {}; }
56
+ } else {
57
+ state = {
58
+ currentCommand: args.command || null,
59
+ currentPhase: args.phase ? {
60
+ name: args.phase,
61
+ index: args.index ? parseInt(args.index, 10) : null,
62
+ total: args.total ? parseInt(args.total, 10) : null,
63
+ progress: args.progress ? parseFloat(args.progress) : null,
64
+ } : null,
65
+ lastCommand: args['last-command'] || null,
66
+ lastFeature: args['last-feature'] || null,
67
+ };
68
+ }
69
+
70
+ state.updatedAt = new Date().toISOString();
71
+
72
+ fs.mkdirSync(path.dirname(STATE_FILE), { recursive: true });
73
+ fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2) + '\n', 'utf8');
74
+ } catch (_err) {
75
+ // Best-effort. Never fail the calling pipeline on state-write issues.
76
+ }
77
+ }
78
+
79
+ main();