cclaw-cli 0.12.0 → 0.14.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 (54) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +25 -1
  3. package/dist/config.js +19 -8
  4. package/dist/constants.d.ts +2 -2
  5. package/dist/constants.js +16 -1
  6. package/dist/content/archive-command.d.ts +2 -0
  7. package/dist/content/archive-command.js +98 -0
  8. package/dist/content/contracts.js +1 -1
  9. package/dist/content/diff-command.d.ts +2 -0
  10. package/dist/content/diff-command.js +83 -0
  11. package/dist/content/feature-command.d.ts +2 -0
  12. package/dist/content/feature-command.js +120 -0
  13. package/dist/content/harnesses-doc.js +11 -0
  14. package/dist/content/hooks.js +48 -2
  15. package/dist/content/learnings.d.ts +0 -2
  16. package/dist/content/learnings.js +4 -33
  17. package/dist/content/meta-skill.js +4 -2
  18. package/dist/content/next-command.js +18 -9
  19. package/dist/content/observe.d.ts +5 -1
  20. package/dist/content/observe.js +134 -2
  21. package/dist/content/ops-command.d.ts +2 -0
  22. package/dist/content/ops-command.js +60 -0
  23. package/dist/content/protocols.js +14 -2
  24. package/dist/content/retro-command.d.ts +2 -0
  25. package/dist/content/retro-command.js +77 -0
  26. package/dist/content/rewind-command.d.ts +3 -0
  27. package/dist/content/rewind-command.js +120 -0
  28. package/dist/content/skills.js +2 -0
  29. package/dist/content/stage-common-guidance.js +2 -1
  30. package/dist/content/status-command.js +43 -35
  31. package/dist/content/tdd-log-command.d.ts +2 -0
  32. package/dist/content/tdd-log-command.js +75 -0
  33. package/dist/content/templates.d.ts +1 -1
  34. package/dist/content/templates.js +36 -6
  35. package/dist/content/tree-command.d.ts +2 -0
  36. package/dist/content/tree-command.js +91 -0
  37. package/dist/content/utility-skills.js +1 -1
  38. package/dist/content/view-command.d.ts +2 -0
  39. package/dist/content/view-command.js +57 -0
  40. package/dist/doctor-registry.js +3 -3
  41. package/dist/doctor.js +149 -3
  42. package/dist/feature-system.d.ts +18 -0
  43. package/dist/feature-system.js +247 -0
  44. package/dist/flow-state.d.ts +25 -0
  45. package/dist/flow-state.js +8 -1
  46. package/dist/harness-adapters.js +95 -4
  47. package/dist/install.js +44 -2
  48. package/dist/policy.js +22 -0
  49. package/dist/runs.d.ts +33 -1
  50. package/dist/runs.js +365 -6
  51. package/dist/tdd-cycle.d.ts +22 -0
  52. package/dist/tdd-cycle.js +82 -0
  53. package/dist/types.d.ts +4 -2
  54. package/package.json +1 -1
@@ -137,38 +137,9 @@ Do not edit source code from this command. Only operate on \`${KNOWLEDGE_PATH}\`
137
137
  export function selfImprovementBlock(stageName) {
138
138
  return `## Operational Self-Improvement
139
139
 
140
- After this stage, ask:
141
- - Did I discover a non-obvious reusable **rule** or **pattern**?
142
- - Did a failure reveal a reusable **lesson**?
143
-
144
- If yes, append one concise JSON line to the canonical knowledge store
145
- (\`${KNOWLEDGE_PATH}\`) using the strict 8-field schema:
146
-
147
- \`\`\`bash
148
- TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
149
- printf '%s\\n' '{"type":"pattern","trigger":"when <situation>","action":"<concrete move>","confidence":"medium","domain":null,"stage":"${stageName}","created":"'"$TS"'","project":null}' >> ${KNOWLEDGE_PATH}
150
- \`\`\`
151
-
152
- Type must be exactly one of: \`rule\`, \`pattern\`, \`lesson\`, \`compound\`.
153
- Fields must appear in the order: \`type, trigger, action, confidence, domain, stage, created, project\`.
154
- Missing optional values must be emitted as \`null\`, never omitted.
155
- `;
156
- }
157
- export function learningsSearchPreamble(stage) {
158
- return `## Prior Knowledge (load at stage start)
159
-
160
- Before stage work, stream \`${KNOWLEDGE_PATH}\` and filter for entries relevant to
161
- this stage (\`${stage}\`), affected domains, and key constraints. Apply matching
162
- entries explicitly. If the file is empty, continue normally.
163
- `;
164
- }
165
- export function learningsAgentsMdBlock() {
166
- return `### Knowledge Store
167
-
168
- \`${KNOWLEDGE_PATH}\` — append-only JSONL memory with entry types \`rule\`, \`pattern\`, \`lesson\`, \`compound\`.
169
- Strict 8-field schema: \`type, trigger, action, confidence, domain, stage, created, project\`.
170
- At session start and stage transitions, tail the file and apply relevant entries.
171
- If a non-obvious reusable rule/pattern/lesson is discovered, append a new line
172
- through \`/cc-learn add\` (never hand-edit).
140
+ Before closeout, capture 1-3 reusable insights in \`${KNOWLEDGE_PATH}\` whenever
141
+ the stage produced non-obvious decisions, patterns, or lessons.
142
+ Prefer \`type=rule|pattern|lesson\` (\`compound\` stays retro-only) and set
143
+ \`stage: "${stageName}"\` unless the insight is explicitly cross-stage.
173
144
  `;
174
145
  }
@@ -3,7 +3,7 @@ export const META_SKILL_NAME = "using-cclaw";
3
3
  export function usingCclawSkillMarkdown() {
4
4
  return `---
5
5
  name: using-cclaw
6
- description: "Routing brain for cclaw. Decide whether to start/resume a stage, answer directly, or use /cc-learn."
6
+ description: "Routing brain for cclaw. Decide whether to start/resume a stage, answer directly, or use utility commands like /cc-learn, /cc-view, and /cc-ops."
7
7
  ---
8
8
 
9
9
  # Using Cclaw
@@ -26,7 +26,9 @@ Task arrives
26
26
  ├─ Pure question / non-software ask? -> answer directly (no stage)
27
27
  ├─ New software work? -> /cc <idea>
28
28
  ├─ Resume existing flow? -> /cc or /cc-next
29
- └─ Knowledge operation? -> /cc-learn
29
+ ├─ Knowledge operation? -> /cc-learn
30
+ ├─ Read-only workspace view? -> /cc-view [status|tree|diff]
31
+ └─ Workspace operation? -> /cc-ops [feature|tdd-log|retro|archive|rewind|rewind-ack]
30
32
  \`\`\`
31
33
 
32
34
  ## Task classification
@@ -33,17 +33,18 @@ This is the only progression command the user needs to drive the entire flow. St
33
33
 
34
34
  - **Do not** invent gate completion: use only \`${flowPath}\` plus observable evidence in repo artifacts.
35
35
  - **Do not** skip stages: advance only from \`currentStage\` to its configured successor.
36
- - If the flow is at the terminal stage with all ship gates satisfied, **report completion**.
36
+ - If the flow reaches terminal ship completion, route closeout in order: **/cc-retro -> /cc-archive**.
37
37
 
38
38
  ## Algorithm (mandatory)
39
39
 
40
40
  1. Read **\`${flowPath}\`**. If missing → **BLOCKED** (state missing).
41
41
  2. Parse JSON. Capture \`currentStage\` and \`stageGateCatalog[currentStage]\`.
42
- 3. Let \`G\` = \`requiredGates\` for **\`currentStage\`** from the stage schema.
43
- 4. Let \`catalog\` = \`stageGateCatalog[currentStage]\` from flow state.
44
- 5. **Satisfied** for gate id \`g\`: \`g\` in \`catalog.passed\` and \`g\` not in \`catalog.blocked\`.
45
- 6. Let \`M\` = \`mandatoryDelegations\` for \`currentStage\`.
46
- 7. If \`M\` is non-empty, inspect **\`${delegationPath}\`**. Treat as satisfied only if the agent is **completed** or **waived**.
42
+ 3. If \`staleStages[currentStage]\` exists, do not advance automatically. Re-run the stage artifact work, then clear the marker with \`/cc-rewind-ack <currentStage>\`.
43
+ 4. Let \`G\` = \`requiredGates\` for **\`currentStage\`** from the stage schema.
44
+ 5. Let \`catalog\` = \`stageGateCatalog[currentStage]\` from flow state.
45
+ 6. **Satisfied** for gate id \`g\`: \`g\` in \`catalog.passed\` and \`g\` not in \`catalog.blocked\`.
46
+ 7. Let \`M\` = \`mandatoryDelegations\` for \`currentStage\`.
47
+ 8. If \`M\` is non-empty, inspect **\`${delegationPath}\`**. Treat as satisfied only if the agent is **completed** or **waived**.
47
48
 
48
49
  ### Path A: Current stage is NOT complete (any gate unmet or delegation missing)
49
50
 
@@ -53,7 +54,10 @@ This is the only progression command the user needs to drive the entire flow. St
53
54
 
54
55
  ### Path B: Current stage IS complete (all gates passed, all delegations satisfied)
55
56
 
56
- → If current stage's \`next\` is **\`done\`**: report **"Flow complete. All stages finished."** and stop.
57
+ → If current stage's \`next\` is **\`done\`**:
58
+ - if \`currentStage === "ship"\` and \`retro.completedAt\` is missing -> route to \`/cc-retro\`,
59
+ - if \`currentStage === "ship"\` and \`retro.completedAt\` is present -> route to \`/cc-archive\`,
60
+ - otherwise report **"Flow complete. All stages finished."** and stop.
57
61
  → Otherwise: load **\`${RUNTIME_ROOT}/skills/<skillFolder>/SKILL.md\`** and **\`${RUNTIME_ROOT}/commands/<nextStage>.md\`** for the successor stage. Execute that stage's protocol.
58
62
 
59
63
  ### Track-aware successor resolution
@@ -120,7 +124,8 @@ Do **not** mark gates satisfied from memory alone. Cite **artifact evidence** (p
120
124
 
121
125
  1. Open **\`${flowPath}\`**.
122
126
  2. Record \`currentStage\` and \`stageGateCatalog[currentStage]\`.
123
- 3. If the file is missing or invalid JSON **BLOCKED** (report and stop).
127
+ 3. If \`staleStages[currentStage]\` exists, re-run the stage and clear marker via \`/cc-rewind-ack <currentStage>\` before advancing.
128
+ 4. If the file is missing or invalid JSON → **BLOCKED** (report and stop).
124
129
 
125
130
  ### Step 2: Evaluate gates
126
131
 
@@ -142,7 +147,11 @@ Execute the stage protocol. The stage skill handles interaction, STOP points, ga
142
147
 
143
148
  **Path B — stage IS complete (all gates met, all delegations done):**
144
149
 
145
- If \`next\` is \`done\` → report **"Flow complete. All stages finished."** and stop.
150
+ If \`next\` is \`done\`:
151
+
152
+ - If \`currentStage\` is \`ship\` and \`retro.completedAt\` is missing -> route to \`/cc-retro\`.
153
+ - If \`currentStage\` is \`ship\` and \`retro.completedAt\` exists -> route to \`/cc-archive\`.
154
+ - Otherwise report **"Flow complete. All stages finished."** and stop.
146
155
 
147
156
  Otherwise load the next stage's skill and command contract, begin execution.
148
157
 
@@ -9,7 +9,11 @@ export interface PromptGuardOptions {
9
9
  strictMode?: boolean;
10
10
  }
11
11
  export declare function promptGuardScript(options?: PromptGuardOptions): string;
12
- export declare function workflowGuardScript(): string;
12
+ export interface WorkflowGuardOptions {
13
+ tddEnforcementMode?: "advisory" | "strict";
14
+ tddTestGlobs?: string[];
15
+ }
16
+ export declare function workflowGuardScript(options?: WorkflowGuardOptions): string;
13
17
  export declare function observeScript(): string;
14
18
  export declare function contextMonitorScript(): string;
15
19
  export declare function summarizeObservationsRuntimeModule(): string;
@@ -153,18 +153,25 @@ fi
153
153
  exit 0
154
154
  `;
155
155
  }
156
- export function workflowGuardScript() {
156
+ export function workflowGuardScript(options = {}) {
157
+ const tddEnforcementMode = options.tddEnforcementMode === "strict" ? "strict" : "advisory";
158
+ const tddTestGlobs = options.tddTestGlobs && options.tddTestGlobs.length > 0
159
+ ? options.tddTestGlobs.join(",")
160
+ : "**/*.test.*,**/*.spec.*,**/test/**";
157
161
  return `#!/usr/bin/env bash
158
162
  # cclaw workflow guard hook — generated by cclaw sync
159
163
  # Enforces stage-aware command discipline and recent flow-state read hygiene.
160
164
  set -uo pipefail
161
165
  WORKFLOW_GUARD_MODE="\${CCLAW_WORKFLOW_GUARD_MODE:-advisory}"
162
166
  MAX_FLOW_READ_AGE_SEC="\${CCLAW_WORKFLOW_GUARD_MAX_AGE_SEC:-1800}"
167
+ TDD_ENFORCEMENT_MODE="${tddEnforcementMode}"
168
+ TDD_TEST_GLOBS="${tddTestGlobs}"
163
169
 
164
170
  ${RUNTIME_SHELL_DETECT_ROOT}
165
171
 
166
172
  STATE_DIR="$ROOT/${RUNTIME_ROOT}/state"
167
173
  FLOW_STATE_FILE="$STATE_DIR/flow-state.json"
174
+ TDD_LOG_FILE="$STATE_DIR/tdd-cycle-log.jsonl"
168
175
  GUARD_STATE_FILE="$STATE_DIR/workflow-guard.json"
169
176
  GUARD_LOG="$STATE_DIR/workflow-guard.jsonl"
170
177
  mkdir -p "$STATE_DIR" 2>/dev/null || true
@@ -234,9 +241,11 @@ NOW_EPOCH=$(date +%s 2>/dev/null || echo "0")
234
241
  REASONS=""
235
242
 
236
243
  CURRENT_STAGE="none"
244
+ CURRENT_RUN="active"
237
245
  if [ -f "$FLOW_STATE_FILE" ]; then
238
246
  if command -v jq >/dev/null 2>&1; then
239
247
  CURRENT_STAGE=$(jq -r '.currentStage // "none"' "$FLOW_STATE_FILE" 2>/dev/null || echo "none")
248
+ CURRENT_RUN=$(jq -r '.activeRunId // "active"' "$FLOW_STATE_FILE" 2>/dev/null || echo "active")
240
249
  elif command -v python3 >/dev/null 2>&1; then
241
250
  CURRENT_STAGE=$(python3 - "$FLOW_STATE_FILE" <<'PY'
242
251
  import json
@@ -252,6 +261,21 @@ except Exception:
252
261
  pass
253
262
  print(stage)
254
263
  PY
264
+ )
265
+ CURRENT_RUN=$(python3 - "$FLOW_STATE_FILE" <<'PY'
266
+ import json
267
+ import sys
268
+ run_id = "active"
269
+ try:
270
+ with open(sys.argv[1], "r", encoding="utf-8") as fh:
271
+ parsed = json.load(fh)
272
+ value = parsed.get("activeRunId")
273
+ if isinstance(value, str) and value:
274
+ run_id = value
275
+ except Exception:
276
+ pass
277
+ print(run_id)
278
+ PY
255
279
  )
256
280
  fi
257
281
  fi
@@ -325,6 +349,99 @@ is_preimplementation_stage() {
325
349
  esac
326
350
  }
327
351
 
352
+ is_tdd_test_payload() {
353
+ local text="$1"
354
+ if printf '%s' "$text" | grep -Eq '/tests?/|\\.test\\.|\\.spec\\.'; then
355
+ return 0
356
+ fi
357
+ if printf '%s' "$TDD_TEST_GLOBS" | grep -Eq '.' && printf '%s' "$text" | grep -Eq '(test|spec)'; then
358
+ return 0
359
+ fi
360
+ return 1
361
+ }
362
+
363
+ is_tdd_runtime_write_payload() {
364
+ local text="$1"
365
+ if printf '%s' "$text" | grep -Eq '\\.cclaw/'; then
366
+ return 1
367
+ fi
368
+ if ! printf '%s' "$text" | grep -Eq '\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|rb|php|cs|swift)'; then
369
+ return 1
370
+ fi
371
+ if is_tdd_test_payload "$text"; then
372
+ return 1
373
+ fi
374
+ return 0
375
+ }
376
+
377
+ has_open_red_cycle() {
378
+ if [ ! -f "$TDD_LOG_FILE" ] || [ ! -s "$TDD_LOG_FILE" ]; then
379
+ return 1
380
+ fi
381
+ local red_count="0"
382
+ local green_count="0"
383
+ if command -v jq >/dev/null 2>&1; then
384
+ red_count=$(jq -r --arg run "$CURRENT_RUN" 'select((.runId // $run) == $run and .phase == "red") | .phase' "$TDD_LOG_FILE" 2>/dev/null | wc -l | tr -d ' ' || echo "0")
385
+ green_count=$(jq -r --arg run "$CURRENT_RUN" 'select((.runId // $run) == $run and .phase == "green") | .phase' "$TDD_LOG_FILE" 2>/dev/null | wc -l | tr -d ' ' || echo "0")
386
+ elif command -v python3 >/dev/null 2>&1; then
387
+ red_count=$(python3 - "$TDD_LOG_FILE" "$CURRENT_RUN" <<'PY'
388
+ import json
389
+ import sys
390
+ count = 0
391
+ run_id = sys.argv[2]
392
+ with open(sys.argv[1], "r", encoding="utf-8") as fh:
393
+ for raw in fh:
394
+ raw = raw.strip()
395
+ if not raw:
396
+ continue
397
+ try:
398
+ parsed = json.loads(raw)
399
+ except Exception:
400
+ continue
401
+ if not isinstance(parsed, dict):
402
+ continue
403
+ if str(parsed.get("runId", run_id)) != run_id:
404
+ continue
405
+ if parsed.get("phase") == "red":
406
+ count += 1
407
+ print(count)
408
+ PY
409
+ )
410
+ green_count=$(python3 - "$TDD_LOG_FILE" "$CURRENT_RUN" <<'PY'
411
+ import json
412
+ import sys
413
+ count = 0
414
+ run_id = sys.argv[2]
415
+ with open(sys.argv[1], "r", encoding="utf-8") as fh:
416
+ for raw in fh:
417
+ raw = raw.strip()
418
+ if not raw:
419
+ continue
420
+ try:
421
+ parsed = json.loads(raw)
422
+ except Exception:
423
+ continue
424
+ if not isinstance(parsed, dict):
425
+ continue
426
+ if str(parsed.get("runId", run_id)) != run_id:
427
+ continue
428
+ if parsed.get("phase") == "green":
429
+ count += 1
430
+ print(count)
431
+ PY
432
+ )
433
+ else
434
+ red_count=$(grep -ci '"phase"[[:space:]]*:[[:space:]]*"red"' "$TDD_LOG_FILE" 2>/dev/null || echo "0")
435
+ green_count=$(grep -ci '"phase"[[:space:]]*:[[:space:]]*"green"' "$TDD_LOG_FILE" 2>/dev/null || echo "0")
436
+ fi
437
+ [ -n "$red_count" ] || red_count="0"
438
+ [ -n "$green_count" ] || green_count="0"
439
+ if [ "$red_count" -gt "$green_count" ]; then
440
+ return 0
441
+ fi
442
+ return 1
443
+ }
444
+
328
445
  detect_target_stage() {
329
446
  local text="$1"
330
447
  for stage in brainstorm scope design spec plan tdd review ship; do
@@ -373,6 +490,18 @@ if is_preimplementation_stage "$CURRENT_STAGE" && is_mutating_tool "$TOOL_LOWER"
373
490
  fi
374
491
  fi
375
492
 
493
+ if [ "$CURRENT_STAGE" = "tdd" ] && is_mutating_tool "$TOOL_LOWER"; then
494
+ if is_tdd_runtime_write_payload "$PAYLOAD_LOWER"; then
495
+ if ! has_open_red_cycle; then
496
+ if [ -n "$REASONS" ]; then
497
+ REASONS="$REASONS,tdd_write_without_open_red"
498
+ else
499
+ REASONS="tdd_write_without_open_red"
500
+ fi
501
+ fi
502
+ fi
503
+ fi
504
+
376
505
  if is_preimplementation_stage "$CURRENT_STAGE" && ! is_plan_mode_safe_tool "$TOOL_LOWER"; then
377
506
  if ! is_mutating_tool "$TOOL_LOWER"; then
378
507
  if ! printf '%s' "$PAYLOAD_LOWER" | grep -Eq '\.cclaw/' && ! is_cclaw_cli_payload "$PAYLOAD_LOWER"; then
@@ -438,7 +567,7 @@ PY
438
567
  fi
439
568
 
440
569
  if [ -n "$REASONS" ]; then
441
- NOTE="Cclaw workflow guard: detected potential flow violation (\${REASONS}). Re-read ${RUNTIME_ROOT}/state/flow-state.json, avoid source edits before tdd stage, and continue from current stage ordering."
570
+ NOTE="Cclaw workflow guard: detected potential flow violation (\${REASONS}). Re-read ${RUNTIME_ROOT}/state/flow-state.json, avoid source edits before tdd stage, and enforce RED -> GREEN -> REFACTOR discipline inside tdd."
442
571
  if command -v jq >/dev/null 2>&1; then
443
572
  ENTRY=$(jq -n -c \
444
573
  --arg ts "$TS" \
@@ -458,6 +587,9 @@ if [ -n "$REASONS" ]; then
458
587
  if printf '%s' "$REASONS" | grep -Eq 'implementation_write_before_'; then
459
588
  SHOULD_BLOCK="true"
460
589
  fi
590
+ if printf '%s' "$REASONS" | grep -Eq 'tdd_write_without_open_red' && [ "$TDD_ENFORCEMENT_MODE" = "strict" ]; then
591
+ SHOULD_BLOCK="true"
592
+ fi
461
593
  if [ "$WORKFLOW_GUARD_MODE" = "strict" ] || [ "$SHOULD_BLOCK" = "true" ]; then
462
594
  printf '[cclaw] %s (blocked by workflow guard)\n' "$NOTE" >&2
463
595
  exit 1
@@ -0,0 +1,2 @@
1
+ export declare function opsCommandContract(): string;
2
+ export declare function opsCommandSkillMarkdown(): string;
@@ -0,0 +1,60 @@
1
+ import { RUNTIME_ROOT } from "../constants.js";
2
+ const OPS_SKILL_FOLDER = "flow-ops";
3
+ const OPS_SKILL_NAME = "flow-ops";
4
+ export function opsCommandContract() {
5
+ return `# /cc-ops
6
+
7
+ ## Purpose
8
+
9
+ Unified operational command surface for non-stage flow actions.
10
+
11
+ Subcommands:
12
+ - \`feature\` -> \`/cc-feature\`
13
+ - \`tdd-log\` -> \`/cc-tdd-log\`
14
+ - \`retro\` -> \`/cc-retro\`
15
+ - \`archive\` -> \`/cc-archive\`
16
+ - \`rewind\` -> \`/cc-rewind\`
17
+ - \`rewind-ack\` -> \`/cc-rewind-ack\`
18
+
19
+ ## HARD-GATE
20
+
21
+ - \`/cc-ops\` is a routing wrapper; execute only one target subcommand per call.
22
+ - Preserve target command safety contracts (retro gate, archive gate, rewind atomicity, etc.).
23
+
24
+ ## Routing
25
+
26
+ 1. Parse required subcommand token.
27
+ 2. Dispatch:
28
+ - \`feature\` -> \`${RUNTIME_ROOT}/commands/feature.md\`
29
+ - \`tdd-log\` -> \`${RUNTIME_ROOT}/commands/tdd-log.md\`
30
+ - \`retro\` -> \`${RUNTIME_ROOT}/commands/retro.md\`
31
+ - \`archive\` -> \`${RUNTIME_ROOT}/commands/archive.md\`
32
+ - \`rewind\` -> \`${RUNTIME_ROOT}/commands/rewind.md\`
33
+ - \`rewind-ack\` -> \`${RUNTIME_ROOT}/commands/rewind-ack.md\`
34
+ 3. Unknown subcommand -> print supported values and stop.
35
+
36
+ ## Primary skill
37
+
38
+ **${RUNTIME_ROOT}/skills/${OPS_SKILL_FOLDER}/SKILL.md**
39
+ `;
40
+ }
41
+ export function opsCommandSkillMarkdown() {
42
+ return `---
43
+ name: ${OPS_SKILL_NAME}
44
+ description: "Unified operational router for feature/tdd-log/retro/archive/rewind commands."
45
+ ---
46
+
47
+ # /cc-ops
48
+
49
+ ## HARD-GATE
50
+
51
+ This wrapper only dispatches. It must not apply state mutations itself.
52
+
53
+ ## Protocol
54
+
55
+ 1. Require a subcommand (\`feature|tdd-log|retro|archive|rewind|rewind-ack\`).
56
+ 2. Route to the matching command contract + skill pair.
57
+ 3. Preserve pass-through args after the subcommand (e.g. \`/cc-ops rewind design\`).
58
+ 4. Echo which subcommand was dispatched for auditability.
59
+ `;
60
+ }
@@ -46,8 +46,20 @@ Shared closeout sequence applied by every stage skill.
46
46
  - update \`guardEvidence\`.
47
47
  3. Persist stage artifact under \`.cclaw/artifacts/\`.
48
48
  4. Run \`npx cclaw doctor\` and resolve failures.
49
- 5. Notify user with stage completion and next action (\`/cc-next\`).
50
- 6. Stop; do not auto-run the next stage unless user asks.
49
+ 5. Capture reusable learnings from this stage artifact:
50
+ - append 1-3 strict-schema JSONL entries when the stage produced non-obvious
51
+ decisions, patterns, or lessons,
52
+ - use \`type=rule|pattern|lesson\` (\`compound\` stays retro-focused).
53
+ 6. Notify user with stage completion and next action (\`/cc-next\`).
54
+ 7. Stop; do not auto-run the next stage unless user asks.
55
+
56
+ ## Automatic learning capture policy
57
+
58
+ - \`standard\` / \`medium\` tracks: required for \`design\`, \`tdd\`, and \`review\`;
59
+ recommended for other stages.
60
+ - \`quick\` track: recommended only (avoid overhead for tiny fixes).
61
+ - "No learning captured" is acceptable only when explicitly justified (e.g. pure
62
+ mechanical change, no new trade-offs).
51
63
 
52
64
  ## Resume protocol
53
65
 
@@ -0,0 +1,2 @@
1
+ export declare function retroCommandContract(): string;
2
+ export declare function retroCommandSkillMarkdown(): string;
@@ -0,0 +1,77 @@
1
+ import { RUNTIME_ROOT } from "../constants.js";
2
+ const RETRO_SKILL_FOLDER = "flow-retro";
3
+ const RETRO_SKILL_NAME = "flow-retro";
4
+ function flowStatePath() {
5
+ return `${RUNTIME_ROOT}/state/flow-state.json`;
6
+ }
7
+ function retroArtifactPath() {
8
+ return `${RUNTIME_ROOT}/artifacts/09-retro.md`;
9
+ }
10
+ function knowledgePath() {
11
+ return `${RUNTIME_ROOT}/knowledge.jsonl`;
12
+ }
13
+ export function retroCommandContract() {
14
+ return `# /cc-retro
15
+
16
+ ## Purpose
17
+
18
+ Mandatory retrospective gate before archive once ship is complete.
19
+
20
+ ## HARD-GATE
21
+
22
+ - Do not mark retro complete without writing \`${retroArtifactPath()}\`.
23
+ - Do not finish retro without appending at least one \`type=compound\` entry into \`${knowledgePath()}\`.
24
+
25
+ ## Algorithm
26
+
27
+ 1. Read \`${flowStatePath()}\`; confirm ship stage is complete for current run.
28
+ 2. Synthesize retrospective artifact \`${retroArtifactPath()}\` with:
29
+ - what slowed this run
30
+ - what accelerated this run
31
+ - concrete repeatable rule for next run
32
+ 3. Append >=1 strict-schema JSONL entry to \`${knowledgePath()}\` with:
33
+ - \`type: "compound"\`
34
+ - \`stage: "ship"\` or \`"retro"\`
35
+ 4. Update flow-state \`retro\` block:
36
+ - \`required: true\`
37
+ - \`completedAt: <ISO>\`
38
+ - \`compoundEntries: <count>\`
39
+ 5. Report completion summary and remind user that \`/cc-archive\` is now unblocked.
40
+
41
+ ## Primary skill
42
+
43
+ **${RUNTIME_ROOT}/skills/${RETRO_SKILL_FOLDER}/SKILL.md**
44
+ `;
45
+ }
46
+ export function retroCommandSkillMarkdown() {
47
+ return `---
48
+ name: ${RETRO_SKILL_NAME}
49
+ description: "Run mandatory retrospective and record compound knowledge before archive."
50
+ ---
51
+
52
+ # /cc-retro
53
+
54
+ ## HARD-GATE
55
+
56
+ Archive must remain blocked until retro artifact exists and compound knowledge was appended.
57
+
58
+ ## Protocol
59
+
60
+ 1. Confirm ship completion from \`${flowStatePath()}\`.
61
+ 2. Create/update \`${retroArtifactPath()}\` with concise retrospective sections:
62
+ - outcomes
63
+ - bottlenecks
64
+ - reusable acceleration patterns
65
+ 3. Append at least one \`compound\` knowledge entry into \`${knowledgePath()}\`.
66
+ 4. Update \`flow-state.json.retro\` with completion timestamp + compound count.
67
+ 5. Print explicit completion line:
68
+ - \`retro gate: complete\`
69
+ - \`compound entries added: <N>\`
70
+
71
+ ## Validation
72
+
73
+ - \`${retroArtifactPath()}\` exists and is non-empty.
74
+ - \`${knowledgePath()}\` contains >=1 valid \`compound\` line.
75
+ - \`retro.completedAt\` is set in flow-state.
76
+ `;
77
+ }
@@ -0,0 +1,3 @@
1
+ export declare function rewindCommandContract(): string;
2
+ export declare function rewindAcknowledgeCommandContract(): string;
3
+ export declare function rewindCommandSkillMarkdown(): string;
@@ -0,0 +1,120 @@
1
+ import { RUNTIME_ROOT } from "../constants.js";
2
+ const REWIND_SKILL_FOLDER = "flow-rewind";
3
+ const REWIND_SKILL_NAME = "flow-rewind";
4
+ function flowStatePath() {
5
+ return `${RUNTIME_ROOT}/state/flow-state.json`;
6
+ }
7
+ function artifactsPath() {
8
+ return `${RUNTIME_ROOT}/artifacts`;
9
+ }
10
+ function rewindLogPath() {
11
+ return `${RUNTIME_ROOT}/state/rewind-log.jsonl`;
12
+ }
13
+ export function rewindCommandContract() {
14
+ return `# /cc-rewind
15
+
16
+ ## Purpose
17
+
18
+ Rewind active flow to an earlier stage and atomically invalidate downstream work.
19
+
20
+ ## HARD-GATE
21
+
22
+ - Never rewind without preserving downstream artifact history.
23
+ - Mark downstream stages as stale; do not leave completedStages pointing to invalidated work.
24
+ - Record a rewind reason in \`${rewindLogPath()}\`.
25
+
26
+ ## Inputs
27
+
28
+ \`/cc-rewind <target-stage> [reason]\`
29
+
30
+ ## Algorithm
31
+
32
+ 1. Read \`${flowStatePath()}\` and current track.
33
+ 2. Validate \`target-stage\` belongs to the active track and is not ahead of current stage.
34
+ 3. Compute downstream stages to invalidate (all stages after target that were completed or current).
35
+ 4. Archive downstream artifacts into \`${artifactsPath()}/_rewind-archive/<rewind-id>/\`.
36
+ 5. Rename active downstream artifacts to \`*.stale.md\`.
37
+ 6. Update flow-state:
38
+ - \`currentStage = target-stage\`
39
+ - trim \`completedStages\` to stages before target-stage
40
+ - clear gate evidence/catalog for target-stage and downstream
41
+ - mark downstream entries in \`staleStages\`
42
+ - append \`rewinds[]\` record
43
+ 7. Append JSON line to \`${rewindLogPath()}\`.
44
+
45
+ ## Output
46
+
47
+ - Rewind id
48
+ - from -> to stage
49
+ - Invalidated stages list
50
+ - Number of stale artifacts
51
+
52
+ ## Primary skill
53
+
54
+ **${RUNTIME_ROOT}/skills/${REWIND_SKILL_FOLDER}/SKILL.md**
55
+ `;
56
+ }
57
+ export function rewindAcknowledgeCommandContract() {
58
+ return `# /cc-rewind-ack
59
+
60
+ ## Purpose
61
+
62
+ Acknowledge and clear stale-stage markers after downstream work is intentionally redone.
63
+
64
+ ## Input
65
+
66
+ \`/cc-rewind-ack <stage>\`
67
+
68
+ ## HARD-GATE
69
+
70
+ - Only clear stale marker for the requested stage.
71
+ - Never modify completedStages from this command.
72
+
73
+ ## Algorithm
74
+
75
+ 1. Read \`${flowStatePath()}\`.
76
+ 2. If \`staleStages.<stage>\` is missing, report no-op.
77
+ 3. Remove \`staleStages.<stage>\`.
78
+ 4. Write updated flow-state.
79
+ 5. Print remaining stale stages (if any).
80
+
81
+ ## Primary skill
82
+
83
+ **${RUNTIME_ROOT}/skills/${REWIND_SKILL_FOLDER}/SKILL.md**
84
+ `;
85
+ }
86
+ export function rewindCommandSkillMarkdown() {
87
+ return `---
88
+ name: ${REWIND_SKILL_NAME}
89
+ description: "Rewind active flow stage safely and acknowledge stale invalidations."
90
+ ---
91
+
92
+ # /cc-rewind + /cc-rewind-ack
93
+
94
+ ## HARD-GATE
95
+
96
+ Rewind is an atomic state transition. Never leave flow-state half-updated (for example currentStage changed but stale markers/artifact archive missing).
97
+
98
+ ## Protocol
99
+
100
+ ### rewind
101
+ 1. Validate target stage belongs to current track and is upstream.
102
+ 2. Archive downstream artifacts under \`${artifactsPath()}/_rewind-archive/<rewind-id>/\`.
103
+ 3. Mark downstream artifacts as stale (\`*.stale.md\`).
104
+ 4. Reset downstream gate catalog and guard evidence.
105
+ 5. Record \`rewinds[]\` and \`staleStages\` in flow-state.
106
+ 6. Append rewind entry into \`${rewindLogPath()}\`.
107
+
108
+ ### rewind-ack
109
+ 1. Load flow-state stale map.
110
+ 2. Remove exactly one stale stage marker.
111
+ 3. Report remaining stale stages.
112
+
113
+ ## Validation checklist
114
+
115
+ - \`${flowStatePath()}\` remains valid JSON.
116
+ - \`currentStage\` equals requested rewind target.
117
+ - invalidated stages are absent from \`completedStages\`.
118
+ - archived copies exist for each moved artifact.
119
+ `;
120
+ }
@@ -1,5 +1,6 @@
1
1
  import { RUNTIME_ROOT } from "../constants.js";
2
2
  import { STAGE_EXAMPLES_REFERENCE_DIR, stageDomainExamples, stageExamples, stageGoodBadExamples } from "./examples.js";
3
+ import { selfImprovementBlock } from "./learnings.js";
3
4
  import { STAGE_COMMON_GUIDANCE_REL_PATH } from "./stage-common-guidance.js";
4
5
  import { stageAutoSubagentDispatch, stageSchema } from "./stage-schema.js";
5
6
  const VERIFICATION_STAGES = ["tdd", "review", "ship"];
@@ -377,6 +378,7 @@ ${mergedAntiPatterns(schema)}
377
378
  ## Verification
378
379
  ${schema.exitCriteria.map((item) => `- [ ] ${item}`).join("\n")}
379
380
 
381
+ ${selfImprovementBlock(schema.stage)}
380
382
  ${completionParametersBlock(schema)}
381
383
  ## Shared Stage Guidance
382
384
  See:
@@ -59,7 +59,8 @@ Rollback / fallback: <if decision proves wrong>
59
59
  ## Self-improvement reminder
60
60
 
61
61
  If a reusable lesson appears during the stage, append one strict-schema JSONL
62
- entry via \`/cc-learn add\`. Do not keep operational lessons only in chat.
62
+ entry (manually via \`/cc-learn add\` or directly in stage closeout protocol).
63
+ Do not keep operational lessons only in chat.
63
64
 
64
65
  ## Progressive disclosure baseline
65
66