cclaw-cli 0.12.0 → 0.13.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 (39) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +14 -1
  3. package/dist/config.js +19 -0
  4. package/dist/constants.d.ts +2 -2
  5. package/dist/constants.js +13 -1
  6. package/dist/content/diff-command.d.ts +2 -0
  7. package/dist/content/diff-command.js +83 -0
  8. package/dist/content/feature-command.d.ts +2 -0
  9. package/dist/content/feature-command.js +120 -0
  10. package/dist/content/harnesses-doc.js +8 -0
  11. package/dist/content/hooks.js +47 -1
  12. package/dist/content/meta-skill.js +3 -2
  13. package/dist/content/next-command.js +8 -6
  14. package/dist/content/observe.d.ts +5 -1
  15. package/dist/content/observe.js +134 -2
  16. package/dist/content/retro-command.d.ts +2 -0
  17. package/dist/content/retro-command.js +77 -0
  18. package/dist/content/rewind-command.d.ts +3 -0
  19. package/dist/content/rewind-command.js +120 -0
  20. package/dist/content/status-command.js +43 -35
  21. package/dist/content/tdd-log-command.d.ts +2 -0
  22. package/dist/content/tdd-log-command.js +75 -0
  23. package/dist/content/templates.js +35 -5
  24. package/dist/content/tree-command.d.ts +2 -0
  25. package/dist/content/tree-command.js +91 -0
  26. package/dist/doctor.js +149 -3
  27. package/dist/feature-system.d.ts +18 -0
  28. package/dist/feature-system.js +247 -0
  29. package/dist/flow-state.d.ts +25 -0
  30. package/dist/flow-state.js +8 -1
  31. package/dist/harness-adapters.js +74 -4
  32. package/dist/install.js +35 -2
  33. package/dist/policy.js +22 -0
  34. package/dist/runs.d.ts +33 -1
  35. package/dist/runs.js +365 -6
  36. package/dist/tdd-cycle.d.ts +22 -0
  37. package/dist/tdd-cycle.js +82 -0
  38. package/dist/types.d.ts +4 -0
  39. package/package.json +1 -1
@@ -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 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 \`cclaw 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
+ }
@@ -19,6 +19,9 @@ function checkpointPath() {
19
19
  function stageActivityPath() {
20
20
  return `${RUNTIME_ROOT}/state/stage-activity.jsonl`;
21
21
  }
22
+ function snapshotPath() {
23
+ return `${RUNTIME_ROOT}/state/flow-state.snapshot.json`;
24
+ }
22
25
  /**
23
26
  * Command contract for /cc-status — a read-only snapshot command.
24
27
  * Does not mutate state. Always safe to run.
@@ -30,8 +33,8 @@ export function statusCommandContract() {
30
33
 
31
34
  ## Purpose
32
35
 
33
- **Read-only snapshot of the cclaw run.** Shows track, current stage, completed stages,
34
- gate coverage, mandatory delegations, and the top 3 knowledge highlights.
36
+ **Read-only visual snapshot of the cclaw run.** Shows progress bar, current stage,
37
+ gate coverage, delegation status, stale markers, and top knowledge highlights.
35
38
 
36
39
  This command **never mutates state**. Use it at session start to orient, or at any
37
40
  time to answer "where are we?" without advancing the flow.
@@ -41,6 +44,7 @@ time to answer "where are we?" without advancing the flow.
41
44
  - **Do not** use \`/cc-status\` output to infer gate completion for decisions — cite
42
45
  artifact evidence via \`/cc-next\` when advancing.
43
46
  - **Do not** mutate \`${flowPath}\` or delegation log from this command.
47
+ - **Do not** rewrite \`${snapshotPath()}\` from this command (use \`/cc-diff\`).
44
48
 
45
49
  ## Algorithm
46
50
 
@@ -54,38 +58,32 @@ time to answer "where are we?" without advancing the flow.
54
58
  - Otherwise scan \`${stageActivityPath()}\` from the end for the first entry whose \`stage\` matches \`currentStage\` and use its \`ts\`.
55
59
  - Compute the duration as \`now - signalTimestamp\` and render compactly: \`<X>m\`, \`<X>h<Y>m\`, or \`<X>d<Y>h\`.
56
60
  - If no signal exists, render \`(unknown)\`.
57
- 5. Read the top of **\`${knowledgePath}\`** surface up to 3 most recent entries
61
+ 5. Optionally read **\`${snapshotPath()}\`** to compute gate delta versus prior baseline:
62
+ - If missing or invalid, render \`delta: (baseline unavailable; run /cc-diff)\`.
63
+ 6. Read the top of **\`${knowledgePath}\`** — surface up to 3 most recent entries
58
64
  (by trailing timestamp or source marker).
59
- 6. Emit the status block described below. Do **not** load any stage skill.
65
+ 7. Emit the visual status block described below. Do **not** load any stage skill.
66
+
67
+ ## Visual markers
68
+
69
+ Default UTF markers: \`✓\` passed, \`▶\` current, \`○\` pending, \`⊘\` skipped, \`⏸\` stale, \`✗\` blocked.
70
+ ASCII fallback (no UTF locale): \`[x]\`, \`[>]\`, \`[ ]\`, \`[-]\`, \`[=]\`, \`[!]\`.
60
71
 
61
72
  ## Status Block Format
62
73
 
63
74
  \`\`\`
64
75
  cclaw status
65
- track: <quick|standard>
66
- current stage: <stage> (<N>/<total> in track)
67
- time in stage: <Xd Yh | Yh Zm | Zm | unknown>
68
- context mode: <activeMode> (default | execution | review | incident | …)
69
- completed stages: <list or "none">
70
- skipped stages: <list or "none">
71
-
72
- gates:
73
- passed: <count> of <required>
74
- blocked: <count>
75
- unmet: <list of gate ids>
76
-
77
- delegations (current stage):
78
- required: <list>
79
- completed: <list>
80
- pending: <list>
81
-
82
- knowledge highlights:
83
- - <latest entry summary line>
84
- - <second entry summary line>
85
- - <third entry summary line>
86
-
87
- next action:
88
- /cc-next (advance or resume current stage)
76
+ flow: <track> · run=<runId> · feature=<feature-id>
77
+ stage: <stage> (<N>/<total>) · time <Xd|XhYm|Xm|unknown> · mode <activeMode>
78
+ bar: [✓ brainstorm] [✓ scope] [▶ design] [○ spec] [○ plan] [○ tdd] [○ review] [○ ship]
79
+ gates: now <passed>/<required> · blocked <count> · delta <summary or baseline-unavailable>
80
+ delegations: [✓ <role>] [○ <role>] ...
81
+ stale: <list or none>
82
+ knowledge:
83
+ - <latest entry summary>
84
+ - <second entry summary>
85
+ - <third entry summary>
86
+ next: /cc-next · /cc-tree · /cc-diff
89
87
  \`\`\`
90
88
 
91
89
  ## Anti-patterns
@@ -93,6 +91,7 @@ cclaw status
93
91
  - Inventing gate status without reading \`${flowPath}\`.
94
92
  - Reporting delegations as satisfied when the log says \`pending\`.
95
93
  - Advancing the stage from \`/cc-status\` — progression belongs to \`/cc-next\`.
94
+ - Hiding stale stages; stale markers must be surfaced directly in the status line.
96
95
 
97
96
  ## Primary skill
98
97
 
@@ -107,7 +106,7 @@ export function statusCommandSkillMarkdown() {
107
106
  const delegationPath = delegationLogPath();
108
107
  return `---
109
108
  name: ${STATUS_SKILL_NAME}
110
- description: "Read-only snapshot of the cclaw flow: track, stage, gate coverage, delegations, knowledge highlights. Never mutates state."
109
+ description: "Read-only visual snapshot of the cclaw flow with progress bar, gate delta, delegations, and stale markers."
111
110
  ---
112
111
 
113
112
  # /cc-status — Flow Status Snapshot
@@ -120,7 +119,7 @@ advancing or mutating anything. Safe to run at any point.
120
119
  ## HARD-GATE
121
120
 
122
121
  Do **not** mutate \`${flowPath}\` or \`${delegationPath}\` from this skill. This is
123
- a read-only command.
122
+ a read-only command. Do **not** update \`${snapshotPath()}\` here.
124
123
 
125
124
  ## Algorithm
126
125
 
@@ -131,19 +130,28 @@ a read-only command.
131
130
  - Prefer \`${checkpointPath()}\` when \`stage === currentStage\` and \`timestamp\` parses as ISO 8601.
132
131
  - Else scan \`${stageActivityPath()}\` from tail for the most recent entry whose \`stage === currentStage\`; use its \`ts\`.
133
132
  - Render \`<X>d<Y>h\`, \`<X>h<Y>m\`, \`<X>m\`, or \`(unknown)\`.
134
- 5. Read \`${RUNTIME_ROOT}/knowledge.jsonl\`. If missing or empty → knowledge highlights are \`(none recorded)\`. Parse each line as JSON and surface its \`trigger\`/\`action\`.
135
- 6. For each gate in \`stageGateCatalog[currentStage].required\`:
133
+ 5. Try reading \`${snapshotPath()}\` for gate delta:
134
+ - If available, compare current stage \`passed\` / \`blocked\` sets against baseline.
135
+ - If unavailable, render \`delta: (baseline unavailable; run /cc-diff)\`.
136
+ 6. Read \`${RUNTIME_ROOT}/knowledge.jsonl\`. If missing or empty → knowledge highlights are \`(none recorded)\`. Parse each line as JSON and surface its \`trigger\`/\`action\`.
137
+ 7. For each gate in \`stageGateCatalog[currentStage].required\`:
136
138
  - Satisfied if present in \`passed\` and absent from \`blocked\`.
137
- 7. Build and print the status block (see command contract for layout).
138
- 8. Suggest the next action:
139
+ 8. Build and print the visual status block:
140
+ - stage header
141
+ - one-line progress bar with per-stage markers
142
+ - gate summary + delta
143
+ - delegation row
144
+ - stale stage row
145
+ 9. Suggest the next action:
139
146
  - If current stage has unmet gates → \`/cc-next\` to resume.
140
147
  - If current stage is complete → \`/cc-next\` to advance (or report "Flow complete" if terminal).
141
148
 
142
149
  ## Output Guidelines
143
150
 
144
- - Keep output compact (≤ 25 lines) — status, not narrative.
151
+ - Keep output compact (≤ 30 lines) — status, not narrative.
145
152
  - Report counts, not full artifact contents.
146
153
  - If any data source is missing or corrupt, say so explicitly rather than guessing.
154
+ - Include \`/cc-tree\` for deep structure and \`/cc-diff\` for before/after map in the final line.
147
155
 
148
156
  ## Anti-patterns
149
157
 
@@ -0,0 +1,2 @@
1
+ export declare function tddLogCommandContract(): string;
2
+ export declare function tddLogCommandSkillMarkdown(): string;
@@ -0,0 +1,75 @@
1
+ import { RUNTIME_ROOT } from "../constants.js";
2
+ const TDD_LOG_SKILL_FOLDER = "tdd-cycle-log";
3
+ const TDD_LOG_SKILL_NAME = "tdd-cycle-log";
4
+ function logPath() {
5
+ return `${RUNTIME_ROOT}/state/tdd-cycle-log.jsonl`;
6
+ }
7
+ function flowStatePath() {
8
+ return `${RUNTIME_ROOT}/state/flow-state.json`;
9
+ }
10
+ export function tddLogCommandContract() {
11
+ return `# /cc-tdd-log
12
+
13
+ ## Purpose
14
+
15
+ Record explicit RED/GREEN/REFACTOR evidence used by workflow guard and doctor checks.
16
+
17
+ ## HARD-GATE
18
+
19
+ - Every implementation write in tdd must be preceded by a logged RED event.
20
+ - Use append-only JSONL at \`${logPath()}\`; never rewrite prior lines.
21
+
22
+ ## Subcommands
23
+
24
+ - \`/cc-tdd-log red <slice> <command> [note]\`
25
+ - \`/cc-tdd-log green <slice> <command> [note]\`
26
+ - \`/cc-tdd-log refactor <slice> <command> [note]\`
27
+ - \`/cc-tdd-log show\`
28
+
29
+ ## Log Schema
30
+
31
+ Each JSON line must include:
32
+ - \`ts\` (ISO timestamp)
33
+ - \`runId\` (from flow-state)
34
+ - \`stage\` (usually \`tdd\`)
35
+ - \`slice\` (e.g. \`S-1\`)
36
+ - \`phase\` (\`red\` | \`green\` | \`refactor\`)
37
+ - \`command\`
38
+ - optional: \`files\`, \`exitCode\`, \`note\`
39
+
40
+ ## Primary skill
41
+
42
+ **${RUNTIME_ROOT}/skills/${TDD_LOG_SKILL_FOLDER}/SKILL.md**
43
+ `;
44
+ }
45
+ export function tddLogCommandSkillMarkdown() {
46
+ return `---
47
+ name: ${TDD_LOG_SKILL_NAME}
48
+ description: "Append RED/GREEN/REFACTOR entries into tdd-cycle-log.jsonl for guard/doctor enforcement."
49
+ ---
50
+
51
+ # /cc-tdd-log
52
+
53
+ ## HARD-GATE
54
+
55
+ Do not fake RED evidence. A \`red\` entry must correspond to a failing test command.
56
+
57
+ ## Protocol
58
+
59
+ 1. Read \`${flowStatePath()}\` and capture \`activeRunId\` + \`currentStage\`.
60
+ 2. Build JSON entry:
61
+ - \`ts\`: now ISO
62
+ - \`runId\`: activeRunId
63
+ - \`stage\`: currentStage
64
+ - \`slice\`: user-provided slice id
65
+ - \`phase\`: red|green|refactor
66
+ - \`command\`: test command or refactor verification command
67
+ 3. Append one line to \`${logPath()}\`.
68
+ 4. \`show\`: print the last 20 lines grouped by slice.
69
+
70
+ ## Validation
71
+
72
+ - File remains valid JSONL (one JSON object per line).
73
+ - For each slice, first phase must be \`red\`.
74
+ `;
75
+ }
@@ -480,11 +480,41 @@ Execution rule: complete and verify each wave before starting the next wave.
480
480
  - SHIPPED | SHIPPED_WITH_EXCEPTIONS | BLOCKED
481
481
  - Exceptions (if any):
482
482
 
483
- ## Compound Step
484
- _Optional retrospective. The goal is to make the **next** feature faster, not to evaluate this one._
485
- _If you have nothing to add, write the explicit line: \`No compound insight this run.\`_
486
- - Insight: <one short line about what should accelerate the next run>
487
- - Action: append one strict-schema JSON line with \`"type":"compound"\` to \`.cclaw/knowledge.jsonl\` capturing the insight (fields: type, trigger, action, confidence, domain, stage, created, project)
483
+ ## Retro Gate Handoff
484
+ - Run \`/cc-retro\` before archive.
485
+ - Retro artifact path: \`.cclaw/artifacts/09-retro.md\`
486
+ - Archive remains blocked until retro gate is complete.
487
+ `,
488
+ "09-retro.md": `# Retro Artifact
489
+
490
+ ## Run Summary
491
+ - Flow track:
492
+ - Scope delivered:
493
+ - Main outcome:
494
+
495
+ ## Friction Log
496
+ | Category | What slowed us down | Evidence | Prevention rule |
497
+ |---|---|---|---|
498
+ | | | | |
499
+
500
+ ## Acceleration Log
501
+ | Category | What helped | Evidence | Reuse trigger |
502
+ |---|---|---|---|
503
+ | | | | |
504
+
505
+ ## Compound Decisions
506
+ | Insight | Trigger pattern | Action rule for next run |
507
+ |---|---|---|
508
+ | | | |
509
+
510
+ ## Knowledge Writes
511
+ - Compound entries appended to \`.cclaw/knowledge.jsonl\`: <N>
512
+ - Entry ids / timestamps:
513
+
514
+ ## Retro Completion
515
+ - RETRO_COMPLETE: yes
516
+ - Completed at (UTC):
517
+ - Notes:
488
518
  `
489
519
  };
490
520
  export const RULEBOOK_MARKDOWN = `# Cclaw Rulebook
@@ -0,0 +1,2 @@
1
+ export declare function treeCommandContract(): string;
2
+ export declare function treeCommandSkillMarkdown(): string;