cclaw-cli 0.48.24 → 0.48.26
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/dist/content/doctor-references.js +2 -1
- package/dist/content/hooks.d.ts +1 -0
- package/dist/content/hooks.js +30 -0
- package/dist/content/ideate-command.js +106 -53
- package/dist/content/meta-skill.js +15 -0
- package/dist/content/node-hooks.js +110 -15
- package/dist/content/observe.js +3 -5
- package/dist/content/skills.js +38 -6
- package/dist/content/stages/brainstorm.js +25 -6
- package/dist/content/stages/design.js +67 -30
- package/dist/content/stages/scope.js +34 -4
- package/dist/content/templates.js +33 -4
- package/dist/doctor.js +3 -2
- package/dist/install.js +4 -2
- package/package.json +1 -1
|
@@ -124,7 +124,8 @@ Reference docs for \`cclaw doctor\` checks.
|
|
|
124
124
|
|
|
125
125
|
Earlier releases relied on \`bash\` to execute generated shell hooks and on
|
|
126
126
|
\`python3\`/\`jq\` as JSON fallback parsers. Node-only mode removes both: hooks
|
|
127
|
-
dispatch through
|
|
127
|
+
dispatch through \`.cclaw/hooks/run-hook.cmd <hook-name>\` (which forwards to
|
|
128
|
+
Node), so these tools
|
|
128
129
|
are no longer part of the supported runtime contract.
|
|
129
130
|
|
|
130
131
|
## Typical fixes
|
package/dist/content/hooks.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function stageCompleteScript(): string;
|
|
2
|
+
export declare function runHookCmdScript(): string;
|
|
2
3
|
export { claudeHooksJsonWithObservation as claudeHooksJson } from "./observe.js";
|
|
3
4
|
export { cursorHooksJsonWithObservation as cursorHooksJson } from "./observe.js";
|
|
4
5
|
export { codexHooksJsonWithObservation as codexHooksJson } from "./observe.js";
|
package/dist/content/hooks.js
CHANGED
|
@@ -120,6 +120,36 @@ async function main() {
|
|
|
120
120
|
void main();
|
|
121
121
|
`;
|
|
122
122
|
}
|
|
123
|
+
export function runHookCmdScript() {
|
|
124
|
+
return `: << 'CMDBLOCK'
|
|
125
|
+
@echo off
|
|
126
|
+
REM Cross-platform wrapper for cclaw Node hook runtime.
|
|
127
|
+
REM Windows executes this batch block; Unix shells treat it as a heredoc comment.
|
|
128
|
+
if "%~1"=="" (
|
|
129
|
+
echo [cclaw] run-hook.cmd: missing hook name >&2
|
|
130
|
+
exit /b 1
|
|
131
|
+
)
|
|
132
|
+
set "HOOK_DIR=%~dp0"
|
|
133
|
+
set "RUNTIME=%HOOK_DIR%run-hook.mjs"
|
|
134
|
+
where node >nul 2>nul
|
|
135
|
+
if %ERRORLEVEL% neq 0 (
|
|
136
|
+
REM Best-effort: missing node should not block harness execution loops.
|
|
137
|
+
exit /b 0
|
|
138
|
+
)
|
|
139
|
+
node "%RUNTIME%" %*
|
|
140
|
+
exit /b %ERRORLEVEL%
|
|
141
|
+
CMDBLOCK
|
|
142
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
143
|
+
if [ "$#" -lt 1 ]; then
|
|
144
|
+
echo "[cclaw] run-hook.cmd: missing hook name" >&2
|
|
145
|
+
exit 1
|
|
146
|
+
fi
|
|
147
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
148
|
+
exit 0
|
|
149
|
+
fi
|
|
150
|
+
exec node "\${SCRIPT_DIR}/run-hook.mjs" "$@"
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
123
153
|
export { claudeHooksJsonWithObservation as claudeHooksJson } from "./observe.js";
|
|
124
154
|
export { cursorHooksJsonWithObservation as cursorHooksJson } from "./observe.js";
|
|
125
155
|
export { codexHooksJsonWithObservation as codexHooksJson } from "./observe.js";
|
|
@@ -43,19 +43,26 @@ same session, or save/discard the backlog.
|
|
|
43
43
|
1. **Resume check.** Glob \`${IDEATE_ARTIFACT_GLOB}\`. If any artifact
|
|
44
44
|
has been modified within the last ${IDEATE_RESUME_WINDOW_DAYS} days,
|
|
45
45
|
offer the user: continue that backlog, start fresh, or cancel.
|
|
46
|
-
2. **
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
4
|
|
56
|
-
|
|
46
|
+
2. **Mode classification.** Explicitly classify subject:
|
|
47
|
+
\`repo-grounded\` / \`elsewhere-software\` / \`elsewhere-non-software\`.
|
|
48
|
+
Do not assume repo-grounded by default.
|
|
49
|
+
3. **Mode-aware grounding (parallel).**
|
|
50
|
+
- Repo-grounded: repo signal scan + \`${RUNTIME_ROOT}/knowledge.jsonl\`
|
|
51
|
+
repetition scan.
|
|
52
|
+
- Elsewhere-software: docs-first grounding (Context7 and official docs).
|
|
53
|
+
- Elsewhere-non-software: constraints and objective grounding.
|
|
54
|
+
4. **Divergent ideation frames (parallel).** Generate candidates with at least
|
|
55
|
+
4 distinct frames: pain/friction, inversion, assumption-break, leverage,
|
|
56
|
+
cross-domain analogy, constraint-flip.
|
|
57
|
+
5. **Adversarial critique pass.** For each candidate, write the strongest
|
|
58
|
+
counter-argument, kill weak ideas, and keep survivors only.
|
|
59
|
+
6. **Produce 5-10 survivors** with impact (High/Medium/Low),
|
|
60
|
+
effort (S/M/L), confidence (High/Medium/Low), and one evidence path per
|
|
61
|
+
survivor.
|
|
62
|
+
7. **Rank by impact/effort**, recommend the top survivor.
|
|
63
|
+
8. **Write the artifact** at
|
|
57
64
|
\`${IDEATE_ARTIFACT_PATTERN}\` using the schema in the skill.
|
|
58
|
-
|
|
65
|
+
9. **Present the handoff prompt** with four concrete options — not A/B/C
|
|
59
66
|
letters. Default = "Start /cc on the top recommendation".
|
|
60
67
|
|
|
61
68
|
## Headless mode
|
|
@@ -99,7 +106,7 @@ repository. Will persist a ranked backlog to
|
|
|
99
106
|
|
|
100
107
|
## Protocol
|
|
101
108
|
|
|
102
|
-
### Phase 0 — Resume
|
|
109
|
+
### Phase 0 — Resume and classify
|
|
103
110
|
|
|
104
111
|
1. Use the harness's file-glob tool (\`Glob\` pattern
|
|
105
112
|
\`${IDEATE_ARTIFACT_GLOB}\` or equivalent \`ls\`/\`find\`).
|
|
@@ -112,57 +119,102 @@ repository. Will persist a ranked backlog to
|
|
|
112
119
|
on disk for history.
|
|
113
120
|
- **Cancel** — stop; do not scan or write anything.
|
|
114
121
|
4. If no recent artifact exists, proceed to Phase 1 silently.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
122
|
+
5. Classify the ideation mode before grounding:
|
|
123
|
+
- \`repo-grounded\` — explicitly tied to this repository.
|
|
124
|
+
- \`elsewhere-software\` — software problem not tied to this repository.
|
|
125
|
+
- \`elsewhere-non-software\` — process/business/non-software problem.
|
|
126
|
+
6. Record the chosen mode in the artifact.
|
|
127
|
+
|
|
128
|
+
### Phase 1 — Mode-aware grounding
|
|
129
|
+
|
|
130
|
+
Run grounding in parallel where available:
|
|
131
|
+
|
|
132
|
+
- For \`repo-grounded\`:
|
|
133
|
+
- \`rg -n 'TODO|FIXME|XXX|HACK|TBD'\` grouped by file.
|
|
134
|
+
- Test-runner output (\`npm test\`, \`pytest\`, \`go test ./...\`) — note
|
|
135
|
+
failures, timeouts, deprecation warnings.
|
|
136
|
+
- Module size outliers (\`wc -l\` or \`du\`) with weak direct test coverage.
|
|
137
|
+
- Docs drift: check that \`README.md\` / \`docs/\` reference files that still
|
|
138
|
+
exist and flags/APIs that still match \`src/\`.
|
|
139
|
+
- \`${RUNTIME_ROOT}/knowledge.jsonl\` entries with \`type: "heuristic"\`
|
|
140
|
+
or repeated \`subject:\` values.
|
|
141
|
+
- For \`elsewhere-software\`:
|
|
142
|
+
- Gather current framework/library docs first.
|
|
143
|
+
- Add one comparison scan for established solutions.
|
|
144
|
+
- For \`elsewhere-non-software\`:
|
|
145
|
+
- Capture objective, constraints, and measured friction before proposing fixes.
|
|
146
|
+
|
|
147
|
+
Record each finding with exact evidence (path, command, or doc source).
|
|
148
|
+
|
|
149
|
+
### Phase 2 — Divergent ideation
|
|
150
|
+
|
|
151
|
+
Generate candidate ideas by frame, in parallel when possible:
|
|
152
|
+
|
|
153
|
+
- pain/friction
|
|
154
|
+
- inversion
|
|
155
|
+
- assumption-break
|
|
156
|
+
- leverage
|
|
157
|
+
- cross-domain analogy
|
|
158
|
+
- constraint-flip
|
|
159
|
+
|
|
160
|
+
Require at least 4 distinct frames in every run. Avoid frame-collapse
|
|
161
|
+
(same idea rewritten 6 times). Keep raw outputs for auditability.
|
|
162
|
+
|
|
163
|
+
### Phase 3 — Critique all, keep survivors
|
|
164
|
+
|
|
165
|
+
For each raw candidate:
|
|
166
|
+
|
|
167
|
+
- Write strongest argument **against** this idea.
|
|
168
|
+
- Identify disqualifiers (duplicate, weak evidence, poor ROI, wrong timing).
|
|
169
|
+
- Mark as \`survivor\` or \`critiqued-out\`.
|
|
170
|
+
|
|
171
|
+
Only survivors advance to ranking.
|
|
172
|
+
|
|
173
|
+
### Phase 4 — Rank and write the artifact
|
|
174
|
+
|
|
175
|
+
1. Keep 5–10 survivors.
|
|
176
|
+
2. For each survivor, include:
|
|
177
|
+
- **ID** — \`I-1\`, \`I-2\`, …
|
|
178
|
+
- **Title** — one short imperative phrase
|
|
179
|
+
- **Impact** — High / Medium / Low
|
|
180
|
+
- **Effort** — S / M / L
|
|
181
|
+
- **Confidence** — High / Medium / Low
|
|
182
|
+
- **Evidence** — path(s) or command output, inline if short
|
|
183
|
+
- **Counter-argument** — strongest concern that survived
|
|
184
|
+
- **Proposed handoff** — exact \`/cc <phrase>\`
|
|
185
|
+
3. Sort by impact/effort ratio; break ties with confidence.
|
|
186
|
+
4. Compute the artifact filename:
|
|
150
187
|
- \`slug\` = first 3–5 words of the top recommendation, lowercase,
|
|
151
188
|
non-alphanumeric collapsed to \`-\`, trimmed. When ideate mode is
|
|
152
189
|
focus-hinted (user passed an argument), use the focus hint instead.
|
|
153
190
|
- \`date\` = today in \`YYYY-MM-DD\` (local time).
|
|
154
191
|
- Path = \`.cclaw/artifacts/ideate-<date>-<slug>.md\`.
|
|
155
|
-
|
|
192
|
+
5. Use the harness's write-file tool (\`Write\`, \`apply_patch\`, or shell
|
|
156
193
|
\`cat <<EOF > path\`) to create the artifact with this schema:
|
|
157
194
|
|
|
158
195
|
\`\`\`markdown
|
|
159
196
|
# Ideation — <date>
|
|
160
197
|
|
|
161
198
|
**Focus:** <user-supplied focus or "open-ended scan">
|
|
199
|
+
**Mode:** <repo-grounded | elsewhere-software | elsewhere-non-software>
|
|
162
200
|
**Generated:** <ISO-8601 timestamp>
|
|
201
|
+
**Frames used:** <comma-separated list>
|
|
202
|
+
**Raw candidates:** <N>
|
|
203
|
+
**Critiqued out:** <M>
|
|
163
204
|
**Recommendation:** I-1
|
|
164
205
|
|
|
165
|
-
##
|
|
206
|
+
## Grounding evidence
|
|
207
|
+
|
|
208
|
+
- <signal and evidence>
|
|
209
|
+
- ...
|
|
210
|
+
|
|
211
|
+
## Critiqued out
|
|
212
|
+
|
|
213
|
+
| Idea | Why it was rejected |
|
|
214
|
+
|---|---|
|
|
215
|
+
| ... | ... |
|
|
216
|
+
|
|
217
|
+
## Ranked survivors
|
|
166
218
|
|
|
167
219
|
| ID | Improvement | Impact | Effort | Confidence | Evidence |
|
|
168
220
|
|---|---|---|---|---|---|
|
|
@@ -173,14 +225,15 @@ Aim for 5–10 candidates. Do not invent candidates without evidence.
|
|
|
173
225
|
|
|
174
226
|
### I-1 — Fix feature-worktree test timeouts
|
|
175
227
|
- **Evidence:** \`npm test\` hangs 40s on tests/unit/feature-system.test.ts:31.
|
|
228
|
+
- **Counter-argument:** Fix may hide deeper orchestration race.
|
|
176
229
|
- **Handoff:** \`/cc Fix feature-worktree test timeouts on macOS\`
|
|
177
230
|
|
|
178
231
|
### I-2 — …
|
|
179
232
|
\`\`\`
|
|
180
233
|
|
|
181
|
-
|
|
234
|
+
6. Confirm in chat: "Wrote <path>."
|
|
182
235
|
|
|
183
|
-
### Phase
|
|
236
|
+
### Phase 5 — Handoff prompt
|
|
184
237
|
|
|
185
238
|
Present **one** structured ask using the harness's native tool
|
|
186
239
|
(${STRUCTURED_ASK_TOOLS}). Each option must name the concrete follow-up —
|
|
@@ -201,7 +254,7 @@ Required options, in this order:
|
|
|
201
254
|
When the structured-ask tool is unavailable, fall back to a plain-text
|
|
202
255
|
lettered list with the same four labels. Do not invent extra options.
|
|
203
256
|
|
|
204
|
-
### Phase
|
|
257
|
+
### Phase 6 — Execute the choice
|
|
205
258
|
|
|
206
259
|
- **Start /cc on I-1** or **different candidate:** announce
|
|
207
260
|
"Handing off to /cc <phrase>" and load the \`using-cclaw\` router
|
|
@@ -40,6 +40,15 @@ If the current stage is ambiguous because \`flow-state.json\` is missing
|
|
|
40
40
|
or corrupt, stop and route through \`/cc\` before any substantive
|
|
41
41
|
response.
|
|
42
42
|
|
|
43
|
+
## Red Flags (stop and re-route)
|
|
44
|
+
|
|
45
|
+
If you think any of these, stop and follow the routing flow:
|
|
46
|
+
|
|
47
|
+
- "This looks simple, I can skip the stage." -> No. Route through \`/cc\`.
|
|
48
|
+
- "I can answer from memory without loading the active stage skill." -> No. Load the skill first.
|
|
49
|
+
- "Hook guard warned, but I can ignore it." -> No. Resolve the warning before continuing.
|
|
50
|
+
- "I'll edit \`.cclaw/state\` directly to move faster." -> No. Use managed commands only.
|
|
51
|
+
|
|
43
52
|
## Routing flow
|
|
44
53
|
|
|
45
54
|
\`\`\`
|
|
@@ -72,6 +81,12 @@ Before stage work:
|
|
|
72
81
|
2. If active stage exists, continue with \`/cc\` or \`/cc-next\`.
|
|
73
82
|
3. Do not jump directly to stage-specific commands.
|
|
74
83
|
|
|
84
|
+
## Platform reliability notes
|
|
85
|
+
|
|
86
|
+
- Managed hook dispatch uses \`.cclaw/hooks/run-hook.cmd\` (cross-platform wrapper).
|
|
87
|
+
- If hooks fail due missing runtime deps (for example \`node\` not on \`PATH\`), run \`cclaw doctor\` before continuing.
|
|
88
|
+
- Prefer cross-platform commands in artifacts/examples (\`npm test\`, \`pnpm test\`, \`python -m pytest\`, etc.) over shell-specific aliases whenever possible.
|
|
89
|
+
|
|
75
90
|
## Stage quick map
|
|
76
91
|
|
|
77
92
|
brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship
|
|
@@ -307,10 +307,12 @@ async function readStdin() {
|
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
async function runCclawInternal(root, args) {
|
|
310
|
+
async function runCclawInternal(root, args, options = {}) {
|
|
311
311
|
return await new Promise((resolve) => {
|
|
312
312
|
const isWindows = process.platform === "win32";
|
|
313
|
+
const captureStdout = options && options.captureStdout === true;
|
|
313
314
|
let settled = false;
|
|
315
|
+
let stdout = "";
|
|
314
316
|
let stderr = "";
|
|
315
317
|
const finalize = (value) => {
|
|
316
318
|
if (settled) return;
|
|
@@ -325,18 +327,27 @@ async function runCclawInternal(root, args) {
|
|
|
325
327
|
{
|
|
326
328
|
cwd: root,
|
|
327
329
|
env: process.env,
|
|
328
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
330
|
+
stdio: ["ignore", captureStdout ? "pipe" : "ignore", "pipe"]
|
|
329
331
|
}
|
|
330
332
|
);
|
|
331
333
|
} catch (error) {
|
|
332
334
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
333
335
|
finalize({
|
|
334
336
|
code: 1,
|
|
337
|
+
stdout,
|
|
335
338
|
stderr,
|
|
336
339
|
missingBinary: code === "ENOENT" || (isWindows && code === "EINVAL")
|
|
337
340
|
});
|
|
338
341
|
return;
|
|
339
342
|
}
|
|
343
|
+
if (captureStdout) {
|
|
344
|
+
child.stdout?.on("data", (chunk) => {
|
|
345
|
+
stdout += String(chunk ?? "");
|
|
346
|
+
if (stdout.length > 16000) {
|
|
347
|
+
stdout = stdout.slice(-16000);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
340
351
|
child.stderr?.on("data", (chunk) => {
|
|
341
352
|
stderr += String(chunk ?? "");
|
|
342
353
|
if (stderr.length > 8000) {
|
|
@@ -347,6 +358,7 @@ async function runCclawInternal(root, args) {
|
|
|
347
358
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
348
359
|
finalize({
|
|
349
360
|
code: 1,
|
|
361
|
+
stdout,
|
|
350
362
|
stderr,
|
|
351
363
|
missingBinary: code === "ENOENT" || (isWindows && code === "EINVAL")
|
|
352
364
|
});
|
|
@@ -355,6 +367,7 @@ async function runCclawInternal(root, args) {
|
|
|
355
367
|
if (signal) {
|
|
356
368
|
finalize({
|
|
357
369
|
code: 1,
|
|
370
|
+
stdout,
|
|
358
371
|
stderr,
|
|
359
372
|
missingBinary: false
|
|
360
373
|
});
|
|
@@ -366,6 +379,7 @@ async function runCclawInternal(root, args) {
|
|
|
366
379
|
: false;
|
|
367
380
|
finalize({
|
|
368
381
|
code: typeof code === "number" ? code : 1,
|
|
382
|
+
stdout,
|
|
369
383
|
stderr,
|
|
370
384
|
missingBinary
|
|
371
385
|
});
|
|
@@ -380,6 +394,32 @@ function detectHarness(env) {
|
|
|
380
394
|
return "codex";
|
|
381
395
|
}
|
|
382
396
|
|
|
397
|
+
function hookEventNameForOutput(hookName) {
|
|
398
|
+
if (hookName === "session-start") return "SessionStart";
|
|
399
|
+
if (hookName === "prompt-guard") return "PreToolUse";
|
|
400
|
+
if (hookName === "workflow-guard") return "PreToolUse";
|
|
401
|
+
if (hookName === "context-monitor") return "PostToolUse";
|
|
402
|
+
if (hookName === "stop-checkpoint") return "Stop";
|
|
403
|
+
if (hookName === "pre-compact") return "PreCompact";
|
|
404
|
+
if (hookName === "verify-current-state") return "UserPromptSubmit";
|
|
405
|
+
return "SessionStart";
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function emitAdvisoryContext(runtime, hookName, note) {
|
|
409
|
+
const normalized = normalizeText(note);
|
|
410
|
+
if (normalized.length === 0) return;
|
|
411
|
+
if (runtime.harness === "claude" || runtime.harness === "codex") {
|
|
412
|
+
runtime.writeJson({
|
|
413
|
+
hookSpecificOutput: {
|
|
414
|
+
hookEventName: hookEventNameForOutput(hookName),
|
|
415
|
+
additionalContext: normalized
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
runtime.writeJson({ additional_context: normalized });
|
|
421
|
+
}
|
|
422
|
+
|
|
383
423
|
async function detectRoot(env) {
|
|
384
424
|
const candidates = [
|
|
385
425
|
env.CCLAW_PROJECT_ROOT,
|
|
@@ -976,21 +1016,55 @@ async function handleSessionStart(runtime) {
|
|
|
976
1016
|
// where lifting becomes relevant; earlier stages update the file silently.
|
|
977
1017
|
let compoundReadinessLine = "";
|
|
978
1018
|
try {
|
|
979
|
-
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1019
|
+
let readiness = null;
|
|
1020
|
+
const internalReadiness = await runCclawInternal(
|
|
1021
|
+
runtime.root,
|
|
1022
|
+
["compound-readiness", "--json"],
|
|
1023
|
+
{ captureStdout: true }
|
|
1024
|
+
);
|
|
1025
|
+
if (internalReadiness.code === 0 && internalReadiness.stdout.trim().length > 0) {
|
|
1026
|
+
try {
|
|
1027
|
+
const parsed = JSON.parse(internalReadiness.stdout);
|
|
1028
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1029
|
+
readiness = parsed;
|
|
1030
|
+
}
|
|
1031
|
+
} catch {
|
|
1032
|
+
readiness = null;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
if (!readiness) {
|
|
1036
|
+
const archivedRunsCount = await countArchivedRunsInline(runtime.root);
|
|
1037
|
+
readiness = await computeCompoundReadinessInline(runtime.root, {
|
|
1038
|
+
prereadRaw: knowledgeRaw,
|
|
1039
|
+
...(typeof archivedRunsCount === "number" ? { archivedRunsCount } : {})
|
|
1040
|
+
});
|
|
1041
|
+
await writeJsonFile(path.join(stateDir, "compound-readiness.json"), readiness);
|
|
1042
|
+
}
|
|
1043
|
+
const readinessObj = toObject(readiness) || {};
|
|
1044
|
+
const ready = Array.isArray(readinessObj.ready) ? readinessObj.ready : [];
|
|
1045
|
+
const readyCount =
|
|
1046
|
+
typeof readinessObj.readyCount === "number" && Number.isFinite(readinessObj.readyCount)
|
|
1047
|
+
? Math.trunc(readinessObj.readyCount)
|
|
1048
|
+
: ready.length;
|
|
1049
|
+
const clusterCount =
|
|
1050
|
+
typeof readinessObj.clusterCount === "number" && Number.isFinite(readinessObj.clusterCount)
|
|
1051
|
+
? Math.trunc(readinessObj.clusterCount)
|
|
1052
|
+
: 0;
|
|
1053
|
+
const threshold =
|
|
1054
|
+
typeof readinessObj.threshold === "number" && Number.isFinite(readinessObj.threshold)
|
|
1055
|
+
? Math.trunc(readinessObj.threshold)
|
|
1056
|
+
: COMPOUND_RECURRENCE_THRESHOLD;
|
|
985
1057
|
if (state.currentStage === "review" || state.currentStage === "ship") {
|
|
986
|
-
if (
|
|
1058
|
+
if (readyCount === 0) {
|
|
987
1059
|
compoundReadinessLine = "Compound readiness: no candidates (clusters=" +
|
|
988
|
-
String(
|
|
1060
|
+
String(clusterCount) + ", threshold=" + String(threshold) + ")";
|
|
989
1061
|
} else {
|
|
990
|
-
const critical =
|
|
1062
|
+
const critical = ready.filter(
|
|
1063
|
+
(entry) => entry && typeof entry === "object" && entry.severity === "critical"
|
|
1064
|
+
).length;
|
|
991
1065
|
const criticalSuffix = critical > 0 ? " (critical=" + String(critical) + ")" : "";
|
|
992
|
-
compoundReadinessLine = "Compound readiness: clusters=" + String(
|
|
993
|
-
", ready=" + String(
|
|
1066
|
+
compoundReadinessLine = "Compound readiness: clusters=" + String(clusterCount) +
|
|
1067
|
+
", ready=" + String(readyCount) + criticalSuffix;
|
|
994
1068
|
}
|
|
995
1069
|
}
|
|
996
1070
|
} catch (err) {
|
|
@@ -1342,7 +1416,9 @@ async function handlePromptGuard(runtime) {
|
|
|
1342
1416
|
const reasons = [];
|
|
1343
1417
|
|
|
1344
1418
|
if (/^(write|edit|multiedit|multi_edit|delete|applypatch|runcommand|shell|terminal|execcommand)$/u.test(toolLower)) {
|
|
1345
|
-
|
|
1419
|
+
// Artifacts, runs, and knowledge writes are part of normal stage flow.
|
|
1420
|
+
// Guard only managed internals that should be mutated via installer/CLI.
|
|
1421
|
+
if (/\\.cclaw\\/(state|hooks|skills|commands|agents)/u.test(payloadLower)) {
|
|
1346
1422
|
reasons.push("write_to_cclaw_runtime");
|
|
1347
1423
|
}
|
|
1348
1424
|
}
|
|
@@ -1356,7 +1432,7 @@ async function handlePromptGuard(runtime) {
|
|
|
1356
1432
|
RUNTIME_ROOT +
|
|
1357
1433
|
" runtime (" +
|
|
1358
1434
|
reasons.join(",") +
|
|
1359
|
-
"). Prefer installer commands
|
|
1435
|
+
"). Prefer installer commands before mutating managed runtime internals (.cclaw/state|hooks|skills|commands|agents).";
|
|
1360
1436
|
await appendJsonLine(guardLog, {
|
|
1361
1437
|
ts: new Date().toISOString(),
|
|
1362
1438
|
harness: runtime.harness,
|
|
@@ -1364,6 +1440,8 @@ async function handlePromptGuard(runtime) {
|
|
|
1364
1440
|
reasons,
|
|
1365
1441
|
note
|
|
1366
1442
|
});
|
|
1443
|
+
const advisoryNote = mode === "strict" ? note + " Blocked by strict mode." : note;
|
|
1444
|
+
emitAdvisoryContext(runtime, "prompt-guard", advisoryNote);
|
|
1367
1445
|
if (mode === "strict") {
|
|
1368
1446
|
process.stderr.write("[cclaw] " + note + " (blocked by strict mode)\\n");
|
|
1369
1447
|
return 1;
|
|
@@ -1877,9 +1955,11 @@ async function handleWorkflowGuard(runtime) {
|
|
|
1877
1955
|
}
|
|
1878
1956
|
|
|
1879
1957
|
if (shouldBlock) {
|
|
1958
|
+
emitAdvisoryContext(runtime, "workflow-guard", note + " Blocked by workflow guard.");
|
|
1880
1959
|
process.stderr.write("[cclaw] " + note + " (blocked by workflow guard)\\n");
|
|
1881
1960
|
return 1;
|
|
1882
1961
|
}
|
|
1962
|
+
emitAdvisoryContext(runtime, "workflow-guard", note);
|
|
1883
1963
|
process.stderr.write("[cclaw] " + note + "\\n");
|
|
1884
1964
|
}
|
|
1885
1965
|
|
|
@@ -1978,6 +2058,7 @@ async function handleContextMonitor(runtime) {
|
|
|
1978
2058
|
remainingPercent,
|
|
1979
2059
|
note
|
|
1980
2060
|
});
|
|
2061
|
+
emitAdvisoryContext(runtime, "context-monitor", note);
|
|
1981
2062
|
process.stderr.write("[cclaw] " + note + "\\n");
|
|
1982
2063
|
nextAdvisoryBand = band;
|
|
1983
2064
|
nextAdvisoryAt = now.toISOString();
|
|
@@ -1998,10 +2079,24 @@ async function handleVerifyCurrentState(runtime) {
|
|
|
1998
2079
|
const mode = resolveStrictness();
|
|
1999
2080
|
const result = await runCclawInternal(runtime.root, ["verify-current-state", "--quiet"]);
|
|
2000
2081
|
if (result.missingBinary) {
|
|
2082
|
+
emitAdvisoryContext(
|
|
2083
|
+
runtime,
|
|
2084
|
+
"verify-current-state",
|
|
2085
|
+
"Cclaw verify-current-state requires cclaw binary on PATH."
|
|
2086
|
+
);
|
|
2001
2087
|
process.stderr.write("[cclaw] hook: cclaw binary is required for verify-current-state\\n");
|
|
2002
2088
|
return 1;
|
|
2003
2089
|
}
|
|
2004
2090
|
if (mode === "strict") {
|
|
2091
|
+
if (result.code !== 0) {
|
|
2092
|
+
emitAdvisoryContext(
|
|
2093
|
+
runtime,
|
|
2094
|
+
"verify-current-state",
|
|
2095
|
+
result.stderr.trim().length > 0
|
|
2096
|
+
? result.stderr.trim()
|
|
2097
|
+
: "Cclaw verify-current-state failed in strict mode."
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2005
2100
|
if (result.code !== 0 && result.stderr.trim().length > 0) {
|
|
2006
2101
|
process.stderr.write(result.stderr);
|
|
2007
2102
|
}
|
package/dist/content/observe.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
2
2
|
import { HOOK_MANIFEST, groupBindingsByEvent } from "./hook-manifest.js";
|
|
3
3
|
function hookDispatcherCommand(hookName) {
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
// JSON.stringify to survive spaces.
|
|
8
|
-
return `node ${RUNTIME_ROOT}/hooks/run-hook.mjs ${hookName}`;
|
|
4
|
+
// Dispatch through the polyglot .cmd wrapper so Windows harnesses can run
|
|
5
|
+
// hooks even when command execution happens under CMD-style shells.
|
|
6
|
+
return `${RUNTIME_ROOT}/hooks/run-hook.cmd ${hookName}`;
|
|
9
7
|
}
|
|
10
8
|
/**
|
|
11
9
|
* Claude / Codex share the same outer envelope: each event is an
|
package/dist/content/skills.js
CHANGED
|
@@ -77,10 +77,8 @@ function reviewSectionsBlock(stage, track) {
|
|
|
77
77
|
const sections = schema.reviewSections
|
|
78
78
|
.map((sec) => {
|
|
79
79
|
const points = sec.evaluationPoints.map((p) => `- ${p}`).join("\n");
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
: "";
|
|
83
|
-
return `### ${sec.title}\n${points}${stop}`;
|
|
80
|
+
const title = sec.stopGate ? `${sec.title} (STOP gate)` : sec.title;
|
|
81
|
+
return `### ${title}\n${points}`;
|
|
84
82
|
})
|
|
85
83
|
.join("\n\n");
|
|
86
84
|
return `## Review Sections
|
|
@@ -297,6 +295,34 @@ After T-3 REFACTOR, before declaring Batch 1 done:
|
|
|
297
295
|
export function stageSkillFolder(stage) {
|
|
298
296
|
return STAGE_TO_SKILL_FOLDER[stage];
|
|
299
297
|
}
|
|
298
|
+
function normalizedGuidanceKey(value) {
|
|
299
|
+
return value
|
|
300
|
+
.replace(/`[^`]+`/gu, " ")
|
|
301
|
+
.replace(/[*_]/gu, " ")
|
|
302
|
+
.replace(/[^a-z0-9]+/giu, " ")
|
|
303
|
+
.replace(/\s+/gu, " ")
|
|
304
|
+
.trim()
|
|
305
|
+
.toLowerCase();
|
|
306
|
+
}
|
|
307
|
+
function dedupeGuidance(items, blockedBy) {
|
|
308
|
+
const blocked = new Set(blockedBy
|
|
309
|
+
.map((item) => normalizedGuidanceKey(item))
|
|
310
|
+
.filter((item) => item.length > 0));
|
|
311
|
+
const seen = new Set();
|
|
312
|
+
const result = [];
|
|
313
|
+
for (const item of items) {
|
|
314
|
+
const key = normalizedGuidanceKey(item);
|
|
315
|
+
if (key.length === 0)
|
|
316
|
+
continue;
|
|
317
|
+
if (blocked.has(key))
|
|
318
|
+
continue;
|
|
319
|
+
if (seen.has(key))
|
|
320
|
+
continue;
|
|
321
|
+
seen.add(key);
|
|
322
|
+
result.push(item);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
300
326
|
export function stageSkillMarkdown(stage, track = "standard") {
|
|
301
327
|
const schema = stageSchema(stage, track);
|
|
302
328
|
const gateList = schema.requiredGates
|
|
@@ -308,6 +334,11 @@ export function stageSkillMarkdown(stage, track = "standard") {
|
|
|
308
334
|
const checklistItems = schema.checklist
|
|
309
335
|
.map((item, i) => `${i + 1}. ${item}`)
|
|
310
336
|
.join("\n");
|
|
337
|
+
const interactionFocus = dedupeGuidance(schema.interactionProtocol, [...schema.checklist, ...schema.process]).slice(0, 5);
|
|
338
|
+
const processSummary = dedupeGuidance(schema.process, schema.checklist).slice(0, 5);
|
|
339
|
+
const processNote = schema.process.length > processSummary.length
|
|
340
|
+
? `- Follow the Checklist above for remaining execution detail (+${schema.process.length - processSummary.length} condensed step${schema.process.length - processSummary.length === 1 ? "" : "s"}).`
|
|
341
|
+
: "";
|
|
311
342
|
const stageRefs = stageSpecificSeeAlso(stage);
|
|
312
343
|
return `---
|
|
313
344
|
name: ${schema.skillName}
|
|
@@ -360,7 +391,7 @@ ${stageDomainExamples(stage)}
|
|
|
360
391
|
${stageExamples(stage)}
|
|
361
392
|
|
|
362
393
|
## Interaction Protocol
|
|
363
|
-
${
|
|
394
|
+
${interactionFocus.length > 0 ? interactionFocus.map((item, i) => `${i + 1}. ${item}`).join("\n") : "- Keep communication concise and decision-focused; rely on the Checklist for execution order."}
|
|
364
395
|
|
|
365
396
|
Shared decision/ask-user protocol:
|
|
366
397
|
\`${DECISION_PROTOCOL_PATH}\`
|
|
@@ -373,7 +404,8 @@ ${gateList}
|
|
|
373
404
|
${evidenceList}
|
|
374
405
|
|
|
375
406
|
## Process
|
|
376
|
-
${
|
|
407
|
+
${processSummary.length > 0 ? processSummary.map((item, i) => `${i + 1}. ${item}`).join("\n") : "1. Execute the Checklist in order.\n2. Satisfy every required gate.\n3. Complete verification before stage closeout."}
|
|
408
|
+
${processNote.length > 0 ? `\n${processNote}` : ""}
|
|
377
409
|
|
|
378
410
|
${reviewSectionsBlock(stage, track)}
|
|
379
411
|
${verificationBlock(stage)}
|
|
@@ -21,11 +21,17 @@ export const BRAINSTORM = {
|
|
|
21
21
|
],
|
|
22
22
|
checklist: [
|
|
23
23
|
"**Explore project context** — check files, docs, recent commits to understand what already exists.",
|
|
24
|
+
"**Assess depth tier first** — classify the request as Lightweight / Standard / Deep. Lightweight = narrow/localized ask; Standard = cross-module but bounded; Deep = platform or multi-surface product change.",
|
|
24
25
|
"**Assess scope** — if the request covers multiple independent subsystems, flag it and help decompose before deep-diving. Each sub-project gets its own brainstorm cycle.",
|
|
26
|
+
"**Short-circuit gate** — if requirements are already concrete and unambiguous, write a minimal brainstorm stub (problem + approved intent + constraints) and hand off to scope.",
|
|
25
27
|
"**Ask clarifying questions** — one at a time, understand purpose, constraints, and success criteria. Prefer multiple choice when possible. Each question should change what we build, not just gather trivia.",
|
|
26
|
-
"**Propose 2-3 architecturally distinct approaches** — with real trade-offs and
|
|
28
|
+
"**Propose 2-3 architecturally distinct approaches** — with real trade-offs and no recommendation yet. At least one option must be a higher-upside challenger that raises ambition vs the user's initial ask.",
|
|
29
|
+
"**Collect user reaction** — ask which approach feels closest and what concerns remain before stating your recommendation.",
|
|
30
|
+
"**Recommend only after reaction** — present final recommendation with rationale that explicitly references user feedback.",
|
|
27
31
|
"**Present design by sections** — scale each section to its complexity. Ask after each section whether it looks right so far. Cover: architecture, key components, data flow.",
|
|
32
|
+
"**Optional visual companion** — when architecture/data flow complexity is medium+ offer a compact diagram (ASCII or Mermaid) before artifact write-up.",
|
|
28
33
|
"**Write artifact** to `.cclaw/artifacts/01-brainstorm.md`.",
|
|
34
|
+
"**Document-quality pass** — run a brief adversarial review of the artifact (gaps, contradictions, missing trade-offs), then patch before user review.",
|
|
29
35
|
"**Self-review** — scan for placeholders/TODOs, check internal consistency, verify scope is focused, resolve any ambiguity.",
|
|
30
36
|
"**User reviews artifact** — ask the user to review the written artifact and explicitly approve or request changes.",
|
|
31
37
|
"**Handoff** — only then complete stage and point to `/cc-next`."
|
|
@@ -37,18 +43,24 @@ export const BRAINSTORM = {
|
|
|
37
43
|
"After 2-3 questions, summarize your emerging understanding before continuing so the user can correct course early.",
|
|
38
44
|
"Each question should change a concrete design decision. Litmus test: if the two most likely answers do not lead to different architectures, make the choice yourself and state it.",
|
|
39
45
|
"Present design in sections scaled to their complexity — a few sentences for simple aspects, detailed for nuanced ones. Get approval after each section.",
|
|
40
|
-
"When proposing approaches,
|
|
46
|
+
"When proposing approaches, do NOT reveal your recommendation yet. Present options first, gather reaction, then recommend.",
|
|
47
|
+
"At least one approach must be a higher-upside challenger; avoid three same-altitude variants.",
|
|
41
48
|
"State explicitly what is being approved when requesting approval.",
|
|
42
49
|
"Run a brief self-review (placeholders, contradictions, scope, ambiguity) before presenting the artifact.",
|
|
43
50
|
"**STOP.** Wait for explicit user approval after writing the artifact. Do NOT auto-advance."
|
|
44
51
|
],
|
|
45
52
|
process: [
|
|
46
53
|
"Explore project context: check files, docs, recent activity.",
|
|
54
|
+
"Classify depth tier (Lightweight / Standard / Deep) before diving.",
|
|
47
55
|
"Assess scope: flag if request is too broad, help decompose first.",
|
|
56
|
+
"Apply short-circuit when requirements are already concrete enough for scope.",
|
|
48
57
|
"Ask clarifying questions one at a time — focus on purpose, constraints, success criteria.",
|
|
49
|
-
"Propose 2-3 architecturally distinct approaches with trade-offs
|
|
58
|
+
"Propose 2-3 architecturally distinct approaches with trade-offs (one must be higher-upside challenger).",
|
|
59
|
+
"Collect user reaction before giving your recommendation.",
|
|
60
|
+
"Recommend after reaction and explain how feedback changed the recommendation.",
|
|
50
61
|
"Present design sections incrementally, get approval after each.",
|
|
51
62
|
"Write approved direction to `.cclaw/artifacts/01-brainstorm.md`.",
|
|
63
|
+
"Run document-quality pass to close contradictions and weak trade-off reasoning.",
|
|
52
64
|
"Self-review: placeholder scan, internal consistency, scope check, ambiguity check.",
|
|
53
65
|
"Request explicit user approval of the artifact.",
|
|
54
66
|
"Handoff to scope only after approval is explicit."
|
|
@@ -62,7 +74,9 @@ export const BRAINSTORM = {
|
|
|
62
74
|
"Artifact written to `.cclaw/artifacts/01-brainstorm.md`.",
|
|
63
75
|
"Project context was explored (files, docs, or recent activity referenced).",
|
|
64
76
|
"Clarifying questions and their answers are captured.",
|
|
65
|
-
"2-3 approaches with trade-offs
|
|
77
|
+
"2-3 approaches with trade-offs are recorded, including one higher-upside challenger option.",
|
|
78
|
+
"User reaction to approaches is captured before final recommendation.",
|
|
79
|
+
"Final recommendation explicitly reflects user reaction.",
|
|
66
80
|
"Approved direction and approval marker are present.",
|
|
67
81
|
"Assumptions and open questions are captured (or explicitly marked as none)."
|
|
68
82
|
],
|
|
@@ -96,6 +110,8 @@ export const BRAINSTORM = {
|
|
|
96
110
|
"Asking questions without exploring existing project context first",
|
|
97
111
|
"Asking bundled or purely informational questions that don't change decisions",
|
|
98
112
|
"Proposing cosmetic option variants instead of architecturally distinct approaches",
|
|
113
|
+
"Revealing recommendation before collecting user reaction",
|
|
114
|
+
"Three same-altitude approaches with no higher-upside challenger",
|
|
99
115
|
"Jumping directly into implementation",
|
|
100
116
|
"Requesting approval without stating what decision is being approved",
|
|
101
117
|
"Questions that only gather preferences without design impact",
|
|
@@ -122,9 +138,12 @@ export const BRAINSTORM = {
|
|
|
122
138
|
{ section: "Context", required: true, validationRule: "Must reference project state and relevant existing code or patterns." },
|
|
123
139
|
{ section: "Problem", required: true, validationRule: "Must define what we're solving, success criteria, and constraints." },
|
|
124
140
|
{ section: "Clarifying Questions", required: false, validationRule: "Must capture question, answer, and decision impact for each clarifying question." },
|
|
125
|
-
{ section: "
|
|
126
|
-
{ section: "
|
|
141
|
+
{ section: "Approach Tier", required: false, validationRule: "Must classify depth as Lightweight/Standard/Deep and explain why." },
|
|
142
|
+
{ section: "Approaches", required: true, validationRule: "Must compare 2-3 architecturally distinct options with real trade-offs and include one higher-upside challenger option." },
|
|
143
|
+
{ section: "Approach Reaction", required: false, validationRule: "Must summarize user reaction before recommendation, including concerns that changed direction." },
|
|
144
|
+
{ section: "Selected Direction", required: true, validationRule: "Must include the selected approach, rationale tied to user reaction, and explicit approval marker." },
|
|
127
145
|
{ section: "Design", required: false, validationRule: "Must cover architecture, key components, and data flow scaled to complexity." },
|
|
146
|
+
{ section: "Visual Companion", required: false, validationRule: "If architecture/data-flow complexity is medium+, include compact ASCII/Mermaid diagram or explicitly justify omission." },
|
|
128
147
|
{ section: "Assumptions and Open Questions", required: false, validationRule: "Must capture unresolved assumptions/open questions, or explicitly state none." }
|
|
129
148
|
]
|
|
130
149
|
};
|
|
@@ -21,16 +21,20 @@ export const DESIGN = {
|
|
|
21
21
|
],
|
|
22
22
|
checklist: [
|
|
23
23
|
"Trivial-Change Escape Hatch — If scope artifact shows ≤3 files, zero new interfaces, and no cross-module data flow, skip full review sections. Produce a mini-design: one paragraph of rationale, list of changed files, one risk to watch. Proceed to spec.",
|
|
24
|
-
"Parallel Research Fleet — run `research/research-fleet.md` before architecture lock.
|
|
24
|
+
"Parallel Research Fleet — run `research/research-fleet.md` before architecture lock. Fleet size scales by complexity: Lightweight=1 lens (pitfalls), Standard=2 lenses (architecture+pitfalls), Deep=4 lenses. Record findings in `.cclaw/artifacts/02a-research.md` and summarize resulting decisions in `## Research Fleet Synthesis`.",
|
|
25
25
|
"Design Doc Check — read existing design docs, scope artifact, brainstorm artifact. If a design doc exists that covers this area, check for 'Supersedes:' and use the latest. Use upstream artifacts as source of truth.",
|
|
26
26
|
"Codebase Investigation — Before any design decision, read the actual code in the blast radius. List every file that will be touched, its current responsibilities, and existing patterns (error handling, naming, test style). Design must conform to discovered patterns, not impose new ones without justification.",
|
|
27
27
|
"Step 0: Scope Challenge — what existing code solves sub-problems? Minimum change set? Complexity check: 8+ files or 2+ new services = complexity smell → flag for possible scope reduction.",
|
|
28
28
|
"Search Before Building — For each technical choice (library, pattern, architecture), search for existing solutions. Label findings: Layer 1 (exact match), Layer 2 (partial match, needs adaptation), Layer 3 (inspiration only), EUREKA (unexpected perfect solution). Default to existing before custom.",
|
|
29
|
-
"Architecture Review —
|
|
30
|
-
"
|
|
29
|
+
"Architecture Review — lock component boundaries and one realistic failure scenario per new codepath. **Mandatory diagrams:** architecture for all tiers; Standard/Deep adds Data-Flow Shadow Paths and Error Flow.",
|
|
30
|
+
"Security & Threat Model Review — trust boundaries, authn/authz, input validation, secrets handling, data exposure risks, abuse cases, and mitigation ownership.",
|
|
31
|
+
"Code Quality Review — code organization, DRY violations, error handling patterns, over/under-engineering assessment. Include stale-diagram audit for touched files.",
|
|
31
32
|
"Test Review — diagram every new flow, data path, error path. For each: what test type covers it? Does one exist? What is the gap? Produce test plan artifact.",
|
|
32
33
|
"Performance Review — N+1 queries, memory concerns, caching opportunities, slow code paths. What breaks at 10x load? At 100x?",
|
|
34
|
+
"Observability & Debuggability Review — logging, metrics, traces, alerts, and on-call diagnosis path for each critical failure mode.",
|
|
35
|
+
"Deployment & Rollout Review — migration sequencing, flag strategy, rollback plan, compatibility window, and post-deploy verification steps.",
|
|
33
36
|
"Parallelization Strategy — If multiple independent modules, produce dependency table: which can be built in parallel? Where are conflict risks? Flag shared-state modules.",
|
|
37
|
+
"Outside Voice + Spec Review Loop — run adversarial second-opinion review, reconcile findings, and iterate up to 3 cycles or until quality score >= 0.8.",
|
|
34
38
|
"Unresolved Decisions — List any design decisions that could not be resolved in this session. For each: what information is missing? Who can provide it? What is the default if no answer comes?",
|
|
35
39
|
"Distribution Check — If the plan creates new artifact types (packages, CLI tools, configs), document the build/publish story. How does it reach the user?",
|
|
36
40
|
"Deferred Items Cross-Reference — Collect every item explicitly deferred during design review. Each must appear in the Unresolved Decisions table or in the upstream scope artifact's deferred list. No deferred item may exist only in conversation — it must be written down."
|
|
@@ -38,29 +42,35 @@ export const DESIGN = {
|
|
|
38
42
|
interactionProtocol: [
|
|
39
43
|
"Review architecture decisions section-by-section.",
|
|
40
44
|
"For EACH issue found in a review section, present it ONE AT A TIME. Do NOT batch multiple issues.",
|
|
41
|
-
"For each issue: use the Decision Protocol — describe concretely with file/line references, present labeled options (A/B/C) with trade-offs, effort estimate (S/M/L/XL), risk level (Low/Med/High), and mark one as (recommended). Do NOT use a numeric Completeness rubric
|
|
45
|
+
"For each issue: use the Decision Protocol — describe concretely with file/line references, present labeled options (A/B/C) with trade-offs, effort estimate (S/M/L/XL), risk level (Low/Med/High), and mark one as (recommended). Do NOT use a numeric Completeness rubric. If the harness's native structured-ask tool is available (`AskUserQuestion` / `AskQuestion` / `question` / `request_user_input`), send exactly ONE question per call and fall back to plain-text letters on schema/tool failure.",
|
|
42
46
|
"Only proceed to the next review section after ALL issues in the current section are resolved.",
|
|
43
47
|
"If a section has no issues, say 'No issues found' and move on.",
|
|
44
48
|
"Do not skip failure-mode mapping.",
|
|
49
|
+
"Use Failure Mode Table columns in fixed order: Method, Exception, Rescue, UserSees. Silent user impact without rescue is treated as critical.",
|
|
45
50
|
"For design baseline approval: present the full baseline. **STOP.** Do NOT proceed until user explicitly approves the design.",
|
|
46
51
|
"**STOP BEFORE ADVANCE.** Mandatory delegation `planner` must be marked completed or explicitly waived in `.cclaw/state/delegation-log.json`. Then close the stage via `node .cclaw/hooks/stage-complete.mjs design` (do not hand-edit `.cclaw/state/flow-state.json`).",
|
|
47
52
|
"Take a firm position on every recommendation. Do NOT hedge with 'it depends' or 'you could do either'. State your opinion, then justify it.",
|
|
48
|
-
"Use pushback
|
|
53
|
+
"Use pushback for weak framing: 'small changes' on shared interfaces can still have large blast radius.",
|
|
49
54
|
"When the user's proposed architecture is suboptimal, say so directly. Offer the alternative with concrete trade-offs, do not bury criticism in praise.",
|
|
50
|
-
"When encountering ambiguity, classify it before acting: (A) ask user for missing info, (B) enumerate interpretations and pick one with justification, (C) propose hypothesis with validation path. Do NOT silently resolve ambiguity."
|
|
55
|
+
"When encountering ambiguity, classify it before acting: (A) ask user for missing info, (B) enumerate interpretations and pick one with justification, (C) propose hypothesis with validation path. Do NOT silently resolve ambiguity.",
|
|
56
|
+
"Before final approval, run outside-voice review loop and reconcile each finding (accept/reject/defer) with rationale.",
|
|
57
|
+
"Bound review-loop retries: max 3 iterations or early stop at quality score >= 0.8."
|
|
51
58
|
],
|
|
52
59
|
process: [
|
|
53
60
|
"Read upstream artifacts (brainstorm, scope).",
|
|
54
|
-
"Run the research fleet playbook and write `.cclaw/artifacts/02a-research.md` before locking architecture choices.",
|
|
61
|
+
"Run the research fleet playbook with tiered fleet size and write `.cclaw/artifacts/02a-research.md` before locking architecture choices.",
|
|
55
62
|
"Investigate codebase: read files in blast radius, catalogue current patterns and responsibilities.",
|
|
56
63
|
"Run Step 0 scope challenge: existing code leverage, minimum change set, complexity check.",
|
|
57
64
|
"Walk through each review section interactively.",
|
|
58
65
|
"Define architecture boundaries and ownership.",
|
|
59
|
-
"Describe data flow and state transitions with edge paths.",
|
|
60
|
-
"Map failure modes and recovery strategy.",
|
|
66
|
+
"Describe data flow and state transitions with edge paths + interaction edge-case matrix.",
|
|
67
|
+
"Map failure modes and recovery strategy using Method/Exception/Rescue/UserSees table.",
|
|
68
|
+
"Add security, observability, and deployment reviews for Standard+ changes.",
|
|
69
|
+
"Run stale-diagram audit in touched files and reconcile drift.",
|
|
61
70
|
"Define test coverage strategy and performance budget.",
|
|
62
|
-
"Produce required outputs: NOT-in-scope section, What-already-exists section, diagrams, failure mode table.",
|
|
63
|
-
"
|
|
71
|
+
"Produce required outputs: NOT-in-scope section, What-already-exists section, architecture + shadow/error diagrams, failure mode table.",
|
|
72
|
+
"Run outside-voice spec review loop (up to 3 iterations, quality score target >= 0.8).",
|
|
73
|
+
"Produce completion dashboard: status per review section, critical/open gap counts, decision count, unresolved items.",
|
|
64
74
|
"Write design lock artifact for downstream spec/plan."
|
|
65
75
|
],
|
|
66
76
|
requiredGates: [
|
|
@@ -73,11 +83,16 @@ export const DESIGN = {
|
|
|
73
83
|
requiredEvidence: [
|
|
74
84
|
"Research artifact written to `.cclaw/artifacts/02a-research.md` with stack/features/architecture/pitfalls sections plus synthesis.",
|
|
75
85
|
"Artifact written to `.cclaw/artifacts/03-design.md`.",
|
|
76
|
-
"Failure-mode table exists
|
|
86
|
+
"Failure-mode table exists in Method/Exception/Rescue/UserSees format.",
|
|
87
|
+
"Data-flow shadow and error-flow diagrams are present for Standard+ complexity.",
|
|
88
|
+
"Security & threat model findings are documented with mitigations.",
|
|
89
|
+
"Observability and deployment plans are explicit for critical flows.",
|
|
90
|
+
"Outside-voice findings and dispositions are recorded (accept/reject/defer).",
|
|
91
|
+
"Spec review loop summary includes iteration count and quality score trajectory.",
|
|
77
92
|
"Test strategy includes unit/integration/e2e expectations.",
|
|
78
93
|
"NOT-in-scope section produced.",
|
|
79
94
|
"What-already-exists section produced.",
|
|
80
|
-
"Completion dashboard lists
|
|
95
|
+
"Completion dashboard lists review section status, critical/open gap counts, decision count, and unresolved items (or 'None')."
|
|
81
96
|
],
|
|
82
97
|
inputs: ["scope agreement artifact", "system constraints", "non-functional requirements"],
|
|
83
98
|
requiredContext: [
|
|
@@ -115,7 +130,11 @@ export const DESIGN = {
|
|
|
115
130
|
commonRationalizations: [
|
|
116
131
|
"Architecture deferred to implementation phase",
|
|
117
132
|
"Missing data-flow edge cases",
|
|
133
|
+
"No interaction-edge-case matrix (double-click, navigate-away, stale-state, large-result)",
|
|
118
134
|
"No performance budget for critical path",
|
|
135
|
+
"Failure mode table omits rescue path or user-visible impact",
|
|
136
|
+
"Skipping security/observability/deployment review for non-trivial change",
|
|
137
|
+
"Skipping outside-voice review loop and treating first draft as final",
|
|
119
138
|
"Batching multiple design issues into one question",
|
|
120
139
|
"Agreeing with user's architecture choice without evaluating alternatives",
|
|
121
140
|
"No NOT-in-scope output section",
|
|
@@ -135,15 +154,19 @@ export const DESIGN = {
|
|
|
135
154
|
{
|
|
136
155
|
title: "Architecture Review",
|
|
137
156
|
evaluationPoints: [
|
|
138
|
-
"System design and
|
|
139
|
-
"Dependency graph and coupling concerns",
|
|
140
|
-
"Data flow patterns and potential bottlenecks",
|
|
141
|
-
"Scaling characteristics and single points of failure",
|
|
142
|
-
"Security architecture (auth, data access, API boundaries)",
|
|
157
|
+
"System design, boundaries, coupling, and bottlenecks",
|
|
143
158
|
"For each new codepath: one realistic production failure scenario"
|
|
144
159
|
],
|
|
145
160
|
stopGate: true
|
|
146
161
|
},
|
|
162
|
+
{
|
|
163
|
+
title: "Security & Threat Model",
|
|
164
|
+
evaluationPoints: [
|
|
165
|
+
"Trust boundaries, authz rules, and sensitive data flows are explicit",
|
|
166
|
+
"Mitigation ownership and residual risk are documented"
|
|
167
|
+
],
|
|
168
|
+
stopGate: true
|
|
169
|
+
},
|
|
147
170
|
{
|
|
148
171
|
title: "Code Quality Review",
|
|
149
172
|
evaluationPoints: [
|
|
@@ -155,6 +178,15 @@ export const DESIGN = {
|
|
|
155
178
|
],
|
|
156
179
|
stopGate: true
|
|
157
180
|
},
|
|
181
|
+
{
|
|
182
|
+
title: "Data Flow & Interaction Edge Cases",
|
|
183
|
+
evaluationPoints: [
|
|
184
|
+
"Happy/nil/empty/error paths are explicit",
|
|
185
|
+
"Interaction edge cases and Standard+ shadow/error diagrams are present",
|
|
186
|
+
"Error-flow includes rescue path and user-visible outcome"
|
|
187
|
+
],
|
|
188
|
+
stopGate: true
|
|
189
|
+
},
|
|
158
190
|
{
|
|
159
191
|
title: "Test Review",
|
|
160
192
|
evaluationPoints: [
|
|
@@ -176,14 +208,20 @@ export const DESIGN = {
|
|
|
176
208
|
stopGate: true
|
|
177
209
|
},
|
|
178
210
|
{
|
|
179
|
-
title: "
|
|
211
|
+
title: "Observability & Debuggability",
|
|
212
|
+
evaluationPoints: [
|
|
213
|
+
"Logs/metrics/traces exist for critical failure modes",
|
|
214
|
+
"Alerting and debug path from symptom to root cause are documented"
|
|
215
|
+
],
|
|
216
|
+
stopGate: true
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
title: "Deployment & Rollout Review",
|
|
180
220
|
evaluationPoints: [
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"Does the change affect existing consumers (APIs, shared modules)?",
|
|
184
|
-
"Is backwards compatibility maintained or is a migration needed?"
|
|
221
|
+
"Migration sequencing, rollout/rollback, and compatibility window are explicit",
|
|
222
|
+
"Post-deploy verification and distribution/build story are documented"
|
|
185
223
|
],
|
|
186
|
-
stopGate:
|
|
224
|
+
stopGate: true
|
|
187
225
|
}
|
|
188
226
|
],
|
|
189
227
|
completionStatus: ["DONE", "DONE_WITH_CONCERNS", "BLOCKED"],
|
|
@@ -201,18 +239,17 @@ export const DESIGN = {
|
|
|
201
239
|
{ section: "Codebase Investigation", required: false, validationRule: "Must list blast-radius files with current responsibilities and discovered patterns." },
|
|
202
240
|
{ section: "Search Before Building", required: false, validationRule: "For each technical choice: Layer 1 (exact match), Layer 2 (partial match), Layer 3 (inspiration), EUREKA labels with reuse-first default." },
|
|
203
241
|
{ section: "Architecture Boundaries", required: true, validationRule: "Must list component boundaries with ownership." },
|
|
204
|
-
{ section: "Architecture Diagram", required: true, validationRule: "At least one diagram (ASCII, Mermaid, or image) showing component boundaries and data flow direction. Diagram must: (1) label every node with a concrete component name (no generic 'Service A/B'), (2) label every arrow with the action or message (no unlabeled arrows), (3) mark direction of data flow explicitly, (4) distinguish synchronous from asynchronous edges (e.g. solid vs dashed, or `sync:` / `async:` prefix), (5) include at least one failure/degraded edge line that contains an arrow plus a failure keyword (`timeout`, `error`, `fallback`, `degraded`, `retry`, etc.)." },
|
|
205
|
-
{ section: "Data Flow", required: false, validationRule: "Must include happy path, nil input, empty input, upstream error paths." },
|
|
206
|
-
{ section: "Failure Mode Table", required: true, validationRule: "
|
|
242
|
+
{ section: "Architecture Diagram", required: true, validationRule: "At least one diagram (ASCII, Mermaid, or image) showing component boundaries and data flow direction. Diagram must: (1) label every node with a concrete component name (no generic 'Service A/B'), (2) label every arrow with the action or message (no unlabeled arrows), (3) mark direction of data flow explicitly, (4) distinguish synchronous from asynchronous edges (e.g. solid vs dashed, or `sync:` / `async:` prefix), (5) include at least one failure/degraded edge line that contains an arrow plus a failure keyword (`timeout`, `error`, `fallback`, `degraded`, `retry`, etc.). Standard/Deep complexity must also include `Data-Flow Shadow Paths` and `Error Flow Diagram` sections." },
|
|
243
|
+
{ section: "Data Flow", required: false, validationRule: "Must include happy path, nil input, empty input, upstream error paths, plus interaction edge-case matrix (double-click, navigate-away, stale-state, large-result, background-job abandonment)." },
|
|
244
|
+
{ section: "Failure Mode Table", required: true, validationRule: "Use Method/Exception/Rescue/UserSees columns and treat silent user impact without rescue as critical." },
|
|
245
|
+
{ section: "Security & Threat Model", required: false, validationRule: "Must list trust boundaries, abuse/failure scenarios, mitigations, and residual risks." },
|
|
207
246
|
{ section: "Test Strategy", required: false, validationRule: "Must define unit/integration/e2e expectations with coverage targets." },
|
|
208
247
|
{ section: "Performance Budget", required: false, validationRule: "For each critical path: metric name, target threshold, and measurement method." },
|
|
209
248
|
{ section: "What Already Exists", required: false, validationRule: "For each sub-problem: existing code/library found (Layer 1-3/EUREKA label), reuse decision, and adaptation needed." },
|
|
210
249
|
{ section: "NOT in scope", required: false, validationRule: "Work considered and explicitly deferred with one-line rationale." },
|
|
211
250
|
{ section: "Parallelization Strategy", required: false, validationRule: "If multi-module: dependency table, parallel lanes, conflict flags." },
|
|
212
251
|
{ section: "Unresolved Decisions", required: false, validationRule: "If any: what info is missing, who provides it, default if unanswered." },
|
|
213
|
-
{ section: "
|
|
214
|
-
{ section: "Patterns to Mirror", required: false, validationRule: "If present: list discovered codebase patterns to follow, with file references and rationale for each." },
|
|
215
|
-
{ section: "Completion Dashboard", required: true, validationRule: "Lists every review section with status (clear / issues-found-resolved / issues-open), decision count, and unresolved items (or 'None')." }
|
|
252
|
+
{ section: "Completion Dashboard", required: true, validationRule: "Lists every review section with status (clear / issues-found-resolved / issues-open), critical/open gap counts, decision count, and unresolved items (or 'None')." }
|
|
216
253
|
],
|
|
217
254
|
trivialOverrideSections: ["Architecture Boundaries", "NOT in scope", "Completion Dashboard"]
|
|
218
255
|
};
|
|
@@ -20,15 +20,19 @@ export const SCOPE = {
|
|
|
20
20
|
"The work is a pure implementation or debugging pass within existing scope"
|
|
21
21
|
],
|
|
22
22
|
checklist: [
|
|
23
|
+
"**Pre-Scope System Audit** — before premise challenge, gather reality snapshot: recent commits (`git log -30 --oneline`), current diff (`git diff --stat`), stash state (`git stash list`), and deferred debt markers (`rg -n 'TODO|FIXME|XXX|HACK'`). Record findings in scope artifact.",
|
|
23
24
|
"**Assess complexity** — Read the brainstorm artifact. If project is simple (single component, clear architecture, personal/prototype), run light-touch scope: mode selection, 3-5 key in/out boundaries, deferred items. Skip Dream State Mapping and Temporal Interrogation. If project is complex (multi-component, team delivery, production), run the full checklist.",
|
|
24
25
|
"**Prime Directives** — Zero silent failures. For each in-scope capability, name concrete failure modes, the exact error surface, and trace all four data-flow paths (happy, nil, empty, upstream error). Include interaction edge cases (double-click, navigate-away, stale state), observability commitments, and explicit deferred-item logging.",
|
|
25
26
|
"**Premise Challenge** — Is this the right problem? What if we do nothing? What are we optimizing for?",
|
|
27
|
+
"**Landscape Check** — for EXPAND/SELECTIVE candidates, perform a brief external scan of comparable products/patterns to calibrate ambition and avoid local maxima.",
|
|
26
28
|
"**Existing Code Leverage** — Search for existing solutions before deciding to build new.",
|
|
29
|
+
"**Taste Calibration** — identify 2-3 high-quality files/modules in this codebase and explicitly align scope quality bar to them.",
|
|
27
30
|
"**Dream State Mapping** — (complex projects only) describe the ideal state 12 months out using `CURRENT STATE -> THIS PLAN -> 12-MONTH IDEAL`, then verify this scope moves toward that target.",
|
|
28
31
|
"**Implementation Alternatives** — Produce 2-3 distinct approaches. For each: Name, Summary, Effort (S/M/L/XL), Risk (Low/Med/High), 2-3 Pros, 2-3 Cons, and explicit Reuses. One option must be minimal viable, one must be ideal architecture.",
|
|
29
32
|
"**Temporal Interrogation** — (complex projects only) simulate implementation timeline: HOUR 1 foundations, HOUR 2-3 core logic, HOUR 4-5 integration surprises, HOUR 6+ polish/tests. Decide what must be locked now vs safely deferred.",
|
|
30
33
|
"**Mode Selection** — Present expand/selective/hold/reduce with recommendation and default heuristic: greenfield -> expand, feature enhancement -> selective, bugfix/hotfix/refactor -> hold, broad blast radius (>15 files or multi-team impact) -> reduce.",
|
|
31
34
|
"**Mode-Specific Analysis** — After mode is selected, run the matching analysis: EXPAND (10x and delight opportunities), SELECTIVE (hold-scope rigor then cherry-picked expansions), HOLD (minimum-change-set hardening), REDUCE (ruthless cuts and follow-up split).",
|
|
35
|
+
"**Outside Voice + Spec Review Loop** — run an adversarial second-opinion pass on the scope artifact, reconcile findings, and iterate up to 3 cycles or until quality score >= 0.8.",
|
|
32
36
|
"**Error and Rescue Registry** — For each capability: what breaks, how detected, what fallback."
|
|
33
37
|
],
|
|
34
38
|
interactionProtocol: [
|
|
@@ -40,19 +44,25 @@ export const SCOPE = {
|
|
|
40
44
|
"Present one structural scope issue at a time for decision. Do NOT batch. Use structured options for each scope boundary question.",
|
|
41
45
|
"Record explicit in-scope and out-of-scope contract.",
|
|
42
46
|
"Once the user accepts or rejects a recommendation, commit fully. Do not re-argue.",
|
|
47
|
+
"Before final scope approval, run an adversarial outside-voice review and reconcile every finding explicitly (accept/reject/defer with rationale).",
|
|
48
|
+
"Bound review-loop retries: max 3 iterations or early stop at quality score >= 0.8.",
|
|
43
49
|
"Produce a clean scope summary after all issues are resolved.",
|
|
44
50
|
"**STOP.** Wait for explicit user approval of scope contract before advancing to design.",
|
|
45
51
|
"**STOP BEFORE ADVANCE.** Mandatory delegation `planner` must be marked completed or explicitly waived in `.cclaw/state/delegation-log.json`. Then close the stage via `node .cclaw/hooks/stage-complete.mjs scope` (do not hand-edit `.cclaw/state/flow-state.json`)."
|
|
46
52
|
],
|
|
47
53
|
process: [
|
|
54
|
+
"Run pre-scope system audit (git log/diff/stash/debt markers).",
|
|
48
55
|
"Run premise challenge and existing-solution leverage check.",
|
|
56
|
+
"When mode is EXPAND/SELECTIVE, run brief landscape check before final scope lock.",
|
|
57
|
+
"Calibrate quality bar against 2-3 strong existing modules/files.",
|
|
49
58
|
"Produce 2-3 scope alternatives in a structured format (Name, Summary, Effort, Risk, Pros, Cons, Reuses) with minimum viable and ideal architecture options included.",
|
|
50
59
|
"Choose scope mode with user approval.",
|
|
51
60
|
"Run mode-specific analysis that matches the selected scope mode.",
|
|
52
61
|
"Walk through scope review sections one at a time.",
|
|
62
|
+
"Run outside-voice spec review loop (up to 3 iterations, quality score target >= 0.8).",
|
|
53
63
|
"Write explicit scope contract, discretion areas, and deferred items.",
|
|
54
64
|
"Freeze non-negotiable boundaries as stable Locked Decisions (D-XX IDs).",
|
|
55
|
-
"Produce scope summary plus completion dashboard (
|
|
65
|
+
"Produce scope summary plus completion dashboard (section status, critical gaps, resolved decisions, unresolved items or `None`)."
|
|
56
66
|
],
|
|
57
67
|
requiredGates: [
|
|
58
68
|
{ id: "scope_mode_selected", description: "One scope mode was explicitly selected." },
|
|
@@ -61,13 +71,16 @@ export const SCOPE = {
|
|
|
61
71
|
],
|
|
62
72
|
requiredEvidence: [
|
|
63
73
|
"Artifact written to `.cclaw/artifacts/02-scope.md`.",
|
|
74
|
+
"Pre-Scope System Audit findings are captured (git log/diff/stash/debt markers).",
|
|
64
75
|
"In-scope and out-of-scope lists are explicit.",
|
|
65
76
|
"Discretion areas are explicit (or marked as `None`).",
|
|
66
77
|
"Selected mode and rationale are documented.",
|
|
67
78
|
"Locked Decisions section lists stable D-XX IDs for non-negotiable boundaries.",
|
|
68
79
|
"Premise challenge findings documented.",
|
|
80
|
+
"Outside Voice findings and dispositions are recorded (accept/reject/defer with rationale).",
|
|
81
|
+
"Spec review loop summary includes iteration count and quality score trajectory.",
|
|
69
82
|
"Deferred items list with one-line rationale for each.",
|
|
70
|
-
"Completion dashboard lists
|
|
83
|
+
"Completion dashboard lists per-section status, critical/open gaps, decision count, and unresolved items (or `None`)."
|
|
71
84
|
],
|
|
72
85
|
inputs: ["brainstorm artifact", "timeline constraints", "product priorities"],
|
|
73
86
|
requiredContext: [
|
|
@@ -95,6 +108,7 @@ export const SCOPE = {
|
|
|
95
108
|
"scope summary produced"
|
|
96
109
|
],
|
|
97
110
|
commonRationalizations: [
|
|
111
|
+
"Skipping pre-scope audit because the task looks small",
|
|
98
112
|
"Scope silently expanded during discussion",
|
|
99
113
|
"No explicit out-of-scope section",
|
|
100
114
|
"Premise accepted without challenge",
|
|
@@ -108,7 +122,8 @@ export const SCOPE = {
|
|
|
108
122
|
"No discretion section (or explicit `None`) in artifact",
|
|
109
123
|
"No deferred/not-in-scope section",
|
|
110
124
|
"No user approval marker",
|
|
111
|
-
"Missing Locked Decisions section or decisions without D-XX IDs"
|
|
125
|
+
"Missing Locked Decisions section or decisions without D-XX IDs",
|
|
126
|
+
"Skipping outside-voice review loop and treating first draft as final"
|
|
112
127
|
],
|
|
113
128
|
policyNeedles: ["Scope mode", "In Scope", "Out of Scope", "Discretion Areas", "NOT in scope", "Premise Challenge", "Locked Decisions"],
|
|
114
129
|
artifactFile: "02-scope.md",
|
|
@@ -160,6 +175,16 @@ export const SCOPE = {
|
|
|
160
175
|
"Is observability (logging, metrics, alerts) explicitly in or out of scope?"
|
|
161
176
|
],
|
|
162
177
|
stopGate: true
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
title: "Outside Voice Reconciliation",
|
|
181
|
+
evaluationPoints: [
|
|
182
|
+
"Were adversarial findings categorized as accept/reject/defer with rationale?",
|
|
183
|
+
"Did any rejected finding still expose a real gap in assumptions?",
|
|
184
|
+
"Is quality score trajectory improving across iterations?",
|
|
185
|
+
"Did the review loop stop because quality threshold was met (>=0.8) or because retry budget was exhausted?"
|
|
186
|
+
],
|
|
187
|
+
stopGate: true
|
|
163
188
|
}
|
|
164
189
|
],
|
|
165
190
|
completionStatus: ["DONE", "DONE_WITH_CONCERNS", "BLOCKED"],
|
|
@@ -169,8 +194,11 @@ export const SCOPE = {
|
|
|
169
194
|
traceabilityRule: "Every scope boundary must be traceable to a brainstorm decision. Every downstream design choice must stay within the scope contract."
|
|
170
195
|
},
|
|
171
196
|
artifactValidation: [
|
|
197
|
+
{ section: "Pre-Scope System Audit", required: false, validationRule: "Must capture git log/diff/stash/debt-marker findings before premise challenge." },
|
|
172
198
|
{ section: "Prime Directives", required: false, validationRule: "For each scoped capability: named failure modes, explicit error surface, four data-flow paths, interaction edge cases, observability expectations, and deferred-item handling." },
|
|
173
199
|
{ section: "Premise Challenge", required: false, validationRule: "Must contain explicit answers to: right problem? direct path? what if nothing?" },
|
|
200
|
+
{ section: "Landscape Check", required: false, validationRule: "When mode is EXPAND/SELECTIVE, include at least one external reference insight and its impact on scope." },
|
|
201
|
+
{ section: "Taste Calibration", required: false, validationRule: "Must reference 2-3 strong in-repo modules/files that define the quality bar or explicitly justify omission." },
|
|
174
202
|
{ section: "Requirements", required: false, validationRule: "Table of stable requirement IDs (R1, R2, R3…) one per row with observable outcome, priority, and source. IDs are assigned once and never renumbered across scope/design/spec/plan/review; dropped requirements stay with Priority `DROPPED`." },
|
|
175
203
|
{ section: "Locked Decisions (D-XX)", required: false, validationRule: "List of stable locked decisions with IDs D-01, D-02... Each ID appears once, includes rationale, and is intended for downstream cross-stage traceability." },
|
|
176
204
|
{ section: "Implementation Alternatives", required: false, validationRule: "2-3 options with Name, Summary, Effort, Risk, Pros, Cons, and Reuses. Must include minimal viable and ideal architecture options." },
|
|
@@ -180,7 +208,9 @@ export const SCOPE = {
|
|
|
180
208
|
{ section: "Discretion Areas", required: false, validationRule: "Explicit list of implementer decision zones, or 'None' if scope is fully locked." },
|
|
181
209
|
{ section: "Deferred Items", required: false, validationRule: "Each item has one-line rationale. If empty, state 'None' explicitly." },
|
|
182
210
|
{ section: "Error & Rescue Registry", required: false, validationRule: "Each scoped capability has: failure mode, detection method, fallback decision." },
|
|
183
|
-
{ section: "
|
|
211
|
+
{ section: "Outside Voice Findings", required: false, validationRule: "Must list external/adversarial findings and disposition (accept/reject/defer) with rationale." },
|
|
212
|
+
{ section: "Spec Review Loop", required: false, validationRule: "Must record iterations (max 3), quality score per iteration, stop reason, and unresolved concerns." },
|
|
213
|
+
{ section: "Completion Dashboard", required: true, validationRule: "Lists per-review-section status, count of critical/open gaps, resolved decisions, and unresolved decisions (or 'None')." },
|
|
184
214
|
{ section: "Scope Summary", required: true, validationRule: "Clean summary: mode, strongest challenges, recommended path, accepted scope, deferred, excluded." },
|
|
185
215
|
{ section: "Dream State Mapping", required: false, validationRule: "If present (complex projects): CURRENT STATE, THIS PLAN, 12-MONTH IDEAL, and alignment verdict." },
|
|
186
216
|
{ section: "Temporal Interrogation", required: false, validationRule: "If present (complex projects): timeline simulation table with decision pressures and lock-now vs defer verdicts." }
|
|
@@ -240,6 +240,17 @@ inputs_hash: sha256:pending
|
|
|
240
240
|
(ASCII, Mermaid, or tool-generated diagram showing component boundaries and data flow direction)
|
|
241
241
|
\`\`\`
|
|
242
242
|
|
|
243
|
+
## Data-Flow Shadow Paths
|
|
244
|
+
| Path | Trigger | Fallback/Degrade behavior |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| | | |
|
|
247
|
+
|
|
248
|
+
## Error Flow Diagram
|
|
249
|
+
|
|
250
|
+
\`\`\`
|
|
251
|
+
(failure detection -> rescue action -> user-visible outcome)
|
|
252
|
+
\`\`\`
|
|
253
|
+
|
|
243
254
|
## What Already Exists
|
|
244
255
|
| Sub-problem | Existing code/library | Layer | Reuse decision |
|
|
245
256
|
|---|---|---|---|
|
|
@@ -251,10 +262,15 @@ inputs_hash: sha256:pending
|
|
|
251
262
|
- Upstream error path:
|
|
252
263
|
- Timeout/downstream path:
|
|
253
264
|
|
|
265
|
+
## Security & Threat Model
|
|
266
|
+
| Boundary | Threat | Mitigation | Owner |
|
|
267
|
+
|---|---|---|---|
|
|
268
|
+
| | | | |
|
|
269
|
+
|
|
254
270
|
## Failure Mode Table
|
|
255
|
-
|
|
|
256
|
-
|
|
257
|
-
| | | | |
|
|
271
|
+
| Method | Exception | Rescue | UserSees |
|
|
272
|
+
|---|---|---|---|
|
|
273
|
+
| | | | |
|
|
258
274
|
|
|
259
275
|
## Test Strategy
|
|
260
276
|
- Unit:
|
|
@@ -266,6 +282,16 @@ inputs_hash: sha256:pending
|
|
|
266
282
|
|---|---|---|---|
|
|
267
283
|
| | | | |
|
|
268
284
|
|
|
285
|
+
## Observability & Debuggability
|
|
286
|
+
| Signal | Source | Alert/Debug path |
|
|
287
|
+
|---|---|---|
|
|
288
|
+
| | | |
|
|
289
|
+
|
|
290
|
+
## Deployment & Rollout
|
|
291
|
+
| Step | Strategy | Rollback plan |
|
|
292
|
+
|---|---|---|
|
|
293
|
+
| | | |
|
|
294
|
+
|
|
269
295
|
## NOT in scope
|
|
270
296
|
-
|
|
271
297
|
|
|
@@ -292,10 +318,13 @@ inputs_hash: sha256:pending
|
|
|
292
318
|
| Review Section | Status | Issues |
|
|
293
319
|
|---|---|---|
|
|
294
320
|
| Architecture Review | | |
|
|
321
|
+
| Security & Threat Model | | |
|
|
295
322
|
| Code Quality Review | | |
|
|
323
|
+
| Data Flow & Interaction Edge Cases | | |
|
|
296
324
|
| Test Review | | |
|
|
297
325
|
| Performance Review | | |
|
|
298
|
-
|
|
|
326
|
+
| Observability & Debuggability | | |
|
|
327
|
+
| Deployment & Rollout Review | | |
|
|
299
328
|
|
|
300
329
|
**Decisions made:** 0 | **Unresolved:** 0
|
|
301
330
|
|
package/dist/doctor.js
CHANGED
|
@@ -674,6 +674,7 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
674
674
|
// Hook scripts
|
|
675
675
|
for (const script of [
|
|
676
676
|
"run-hook.mjs",
|
|
677
|
+
"run-hook.cmd",
|
|
677
678
|
"stage-complete.mjs",
|
|
678
679
|
"opencode-plugin.mjs"
|
|
679
680
|
]) {
|
|
@@ -1021,7 +1022,7 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
1021
1022
|
if (!(await exists(candidate)))
|
|
1022
1023
|
continue;
|
|
1023
1024
|
const content = await fs.readFile(candidate, "utf8");
|
|
1024
|
-
if (/
|
|
1025
|
+
if (/bash\s+\.cclaw\/hooks\/|\.cclaw\/hooks\/(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor)\.sh/u.test(content)) {
|
|
1025
1026
|
legacyDispatchFiles.push(path.relative(projectRoot, candidate));
|
|
1026
1027
|
}
|
|
1027
1028
|
}
|
|
@@ -1029,7 +1030,7 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
1029
1030
|
name: "warning:windows:hook_dispatch_node_only",
|
|
1030
1031
|
ok: legacyDispatchFiles.length === 0,
|
|
1031
1032
|
details: legacyDispatchFiles.length === 0
|
|
1032
|
-
? "hook configs use
|
|
1033
|
+
? "hook configs use managed .cclaw/hooks/run-hook.cmd dispatch commands"
|
|
1033
1034
|
: `warning: legacy shell hook dispatch remains in ${legacyDispatchFiles.join(", ")}`
|
|
1034
1035
|
});
|
|
1035
1036
|
// Knowledge store exists (canonical JSONL, no markdown mirror)
|
package/dist/install.js
CHANGED
|
@@ -24,7 +24,7 @@ import { rewindCommandContract, rewindCommandSkillMarkdown } from "./content/rew
|
|
|
24
24
|
import { subagentDrivenDevSkill, parallelAgentsSkill } from "./content/subagents.js";
|
|
25
25
|
import { sessionHooksSkillMarkdown } from "./content/session-hooks.js";
|
|
26
26
|
import { ironLawRuntimeDocument, ironLawsSkillMarkdown } from "./content/iron-laws.js";
|
|
27
|
-
import { stageCompleteScript, opencodePluginJs, claudeHooksJson, codexHooksJson, cursorHooksJson } from "./content/hooks.js";
|
|
27
|
+
import { stageCompleteScript, runHookCmdScript, opencodePluginJs, claudeHooksJson, codexHooksJson, cursorHooksJson } from "./content/hooks.js";
|
|
28
28
|
import { nodeHookRuntimeScript } from "./content/node-hooks.js";
|
|
29
29
|
import { META_SKILL_NAME, usingCclawSkillMarkdown } from "./content/meta-skill.js";
|
|
30
30
|
import { decisionProtocolMarkdown, completionProtocolMarkdown, ethosProtocolMarkdown } from "./content/protocols.js";
|
|
@@ -734,12 +734,14 @@ async function writeHooks(projectRoot, config) {
|
|
|
734
734
|
tddProductionPathPatterns: config.tdd?.productionPathPatterns,
|
|
735
735
|
compoundRecurrenceThreshold: config.compound?.recurrenceThreshold
|
|
736
736
|
}));
|
|
737
|
+
await writeFileSafe(path.join(hooksDir, "run-hook.cmd"), runHookCmdScript());
|
|
737
738
|
const opencodePluginSource = opencodePluginJs();
|
|
738
739
|
await writeFileSafe(path.join(hooksDir, "opencode-plugin.mjs"), opencodePluginSource);
|
|
739
740
|
try {
|
|
740
741
|
for (const script of [
|
|
741
742
|
"stage-complete.mjs",
|
|
742
743
|
"run-hook.mjs",
|
|
744
|
+
"run-hook.cmd",
|
|
743
745
|
"opencode-plugin.mjs"
|
|
744
746
|
]) {
|
|
745
747
|
await fs.chmod(path.join(hooksDir, script), 0o755);
|
|
@@ -1440,7 +1442,7 @@ function isManagedRuntimeHookCommand(command) {
|
|
|
1440
1442
|
// (e.g. `node .cclaw\hooks\run-hook.mjs ...`) still round-trip through
|
|
1441
1443
|
// sync without being duplicated alongside freshly generated entries.
|
|
1442
1444
|
const normalized = command.trim().replace(/\s+/gu, " ").replace(/\\/gu, "/");
|
|
1443
|
-
if (/(^|\s)(?:node\s+)?(?:"|')?(?:\.\/)?\.cclaw\/hooks\/run-hook\.mjs(?:"|')?\s+(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor|verify-current-state)(?:\s|$)/u.test(normalized)) {
|
|
1445
|
+
if (/(^|\s)(?:node\s+)?(?:"|')?(?:\.\/)?\.cclaw\/hooks\/run-hook\.(?:mjs|cmd)(?:"|')?\s+(?:session-start|stop-checkpoint|pre-compact|prompt-guard|workflow-guard|context-monitor|verify-current-state)(?:\s|$)/u.test(normalized)) {
|
|
1444
1446
|
return true;
|
|
1445
1447
|
}
|
|
1446
1448
|
// Codex UserPromptSubmit non-blocking state nudge.
|