cclaw-cli 0.46.9 → 0.46.11
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/harnesses-doc.d.ts +1 -0
- package/dist/content/harnesses-doc.js +35 -0
- package/dist/content/hook-events.js +1 -1
- package/dist/content/opencode-plugin.js +3 -14
- package/dist/content/skills.d.ts +2 -2
- package/dist/content/skills.js +32 -32
- package/dist/content/stage-schema.d.ts +6 -6
- package/dist/content/stage-schema.js +22 -27
- package/dist/content/stages/tdd.d.ts +2 -0
- package/dist/content/stages/tdd.js +63 -1
- package/dist/doctor.js +28 -1
- package/dist/flow-state.js +3 -3
- package/dist/gate-evidence.js +8 -7
- package/dist/hook-schemas/codex-hooks.v1.json +1 -0
- package/dist/install.js +4 -2
- package/dist/internal/advance-stage.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HARNESS_ADAPTERS, harnessTier } from "../harness-adapters.js";
|
|
2
2
|
import { HOOK_EVENTS_BY_HARNESS, HOOK_SEMANTIC_EVENTS } from "./hook-events.js";
|
|
3
3
|
import { HARNESS_PLAYBOOKS_DIR, harnessPlaybookFileName } from "./harness-playbooks.js";
|
|
4
|
+
import { HARNESS_TOOL_REFS_DIR } from "./harness-tool-refs.js";
|
|
4
5
|
function harnessTitle(harness) {
|
|
5
6
|
switch (harness) {
|
|
6
7
|
case "claude":
|
|
@@ -123,3 +124,37 @@ Harness-specific additions:
|
|
|
123
124
|
- \`cclaw doctor\` validates shim, hook, and lifecycle surfaces against this capability model.
|
|
124
125
|
`;
|
|
125
126
|
}
|
|
127
|
+
export function harnessDocsOverviewMarkdown() {
|
|
128
|
+
const harnesses = Object.keys(HARNESS_ADAPTERS);
|
|
129
|
+
const rows = harnesses
|
|
130
|
+
.map((harness) => {
|
|
131
|
+
const tier = harnessTier(harness);
|
|
132
|
+
const toolMap = `\`.cclaw/${HARNESS_TOOL_REFS_DIR}/${harness}.md\``;
|
|
133
|
+
const playbook = `\`.cclaw/${HARNESS_PLAYBOOKS_DIR}/${harnessPlaybookFileName(harness)}\``;
|
|
134
|
+
return `| ${harnessTitle(harness)} | \`${harness}\` | \`${tier}\` | ${toolMap} | ${playbook} |`;
|
|
135
|
+
})
|
|
136
|
+
.join("\n");
|
|
137
|
+
return `# Harness Docs Overview
|
|
138
|
+
|
|
139
|
+
Single entrypoint for harness-specific references generated by cclaw sync.
|
|
140
|
+
|
|
141
|
+
## Core references
|
|
142
|
+
|
|
143
|
+
- Integration matrix: \`.cclaw/references/harnesses.md\`
|
|
144
|
+
- Tool-map index: \`.cclaw/references/${HARNESS_TOOL_REFS_DIR}/README.md\`
|
|
145
|
+
- Playbook index: \`.cclaw/references/${HARNESS_PLAYBOOKS_DIR}/README.md\`
|
|
146
|
+
|
|
147
|
+
## Per-harness quick links
|
|
148
|
+
|
|
149
|
+
| Harness | ID | Tier | Tool map | Playbook |
|
|
150
|
+
|---|---|---|---|---|
|
|
151
|
+
${rows}
|
|
152
|
+
|
|
153
|
+
## How to use this pack
|
|
154
|
+
|
|
155
|
+
1. Start with \`harnesses.md\` to understand capability/tier differences.
|
|
156
|
+
2. Open the harness-specific tool map before writing stage logic that depends on tool names.
|
|
157
|
+
3. Open the harness-specific playbook before asserting delegation parity behavior.
|
|
158
|
+
4. If docs disagree, treat \`harnesses.md\` + harness adapter capabilities as source of truth and regenerate.
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
@@ -29,7 +29,7 @@ export const HOOK_EVENTS_BY_HARNESS = {
|
|
|
29
29
|
pre_tool_workflow_guard: "plugin tool.execute.before -> workflow-guard.sh",
|
|
30
30
|
post_tool_context_monitor: "plugin tool.execute.after -> context-monitor.sh",
|
|
31
31
|
stop_checkpoint: "plugin session.idle -> stop-checkpoint.sh",
|
|
32
|
-
precompact_digest: "plugin session.
|
|
32
|
+
precompact_digest: "plugin session.compacted -> pre-compact.sh"
|
|
33
33
|
},
|
|
34
34
|
codex: {
|
|
35
35
|
// Codex CLI v0.114+ exposes lifecycle hooks via `.codex/hooks.json`,
|
|
@@ -240,23 +240,12 @@ export default function cclawPlugin(ctx) {
|
|
|
240
240
|
// the system transform hook instead.
|
|
241
241
|
refreshBootstrapCache();
|
|
242
242
|
}
|
|
243
|
+
if (eventType === "session.compacted") {
|
|
244
|
+
await runHookScript("pre-compact.sh", eventData ?? {});
|
|
245
|
+
}
|
|
243
246
|
if (eventType === "session.idle") {
|
|
244
247
|
await runHookScript("stop-checkpoint.sh", { loop_count: 0 });
|
|
245
248
|
}
|
|
246
|
-
if (eventType === "tool.execute.before") {
|
|
247
|
-
const toolPayload = normalizeToolPayload(eventData, undefined);
|
|
248
|
-
const promptOk = await runHookScript("prompt-guard.sh", toolPayload);
|
|
249
|
-
const workflowOk = await runHookScript("workflow-guard.sh", toolPayload);
|
|
250
|
-
if (!promptOk || !workflowOk) {
|
|
251
|
-
throw new Error(
|
|
252
|
-
"cclaw OpenCode guard blocked tool.execute.before (prompt/workflow guard non-zero exit)."
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
if (eventType === "tool.execute.after") {
|
|
257
|
-
const toolPayload = normalizeToolPayload(eventData, undefined);
|
|
258
|
-
await runHookScript("context-monitor.sh", toolPayload);
|
|
259
|
-
}
|
|
260
249
|
},
|
|
261
250
|
"tool.execute.before": async (input, output) => {
|
|
262
251
|
const payload = normalizeToolPayload(input, output);
|
package/dist/content/skills.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { FlowStage } from "../types.js";
|
|
1
|
+
import type { FlowStage, FlowTrack } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Long-form Batch Execution walkthrough. Rendered once into
|
|
4
4
|
* \`.cclaw/references/stages/tdd-batch-walkthrough.md\` by the installer.
|
|
5
5
|
*/
|
|
6
6
|
export declare const TDD_BATCH_WALKTHROUGH_MARKDOWN = "# TDD \u2014 Batch Execution Walkthrough\n\nDetailed RED / GREEN / REFACTOR transcript for a 3-task batch. Illustrative\nonly \u2014 do not copy the command names blindly, match them to your stack.\n\n## Batch 1 example tasks\n\n| Task ID | Description | AC | Verification |\n|---|---|---|---|\n| T-1 `[~3m]` | Add `User.emailNormalized` column | AC-1 | `npm test -- users/schema` |\n| T-2 `[~4m]` | Normalize on write in `UserRepo.save` | AC-1 | `npm test -- users/repo` |\n| T-3 `[~3m]` | Reject duplicates in `UserService.signup` | AC-2 | `npm test -- users/service` |\n\n## Execution transcript\n\n### T-1 \u2014 RED\n\n> Run: `npm test -- users/schema` \u2192 **FAIL** (missing column: `emailNormalized`). Captured the failure stack as RED evidence. No production code touched yet.\n\n### T-1 \u2014 GREEN\n\n> Added the column in the schema module. Re-ran `npm test -- users/schema` \u2192 **PASS**. Ran the full suite `npm test` \u2192 **PASS**. Captured both outputs as GREEN evidence.\n\n### T-1 \u2014 REFACTOR\n\n> Extracted the column definition into a shared `NormalizedEmail` type used by T-2/T-3. Re-ran `npm test` \u2192 **PASS**. Captured REFACTOR note: \"Extracted NormalizedEmail type to keep T-2/T-3 DRY; zero behavior change, all tests still green.\"\n\n### T-2 \u2014 RED / GREEN / REFACTOR\n\nWrite the repo test that expects normalised writes, watch it fail (RED), implement normalisation inside `UserRepo.save` only (GREEN), then refactor the normaliser out of the repo into a helper shared with T-3 (REFACTOR).\n\n### T-3 \u2014 RED / GREEN / REFACTOR\n\nWrite the service-level duplicate test that expects a rejection, watch it fail (RED), add the duplicate check in `UserService.signup` (GREEN), refactor the error message into a named constant (REFACTOR).\n\n## Batch gate check\n\nAfter T-3 REFACTOR, before declaring Batch 1 done:\n\n1. Run the full suite (`npm test`) one final time \u2192 **PASS** captured as batch-exit evidence.\n2. Verify the TDD artifact contains RED, GREEN, and REFACTOR evidence for T-1, T-2, **and** T-3. No partial batches.\n3. Only now mark Batch 1 complete. Batch 2 cannot start until this step.\n\n## When to stop mid-batch (do NOT push through)\n\n- A RED test fails for a reason you did not predict (e.g. an unrelated flaky test) \u2192 **pause**, diagnose, log an operational-self-improvement entry, and decide with the user before proceeding.\n- A GREEN step would require touching code outside the task's acceptance criterion \u2192 **pause**, the task is scoped wrong; adjust the plan or open a follow-up task.\n- The same RED failure reappears after a GREEN change \u2192 **escalate** per the 3-attempts rule; do not keep patching.\n";
|
|
7
7
|
export declare function stageSkillFolder(stage: FlowStage): string;
|
|
8
|
-
export declare function stageSkillMarkdown(stage: FlowStage): string;
|
|
8
|
+
export declare function stageSkillMarkdown(stage: FlowStage, track?: FlowTrack): string;
|
package/dist/content/skills.js
CHANGED
|
@@ -5,8 +5,8 @@ import { stageAutoSubagentDispatch, stageSchema } from "./stage-schema.js";
|
|
|
5
5
|
const VERIFICATION_STAGES = ["tdd", "review", "ship"];
|
|
6
6
|
const DECISION_PROTOCOL_PATH = `${RUNTIME_ROOT}/references/protocols/decision.md`;
|
|
7
7
|
const COMPLETION_PROTOCOL_PATH = `${RUNTIME_ROOT}/references/protocols/completion.md`;
|
|
8
|
-
function whenNotToUseBlock(stage) {
|
|
9
|
-
const schema = stageSchema(stage);
|
|
8
|
+
function whenNotToUseBlock(stage, track) {
|
|
9
|
+
const schema = stageSchema(stage, track);
|
|
10
10
|
if (schema.whenNotToUse.length === 0) {
|
|
11
11
|
return "";
|
|
12
12
|
}
|
|
@@ -15,8 +15,8 @@ ${schema.whenNotToUse.map((item) => `- ${item}`).join("\n")}
|
|
|
15
15
|
|
|
16
16
|
`;
|
|
17
17
|
}
|
|
18
|
-
function contextLoadingBlock(stage) {
|
|
19
|
-
const trace = stageSchema(stage).crossStageTrace;
|
|
18
|
+
function contextLoadingBlock(stage, track) {
|
|
19
|
+
const trace = stageSchema(stage, track).crossStageTrace;
|
|
20
20
|
const readLines = trace.readsFrom.length > 0
|
|
21
21
|
? trace.readsFrom.map((value) => `- \`${value}\``).join("\n")
|
|
22
22
|
: "- (first stage — no upstream artifacts)";
|
|
@@ -31,7 +31,7 @@ ${readLines}
|
|
|
31
31
|
\`.cclaw/knowledge.jsonl\` when the digest is insufficient.
|
|
32
32
|
`;
|
|
33
33
|
}
|
|
34
|
-
function autoSubagentDispatchBlock(stage) {
|
|
34
|
+
function autoSubagentDispatchBlock(stage, track) {
|
|
35
35
|
const rules = stageAutoSubagentDispatch(stage);
|
|
36
36
|
if (rules.length === 0)
|
|
37
37
|
return "";
|
|
@@ -41,7 +41,7 @@ function autoSubagentDispatchBlock(stage) {
|
|
|
41
41
|
return `| ${rule.agent} | ${rule.mode} | ${userGate} | ${rule.when} |`;
|
|
42
42
|
})
|
|
43
43
|
.join("\n");
|
|
44
|
-
const mandatory = stageSchema(stage).mandatoryDelegations;
|
|
44
|
+
const mandatory = stageSchema(stage, track).mandatoryDelegations;
|
|
45
45
|
const mandatoryList = mandatory.length > 0 ? mandatory.map((a) => `\`${a}\``).join(", ") : "none";
|
|
46
46
|
const delegationLogRel = `${RUNTIME_ROOT}/state/delegation-log.json`;
|
|
47
47
|
return `## Automatic Subagent Dispatch
|
|
@@ -54,8 +54,8 @@ Mandatory delegations for this stage: ${mandatoryList}.
|
|
|
54
54
|
Record completion/waiver in \`${delegationLogRel}\` before stage completion.
|
|
55
55
|
`;
|
|
56
56
|
}
|
|
57
|
-
function researchPlaybooksBlock(stage) {
|
|
58
|
-
const playbooks = stageSchema(stage).researchPlaybooks ?? [];
|
|
57
|
+
function researchPlaybooksBlock(stage, track) {
|
|
58
|
+
const playbooks = stageSchema(stage, track).researchPlaybooks ?? [];
|
|
59
59
|
if (playbooks.length === 0)
|
|
60
60
|
return "";
|
|
61
61
|
const rows = playbooks
|
|
@@ -70,8 +70,8 @@ and record outcomes in the stage artifact when relevant.
|
|
|
70
70
|
${rows}
|
|
71
71
|
`;
|
|
72
72
|
}
|
|
73
|
-
function reviewSectionsBlock(stage) {
|
|
74
|
-
const schema = stageSchema(stage);
|
|
73
|
+
function reviewSectionsBlock(stage, track) {
|
|
74
|
+
const schema = stageSchema(stage, track);
|
|
75
75
|
if (schema.reviewSections.length === 0)
|
|
76
76
|
return "";
|
|
77
77
|
const sections = schema.reviewSections
|
|
@@ -103,8 +103,8 @@ Reference utility skill:
|
|
|
103
103
|
\`.cclaw/skills/verification-before-completion/SKILL.md\`
|
|
104
104
|
`;
|
|
105
105
|
}
|
|
106
|
-
function batchExecutionModeBlock(stage) {
|
|
107
|
-
const schema = stageSchema(stage);
|
|
106
|
+
function batchExecutionModeBlock(stage, track) {
|
|
107
|
+
const schema = stageSchema(stage, track);
|
|
108
108
|
if (!schema.batchExecutionAllowed)
|
|
109
109
|
return "";
|
|
110
110
|
return `## Batch Execution Mode
|
|
@@ -118,8 +118,8 @@ Detailed walkthrough:
|
|
|
118
118
|
\`.cclaw/${STAGE_EXAMPLES_REFERENCE_DIR}/tdd-batch-walkthrough.md\`
|
|
119
119
|
`;
|
|
120
120
|
}
|
|
121
|
-
function crossStageTraceBlock(stage) {
|
|
122
|
-
const trace = stageSchema(stage).crossStageTrace;
|
|
121
|
+
function crossStageTraceBlock(stage, track) {
|
|
122
|
+
const trace = stageSchema(stage, track).crossStageTrace;
|
|
123
123
|
const reads = trace.readsFrom.length > 0
|
|
124
124
|
? trace.readsFrom.map((r) => `- ${r}`).join("\n")
|
|
125
125
|
: "- (first stage — no upstream artifacts)";
|
|
@@ -137,8 +137,8 @@ ${writes}
|
|
|
137
137
|
Rule: ${trace.traceabilityRule}
|
|
138
138
|
`;
|
|
139
139
|
}
|
|
140
|
-
function artifactValidationBlock(stage) {
|
|
141
|
-
const validations = stageSchema(stage).artifactValidation;
|
|
140
|
+
function artifactValidationBlock(stage, track) {
|
|
141
|
+
const validations = stageSchema(stage, track).artifactValidation;
|
|
142
142
|
if (validations.length === 0)
|
|
143
143
|
return "";
|
|
144
144
|
const rows = validations
|
|
@@ -206,7 +206,7 @@ function stageSpecificSeeAlso(stage) {
|
|
|
206
206
|
};
|
|
207
207
|
return refs[stage];
|
|
208
208
|
}
|
|
209
|
-
function completionParametersBlock(schema) {
|
|
209
|
+
function completionParametersBlock(schema, track) {
|
|
210
210
|
const gateList = schema.requiredGates.map((g) => `\`${g.id}\``).join(", ");
|
|
211
211
|
const mandatory = schema.mandatoryDelegations.length > 0
|
|
212
212
|
? schema.mandatoryDelegations.map((a) => `\`${a}\``).join(", ")
|
|
@@ -214,7 +214,7 @@ function completionParametersBlock(schema) {
|
|
|
214
214
|
const nextStage = schema.next === "done" ? "done" : schema.next;
|
|
215
215
|
const nextDescription = schema.next === "done"
|
|
216
216
|
? "flow complete"
|
|
217
|
-
: stageSchema(schema.next).skillDescription;
|
|
217
|
+
: stageSchema(schema.next, track).skillDescription;
|
|
218
218
|
return `## Completion Parameters
|
|
219
219
|
|
|
220
220
|
- \`stage\`: \`${schema.stage}\`
|
|
@@ -230,8 +230,8 @@ Apply shared completion logic from:
|
|
|
230
230
|
\`${COMPLETION_PROTOCOL_PATH}\`
|
|
231
231
|
`;
|
|
232
232
|
}
|
|
233
|
-
function quickStartBlock(stage) {
|
|
234
|
-
const schema = stageSchema(stage);
|
|
233
|
+
function quickStartBlock(stage, track) {
|
|
234
|
+
const schema = stageSchema(stage, track);
|
|
235
235
|
const gatePreview = schema.requiredGates.slice(0, 3).map((g) => `\`${g.id}\``).join(", ");
|
|
236
236
|
return `## Quick Start
|
|
237
237
|
|
|
@@ -297,8 +297,8 @@ After T-3 REFACTOR, before declaring Batch 1 done:
|
|
|
297
297
|
export function stageSkillFolder(stage) {
|
|
298
298
|
return stageSchema(stage).skillFolder;
|
|
299
299
|
}
|
|
300
|
-
export function stageSkillMarkdown(stage) {
|
|
301
|
-
const schema = stageSchema(stage);
|
|
300
|
+
export function stageSkillMarkdown(stage, track = "standard") {
|
|
301
|
+
const schema = stageSchema(stage, track);
|
|
302
302
|
const gateList = schema.requiredGates
|
|
303
303
|
.map((g) => `- \`${g.id}\` — ${g.description}`)
|
|
304
304
|
.join("\n");
|
|
@@ -324,7 +324,7 @@ If you are about to violate the Iron Law, STOP. No amount of urgency, partial pr
|
|
|
324
324
|
|
|
325
325
|
</EXTREMELY-IMPORTANT>
|
|
326
326
|
|
|
327
|
-
${quickStartBlock(stage)}
|
|
327
|
+
${quickStartBlock(stage, track)}
|
|
328
328
|
|
|
329
329
|
## Overview
|
|
330
330
|
${schema.purpose}
|
|
@@ -332,16 +332,16 @@ ${schema.purpose}
|
|
|
332
332
|
## When to Use
|
|
333
333
|
${schema.whenToUse.map((item) => `- ${item}`).join("\n")}
|
|
334
334
|
|
|
335
|
-
${whenNotToUseBlock(stage)}
|
|
335
|
+
${whenNotToUseBlock(stage, track)}
|
|
336
336
|
## Inputs
|
|
337
337
|
${schema.inputs.length > 0 ? schema.inputs.map((item) => `- ${item}`).join("\n") : "- (first stage — no required inputs)"}
|
|
338
338
|
|
|
339
339
|
## Required Context
|
|
340
340
|
${schema.requiredContext.length > 0 ? schema.requiredContext.map((item) => `- ${item}`).join("\n") : "- None beyond this skill"}
|
|
341
341
|
|
|
342
|
-
${contextLoadingBlock(stage)}
|
|
343
|
-
${autoSubagentDispatchBlock(stage)}
|
|
344
|
-
${researchPlaybooksBlock(stage)}
|
|
342
|
+
${contextLoadingBlock(stage, track)}
|
|
343
|
+
${autoSubagentDispatchBlock(stage, track)}
|
|
344
|
+
${researchPlaybooksBlock(stage, track)}
|
|
345
345
|
|
|
346
346
|
## Outputs
|
|
347
347
|
${schema.outputs.map((item) => `- ${item}`).join("\n")}
|
|
@@ -365,7 +365,7 @@ ${schema.interactionProtocol.map((item, i) => `${i + 1}. ${item}`).join("\n")}
|
|
|
365
365
|
Shared decision/ask-user protocol:
|
|
366
366
|
\`${DECISION_PROTOCOL_PATH}\`
|
|
367
367
|
|
|
368
|
-
${batchExecutionModeBlock(stage)}
|
|
368
|
+
${batchExecutionModeBlock(stage, track)}
|
|
369
369
|
## Required Gates
|
|
370
370
|
${gateList}
|
|
371
371
|
|
|
@@ -375,10 +375,10 @@ ${evidenceList}
|
|
|
375
375
|
## Process
|
|
376
376
|
${schema.process.map((item, i) => `${i + 1}. ${item}`).join("\n")}
|
|
377
377
|
|
|
378
|
-
${reviewSectionsBlock(stage)}
|
|
378
|
+
${reviewSectionsBlock(stage, track)}
|
|
379
379
|
${verificationBlock(stage)}
|
|
380
|
-
${crossStageTraceBlock(stage)}
|
|
381
|
-
${artifactValidationBlock(stage)}
|
|
380
|
+
${crossStageTraceBlock(stage, track)}
|
|
381
|
+
${artifactValidationBlock(stage, track)}
|
|
382
382
|
|
|
383
383
|
## Anti-Patterns & Red Flags
|
|
384
384
|
${mergedAntiPatterns(schema)}
|
|
@@ -386,7 +386,7 @@ ${mergedAntiPatterns(schema)}
|
|
|
386
386
|
## Verification
|
|
387
387
|
${schema.exitCriteria.map((item) => `- [ ] ${item}`).join("\n")}
|
|
388
388
|
|
|
389
|
-
${completionParametersBlock(schema)}
|
|
389
|
+
${completionParametersBlock(schema, track)}
|
|
390
390
|
## Shared Stage Guidance
|
|
391
391
|
See:
|
|
392
392
|
- \`${STAGE_COMMON_GUIDANCE_REL_PATH}\`
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { FlowStage, TransitionRule } from "../types.js";
|
|
1
|
+
import type { FlowStage, FlowTrack, TransitionRule } from "../types.js";
|
|
2
2
|
import type { StageAutoSubagentDispatch, StageSchema } from "./stages/schema-types.js";
|
|
3
3
|
export type { ArtifactValidation, CrossStageTrace, ReviewSection, StageAutoSubagentDispatch, StageGate, StageSchema, StageSchemaInput } from "./stages/schema-types.js";
|
|
4
4
|
/** Transition guard: agents with `mode: "mandatory"` in auto-subagent dispatch for this stage. */
|
|
5
5
|
export declare function mandatoryDelegationsForStage(stage: FlowStage): string[];
|
|
6
|
-
export declare function stageSchema(stage: FlowStage): StageSchema;
|
|
7
|
-
export declare function orderedStageSchemas(): StageSchema[];
|
|
8
|
-
export declare function stageGateIds(stage: FlowStage): string[];
|
|
9
|
-
export declare function stageRecommendedGateIds(stage: FlowStage): string[];
|
|
6
|
+
export declare function stageSchema(stage: FlowStage, track?: FlowTrack): StageSchema;
|
|
7
|
+
export declare function orderedStageSchemas(track?: FlowTrack): StageSchema[];
|
|
8
|
+
export declare function stageGateIds(stage: FlowStage, track?: FlowTrack): string[];
|
|
9
|
+
export declare function stageRecommendedGateIds(stage: FlowStage, track?: FlowTrack): string[];
|
|
10
10
|
export declare function nextCclawCommand(stage: FlowStage): string;
|
|
11
11
|
export declare function buildTransitionRules(): TransitionRule[];
|
|
12
|
-
export declare function stagePolicyNeedles(stage: FlowStage): string[];
|
|
12
|
+
export declare function stagePolicyNeedles(stage: FlowStage, track?: FlowTrack): string[];
|
|
13
13
|
export declare function stageAutoSubagentDispatch(stage: FlowStage): StageAutoSubagentDispatch[];
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import { COMMAND_FILE_ORDER } from "../constants.js";
|
|
2
2
|
import { BRAINSTORM, SCOPE, DESIGN, SPEC, PLAN, TDD, REVIEW, SHIP } from "./stages/index.js";
|
|
3
|
-
|
|
4
|
-
// NOTE: The former QUESTION_FORMAT_SPEC / ERROR_BUDGET_SPEC exports were
|
|
5
|
-
// hoisted into `src/content/meta-skill.ts` (Shared Decision + Tool-Use
|
|
6
|
-
// Protocol). They are no longer re-exported from here to avoid duplication
|
|
7
|
-
// and drift. Stage skills cite the meta-skill by path instead.
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
/**
|
|
10
|
-
* Gate tiers:
|
|
11
|
-
* - required: blocking for stage completion.
|
|
12
|
-
* - recommended: quality signal; unmet -> DONE_WITH_CONCERNS, not BLOCKED.
|
|
13
|
-
*/
|
|
3
|
+
import { tddStageForTrack } from "./stages/tdd.js";
|
|
14
4
|
const REQUIRED_GATE_IDS = {
|
|
15
5
|
brainstorm: [
|
|
16
6
|
"brainstorm_approaches_compared",
|
|
@@ -39,11 +29,12 @@ const REQUIRED_GATE_IDS = {
|
|
|
39
29
|
"plan_acceptance_mapped",
|
|
40
30
|
"plan_wait_for_confirm"
|
|
41
31
|
],
|
|
42
|
-
tdd: [
|
|
32
|
+
tdd: (track) => [
|
|
43
33
|
"tdd_red_test_written",
|
|
44
34
|
"tdd_green_full_suite",
|
|
45
35
|
"tdd_refactor_completed",
|
|
46
|
-
"tdd_verified_before_complete"
|
|
36
|
+
"tdd_verified_before_complete",
|
|
37
|
+
...(track === "quick" ? [] : ["tdd_traceable_to_plan"])
|
|
47
38
|
],
|
|
48
39
|
review: [
|
|
49
40
|
"review_layer1_spec_compliance",
|
|
@@ -64,12 +55,16 @@ const REQUIRED_ARTIFACT_SECTIONS = {
|
|
|
64
55
|
design: ["Architecture Boundaries", "Architecture Diagram", "Failure Mode Table", "Completion Dashboard"],
|
|
65
56
|
spec: ["Acceptance Criteria", "Edge Cases", "Testability Map", "Approval"],
|
|
66
57
|
plan: ["Task List", "Dependency Batches", "Acceptance Mapping", "WAIT_FOR_CONFIRM"],
|
|
67
|
-
tdd: ["RED Evidence", "GREEN Evidence", "REFACTOR Notes", "Traceability"],
|
|
58
|
+
tdd: ["RED Evidence", "GREEN Evidence", "REFACTOR Notes", "Traceability", "Verification Ladder"],
|
|
68
59
|
review: ["Layer 1 Verdict", "Review Army Contract", "Severity Summary", "Final Verdict"],
|
|
69
60
|
ship: ["Preflight Results", "Release Notes", "Rollback Plan", "Finalization"]
|
|
70
61
|
};
|
|
71
|
-
function
|
|
72
|
-
const
|
|
62
|
+
function resolveRequiredGateIds(stage, track) {
|
|
63
|
+
const raw = REQUIRED_GATE_IDS[stage];
|
|
64
|
+
return typeof raw === "function" ? raw(track) : raw;
|
|
65
|
+
}
|
|
66
|
+
function tieredStageGates(stage, gates, track) {
|
|
67
|
+
const requiredSet = new Set(resolveRequiredGateIds(stage, track));
|
|
73
68
|
return gates.map((gate) => {
|
|
74
69
|
return {
|
|
75
70
|
...gate,
|
|
@@ -233,9 +228,9 @@ export function mandatoryDelegationsForStage(stage) {
|
|
|
233
228
|
.filter((d) => d.mode === "mandatory")
|
|
234
229
|
.map((d) => d.agent);
|
|
235
230
|
}
|
|
236
|
-
export function stageSchema(stage) {
|
|
237
|
-
const base = STAGE_SCHEMA_MAP[stage];
|
|
238
|
-
const tieredGates = tieredStageGates(stage, base.requiredGates);
|
|
231
|
+
export function stageSchema(stage, track = "standard") {
|
|
232
|
+
const base = stage === "tdd" ? tddStageForTrack(track) : STAGE_SCHEMA_MAP[stage];
|
|
233
|
+
const tieredGates = tieredStageGates(stage, base.requiredGates, track);
|
|
239
234
|
const tieredValidation = tieredArtifactValidation(stage, base.artifactValidation);
|
|
240
235
|
return {
|
|
241
236
|
...base,
|
|
@@ -244,16 +239,16 @@ export function stageSchema(stage) {
|
|
|
244
239
|
mandatoryDelegations: mandatoryDelegationsForStage(stage)
|
|
245
240
|
};
|
|
246
241
|
}
|
|
247
|
-
export function orderedStageSchemas() {
|
|
248
|
-
return COMMAND_FILE_ORDER.map((stage) => stageSchema(stage));
|
|
242
|
+
export function orderedStageSchemas(track = "standard") {
|
|
243
|
+
return COMMAND_FILE_ORDER.map((stage) => stageSchema(stage, track));
|
|
249
244
|
}
|
|
250
|
-
export function stageGateIds(stage) {
|
|
251
|
-
return stageSchema(stage).requiredGates
|
|
245
|
+
export function stageGateIds(stage, track = "standard") {
|
|
246
|
+
return stageSchema(stage, track).requiredGates
|
|
252
247
|
.filter((gate) => gate.tier === "required")
|
|
253
248
|
.map((gate) => gate.id);
|
|
254
249
|
}
|
|
255
|
-
export function stageRecommendedGateIds(stage) {
|
|
256
|
-
return stageSchema(stage).requiredGates
|
|
250
|
+
export function stageRecommendedGateIds(stage, track = "standard") {
|
|
251
|
+
return stageSchema(stage, track).requiredGates
|
|
257
252
|
.filter((gate) => gate.tier === "recommended")
|
|
258
253
|
.map((gate) => gate.id);
|
|
259
254
|
}
|
|
@@ -275,8 +270,8 @@ export function buildTransitionRules() {
|
|
|
275
270
|
}
|
|
276
271
|
return rules;
|
|
277
272
|
}
|
|
278
|
-
export function stagePolicyNeedles(stage) {
|
|
279
|
-
return stageSchema(stage).policyNeedles;
|
|
273
|
+
export function stagePolicyNeedles(stage, track = "standard") {
|
|
274
|
+
return stageSchema(stage, track).policyNeedles;
|
|
280
275
|
}
|
|
281
276
|
export function stageAutoSubagentDispatch(stage) {
|
|
282
277
|
return STAGE_AUTO_SUBAGENT_DISPATCH[stage];
|
|
@@ -179,7 +179,7 @@ export const TDD = {
|
|
|
179
179
|
{ section: "GREEN Evidence", required: true, validationRule: "Full suite pass output captured." },
|
|
180
180
|
{ section: "REFACTOR Notes", required: true, validationRule: "What changed, why, behavior preservation confirmed." },
|
|
181
181
|
{ section: "Traceability", required: true, validationRule: "Plan task ID and spec criterion linked." },
|
|
182
|
-
{ section: "Verification Ladder", required:
|
|
182
|
+
{ section: "Verification Ladder", required: true, validationRule: "Per-slice verification tier (static, command, behavioral, human) with evidence captured for the highest tier reached this turn." },
|
|
183
183
|
{ section: "Coverage Targets", required: false, validationRule: "If present: per-module or per-code-type coverage thresholds with current values and measurement commands." },
|
|
184
184
|
{ section: "Test Pyramid Shape", required: false, validationRule: "If present: per-slice count of Small/Medium/Large tests added, to let reviewers verify the suite is not drifting top-heavy." },
|
|
185
185
|
{ section: "Prove-It Reproduction", required: false, validationRule: "Required for bug-fix slices: original failing reproduction test (RED without fix), passing output with fix (GREEN), and a note confirming the test fails again if the fix is reverted." },
|
|
@@ -187,3 +187,65 @@ export const TDD = {
|
|
|
187
187
|
],
|
|
188
188
|
batchExecutionAllowed: true
|
|
189
189
|
};
|
|
190
|
+
function quickTrackText(value) {
|
|
191
|
+
return value
|
|
192
|
+
.replace(/\btask from the plan\b/giu, "acceptance criterion from the spec")
|
|
193
|
+
.replace(/\bplan task ID\b/giu, "acceptance criterion ID")
|
|
194
|
+
.replace(/\bplan task\b/giu, "acceptance criterion")
|
|
195
|
+
.replace(/\bplan row\b/giu, "acceptance row")
|
|
196
|
+
.replace(/\bplan slice\b/giu, "acceptance slice")
|
|
197
|
+
.replace(/\bplan artifact\b/giu, "spec artifact")
|
|
198
|
+
.replace(/\btraceable to plan slice\b/giu, "traceable to acceptance criterion")
|
|
199
|
+
.replace(/05-plan\.md/gu, "04-spec.md");
|
|
200
|
+
}
|
|
201
|
+
function tddQuickTrackVariant() {
|
|
202
|
+
return {
|
|
203
|
+
...TDD,
|
|
204
|
+
skillDescription: quickTrackText(TDD.skillDescription),
|
|
205
|
+
hardGate: quickTrackText(TDD.hardGate),
|
|
206
|
+
checklist: TDD.checklist.map(quickTrackText),
|
|
207
|
+
interactionProtocol: TDD.interactionProtocol.map(quickTrackText),
|
|
208
|
+
process: TDD.process.map(quickTrackText),
|
|
209
|
+
requiredGates: TDD.requiredGates.map((gate) => gate.id === "tdd_traceable_to_plan"
|
|
210
|
+
? { ...gate, description: "Change traceability to acceptance criterion is explicit." }
|
|
211
|
+
: gate),
|
|
212
|
+
requiredEvidence: TDD.requiredEvidence.map(quickTrackText),
|
|
213
|
+
inputs: TDD.inputs.map(quickTrackText),
|
|
214
|
+
requiredContext: ["spec artifact", "existing test patterns"],
|
|
215
|
+
policyNeedles: TDD.policyNeedles.map(quickTrackText),
|
|
216
|
+
reviewSections: TDD.reviewSections.map((section) => ({
|
|
217
|
+
...section,
|
|
218
|
+
evaluationPoints: section.evaluationPoints.map(quickTrackText)
|
|
219
|
+
})),
|
|
220
|
+
crossStageTrace: {
|
|
221
|
+
...TDD.crossStageTrace,
|
|
222
|
+
readsFrom: [".cclaw/artifacts/04-spec.md"],
|
|
223
|
+
traceabilityRule: "Every RED test traces to an acceptance criterion. Every GREEN change traces to a RED test. Evidence chain must be unbroken."
|
|
224
|
+
},
|
|
225
|
+
artifactValidation: TDD.artifactValidation.map((row) => {
|
|
226
|
+
if (row.section === "Acceptance Mapping") {
|
|
227
|
+
return {
|
|
228
|
+
...row,
|
|
229
|
+
required: true,
|
|
230
|
+
validationRule: "Each RED test links to a spec acceptance criterion ID (for example AC-1)."
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
if (row.section === "Traceability") {
|
|
234
|
+
return {
|
|
235
|
+
...row,
|
|
236
|
+
validationRule: "Acceptance criterion IDs are linked to RED/GREEN evidence."
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
...row,
|
|
241
|
+
validationRule: quickTrackText(row.validationRule)
|
|
242
|
+
};
|
|
243
|
+
})
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
export function tddStageForTrack(track) {
|
|
247
|
+
if (track === "quick") {
|
|
248
|
+
return tddQuickTrackVariant();
|
|
249
|
+
}
|
|
250
|
+
return TDD;
|
|
251
|
+
}
|
package/dist/doctor.js
CHANGED
|
@@ -623,6 +623,8 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
623
623
|
"session-start.sh",
|
|
624
624
|
"stop-checkpoint.sh",
|
|
625
625
|
"run-hook.cmd",
|
|
626
|
+
"stage-complete.sh",
|
|
627
|
+
"pre-compact.sh",
|
|
626
628
|
"prompt-guard.sh",
|
|
627
629
|
"workflow-guard.sh",
|
|
628
630
|
"context-monitor.sh"
|
|
@@ -816,10 +818,13 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
816
818
|
const codexDoc = await readHookDocument(codexHooksFile);
|
|
817
819
|
const codexHooks = toObject(codexDoc?.hooks) ?? {};
|
|
818
820
|
const codexSessionCmds = collectHookCommands(codexHooks.SessionStart);
|
|
821
|
+
const codexUserPromptCmds = collectHookCommands(codexHooks.UserPromptSubmit);
|
|
819
822
|
const codexPreCmds = collectHookCommands(codexHooks.PreToolUse);
|
|
820
823
|
const codexPostCmds = collectHookCommands(codexHooks.PostToolUse);
|
|
821
824
|
const codexStopCmds = collectHookCommands(codexHooks.Stop);
|
|
822
825
|
const codexWiringOk = codexSessionCmds.some((cmd) => cmd.includes("session-start.sh")) &&
|
|
826
|
+
codexUserPromptCmds.some((cmd) => cmd.includes("prompt-guard.sh")) &&
|
|
827
|
+
codexUserPromptCmds.some((cmd) => cmd.includes("verify-current-state --quiet")) &&
|
|
823
828
|
codexPreCmds.some((cmd) => cmd.includes("prompt-guard.sh")) &&
|
|
824
829
|
codexPreCmds.some((cmd) => cmd.includes("workflow-guard.sh")) &&
|
|
825
830
|
codexPostCmds.some((cmd) => cmd.includes("context-monitor.sh")) &&
|
|
@@ -827,7 +832,7 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
827
832
|
checks.push({
|
|
828
833
|
name: "hook:wiring:codex",
|
|
829
834
|
ok: codexWiringOk,
|
|
830
|
-
details: `${codexHooksFile} must wire
|
|
835
|
+
details: `${codexHooksFile} must wire SessionStart, UserPromptSubmit(prompt-guard + verify-current-state), PreToolUse(prompt/workflow), PostToolUse(context-monitor), and Stop(stop-checkpoint). PreToolUse/PostToolUse run Bash-only in Codex v0.114+`
|
|
831
836
|
});
|
|
832
837
|
// Feature flag warning: Codex ignores `.codex/hooks.json` unless the
|
|
833
838
|
// user has `[features] codex_hooks = true` in `~/.codex/config.toml`.
|
|
@@ -895,6 +900,8 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
895
900
|
if (configuredHarnesses.includes("opencode")) {
|
|
896
901
|
const file = path.join(projectRoot, ".opencode/plugins/cclaw-plugin.mjs");
|
|
897
902
|
let ok = false;
|
|
903
|
+
let singleHandlerPathOk = false;
|
|
904
|
+
let precompactHookOk = false;
|
|
898
905
|
if (await exists(file)) {
|
|
899
906
|
const content = await fs.readFile(file, "utf8");
|
|
900
907
|
ok =
|
|
@@ -904,16 +911,36 @@ export async function doctorChecks(projectRoot, options = {}) {
|
|
|
904
911
|
content.includes("prompt-guard.sh") &&
|
|
905
912
|
content.includes("workflow-guard.sh") &&
|
|
906
913
|
content.includes("context-monitor.sh") &&
|
|
914
|
+
content.includes("pre-compact.sh") &&
|
|
907
915
|
content.includes('"session.idle"') &&
|
|
908
916
|
content.includes('"session.resumed"') &&
|
|
917
|
+
content.includes('"session.compacted"') &&
|
|
909
918
|
content.includes('"session.cleared"') &&
|
|
910
919
|
content.includes('"experimental.chat.system.transform"');
|
|
920
|
+
singleHandlerPathOk =
|
|
921
|
+
!content.includes('eventType === "tool.execute.before"') &&
|
|
922
|
+
!content.includes('eventType === "tool.execute.after"') &&
|
|
923
|
+
content.includes('"tool.execute.before": async') &&
|
|
924
|
+
content.includes('"tool.execute.after": async');
|
|
925
|
+
precompactHookOk =
|
|
926
|
+
content.includes('eventType === "session.compacted"') &&
|
|
927
|
+
content.includes('runHookScript("pre-compact.sh"');
|
|
911
928
|
}
|
|
912
929
|
checks.push({
|
|
913
930
|
name: "lifecycle:opencode:rehydration_events",
|
|
914
931
|
ok,
|
|
915
932
|
details: `${file} must include event lifecycle handler, tool.execute.before/after with prompt/workflow/context hooks, session.idle checkpoint, and transform rehydration`
|
|
916
933
|
});
|
|
934
|
+
checks.push({
|
|
935
|
+
name: "hook:opencode:single_tool_handler_path",
|
|
936
|
+
ok: singleHandlerPathOk,
|
|
937
|
+
details: `${file} must route tool.execute.before/after through dedicated handlers exactly once (no duplicate event() branches).`
|
|
938
|
+
});
|
|
939
|
+
checks.push({
|
|
940
|
+
name: "hook:opencode:precompact_digest",
|
|
941
|
+
ok: precompactHookOk,
|
|
942
|
+
details: `${file} must run pre-compact.sh on session.compacted before bootstrap refresh.`
|
|
943
|
+
});
|
|
917
944
|
const runtimeShape = await opencodePluginRuntimeShapeCheck(projectRoot);
|
|
918
945
|
checks.push({
|
|
919
946
|
name: "hook:opencode:runtime_shape",
|
package/dist/flow-state.js
CHANGED
|
@@ -59,10 +59,10 @@ export function createInitialFlowState(activeRunIdOrOptions = "active", maybeTra
|
|
|
59
59
|
const track = options.track ?? "standard";
|
|
60
60
|
const skippedStages = skippedStagesForTrack(track);
|
|
61
61
|
const stageGateCatalog = {};
|
|
62
|
-
for (const schema of orderedStageSchemas()) {
|
|
62
|
+
for (const schema of orderedStageSchemas(track)) {
|
|
63
63
|
stageGateCatalog[schema.stage] = {
|
|
64
|
-
required: stageGateIds(schema.stage),
|
|
65
|
-
recommended: stageRecommendedGateIds(schema.stage),
|
|
64
|
+
required: stageGateIds(schema.stage, track),
|
|
65
|
+
recommended: stageRecommendedGateIds(schema.stage, track),
|
|
66
66
|
conditional: [],
|
|
67
67
|
triggered: [],
|
|
68
68
|
passed: [],
|
package/dist/gate-evidence.js
CHANGED
|
@@ -5,8 +5,8 @@ import { RUNTIME_ROOT } from "./constants.js";
|
|
|
5
5
|
import { stageSchema } from "./content/stage-schema.js";
|
|
6
6
|
import { exists } from "./fs-utils.js";
|
|
7
7
|
import { readFlowState, writeFlowState } from "./runs.js";
|
|
8
|
-
async function currentStageArtifactExists(projectRoot, stage) {
|
|
9
|
-
const artifactFile = stageSchema(stage).artifactFile;
|
|
8
|
+
async function currentStageArtifactExists(projectRoot, stage, track) {
|
|
9
|
+
const artifactFile = stageSchema(stage, track).artifactFile;
|
|
10
10
|
const candidates = [
|
|
11
11
|
path.join(projectRoot, RUNTIME_ROOT, "artifacts", artifactFile),
|
|
12
12
|
path.join(projectRoot, artifactFile)
|
|
@@ -34,7 +34,7 @@ function sameStringArray(a, b) {
|
|
|
34
34
|
}
|
|
35
35
|
export async function verifyCurrentStageGateEvidence(projectRoot, flowState) {
|
|
36
36
|
const stage = flowState.currentStage;
|
|
37
|
-
const schema = stageSchema(stage);
|
|
37
|
+
const schema = stageSchema(stage, flowState.track);
|
|
38
38
|
const catalog = flowState.stageGateCatalog[stage];
|
|
39
39
|
const required = schema.requiredGates
|
|
40
40
|
.filter((gate) => gate.tier === "required")
|
|
@@ -92,7 +92,7 @@ export async function verifyCurrentStageGateEvidence(projectRoot, flowState) {
|
|
|
92
92
|
issues.push(`blocked gate "${gateId}" is not defined for stage "${stage}".`);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
const artifactPresent = await currentStageArtifactExists(projectRoot, stage);
|
|
95
|
+
const artifactPresent = await currentStageArtifactExists(projectRoot, stage, flowState.track);
|
|
96
96
|
const shouldValidateArtifact = artifactPresent || catalog.passed.length > 0 || flowState.completedStages.includes(stage);
|
|
97
97
|
if (shouldValidateArtifact) {
|
|
98
98
|
const lint = await lintArtifact(projectRoot, stage);
|
|
@@ -149,7 +149,7 @@ export function verifyCompletedStagesGateClosure(flowState) {
|
|
|
149
149
|
const issues = [];
|
|
150
150
|
const openStages = [];
|
|
151
151
|
for (const stage of flowState.completedStages) {
|
|
152
|
-
const schema = stageSchema(stage);
|
|
152
|
+
const schema = stageSchema(stage, flowState.track);
|
|
153
153
|
const catalog = flowState.stageGateCatalog[stage];
|
|
154
154
|
const required = schema.requiredGates
|
|
155
155
|
.filter((gate) => gate.tier === "required")
|
|
@@ -177,10 +177,11 @@ export function verifyCompletedStagesGateClosure(flowState) {
|
|
|
177
177
|
}
|
|
178
178
|
export function reconcileCurrentStageGateCatalog(flowState) {
|
|
179
179
|
const stage = flowState.currentStage;
|
|
180
|
-
const
|
|
180
|
+
const schema = stageSchema(stage, flowState.track);
|
|
181
|
+
const required = schema.requiredGates
|
|
181
182
|
.filter((gate) => gate.tier === "required")
|
|
182
183
|
.map((gate) => gate.id);
|
|
183
|
-
const recommended =
|
|
184
|
+
const recommended = schema.requiredGates
|
|
184
185
|
.filter((gate) => gate.tier === "recommended")
|
|
185
186
|
.map((gate) => gate.id);
|
|
186
187
|
const conditional = [];
|
package/dist/install.js
CHANGED
|
@@ -36,7 +36,7 @@ import { LANGUAGE_RULE_PACK_DIR, LANGUAGE_RULE_PACK_FILES, LANGUAGE_RULE_PACK_GE
|
|
|
36
36
|
import { RESEARCH_PLAYBOOKS } from "./content/research-playbooks.js";
|
|
37
37
|
import { HARNESS_TOOL_REFS_DIR, HARNESS_TOOL_REFS_INDEX_MD, harnessToolRefMarkdown } from "./content/harness-tool-refs.js";
|
|
38
38
|
import { DOCTOR_REFERENCE_MARKDOWN } from "./content/doctor-references.js";
|
|
39
|
-
import { harnessIntegrationDocMarkdown } from "./content/harnesses-doc.js";
|
|
39
|
+
import { harnessDocsOverviewMarkdown, harnessIntegrationDocMarkdown } from "./content/harnesses-doc.js";
|
|
40
40
|
import { HARNESS_PLAYBOOKS_DIR, harnessPlaybookFileName, harnessPlaybookMarkdown, harnessPlaybooksIndexMarkdown } from "./content/harness-playbooks.js";
|
|
41
41
|
import { HOOK_EVENTS_BY_HARNESS, HOOK_SEMANTIC_EVENTS } from "./content/hook-events.js";
|
|
42
42
|
import { createInitialFlowState } from "./flow-state.js";
|
|
@@ -213,9 +213,10 @@ async function writeEvalScaffold(projectRoot) {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
async function writeSkills(projectRoot, config) {
|
|
216
|
+
const skillTrack = config?.defaultTrack ?? "standard";
|
|
216
217
|
for (const stage of COMMAND_FILE_ORDER) {
|
|
217
218
|
const folder = stageSkillFolder(stage);
|
|
218
|
-
await writeFileSafe(runtimePath(projectRoot, "skills", folder, "SKILL.md"), stageSkillMarkdown(stage));
|
|
219
|
+
await writeFileSafe(runtimePath(projectRoot, "skills", folder, "SKILL.md"), stageSkillMarkdown(stage, skillTrack));
|
|
219
220
|
// Progressive disclosure (A.2#8): materialize the full example artifact as
|
|
220
221
|
// a sibling reference file. The stage skill only links to it; agents load
|
|
221
222
|
// the reference on demand.
|
|
@@ -294,6 +295,7 @@ async function writeSkills(projectRoot, config) {
|
|
|
294
295
|
await writeFileSafe(runtimePath(projectRoot, ...doctorRefsDir, fileName), markdown);
|
|
295
296
|
}
|
|
296
297
|
await writeFileSafe(runtimePath(projectRoot, "references", "harnesses.md"), harnessIntegrationDocMarkdown());
|
|
298
|
+
await writeFileSafe(runtimePath(projectRoot, "references", "harnesses-overview.md"), harnessDocsOverviewMarkdown());
|
|
297
299
|
// Per-harness parity playbooks. Generated for every supported harness
|
|
298
300
|
// regardless of which harnesses the project installed — the index always
|
|
299
301
|
// resolves, and doctor only asserts presence of the installed harnesses'
|
|
@@ -354,7 +354,7 @@ async function runAdvanceStage(projectRoot, args, io) {
|
|
|
354
354
|
io.stderr.write(`cclaw internal advance-stage: current stage is "${flowState.currentStage}", not "${args.stage}".\n`);
|
|
355
355
|
return 1;
|
|
356
356
|
}
|
|
357
|
-
const schema = stageSchema(args.stage);
|
|
357
|
+
const schema = stageSchema(args.stage, flowState.track);
|
|
358
358
|
const requiredGateIds = schema.requiredGates
|
|
359
359
|
.filter((gate) => gate.tier === "required")
|
|
360
360
|
.map((gate) => gate.id);
|