cclaw-cli 7.7.0 → 8.1.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.
- package/README.md +210 -134
- package/dist/artifact-frontmatter.d.ts +51 -0
- package/dist/artifact-frontmatter.js +131 -0
- package/dist/artifact-paths.d.ts +7 -27
- package/dist/artifact-paths.js +20 -249
- package/dist/cancel.d.ts +16 -0
- package/dist/cancel.js +66 -0
- package/dist/cli.d.ts +2 -27
- package/dist/cli.js +90 -508
- package/dist/compound.d.ts +26 -0
- package/dist/compound.js +96 -0
- package/dist/config.d.ts +14 -51
- package/dist/config.js +23 -359
- package/dist/constants.d.ts +11 -18
- package/dist/constants.js +19 -106
- package/dist/content/antipatterns.d.ts +1 -0
- package/dist/content/antipatterns.js +109 -0
- package/dist/content/artifact-templates.d.ts +10 -0
- package/dist/content/artifact-templates.js +550 -0
- package/dist/content/cancel-command.d.ts +2 -2
- package/dist/content/cancel-command.js +25 -17
- package/dist/content/core-agents.d.ts +9 -233
- package/dist/content/core-agents.js +39 -766
- package/dist/content/decision-protocol.d.ts +1 -12
- package/dist/content/decision-protocol.js +27 -20
- package/dist/content/examples.d.ts +8 -42
- package/dist/content/examples.js +293 -425
- package/dist/content/idea-command.d.ts +2 -0
- package/dist/content/idea-command.js +38 -0
- package/dist/content/iron-laws.d.ts +4 -138
- package/dist/content/iron-laws.js +18 -197
- package/dist/content/meta-skill.d.ts +1 -3
- package/dist/content/meta-skill.js +57 -132
- package/dist/content/node-hooks.d.ts +12 -8
- package/dist/content/node-hooks.js +188 -838
- package/dist/content/recovery.d.ts +8 -0
- package/dist/content/recovery.js +179 -0
- package/dist/content/reference-patterns.d.ts +4 -13
- package/dist/content/reference-patterns.js +260 -389
- package/dist/content/research-playbooks.d.ts +8 -8
- package/dist/content/research-playbooks.js +108 -121
- package/dist/content/review-loop.d.ts +6 -192
- package/dist/content/review-loop.js +29 -731
- package/dist/content/skills.d.ts +8 -38
- package/dist/content/skills.js +681 -732
- package/dist/content/specialist-prompts/architect.d.ts +1 -0
- package/dist/content/specialist-prompts/architect.js +225 -0
- package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
- package/dist/content/specialist-prompts/brainstormer.js +168 -0
- package/dist/content/specialist-prompts/index.d.ts +2 -0
- package/dist/content/specialist-prompts/index.js +14 -0
- package/dist/content/specialist-prompts/planner.d.ts +1 -0
- package/dist/content/specialist-prompts/planner.js +182 -0
- package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
- package/dist/content/specialist-prompts/reviewer.js +193 -0
- package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
- package/dist/content/specialist-prompts/security-reviewer.js +133 -0
- package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
- package/dist/content/specialist-prompts/slice-builder.js +232 -0
- package/dist/content/stage-playbooks.d.ts +8 -0
- package/dist/content/stage-playbooks.js +404 -0
- package/dist/content/start-command.d.ts +2 -12
- package/dist/content/start-command.js +221 -207
- package/dist/flow-state.d.ts +21 -178
- package/dist/flow-state.js +67 -170
- package/dist/fs-utils.d.ts +6 -26
- package/dist/fs-utils.js +29 -162
- package/dist/gitignore.d.ts +2 -1
- package/dist/gitignore.js +51 -34
- package/dist/harness-detect.d.ts +10 -0
- package/dist/harness-detect.js +29 -0
- package/dist/install.d.ts +27 -15
- package/dist/install.js +230 -1342
- package/dist/knowledge-store.d.ts +19 -163
- package/dist/knowledge-store.js +56 -590
- package/dist/logger.d.ts +8 -3
- package/dist/logger.js +13 -4
- package/dist/orchestrator-routing.d.ts +29 -0
- package/dist/orchestrator-routing.js +156 -0
- package/dist/run-persistence.d.ts +7 -118
- package/dist/run-persistence.js +29 -845
- package/dist/runtime/run-hook.entry.d.ts +1 -3
- package/dist/runtime/run-hook.entry.js +19 -4
- package/dist/runtime/run-hook.mjs +13 -1024
- package/dist/types.d.ts +25 -261
- package/dist/types.js +8 -36
- package/package.json +6 -3
- package/dist/artifact-linter/brainstorm.d.ts +0 -2
- package/dist/artifact-linter/brainstorm.js +0 -353
- package/dist/artifact-linter/design.d.ts +0 -18
- package/dist/artifact-linter/design.js +0 -444
- package/dist/artifact-linter/findings-dedup.d.ts +0 -56
- package/dist/artifact-linter/findings-dedup.js +0 -232
- package/dist/artifact-linter/plan.d.ts +0 -2
- package/dist/artifact-linter/plan.js +0 -826
- package/dist/artifact-linter/review-army.d.ts +0 -49
- package/dist/artifact-linter/review-army.js +0 -520
- package/dist/artifact-linter/review.d.ts +0 -2
- package/dist/artifact-linter/review.js +0 -113
- package/dist/artifact-linter/scope.d.ts +0 -2
- package/dist/artifact-linter/scope.js +0 -158
- package/dist/artifact-linter/shared.d.ts +0 -637
- package/dist/artifact-linter/shared.js +0 -2163
- package/dist/artifact-linter/ship.d.ts +0 -2
- package/dist/artifact-linter/ship.js +0 -250
- package/dist/artifact-linter/spec.d.ts +0 -2
- package/dist/artifact-linter/spec.js +0 -176
- package/dist/artifact-linter/tdd.d.ts +0 -118
- package/dist/artifact-linter/tdd.js +0 -1404
- package/dist/artifact-linter.d.ts +0 -15
- package/dist/artifact-linter.js +0 -517
- package/dist/codex-feature-flag.d.ts +0 -58
- package/dist/codex-feature-flag.js +0 -193
- package/dist/content/closeout-guidance.d.ts +0 -14
- package/dist/content/closeout-guidance.js +0 -44
- package/dist/content/diff-command.d.ts +0 -1
- package/dist/content/diff-command.js +0 -43
- package/dist/content/harness-doc.d.ts +0 -1
- package/dist/content/harness-doc.js +0 -65
- package/dist/content/hook-events.d.ts +0 -9
- package/dist/content/hook-events.js +0 -23
- package/dist/content/hook-manifest.d.ts +0 -81
- package/dist/content/hook-manifest.js +0 -156
- package/dist/content/hooks.d.ts +0 -11
- package/dist/content/hooks.js +0 -1972
- package/dist/content/idea.d.ts +0 -60
- package/dist/content/idea.js +0 -416
- package/dist/content/language-policy.d.ts +0 -2
- package/dist/content/language-policy.js +0 -13
- package/dist/content/learnings.d.ts +0 -6
- package/dist/content/learnings.js +0 -141
- package/dist/content/observe.d.ts +0 -19
- package/dist/content/observe.js +0 -86
- package/dist/content/opencode-plugin.d.ts +0 -1
- package/dist/content/opencode-plugin.js +0 -635
- package/dist/content/review-prompts.d.ts +0 -1
- package/dist/content/review-prompts.js +0 -104
- package/dist/content/runtime-shared-snippets.d.ts +0 -8
- package/dist/content/runtime-shared-snippets.js +0 -80
- package/dist/content/session-hooks.d.ts +0 -7
- package/dist/content/session-hooks.js +0 -107
- package/dist/content/skills-elicitation.d.ts +0 -1
- package/dist/content/skills-elicitation.js +0 -167
- package/dist/content/stage-command.d.ts +0 -2
- package/dist/content/stage-command.js +0 -17
- package/dist/content/stage-schema.d.ts +0 -117
- package/dist/content/stage-schema.js +0 -955
- package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
- package/dist/content/stages/_lint-metadata/index.js +0 -97
- package/dist/content/stages/brainstorm.d.ts +0 -2
- package/dist/content/stages/brainstorm.js +0 -184
- package/dist/content/stages/design.d.ts +0 -2
- package/dist/content/stages/design.js +0 -288
- package/dist/content/stages/index.d.ts +0 -8
- package/dist/content/stages/index.js +0 -11
- package/dist/content/stages/plan.d.ts +0 -2
- package/dist/content/stages/plan.js +0 -191
- package/dist/content/stages/review.d.ts +0 -2
- package/dist/content/stages/review.js +0 -240
- package/dist/content/stages/schema-types.d.ts +0 -203
- package/dist/content/stages/schema-types.js +0 -1
- package/dist/content/stages/scope.d.ts +0 -2
- package/dist/content/stages/scope.js +0 -254
- package/dist/content/stages/ship.d.ts +0 -2
- package/dist/content/stages/ship.js +0 -159
- package/dist/content/stages/spec.d.ts +0 -2
- package/dist/content/stages/spec.js +0 -170
- package/dist/content/stages/tdd.d.ts +0 -4
- package/dist/content/stages/tdd.js +0 -273
- package/dist/content/state-contracts.d.ts +0 -1
- package/dist/content/state-contracts.js +0 -63
- package/dist/content/status-command.d.ts +0 -4
- package/dist/content/status-command.js +0 -109
- package/dist/content/subagent-context-skills.d.ts +0 -4
- package/dist/content/subagent-context-skills.js +0 -279
- package/dist/content/subagents.d.ts +0 -3
- package/dist/content/subagents.js +0 -997
- package/dist/content/templates.d.ts +0 -26
- package/dist/content/templates.js +0 -1692
- package/dist/content/track-render-context.d.ts +0 -18
- package/dist/content/track-render-context.js +0 -53
- package/dist/content/tree-command.d.ts +0 -1
- package/dist/content/tree-command.js +0 -64
- package/dist/content/utility-skills.d.ts +0 -30
- package/dist/content/utility-skills.js +0 -160
- package/dist/content/view-command.d.ts +0 -2
- package/dist/content/view-command.js +0 -92
- package/dist/delegation.d.ts +0 -649
- package/dist/delegation.js +0 -1539
- package/dist/early-loop.d.ts +0 -70
- package/dist/early-loop.js +0 -302
- package/dist/execution-topology.d.ts +0 -36
- package/dist/execution-topology.js +0 -73
- package/dist/gate-evidence.d.ts +0 -85
- package/dist/gate-evidence.js +0 -631
- package/dist/harness-adapters.d.ts +0 -151
- package/dist/harness-adapters.js +0 -756
- package/dist/harness-selection.d.ts +0 -31
- package/dist/harness-selection.js +0 -214
- package/dist/hook-schema.d.ts +0 -6
- package/dist/hook-schema.js +0 -114
- package/dist/hook-schemas/claude-hooks.v1.json +0 -10
- package/dist/hook-schemas/codex-hooks.v1.json +0 -10
- package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
- package/dist/init-detect.d.ts +0 -2
- package/dist/init-detect.js +0 -50
- package/dist/internal/advance-stage/advance.d.ts +0 -89
- package/dist/internal/advance-stage/advance.js +0 -655
- package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
- package/dist/internal/advance-stage/cancel-run.js +0 -19
- package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
- package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
- package/dist/internal/advance-stage/helpers.d.ts +0 -14
- package/dist/internal/advance-stage/helpers.js +0 -145
- package/dist/internal/advance-stage/hook.d.ts +0 -8
- package/dist/internal/advance-stage/hook.js +0 -40
- package/dist/internal/advance-stage/parsers.d.ts +0 -72
- package/dist/internal/advance-stage/parsers.js +0 -357
- package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
- package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
- package/dist/internal/advance-stage/review-loop.d.ts +0 -16
- package/dist/internal/advance-stage/review-loop.js +0 -199
- package/dist/internal/advance-stage/rewind.d.ts +0 -14
- package/dist/internal/advance-stage/rewind.js +0 -108
- package/dist/internal/advance-stage/start-flow.d.ts +0 -13
- package/dist/internal/advance-stage/start-flow.js +0 -241
- package/dist/internal/advance-stage/verify.d.ts +0 -21
- package/dist/internal/advance-stage/verify.js +0 -185
- package/dist/internal/advance-stage.d.ts +0 -7
- package/dist/internal/advance-stage.js +0 -138
- package/dist/internal/cohesion-contract-stub.d.ts +0 -24
- package/dist/internal/cohesion-contract-stub.js +0 -148
- package/dist/internal/compound-readiness.d.ts +0 -23
- package/dist/internal/compound-readiness.js +0 -102
- package/dist/internal/detect-public-api-changes.d.ts +0 -5
- package/dist/internal/detect-public-api-changes.js +0 -45
- package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
- package/dist/internal/detect-supply-chain-changes.js +0 -138
- package/dist/internal/early-loop-status.d.ts +0 -7
- package/dist/internal/early-loop-status.js +0 -93
- package/dist/internal/envelope-validate.d.ts +0 -7
- package/dist/internal/envelope-validate.js +0 -66
- package/dist/internal/flow-state-repair.d.ts +0 -20
- package/dist/internal/flow-state-repair.js +0 -104
- package/dist/internal/plan-split-waves.d.ts +0 -190
- package/dist/internal/plan-split-waves.js +0 -764
- package/dist/internal/runtime-integrity.d.ts +0 -7
- package/dist/internal/runtime-integrity.js +0 -268
- package/dist/internal/slice-commit.d.ts +0 -7
- package/dist/internal/slice-commit.js +0 -619
- package/dist/internal/tdd-loop-status.d.ts +0 -14
- package/dist/internal/tdd-loop-status.js +0 -68
- package/dist/internal/tdd-red-evidence.d.ts +0 -7
- package/dist/internal/tdd-red-evidence.js +0 -153
- package/dist/internal/waiver-grant.d.ts +0 -62
- package/dist/internal/waiver-grant.js +0 -294
- package/dist/internal/wave-status.d.ts +0 -63
- package/dist/internal/wave-status.js +0 -450
- package/dist/managed-resources.d.ts +0 -53
- package/dist/managed-resources.js +0 -313
- package/dist/policy.d.ts +0 -10
- package/dist/policy.js +0 -167
- package/dist/retro-gate.d.ts +0 -9
- package/dist/retro-gate.js +0 -47
- package/dist/run-archive.d.ts +0 -61
- package/dist/run-archive.js +0 -391
- package/dist/runs.d.ts +0 -2
- package/dist/runs.js +0 -2
- package/dist/stack-detection.d.ts +0 -116
- package/dist/stack-detection.js +0 -489
- package/dist/streaming/event-stream.d.ts +0 -31
- package/dist/streaming/event-stream.js +0 -114
- package/dist/tdd-cycle.d.ts +0 -107
- package/dist/tdd-cycle.js +0 -289
- package/dist/tdd-verification-evidence.d.ts +0 -17
- package/dist/tdd-verification-evidence.js +0 -122
- package/dist/track-heuristics.d.ts +0 -27
- package/dist/track-heuristics.js +0 -154
- package/dist/util/slice-id.d.ts +0 -58
- package/dist/util/slice-id.js +0 -89
- package/dist/worktree-manager.d.ts +0 -20
- package/dist/worktree-manager.js +0 -108
package/README.md
CHANGED
|
@@ -1,197 +1,273 @@
|
|
|
1
1
|
# cclaw
|
|
2
2
|
|
|
3
|
-
**cclaw is a
|
|
3
|
+
**cclaw is a lightweight harness-first flow toolkit for coding agents.** It installs three slash commands, six on-demand specialists, twelve auto-trigger skills (including TDD cycle and conversation-language), ten artifact templates, four stage runbooks, eight reference patterns, five research playbooks, five recovery playbooks, thirteen worked examples, an antipatterns library, a decision protocol, a meta-skill, and a tiny runtime — together a deep content layer wrapped around a runtime under 1 KLOC — so Claude Code, Cursor, OpenCode, or Codex can move from idea to shipped change with a clear plan, AC traceability, TDD per AC, and almost no ceremony.
|
|
4
4
|
|
|
5
5
|
```text
|
|
6
6
|
idea
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
│
|
|
8
|
+
▼
|
|
9
|
+
/cc <task>
|
|
10
|
+
│
|
|
11
|
+
┌─────┴─────────────────────────────────────┐
|
|
12
|
+
│ Phase 0 calibration: │
|
|
13
|
+
│ targeted change or multi-component? │
|
|
14
|
+
└─────┬─────────────────┬───────────────────┘
|
|
15
|
+
│trivial │small/medium │large/risky
|
|
16
|
+
▼ ▼ ▼
|
|
17
|
+
edit + commit plan → build brainstormer →
|
|
18
|
+
per AC → review → ship architect → planner
|
|
19
|
+
(each is optional)
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
compound (auto, gated)
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
active artifacts → shipped/<slug>/
|
|
20
26
|
```
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
Three slash commands. Four stages (`plan → build → review → ship`, where **build IS a TDD cycle**: RED → GREEN → REFACTOR per AC). Six specialists. Eleven skills (including a TDD-cycle skill that's always-on while building). Ten templates. Four runbooks. Eight reference patterns. Five research playbooks. Five recovery playbooks. Thirteen worked examples. Two mandatory gates (AC traceability + TDD phase chain).
|
|
23
29
|
|
|
24
|
-
##
|
|
30
|
+
## What changed in v8
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
cclaw v8.0 is a breaking redesign. We dropped the 7.x stage machine: no more `brainstorm` / `scope` / `design` / `spec` / `tdd` mandatory stages, no more 18 specialists, no more 9 state files, no more 30 stage gates. v7.x runs are not migrated; see [docs/migration-v7-to-v8.md](docs/migration-v7-to-v8.md).
|
|
33
|
+
|
|
34
|
+
What we kept and made deeper:
|
|
35
|
+
|
|
36
|
+
- plans with **acceptance criteria + YAML frontmatter** (`slug`, `stage`, `status`, `ac[]`, `last_specialist`, `refines`, `shipped_at`, `ship_commit`, `review_iterations`, `security_flag`);
|
|
37
|
+
- **build is a TDD stage** — every AC goes through RED → GREEN → REFACTOR; `commit-helper.mjs --phase=red|green|refactor` enforces the cycle (production files in RED are rejected, GREEN without prior RED is rejected, REFACTOR is mandatory);
|
|
38
|
+
- **AC ↔ commit traceability** enforced by `commit-helper.mjs`;
|
|
39
|
+
- **artifact templates** for every stage (`plan`, `build`, `review`, `ship`, `decisions`, `learnings`, `manifest`, `ideas`, `iron-laws`);
|
|
40
|
+
- **twelve auto-trigger skills** — plan-authoring, AC traceability, refinement, parallel-build, security-review, review-loop, commit-message-quality, AC-quality, refactor-safety, breaking-changes, conversation-language (always-on), anti-slop (always-on), plus a meta-skill that ties them together;
|
|
41
|
+
- **stage runbooks** (`.cclaw/lib/runbooks/{plan,build,review,ship}.md`) — strict checklists per stage with common pitfalls;
|
|
42
|
+
- **reference patterns** (`.cclaw/lib/patterns/`) — eight task-type playbooks (api-endpoint, auth-flow, schema-migration, ui-component, perf-fix, refactor, security-hardening, doc-rewrite) the orchestrator opens before authoring AC;
|
|
43
|
+
- **research playbooks** (`.cclaw/lib/research/`) — reading the codebase (files + tests + integration boundaries), time-boxing, using prior shipped slugs;
|
|
44
|
+
- **recovery playbooks** (`.cclaw/lib/recovery/`) — AC traceability break, review hard cap reached, parallel-build slice conflict, frontmatter corruption, schemaVersion mismatch;
|
|
45
|
+
- **examples library** (`.cclaw/lib/examples/`) — eight real-looking plan / build / review / ship / decision / learning / commit-helper artifacts;
|
|
46
|
+
- **antipatterns** (`.cclaw/lib/antipatterns.md`) — twelve known failure modes the reviewer cites as findings;
|
|
47
|
+
- **decision protocol** (`.cclaw/lib/decision-protocol.md`) — short-form digest of "is this even a decision?"; full D-N schema lives in `lib/agents/architect.md`, worked decisions in `lib/examples/`;
|
|
48
|
+
- **resumable refinement** via frontmatter on shipped slugs (`refines: <old-slug>`);
|
|
49
|
+
- durable artifacts your team and graph tools (Graphify, GitNexus, etc.) can index.
|
|
50
|
+
|
|
51
|
+
## First 5 minutes
|
|
52
|
+
|
|
53
|
+
Requirements: Node.js 20+ and a git project.
|
|
27
54
|
|
|
28
55
|
```bash
|
|
29
56
|
cd /path/to/your/repo
|
|
30
|
-
npx cclaw-cli
|
|
57
|
+
npx cclaw-cli init # auto-detect harness from project root
|
|
58
|
+
npx cclaw-cli init --harness=claude,cursor,opencode,codex # explicit selection
|
|
31
59
|
```
|
|
32
60
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```text
|
|
36
|
-
/cc <idea> start, resume, or continue a tracked flow
|
|
37
|
-
/cc-idea generate or refresh an idea backlog
|
|
38
|
-
/cc-cancel end the current run cleanly with a reason
|
|
39
|
-
```
|
|
61
|
+
`init` resolves harnesses in this order:
|
|
40
62
|
|
|
41
|
-
|
|
42
|
-
`.cclaw/
|
|
43
|
-
|
|
63
|
+
1. `--harness=<id>[,<id>]` flag if passed.
|
|
64
|
+
2. Existing `.cclaw/config.yaml` (so subsequent `init` / `sync` / `upgrade` are deterministic).
|
|
65
|
+
3. Auto-detect from project root markers: `.claude/`, `.cursor/`, `.opencode/`, `.codex/`, `.agents/skills/`, `CLAUDE.md`, `opencode.json`, `opencode.jsonc`.
|
|
66
|
+
4. If nothing detected and no flag passed → exit with an actionable error. cclaw never silently picks a harness for you.
|
|
44
67
|
|
|
45
|
-
|
|
68
|
+
Then work entirely inside your harness:
|
|
46
69
|
|
|
47
|
-
```
|
|
48
|
-
|
|
70
|
+
```text
|
|
71
|
+
/cc <task> plan / build / review / ship — orchestrator routes everything
|
|
72
|
+
/cc-cancel stop the active run cleanly (artifacts move to .cclaw/flows/cancelled/<slug>/)
|
|
73
|
+
/cc-idea drop a half-formed idea into .cclaw/ideas.md (no flow started)
|
|
49
74
|
```
|
|
50
75
|
|
|
51
|
-
|
|
76
|
+
There is no `cclaw plan`, `cclaw status`, `cclaw ship`, or `cclaw migrate` CLI command. Flow control lives in `/cc` inside the harness.
|
|
77
|
+
|
|
78
|
+
## Six specialists, all on demand
|
|
79
|
+
|
|
80
|
+
| id | modes | when |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `brainstormer` | frame / scope / alternatives | ambiguous request, need a frame and scope |
|
|
83
|
+
| `architect` | architecture / feasibility | structural decisions or feasibility check |
|
|
84
|
+
| `planner` | research / work-breakdown / topology | breaking work into AC and choosing topology |
|
|
85
|
+
| `reviewer` | code / text-review / integration / release / adversarial | reviews of any kind |
|
|
86
|
+
| `security-reviewer` | threat-model / sensitive-change | auth / secrets / supply chain / data exposure |
|
|
87
|
+
| `slice-builder` | build / fix-only | implementing AC and applying scoped fixes |
|
|
88
|
+
|
|
89
|
+
Specialists are proposed only when the task is large, abstract, risky, security-sensitive, or spans multiple components. Trivial and small/medium tasks run inline. Each prompt is 150-280 lines and includes an explicit output schema, two or more worked examples, edge cases, common pitfalls, and hard rules (see `.cclaw/lib/agents/*.md` after install). The orchestrator pulls additional context from runbooks, patterns, examples, and recovery playbooks as needed; see [docs/skills.md](docs/skills.md) for the auto-trigger layer that wraps every invocation.
|
|
90
|
+
|
|
91
|
+
## Plan artifact, by example
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
---
|
|
95
|
+
slug: approval-page
|
|
96
|
+
stage: plan
|
|
97
|
+
status: active
|
|
98
|
+
ac:
|
|
99
|
+
- id: AC-1
|
|
100
|
+
text: "User sees an approval status pill on the dashboard."
|
|
101
|
+
status: pending
|
|
102
|
+
- id: AC-2
|
|
103
|
+
text: "Pending approvals show a tooltip with the approver's name."
|
|
104
|
+
status: pending
|
|
105
|
+
last_specialist: null
|
|
106
|
+
refines: null
|
|
107
|
+
shipped_at: null
|
|
108
|
+
ship_commit: null
|
|
109
|
+
review_iterations: 0
|
|
110
|
+
security_flag: false
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# approval-page
|
|
114
|
+
|
|
115
|
+
> One paragraph: what we are doing and why.
|
|
116
|
+
|
|
117
|
+
## Acceptance Criteria
|
|
118
|
+
|
|
119
|
+
| id | text | status | commit |
|
|
120
|
+
| --- | --- | --- | --- |
|
|
121
|
+
| AC-1 | User sees an approval status pill on the dashboard. | pending | — |
|
|
122
|
+
| AC-2 | Pending approvals show a tooltip with the approver's name. | pending | — |
|
|
123
|
+
```
|
|
52
124
|
|
|
53
|
-
|
|
125
|
+
The same shape applies to `build.md` (commit log), `review.md` (findings + Five Failure Modes pass), `ship.md` (release notes + push/PR refs), `decisions.md` (architect output), `learnings.md` (compound output). Templates live in `.cclaw/lib/templates/`.
|
|
54
126
|
|
|
55
|
-
|
|
127
|
+
## Artifact tree
|
|
56
128
|
|
|
57
|
-
```
|
|
129
|
+
```
|
|
58
130
|
.cclaw/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
131
|
+
config.yaml cclaw config (harness, flow defaults)
|
|
132
|
+
ideas.md append-only idea backlog (/cc-idea)
|
|
133
|
+
knowledge.jsonl cross-feature learnings index, append-only
|
|
134
|
+
state/
|
|
135
|
+
flow-state.json ~500 bytes, schemaVersion: 2
|
|
136
|
+
hooks/
|
|
137
|
+
session-start.mjs rehydrates flow state on harness boot
|
|
138
|
+
stop-handoff.mjs short reminder when stopping mid-flow
|
|
139
|
+
commit-helper.mjs atomic commit per AC + traceability + TDD phase gate
|
|
140
|
+
flows/ everything that comes out of a /cc run
|
|
141
|
+
<slug>/ one folder per active flow
|
|
142
|
+
plan.md current work + AC
|
|
143
|
+
build.md implementation log + TDD evidence
|
|
144
|
+
review.md Concern Ledger + iteration logs
|
|
145
|
+
ship.md preflight + AC↔commit map + rollback + finalization
|
|
146
|
+
decisions.md architect output (optional; only when architect ran)
|
|
147
|
+
learnings.md compound output (optional; only when gated)
|
|
148
|
+
shipped/<slug>/ plan.md, build.md, review.md, ship.md,
|
|
149
|
+
decisions.md, learnings.md, manifest.md
|
|
150
|
+
cancelled/<slug>/ when /cc-cancel is invoked
|
|
151
|
+
lib/ reference content shipped by the installer
|
|
152
|
+
agents/ 6 specialist prompts (each ends with a Composition footer
|
|
153
|
+
locking it to its lane — no nested orchestration)
|
|
154
|
+
skills/ 12 auto-trigger skills (2 always-on: conversation-language,
|
|
155
|
+
anti-slop; 10 stage- or event-gated)
|
|
156
|
+
templates/ 9 templates (plan, build, review, ship, decisions,
|
|
157
|
+
learnings, manifest, ideas, iron-laws)
|
|
158
|
+
runbooks/ 4 stage runbooks (plan, build, review, ship)
|
|
159
|
+
patterns/ 8 task-type playbooks
|
|
160
|
+
research/ 3 research playbooks
|
|
161
|
+
recovery/ 5 recovery playbooks
|
|
162
|
+
examples/ 8 worked examples
|
|
163
|
+
antipatterns.md 12 named failure modes
|
|
164
|
+
decision-protocol.md short-form digest; full schema in lib/agents/architect.md
|
|
65
165
|
```
|
|
66
166
|
|
|
67
|
-
|
|
167
|
+
`.cclaw/state/` and `.cclaw/worktrees/` are appended to `.gitignore` on init (transient per-session data). The rest of `.cclaw/` is committable; graphify, team review, and the next agent all need it.
|
|
68
168
|
|
|
69
|
-
|
|
70
|
-
- **Real gates** for evidence, tests, review, delegation, stale-stage recovery, and closeout.
|
|
71
|
-
- **Adaptive TDD execution**: feature-atomic slices carry internal 2-5 minute RED/GREEN/REFACTOR steps; cclaw routes them inline, through one builder, through parallel builders, or through strict micro-slices when risk demands it.
|
|
72
|
-
- **Subagents with accountability**: controller owns state, workers do bounded implementation units, overseers validate, evidence lands in `delegation-log.json`.
|
|
73
|
-
- **Recovery instead of confusion**: `npx cclaw-cli sync` tells you blockers and next fixes.
|
|
74
|
-
- **Portable harness behavior** across Claude Code, Cursor, OpenCode, and Codex.
|
|
169
|
+
The split is deliberate. Active and archived flow artifacts go under `flows/` so the orchestrator never confuses them with the read-only library under `lib/`. Runtime (`state/`, `hooks/`) stays at the top so harness hooks can find it without traversal. Active flows are grouped by slug — open `flows/<slug>/` and every artifact for that flow is right there, instead of scattered across six per-stage subdirectories.
|
|
75
170
|
|
|
76
|
-
##
|
|
171
|
+
## AC traceability gate (mandatory)
|
|
77
172
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
173
|
+
Ship is blocked unless every AC in the active plan is `status: committed` with a real commit SHA. The `commit-helper.mjs` hook is the only supported way to commit during `/cc`:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
git add path/to/changed/file
|
|
177
|
+
node .cclaw/hooks/commit-helper.mjs --ac=AC-1 --message="implement approval pill"
|
|
178
|
+
```
|
|
81
179
|
|
|
82
|
-
|
|
83
|
-
The agent writes/updates per-stage files like .cclaw/artifacts/00-idea.md, 01-brainstorm-<slug>.md, 02-scope-<slug>.md
|
|
180
|
+
The hook checks that `AC-1` is declared in `plan.md`, refuses to run when `flow-state.json` schemaVersion is not `2`, runs `git commit`, captures the new SHA, and writes it back into `flow-state.json`. If you commit by hand, AC traceability breaks and ship will refuse.
|
|
84
181
|
|
|
85
|
-
|
|
86
|
-
stage-complete records evidence in flow-state.json
|
|
182
|
+
## Compound learnings (automatic, gated)
|
|
87
183
|
|
|
88
|
-
|
|
89
|
-
npx cclaw-cli sync
|
|
184
|
+
After ship, cclaw automatically checks whether the run produced something worth remembering:
|
|
90
185
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
186
|
+
- a non-trivial decision was recorded by `architect` or `planner`, **or**
|
|
187
|
+
- review needed three or more iterations, **or**
|
|
188
|
+
- a security review ran or `security_flag` is true, **or**
|
|
189
|
+
- the user explicitly asked to capture (`/cc <task> --capture-learnings`).
|
|
94
190
|
|
|
95
|
-
|
|
191
|
+
If yes → `flows/<slug>/learnings.md` is written from the template, and one line is appended to `knowledge.jsonl` recording the slug, ship_commit, signals, and `refines` chain. If no → silently skipped, so the index stays signal-rich. Then everything moves to `flows/shipped/<slug>/` with a `manifest.md`.
|
|
96
192
|
|
|
97
|
-
|
|
98
|
-
quick spec -> tdd -> review -> ship
|
|
99
|
-
medium brainstorm -> spec -> plan -> tdd -> review -> ship
|
|
100
|
-
standard brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship
|
|
101
|
-
```
|
|
193
|
+
## Parallel-build (cap: 5 slices, git worktree)
|
|
102
194
|
|
|
103
|
-
|
|
195
|
+
Inline is the default. Parallel-build is opt-in and only when planner declares it. Pre-conditions: ≥4 AC, ≥2 distinct touchSurface clusters, every AC `parallelSafe: true`, no AC depends on outputs of another AC in the same wave.
|
|
104
196
|
|
|
105
|
-
|
|
197
|
+
A **slice = 1+ AC with a shared touchSurface**. If planner produces more than 5 slices, planner must merge thinner slices into fatter ones — never generate "wave 2", "wave 3". The 5-slice cap is the v7-era constraint kept on purpose: orchestration cost grows non-linearly past 5 sub-agents, and 5 fits comfortably under every harness's sub-agent quota.
|
|
106
198
|
|
|
107
|
-
|
|
199
|
+
When the harness supports sub-agent dispatch, each parallel slice runs in its own worktree:
|
|
108
200
|
|
|
109
|
-
```
|
|
110
|
-
|
|
201
|
+
```bash
|
|
202
|
+
git worktree add .cclaw/worktrees/<slug>-slice-1 -b cclaw/<slug>/slice-1
|
|
203
|
+
git worktree add .cclaw/worktrees/<slug>-slice-2 -b cclaw/<slug>/slice-2
|
|
204
|
+
git worktree add .cclaw/worktrees/<slug>-slice-3 -b cclaw/<slug>/slice-3
|
|
111
205
|
```
|
|
112
206
|
|
|
113
|
-
|
|
207
|
+
Each slice-builder runs RED → GREEN → REFACTOR for every AC it owns sequentially inside its worktree. After the wave, `reviewer` in `integration` mode reads from each worktree's branch and the orchestrator merges them in. If the harness does not support sub-agent dispatch (or worktree creation fails), parallel-build degrades silently to inline-sequential — recorded but not an error.
|
|
114
208
|
|
|
115
|
-
|
|
116
|
-
Current: tdd (standard)
|
|
117
|
-
Blocked by: NO_SOURCE_CONTEXT
|
|
118
|
-
Next: cclaw internal rewind plan "add bootstrap slice", then /cc
|
|
119
|
-
Evidence needed: fresh RED/GREEN/REFACTOR slice and verification output
|
|
120
|
-
```
|
|
209
|
+
For ≤4 AC the orchestrator picks `inline` even when AC look "parallelSafe". Dispatch overhead is not worth saving 1-2 AC of wall-clock.
|
|
121
210
|
|
|
122
|
-
|
|
211
|
+
## When sub-agents help (and when they don't)
|
|
123
212
|
|
|
213
|
+
Use a sub-agent for:
|
|
124
214
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
| Missing gates | Run `/cc`, finish the stage, then complete with evidence. |
|
|
128
|
-
| Mandatory delegation missing evidence | Dispatch the worker/overseer or waive explicitly with rationale. |
|
|
129
|
-
| `NO_SOURCE_CONTEXT` or `NO_TEST_SURFACE` | Rewind to `plan`/`spec`, define the source or test surface, then resume TDD. |
|
|
130
|
-
| `NO_IMPLEMENTABLE_SLICE` or `RED_NOT_EXPRESSIBLE` | Rework `design`/`spec`/`plan` until one vertical slice is testable. |
|
|
131
|
-
| `NO_VCS_MODE` | Restore git, set `vcs: none` with hash evidence, or configure `tdd.verificationRef`. |
|
|
132
|
-
| Review blocked | `cclaw internal rewind tdd "review_blocked_by_critical <finding-ids>"`. |
|
|
133
|
-
| Stale stage after rewind | Redo the marked stage, then `cclaw internal rewind --ack <stage>`. |
|
|
134
|
-
| Broken hooks or generated files | `npx cclaw-cli sync`, then follow the fail-fast error guidance if it still fails. |
|
|
215
|
+
- **Parallel slice dispatch** during `parallel-build` (cap: 5).
|
|
216
|
+
- **Specialist context isolation** for `architect`, `security-reviewer`, integration `reviewer` when the harness supports it. A fresh sub-agent reads a small focused filebag instead of the orchestrator's full history.
|
|
135
217
|
|
|
218
|
+
Don't use a sub-agent for:
|
|
136
219
|
|
|
137
|
-
|
|
220
|
+
- Trivial / small / medium slugs (≤4 AC). Run inline.
|
|
221
|
+
- Sequential work that doesn't actually parallelize.
|
|
222
|
+
- Routine work the orchestrator can finish in 1-2 turns.
|
|
138
223
|
|
|
139
|
-
|
|
140
|
-
user goal
|
|
141
|
-
|
|
|
142
|
-
v
|
|
143
|
-
controller ---------------> worker: bounded implementation/test/doc task
|
|
144
|
-
| |
|
|
145
|
-
| v
|
|
146
|
-
+----------------------> overseer: read-only validation
|
|
147
|
-
|
|
|
148
|
-
v
|
|
149
|
-
evidence refs + terminal status
|
|
150
|
-
|
|
|
151
|
-
v
|
|
152
|
-
.cclaw/state/delegation-log.json
|
|
153
|
-
```
|
|
224
|
+
## Five Failure Modes + review Ralph loop
|
|
154
225
|
|
|
155
|
-
|
|
226
|
+
Reviews check the Five Failure Modes — hallucinated actions, scope creep, cascading errors, context loss, tool misuse — every iteration. The Five Failure Modes pass is wrapped by the `review-loop` auto-trigger skill so the agent cannot skip it.
|
|
156
227
|
|
|
157
|
-
|
|
228
|
+
Reviews are not single-shot. They are a Ralph loop with an explicit ledger:
|
|
158
229
|
|
|
159
|
-
|
|
230
|
+
1. Iteration 1 lists every finding as F-1, F-2, … in an append-only **Concern Ledger** at the top of `flows/<slug>/review.md`. Each row carries severity (`block` / `warn`), status (`open` / `closed` / `superseded`), and a `file:line` citation.
|
|
231
|
+
2. Iteration N+1 must reread every open row, mark it `closed | open | superseded by F-K`, and append new findings as F-(max+1). It cannot delete or rewrite earlier rows.
|
|
232
|
+
3. The loop ends when (a) every row is `closed`, (b) two consecutive iterations record zero new `block` findings AND every open row is `warn`, or (c) the 5-iteration hard cap fires with at least one open block row — at which point `/cc` stops and reports instead of looping forever.
|
|
160
233
|
|
|
161
|
-
-
|
|
162
|
-
- Required gates need evidence before advancement.
|
|
163
|
-
- Mandatory delegations need terminal evidence or explicit waiver.
|
|
164
|
-
- Stale stages block until redone and acknowledged.
|
|
165
|
-
- Review criticals route back to TDD.
|
|
166
|
-
- Ship continues through `post_ship_review -> archive` with `closeout.shipSubstate`.
|
|
234
|
+
A typical run converges in 1-3 iterations. The hard cap is a circuit breaker, not a target.
|
|
167
235
|
|
|
168
|
-
|
|
236
|
+
## Conversation language
|
|
169
237
|
|
|
170
|
-
-
|
|
171
|
-
- Proactive subagents that are not mandatory for the active stage/tier.
|
|
172
|
-
- Reference patterns that shape prompts but do not add runtime states.
|
|
238
|
+
cclaw replies in the user's language for prose. It NEVER translates wire-protocol identifiers — slugs, `AC-N`, `D-N`, `F-N`, frontmatter keys, file paths, hook output, specialist names, or commit tags. This is enforced by the always-on `conversation-language` skill so a Russian-speaking user, for example, gets Russian explanations but still sees `flow-state.json` and `AC-1` verbatim.
|
|
173
239
|
|
|
174
|
-
##
|
|
240
|
+
## Hooks (default profile: minimal)
|
|
175
241
|
|
|
176
|
-
|
|
242
|
+
Three hooks ship by default and only `commit-helper.mjs` is mandatory:
|
|
177
243
|
|
|
178
|
-
-
|
|
179
|
-
-
|
|
180
|
-
-
|
|
181
|
-
- [Generated Agent Block Example](./docs/agents-block.example.md): what gets injected into harness guidance.
|
|
244
|
+
- `session-start.mjs` — rehydrates flow state and prints active slug
|
|
245
|
+
- `stop-handoff.mjs` — short reminder when stopping mid-flow
|
|
246
|
+
- `commit-helper.mjs` — atomic commit per AC + traceability check
|
|
182
247
|
|
|
183
|
-
## CLI
|
|
248
|
+
## CLI commands
|
|
184
249
|
|
|
185
250
|
```bash
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
npx cclaw-cli --version
|
|
251
|
+
cclaw init # install assets in the current project
|
|
252
|
+
cclaw sync # reapply assets to match the current code
|
|
253
|
+
cclaw upgrade # sync after upgrading the npm package
|
|
254
|
+
cclaw uninstall # remove cclaw assets from the project
|
|
255
|
+
cclaw version # print version
|
|
256
|
+
cclaw help # short help
|
|
193
257
|
```
|
|
194
258
|
|
|
259
|
+
Flow-control commands (`plan`, `status`, `ship`, `migrate`, `build`, `review`) are intentionally **not** part of the CLI. They live as `/cc` instructions inside the harness.
|
|
260
|
+
|
|
261
|
+
## More docs
|
|
262
|
+
|
|
263
|
+
- [docs/v8-vision.md](docs/v8-vision.md) — locked decisions, full kill-list, references review
|
|
264
|
+
- [docs/scheme-of-work.md](docs/scheme-of-work.md) — flow walk-through with all checkpoints
|
|
265
|
+
- [docs/skills.md](docs/skills.md) — six auto-trigger skills and what they enforce
|
|
266
|
+
- [docs/config.md](docs/config.md) — `.cclaw/config.yaml` reference
|
|
267
|
+
- [docs/harnesses.md](docs/harnesses.md) — what each harness installs
|
|
268
|
+
- [docs/quality-gates.md](docs/quality-gates.md) — AC traceability + Five Failure Modes
|
|
269
|
+
- [docs/migration-v7-to-v8.md](docs/migration-v7-to-v8.md) — from cclaw 7.x
|
|
270
|
+
|
|
195
271
|
## License
|
|
196
272
|
|
|
197
|
-
[
|
|
273
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AcceptanceCriterionState, FlowStage, DiscoverySpecialistId, ArtifactStatus } from "./types.js";
|
|
2
|
+
export interface ArtifactFrontmatter {
|
|
3
|
+
slug: string;
|
|
4
|
+
stage: FlowStage | "shipped" | "cancelled";
|
|
5
|
+
status: ArtifactStatus | "cancelled";
|
|
6
|
+
ac?: AcceptanceCriterionState[];
|
|
7
|
+
last_specialist?: DiscoverySpecialistId | null;
|
|
8
|
+
refines?: string | null;
|
|
9
|
+
shipped_at?: string | null;
|
|
10
|
+
ship_commit?: string | null;
|
|
11
|
+
review_iterations?: number;
|
|
12
|
+
security_flag?: boolean;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface ParsedArtifact {
|
|
16
|
+
frontmatter: ArtifactFrontmatter;
|
|
17
|
+
body: string;
|
|
18
|
+
raw: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class FrontmatterError extends Error {
|
|
21
|
+
readonly path?: string | undefined;
|
|
22
|
+
constructor(message: string, path?: string | undefined);
|
|
23
|
+
}
|
|
24
|
+
export declare function parseArtifact(raw: string, sourcePath?: string): ParsedArtifact;
|
|
25
|
+
export declare function renderArtifact(parsed: ParsedArtifact): string;
|
|
26
|
+
export declare function readArtifact(filePath: string): Promise<ParsedArtifact>;
|
|
27
|
+
export declare function writeArtifact(filePath: string, parsed: ParsedArtifact): Promise<void>;
|
|
28
|
+
export declare function extractAcceptanceCriteriaFromBody(body: string): Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
text: string;
|
|
31
|
+
commit?: string;
|
|
32
|
+
status: AcceptanceCriterionState["status"];
|
|
33
|
+
}>;
|
|
34
|
+
export declare function mergeAcceptanceCriteria(fromBody: Array<{
|
|
35
|
+
id: string;
|
|
36
|
+
text: string;
|
|
37
|
+
commit?: string;
|
|
38
|
+
status: AcceptanceCriterionState["status"];
|
|
39
|
+
}>, fromFrontmatter: AcceptanceCriterionState[] | undefined): AcceptanceCriterionState[];
|
|
40
|
+
export interface SyncFrontmatterPatch {
|
|
41
|
+
ac?: AcceptanceCriterionState[];
|
|
42
|
+
last_specialist?: ArtifactFrontmatter["last_specialist"];
|
|
43
|
+
review_iterations?: number;
|
|
44
|
+
security_flag?: boolean;
|
|
45
|
+
shipped_at?: string | null;
|
|
46
|
+
ship_commit?: string | null;
|
|
47
|
+
refines?: string | null;
|
|
48
|
+
}
|
|
49
|
+
export declare function syncFrontmatter(projectRoot: string, slug: string, stage: FlowStage, patch: SyncFrontmatterPatch): Promise<ParsedArtifact>;
|
|
50
|
+
export declare function isFrontmatterCancelled(frontmatter: ArtifactFrontmatter): boolean;
|
|
51
|
+
export declare function isFrontmatterShipped(frontmatter: ArtifactFrontmatter): boolean;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import YAML from "yaml";
|
|
3
|
+
import { activeArtifactPath } from "./artifact-paths.js";
|
|
4
|
+
import { exists, writeFileSafe } from "./fs-utils.js";
|
|
5
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/u;
|
|
6
|
+
const AC_LINE_RE = /^[\s>*+-]*\*{0,2}\s*(AC-\d+)\s*[:\-—)]\s*(.+?)\s*$/iu;
|
|
7
|
+
const AC_COMMIT_RE = /\(?(commit\s*[:=]?\s*([0-9a-f]{7,40})|sha\s*[:=]?\s*([0-9a-f]{7,40})|@([0-9a-f]{7,40}))\)?/iu;
|
|
8
|
+
const AC_PENDING_RE = /\(commit\s*[:=]?\s*pending\)/iu;
|
|
9
|
+
export class FrontmatterError extends Error {
|
|
10
|
+
path;
|
|
11
|
+
constructor(message, path) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.path = path;
|
|
14
|
+
this.name = "FrontmatterError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function parseArtifact(raw, sourcePath) {
|
|
18
|
+
const trimmed = raw.replace(/^\uFEFF/u, "");
|
|
19
|
+
const match = FRONTMATTER_RE.exec(trimmed);
|
|
20
|
+
if (!match) {
|
|
21
|
+
throw new FrontmatterError(`Artifact is missing the required YAML frontmatter block (---).${sourcePath ? ` (${sourcePath})` : ""}`, sourcePath);
|
|
22
|
+
}
|
|
23
|
+
const yamlBody = match[1] ?? "";
|
|
24
|
+
const body = match[2] ?? "";
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = YAML.parse(yamlBody);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
throw new FrontmatterError(`Invalid YAML frontmatter: ${err.message}`, sourcePath);
|
|
31
|
+
}
|
|
32
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
33
|
+
throw new FrontmatterError("Frontmatter must be a YAML object.", sourcePath);
|
|
34
|
+
}
|
|
35
|
+
const frontmatter = parsed;
|
|
36
|
+
if (typeof frontmatter.slug !== "string" || frontmatter.slug.length === 0) {
|
|
37
|
+
throw new FrontmatterError("Frontmatter must declare a non-empty `slug`.", sourcePath);
|
|
38
|
+
}
|
|
39
|
+
if (typeof frontmatter.stage !== "string") {
|
|
40
|
+
throw new FrontmatterError("Frontmatter must declare a `stage` (plan/build/review/ship/shipped/cancelled).", sourcePath);
|
|
41
|
+
}
|
|
42
|
+
if (typeof frontmatter.status !== "string") {
|
|
43
|
+
throw new FrontmatterError("Frontmatter must declare a `status` (active/shipped/cancelled).", sourcePath);
|
|
44
|
+
}
|
|
45
|
+
if (frontmatter.ac !== undefined && !Array.isArray(frontmatter.ac)) {
|
|
46
|
+
throw new FrontmatterError("Frontmatter `ac` must be an array.", sourcePath);
|
|
47
|
+
}
|
|
48
|
+
return { frontmatter, body, raw };
|
|
49
|
+
}
|
|
50
|
+
export function renderArtifact(parsed) {
|
|
51
|
+
const yaml = YAML.stringify(parsed.frontmatter, { indent: 2 }).trim();
|
|
52
|
+
const body = parsed.body.startsWith("\n") ? parsed.body : `\n${parsed.body}`;
|
|
53
|
+
return `---\n${yaml}\n---\n${body.replace(/^\n/u, "")}\n`;
|
|
54
|
+
}
|
|
55
|
+
export async function readArtifact(filePath) {
|
|
56
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
57
|
+
return parseArtifact(raw, filePath);
|
|
58
|
+
}
|
|
59
|
+
export async function writeArtifact(filePath, parsed) {
|
|
60
|
+
await writeFileSafe(filePath, renderArtifact(parsed));
|
|
61
|
+
}
|
|
62
|
+
export function extractAcceptanceCriteriaFromBody(body) {
|
|
63
|
+
const results = [];
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
for (const rawLine of body.split(/\r?\n/u)) {
|
|
66
|
+
const line = rawLine.replace(/<[^>]+>/gu, "").trim();
|
|
67
|
+
const match = AC_LINE_RE.exec(line);
|
|
68
|
+
if (!match)
|
|
69
|
+
continue;
|
|
70
|
+
const id = match[1].toUpperCase();
|
|
71
|
+
if (seen.has(id))
|
|
72
|
+
continue;
|
|
73
|
+
seen.add(id);
|
|
74
|
+
let text = match[2].trim();
|
|
75
|
+
let commit;
|
|
76
|
+
let status = "pending";
|
|
77
|
+
const commitMatch = AC_COMMIT_RE.exec(text);
|
|
78
|
+
if (commitMatch && !AC_PENDING_RE.test(text)) {
|
|
79
|
+
commit = commitMatch[2] ?? commitMatch[3] ?? commitMatch[4];
|
|
80
|
+
if (commit)
|
|
81
|
+
status = "committed";
|
|
82
|
+
}
|
|
83
|
+
text = text.replace(AC_COMMIT_RE, "").replace(AC_PENDING_RE, "").replace(/\s{2,}/gu, " ").replace(/[\s\-:—]+$/u, "").trim();
|
|
84
|
+
results.push({ id, text, commit, status });
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
export function mergeAcceptanceCriteria(fromBody, fromFrontmatter) {
|
|
89
|
+
const fmIndex = new Map();
|
|
90
|
+
for (const ac of fromFrontmatter ?? [])
|
|
91
|
+
fmIndex.set(ac.id, ac);
|
|
92
|
+
const merged = [];
|
|
93
|
+
for (const item of fromBody) {
|
|
94
|
+
const fm = fmIndex.get(item.id);
|
|
95
|
+
const commit = item.commit ?? fm?.commit;
|
|
96
|
+
const status = commit ? "committed" : (fm?.status ?? "pending");
|
|
97
|
+
merged.push({
|
|
98
|
+
id: item.id,
|
|
99
|
+
text: item.text || fm?.text || item.id,
|
|
100
|
+
commit,
|
|
101
|
+
status
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
for (const [id, ac] of fmIndex) {
|
|
105
|
+
if (!merged.some((entry) => entry.id === id))
|
|
106
|
+
merged.push(ac);
|
|
107
|
+
}
|
|
108
|
+
return merged;
|
|
109
|
+
}
|
|
110
|
+
export async function syncFrontmatter(projectRoot, slug, stage, patch) {
|
|
111
|
+
const filePath = activeArtifactPath(projectRoot, stage, slug);
|
|
112
|
+
if (!(await exists(filePath))) {
|
|
113
|
+
throw new FrontmatterError(`Artifact flows/${slug}/${stage}.md not found.`, filePath);
|
|
114
|
+
}
|
|
115
|
+
const parsed = await readArtifact(filePath);
|
|
116
|
+
const next = { ...parsed.frontmatter };
|
|
117
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
118
|
+
if (value === undefined)
|
|
119
|
+
continue;
|
|
120
|
+
next[key] = value;
|
|
121
|
+
}
|
|
122
|
+
const updated = { ...parsed, frontmatter: next };
|
|
123
|
+
await writeArtifact(filePath, updated);
|
|
124
|
+
return updated;
|
|
125
|
+
}
|
|
126
|
+
export function isFrontmatterCancelled(frontmatter) {
|
|
127
|
+
return frontmatter.status === "cancelled" || frontmatter.stage === "cancelled";
|
|
128
|
+
}
|
|
129
|
+
export function isFrontmatterShipped(frontmatter) {
|
|
130
|
+
return frontmatter.status === "shipped" || frontmatter.stage === "shipped";
|
|
131
|
+
}
|
package/dist/artifact-paths.d.ts
CHANGED
|
@@ -1,28 +1,8 @@
|
|
|
1
|
-
import type { FlowStage
|
|
2
|
-
export type
|
|
3
|
-
export
|
|
4
|
-
projectRoot: string;
|
|
5
|
-
track?: FlowTrack;
|
|
6
|
-
/**
|
|
7
|
-
* Optional brainstorm topic used for `<slug>` interpolation.
|
|
8
|
-
* When omitted, the resolver attempts to infer it from `00-idea.md`.
|
|
9
|
-
*/
|
|
10
|
-
topic?: string;
|
|
11
|
-
/**
|
|
12
|
-
* - read: locate an existing artifact first (new slug shape, then legacy fallback).
|
|
13
|
-
* - write: return a non-colliding writable path for a new artifact.
|
|
14
|
-
*/
|
|
15
|
-
intent?: ArtifactPathIntent;
|
|
16
|
-
}
|
|
17
|
-
export interface ResolvedArtifactPath {
|
|
18
|
-
stage: FlowStage;
|
|
19
|
-
fileName: string;
|
|
20
|
-
relPath: string;
|
|
21
|
-
absPath: string;
|
|
22
|
-
source: "existing" | "generated";
|
|
23
|
-
legacy: boolean;
|
|
24
|
-
}
|
|
25
|
-
export declare function isSlugArtifactPattern(filePattern: string): boolean;
|
|
26
|
-
export declare function legacyArtifactFileName(filePattern: string): string;
|
|
1
|
+
import type { FlowStage } from "./types.js";
|
|
2
|
+
export type ArtifactStage = FlowStage | "decisions" | "learnings";
|
|
3
|
+
export declare const ARTIFACT_FILE_NAMES: Record<ArtifactStage, string>;
|
|
27
4
|
export declare function slugifyArtifactTopic(topic: string): string;
|
|
28
|
-
export declare function
|
|
5
|
+
export declare function activeArtifactDir(projectRoot: string, slug: string): string;
|
|
6
|
+
export declare function activeArtifactPath(projectRoot: string, stage: ArtifactStage, slug: string): string;
|
|
7
|
+
export declare function shippedArtifactDir(projectRoot: string, slug: string): string;
|
|
8
|
+
export declare function shippedArtifactPath(projectRoot: string, slug: string, stage: ArtifactStage): string;
|