cclaw-cli 0.51.25 → 0.51.27
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/artifact-linter.js +574 -0
- package/dist/content/core-agents.js +21 -1
- package/dist/content/examples.js +9 -8
- package/dist/content/harness-doc.d.ts +1 -0
- package/dist/content/harness-doc.js +47 -0
- package/dist/content/hooks.d.ts +1 -0
- package/dist/content/hooks.js +369 -0
- package/dist/content/skills.d.ts +9 -0
- package/dist/content/skills.js +132 -5
- package/dist/content/stages/brainstorm.js +5 -5
- package/dist/content/status-command.js +8 -2
- package/dist/content/subagents.js +6 -2
- package/dist/content/templates.js +312 -20
- package/dist/content/tree-command.js +7 -1
- package/dist/delegation.d.ts +62 -4
- package/dist/delegation.js +218 -16
- package/dist/doctor-registry.js +9 -0
- package/dist/doctor.js +75 -2
- package/dist/harness-adapters.d.ts +48 -0
- package/dist/harness-adapters.js +123 -4
- package/dist/install.js +3 -1
- package/dist/internal/advance-stage.js +68 -18
- package/package.json +1 -1
package/dist/harness-adapters.js
CHANGED
|
@@ -71,6 +71,12 @@ export function harnessShimSkillNames() {
|
|
|
71
71
|
export const HARNESS_ADAPTERS = {
|
|
72
72
|
claude: {
|
|
73
73
|
id: "claude",
|
|
74
|
+
reality: {
|
|
75
|
+
declaredSupport: "full",
|
|
76
|
+
runtimeLaunch: "native Task launch",
|
|
77
|
+
proofRequired: "spanId+dispatchId or workerRunId+ACK for isolated completion",
|
|
78
|
+
proofSource: ".cclaw/state/delegation-events.jsonl plus delegation-log.json"
|
|
79
|
+
},
|
|
74
80
|
commandDir: ".claude/commands",
|
|
75
81
|
shimKind: "command",
|
|
76
82
|
capabilities: {
|
|
@@ -82,6 +88,12 @@ export const HARNESS_ADAPTERS = {
|
|
|
82
88
|
},
|
|
83
89
|
cursor: {
|
|
84
90
|
id: "cursor",
|
|
91
|
+
reality: {
|
|
92
|
+
declaredSupport: "generic",
|
|
93
|
+
runtimeLaunch: "generic Task/Subagent launch with cclaw role prompt",
|
|
94
|
+
proofRequired: "spanId+dispatchId/evidenceRefs for generic-dispatch completion",
|
|
95
|
+
proofSource: ".cclaw/state/delegation-events.jsonl plus artifact evidenceRefs"
|
|
96
|
+
},
|
|
85
97
|
commandDir: ".cursor/commands",
|
|
86
98
|
shimKind: "command",
|
|
87
99
|
capabilities: {
|
|
@@ -97,6 +109,12 @@ export const HARNESS_ADAPTERS = {
|
|
|
97
109
|
},
|
|
98
110
|
opencode: {
|
|
99
111
|
id: "opencode",
|
|
112
|
+
reality: {
|
|
113
|
+
declaredSupport: "full",
|
|
114
|
+
runtimeLaunch: "prompt-level launch via Task or @agent against generated .opencode/agents",
|
|
115
|
+
proofRequired: "spanId+dispatchId+ackTs+completedTs before isolated completion",
|
|
116
|
+
proofSource: ".opencode/agents/<agent>.md and .cclaw/state/delegation-events.jsonl"
|
|
117
|
+
},
|
|
100
118
|
commandDir: ".opencode/commands",
|
|
101
119
|
shimKind: "command",
|
|
102
120
|
capabilities: {
|
|
@@ -119,6 +137,12 @@ export const HARNESS_ADAPTERS = {
|
|
|
119
137
|
},
|
|
120
138
|
codex: {
|
|
121
139
|
id: "codex",
|
|
140
|
+
reality: {
|
|
141
|
+
declaredSupport: "full",
|
|
142
|
+
runtimeLaunch: "prompt-level launch by asking Codex to spawn generated custom agents",
|
|
143
|
+
proofRequired: "spanId+dispatchId+ackTs+completedTs before isolated completion",
|
|
144
|
+
proofSource: ".codex/agents/<agent>.toml and .cclaw/state/delegation-events.jsonl"
|
|
145
|
+
},
|
|
122
146
|
// Codex CLI reads skills from the universal `.agents/skills/` path
|
|
123
147
|
// (OpenAI Codex 0.89, Jan 2026). It does NOT have a native
|
|
124
148
|
// `.codex/commands/*` slash-command discovery — cclaw installs
|
|
@@ -155,11 +179,106 @@ export function harnessDispatchSurface(harnessId) {
|
|
|
155
179
|
case "cursor":
|
|
156
180
|
return "Use Cursor Subagent/Task with a generic subagent_type (explore for read-only mapping, generalPurpose for broader work, shell/browser-use when specifically needed) and paste the cclaw role prompt; record fulfillmentMode: \"generic-dispatch\" with evidenceRefs.";
|
|
157
181
|
case "opencode":
|
|
158
|
-
return "Use OpenCode subagents: invoke the generated .opencode/agents/<agent>.md agent via Task or @<agent
|
|
182
|
+
return "Use OpenCode subagents: invoke the generated .opencode/agents/<agent>.md agent via Task or @<agent>; record scheduled/launched/acknowledged/completed events with spanId+dispatchId before claiming fulfillmentMode: \"isolated\".";
|
|
159
183
|
case "codex":
|
|
160
|
-
return "Use Codex native subagents: ask Codex to spawn the generated .codex/agents/<agent>.toml agent(s) by name
|
|
184
|
+
return "Use Codex native subagents: ask Codex to spawn the generated .codex/agents/<agent>.toml agent(s) by name; record scheduled/launched/acknowledged/completed events with spanId+dispatchId before claiming fulfillmentMode: \"isolated\".";
|
|
161
185
|
}
|
|
162
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Per-harness lifecycle recipe used by skills and harness docs to render the
|
|
189
|
+
* canonical scheduled -> launched -> acknowledged -> completed sequence in
|
|
190
|
+
* structural form. The recipe never embeds task-specific or domain-specific
|
|
191
|
+
* placeholders — only neutral angle-bracket tokens (`<agent-name>`, `<stage>`,
|
|
192
|
+
* `<span-id>`, `<dispatch-id>`, `<agent-def-path>`, `<iso-ts>`).
|
|
193
|
+
*
|
|
194
|
+
* This function returns the **canonical primary recipe** for each shipped
|
|
195
|
+
* harness — the dispatch surface that maps 1:1 onto the harness's vendor-
|
|
196
|
+
* native subagent surface:
|
|
197
|
+
*
|
|
198
|
+
* - `claude` -> `claude-task` (isolated)
|
|
199
|
+
* - `cursor` -> `cursor-task` (generic-dispatch)
|
|
200
|
+
* - `opencode` -> `opencode-agent` (isolated)
|
|
201
|
+
* - `codex` -> `codex-agent` (isolated)
|
|
202
|
+
*
|
|
203
|
+
* The remaining `--dispatch-surface` enum values (`generic-task`,
|
|
204
|
+
* `role-switch`, `manual`) are universal fallback paths available to any
|
|
205
|
+
* harness when the canonical surface is unavailable; they are documented in
|
|
206
|
+
* the dispatch-surface table in `docs/harnesses.md` rather than per-harness
|
|
207
|
+
* here, because their lifecycle commands are structurally identical except
|
|
208
|
+
* for the surface token. No shipped harness has a non-canonical *primary*
|
|
209
|
+
* surface, so this function only needs to enumerate the four canonical
|
|
210
|
+
* recipes above.
|
|
211
|
+
*/
|
|
212
|
+
export function harnessDelegationRecipe(harnessId) {
|
|
213
|
+
const helper = "node .cclaw/hooks/delegation-record.mjs";
|
|
214
|
+
const common = "--stage=<stage> --agent=<agent-name> --mode=mandatory --span-id=<span-id> --dispatch-id=<dispatch-id>";
|
|
215
|
+
switch (harnessId) {
|
|
216
|
+
case "claude":
|
|
217
|
+
return {
|
|
218
|
+
harnessId,
|
|
219
|
+
dispatchSurface: "claude-task",
|
|
220
|
+
agentDefinitionDirectory: ".claude/agents/",
|
|
221
|
+
agentDefinitionExample: ".claude/agents/<agent-name>.md",
|
|
222
|
+
invocationLine: "Call Task with subagent_type=<agent-name> and prompt body that paraphrases the stage skill role.",
|
|
223
|
+
fulfillmentMode: "isolated",
|
|
224
|
+
lifecycleCommands: [
|
|
225
|
+
`${helper} ${common} --status=scheduled --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --json`,
|
|
226
|
+
`${helper} ${common} --status=launched --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --launched-ts=<iso-ts> --json`,
|
|
227
|
+
`${helper} ${common} --status=acknowledged --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --ack-ts=<iso-ts> --json`,
|
|
228
|
+
`${helper} ${common} --status=completed --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --completed-ts=<iso-ts> --json`
|
|
229
|
+
]
|
|
230
|
+
};
|
|
231
|
+
case "cursor":
|
|
232
|
+
return {
|
|
233
|
+
harnessId,
|
|
234
|
+
dispatchSurface: "cursor-task",
|
|
235
|
+
agentDefinitionDirectory: ".cclaw/agents/",
|
|
236
|
+
agentDefinitionExample: ".cclaw/agents/<agent-name>.md",
|
|
237
|
+
invocationLine: "Call Task with a generic subagent_type and paste the cclaw role prompt; capture worker output as evidenceRefs in the artifact.",
|
|
238
|
+
fulfillmentMode: "generic-dispatch",
|
|
239
|
+
lifecycleCommands: [
|
|
240
|
+
`${helper} ${common} --status=scheduled --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --json`,
|
|
241
|
+
`${helper} ${common} --status=launched --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --launched-ts=<iso-ts> --json`,
|
|
242
|
+
`${helper} ${common} --status=acknowledged --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --ack-ts=<iso-ts> --json`,
|
|
243
|
+
`${helper} ${common} --status=completed --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --completed-ts=<iso-ts> --evidence-ref=<artifact-anchor> --json`
|
|
244
|
+
]
|
|
245
|
+
};
|
|
246
|
+
case "opencode":
|
|
247
|
+
return {
|
|
248
|
+
harnessId,
|
|
249
|
+
dispatchSurface: "opencode-agent",
|
|
250
|
+
agentDefinitionDirectory: ".opencode/agents/",
|
|
251
|
+
agentDefinitionExample: ".opencode/agents/<agent-name>.md",
|
|
252
|
+
invocationLine: "Invoke the generated agent via Task or `@<agent-name>`; the agent body lives in `.opencode/agents/<agent-name>.md`.",
|
|
253
|
+
fulfillmentMode: "isolated",
|
|
254
|
+
lifecycleCommands: [
|
|
255
|
+
`${helper} ${common} --status=scheduled --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --json`,
|
|
256
|
+
`${helper} ${common} --status=launched --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --launched-ts=<iso-ts> --json`,
|
|
257
|
+
`${helper} ${common} --status=acknowledged --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --ack-ts=<iso-ts> --json`,
|
|
258
|
+
`${helper} ${common} --status=completed --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --completed-ts=<iso-ts> --json`
|
|
259
|
+
]
|
|
260
|
+
};
|
|
261
|
+
case "codex":
|
|
262
|
+
return {
|
|
263
|
+
harnessId,
|
|
264
|
+
dispatchSurface: "codex-agent",
|
|
265
|
+
agentDefinitionDirectory: ".codex/agents/",
|
|
266
|
+
agentDefinitionExample: ".codex/agents/<agent-name>.toml",
|
|
267
|
+
invocationLine: "Ask Codex to spawn the named custom agent; the agent definition lives in `.codex/agents/<agent-name>.toml`.",
|
|
268
|
+
fulfillmentMode: "isolated",
|
|
269
|
+
lifecycleCommands: [
|
|
270
|
+
`${helper} ${common} --status=scheduled --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --json`,
|
|
271
|
+
`${helper} ${common} --status=launched --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --launched-ts=<iso-ts> --json`,
|
|
272
|
+
`${helper} ${common} --status=acknowledged --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --ack-ts=<iso-ts> --json`,
|
|
273
|
+
`${helper} ${common} --status=completed --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --completed-ts=<iso-ts> --json`
|
|
274
|
+
]
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/** All four harness recipes in tier-stable order. */
|
|
279
|
+
export function harnessDelegationRecipes() {
|
|
280
|
+
return harnessesByTier().map((id) => harnessDelegationRecipe(id));
|
|
281
|
+
}
|
|
163
282
|
export function harnessDispatchFallback(harnessId) {
|
|
164
283
|
const adapter = HARNESS_ADAPTERS[harnessId];
|
|
165
284
|
if (adapter.capabilities.subagentFallback !== "role-switch") {
|
|
@@ -597,7 +716,7 @@ async function cleanupLegacyCodexSurfaces(projectRoot) {
|
|
|
597
716
|
}
|
|
598
717
|
}
|
|
599
718
|
function codexAgentToml(agent) {
|
|
600
|
-
const instructions = `${agent
|
|
719
|
+
const instructions = `${agentMarkdown(agent)}\n\n${enhancedAgentInstruction(agent.name)}`.trim();
|
|
601
720
|
const sandboxMode = agent.tools.some((tool) => ["Write", "Edit", "Bash"].includes(tool))
|
|
602
721
|
? "workspace-write"
|
|
603
722
|
: "read-only";
|
|
@@ -625,7 +744,7 @@ permission:
|
|
|
625
744
|
${agentMarkdown(agent)}`;
|
|
626
745
|
}
|
|
627
746
|
function enhancedAgentInstruction(agentName) {
|
|
628
|
-
return
|
|
747
|
+
return `## Worker ACK Contract\n\nYou are the cclaw ${agentName} subagent. Follow the parent prompt as the task boundary. ACK first with JSON containing spanId, dispatchId or workerRunId, dispatchSurface, agentDefinitionPath, ackTs, and status: "ACK". Finish with the strict return schema plus the same spanId+dispatchId proof so the parent can append .cclaw/state/delegation-events.jsonl and .cclaw/state/delegation-log.json. Do not let the parent claim isolated completion without matching ACK/result proof. Do not recursively orchestrate other agents unless the parent explicitly asks.`;
|
|
629
748
|
}
|
|
630
749
|
async function syncAgentFiles(projectRoot, harnesses) {
|
|
631
750
|
const agentsDir = path.join(projectRoot, RUNTIME_ROOT, "agents");
|
package/dist/install.js
CHANGED
|
@@ -13,7 +13,7 @@ import { viewCommandContract, viewCommandSkillMarkdown } from "./content/view-co
|
|
|
13
13
|
import { subagentDrivenDevSkill, parallelAgentsSkill } from "./content/subagents.js";
|
|
14
14
|
import { sessionHooksSkillMarkdown } from "./content/session-hooks.js";
|
|
15
15
|
import { ironLawRuntimeDocument, ironLawsSkillMarkdown } from "./content/iron-laws.js";
|
|
16
|
-
import { stageCompleteScript, startFlowScript, runHookCmdScript, opencodePluginJs, claudeHooksJson, codexHooksJson, cursorHooksJson } from "./content/hooks.js";
|
|
16
|
+
import { stageCompleteScript, startFlowScript, runHookCmdScript, delegationRecordScript, opencodePluginJs, claudeHooksJson, codexHooksJson, cursorHooksJson } from "./content/hooks.js";
|
|
17
17
|
import { nodeHookRuntimeScript } from "./content/node-hooks.js";
|
|
18
18
|
import { META_SKILL_NAME, usingCclawSkillMarkdown } from "./content/meta-skill.js";
|
|
19
19
|
import { ARTIFACT_TEMPLATES, CURSOR_WORKFLOW_RULE_MDC, RULEBOOK_MARKDOWN, buildRulesJson } from "./content/templates.js";
|
|
@@ -884,6 +884,7 @@ async function writeHooks(projectRoot, config) {
|
|
|
884
884
|
compoundRecurrenceThreshold: config.compound?.recurrenceThreshold
|
|
885
885
|
}));
|
|
886
886
|
await writeFileSafe(path.join(hooksDir, "run-hook.cmd"), runHookCmdScript());
|
|
887
|
+
await writeFileSafe(path.join(hooksDir, "delegation-record.mjs"), delegationRecordScript());
|
|
887
888
|
const opencodePluginSource = opencodePluginJs();
|
|
888
889
|
await writeFileSafe(path.join(hooksDir, "opencode-plugin.mjs"), opencodePluginSource);
|
|
889
890
|
try {
|
|
@@ -892,6 +893,7 @@ async function writeHooks(projectRoot, config) {
|
|
|
892
893
|
"start-flow.mjs",
|
|
893
894
|
"run-hook.mjs",
|
|
894
895
|
"run-hook.cmd",
|
|
896
|
+
"delegation-record.mjs",
|
|
895
897
|
"opencode-plugin.mjs"
|
|
896
898
|
]) {
|
|
897
899
|
await fs.chmod(path.join(hooksDir, script), 0o755);
|
|
@@ -6,7 +6,7 @@ import { resolveArtifactPath } from "../artifact-paths.js";
|
|
|
6
6
|
import { RUNTIME_ROOT, SHIP_FINALIZATION_MODES } from "../constants.js";
|
|
7
7
|
import { ensureDir } from "../fs-utils.js";
|
|
8
8
|
import { stageAutoSubagentDispatch, stageSchema } from "../content/stage-schema.js";
|
|
9
|
-
import { appendDelegation, checkMandatoryDelegations, readDelegationLedger } from "../delegation.js";
|
|
9
|
+
import { appendDelegation, checkMandatoryDelegations, readDelegationEvents, readDelegationLedger } from "../delegation.js";
|
|
10
10
|
import { verifyCompletedStagesGateClosure, verifyCurrentStageGateEvidence } from "../gate-evidence.js";
|
|
11
11
|
import { extractMarkdownSectionBody, parseLearningsSection } from "../artifact-linter.js";
|
|
12
12
|
import { getAvailableTransitions, getTransitionGuards, isFlowTrack, createInitialFlowState } from "../flow-state.js";
|
|
@@ -669,6 +669,9 @@ async function buildValidationReport(projectRoot, flowState, options = {}) {
|
|
|
669
669
|
missing: delegation.missing,
|
|
670
670
|
waived: delegation.waived,
|
|
671
671
|
missingEvidence: delegation.missingEvidence,
|
|
672
|
+
missingDispatchProof: delegation.missingDispatchProof,
|
|
673
|
+
legacyInferredCompletions: delegation.legacyInferredCompletions,
|
|
674
|
+
corruptEventLines: delegation.corruptEventLines,
|
|
672
675
|
staleWorkers: delegation.staleWorkers,
|
|
673
676
|
expectedMode: delegation.expectedMode
|
|
674
677
|
},
|
|
@@ -897,6 +900,48 @@ async function runAdvanceStage(projectRoot, args, io) {
|
|
|
897
900
|
allowBlockedReviewRoute: blockedReviewRoute
|
|
898
901
|
});
|
|
899
902
|
if (!validation.ok) {
|
|
903
|
+
const ledgerForDiag = await readDelegationLedger(projectRoot).catch(() => ({ entries: [] }));
|
|
904
|
+
const eventsForDiag = await readDelegationEvents(projectRoot).catch(() => ({ events: [], corruptLines: [] }));
|
|
905
|
+
const ledgerEntriesText = await fs.readFile(path.join(projectRoot, ".cclaw/state/delegation-events.jsonl"), "utf8").catch(() => "");
|
|
906
|
+
const corruptSnippets = (() => {
|
|
907
|
+
if (validation.delegation.corruptEventLines.length === 0)
|
|
908
|
+
return [];
|
|
909
|
+
const lines = ledgerEntriesText.split(/\r?\n/u);
|
|
910
|
+
return validation.delegation.corruptEventLines.slice(0, 3).map((lineNo) => {
|
|
911
|
+
const line = lines[lineNo - 1] ?? "";
|
|
912
|
+
const sample = line.length > 120 ? `${line.slice(0, 117)}...` : line;
|
|
913
|
+
return `line ${lineNo}: ${sample}`;
|
|
914
|
+
});
|
|
915
|
+
})();
|
|
916
|
+
const dispatchProofDetails = validation.delegation.missingDispatchProof.flatMap((agent) => {
|
|
917
|
+
const rows = ledgerForDiag.entries.filter((entry) => entry.agent === agent && entry.status === "completed");
|
|
918
|
+
return rows.map((row) => `${agent}(spanId=${row.spanId ?? "unknown"})`);
|
|
919
|
+
});
|
|
920
|
+
const nextActions = [];
|
|
921
|
+
if (validation.delegation.missing.length > 0) {
|
|
922
|
+
nextActions.push(`Complete or waive mandatory delegation(s): ${validation.delegation.missing.join(", ")}. Helper: \`node .cclaw/hooks/stage-complete.mjs ${args.stage} --waive-delegation=${validation.delegation.missing.join(",")} --waiver-reason="<why safe>"\`.`);
|
|
923
|
+
}
|
|
924
|
+
if (validation.delegation.missingEvidence.length > 0) {
|
|
925
|
+
nextActions.push(`Role-switch fallback completion needs --evidence-ref or escalate to a real isolated dispatch surface.`);
|
|
926
|
+
}
|
|
927
|
+
if (validation.delegation.missingDispatchProof.length > 0) {
|
|
928
|
+
nextActions.push(`Isolated completion(s) ${dispatchProofDetails.join(", ") || validation.delegation.missingDispatchProof.join(", ")} lack matching dispatch proof; run the helper lifecycle scheduled -> launched -> acknowledged -> completed with --span-id, --dispatch-id, --dispatch-surface and --agent-definition-path before advancing.`);
|
|
929
|
+
}
|
|
930
|
+
if (validation.delegation.legacyInferredCompletions.length > 0) {
|
|
931
|
+
nextActions.push(`Pre-v3 ledger entries found: ${validation.delegation.legacyInferredCompletions.join(", ")}. Run \`node .cclaw/hooks/delegation-record.mjs --rerecord --span-id=<id> --dispatch-id=<id> --dispatch-surface=<surface> --agent-definition-path=<path>\` to upgrade the row to dispatch-proof shape.`);
|
|
932
|
+
}
|
|
933
|
+
if (validation.delegation.corruptEventLines.length > 0) {
|
|
934
|
+
nextActions.push(`delegation-events.jsonl has ${validation.delegation.corruptEventLines.length} corrupt line(s) at ${validation.delegation.corruptEventLines.slice(0, 3).join(", ")}${validation.delegation.corruptEventLines.length > 3 ? ", ..." : ""}; remove or fix them before advancing.`);
|
|
935
|
+
}
|
|
936
|
+
if (validation.delegation.staleWorkers.length > 0) {
|
|
937
|
+
nextActions.push(`Stale scheduled delegations ${validation.delegation.staleWorkers.join(", ")} have no terminal row sharing the same spanId; emit launched/acknowledged/completed (or failed/stale) before advancing.`);
|
|
938
|
+
}
|
|
939
|
+
if (validation.gates.issues.length > 0) {
|
|
940
|
+
nextActions.push("Fix the artifact/gate issue shown in gates.issues, then rerun stage-complete.");
|
|
941
|
+
}
|
|
942
|
+
if (validation.completedStages.issues.length > 0) {
|
|
943
|
+
nextActions.push("Repair previously completed stage gate closure before advancing.");
|
|
944
|
+
}
|
|
900
945
|
if (args.json) {
|
|
901
946
|
io.stdout.write(`${JSON.stringify({
|
|
902
947
|
ok: false,
|
|
@@ -906,23 +951,12 @@ async function runAdvanceStage(projectRoot, args, io) {
|
|
|
906
951
|
delegation: validation.delegation,
|
|
907
952
|
gates: validation.gates,
|
|
908
953
|
completedStages: validation.completedStages,
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
: []),
|
|
916
|
-
...(validation.delegation.staleWorkers.length > 0
|
|
917
|
-
? ["Resolve scheduled delegation span(s) without terminal lifecycle evidence before advancing."]
|
|
918
|
-
: []),
|
|
919
|
-
...(validation.gates.issues.length > 0
|
|
920
|
-
? ["Fix the artifact/gate issue shown in gates.issues, then rerun stage-complete."]
|
|
921
|
-
: []),
|
|
922
|
-
...(validation.completedStages.issues.length > 0
|
|
923
|
-
? ["Repair previously completed stage gate closure before advancing."]
|
|
924
|
-
: [])
|
|
925
|
-
]
|
|
954
|
+
diagnostics: {
|
|
955
|
+
dispatchProofRows: dispatchProofDetails,
|
|
956
|
+
corruptEventSamples: corruptSnippets,
|
|
957
|
+
unawareEvents: eventsForDiag.corruptLines.length
|
|
958
|
+
},
|
|
959
|
+
nextActions
|
|
926
960
|
})}\n`);
|
|
927
961
|
}
|
|
928
962
|
io.stderr.write(`cclaw internal advance-stage: validation failed for stage "${args.stage}".\n`);
|
|
@@ -932,9 +966,25 @@ async function runAdvanceStage(projectRoot, args, io) {
|
|
|
932
966
|
}
|
|
933
967
|
if (validation.delegation.missingEvidence.length > 0) {
|
|
934
968
|
io.stderr.write(`- role-switch evidence missing: ${validation.delegation.missingEvidence.join(", ")}\n`);
|
|
969
|
+
io.stderr.write(` next action: include --evidence-ref=<artifact#anchor> when emitting the completed event, or escalate to a true isolated dispatch surface.\n`);
|
|
970
|
+
}
|
|
971
|
+
if (validation.delegation.missingDispatchProof.length > 0) {
|
|
972
|
+
io.stderr.write(`- isolated completion lacks dispatch proof: ${dispatchProofDetails.join(", ") || validation.delegation.missingDispatchProof.join(", ")}\n`);
|
|
973
|
+
io.stderr.write(` next action: emit scheduled -> launched -> acknowledged -> completed with --span-id, --dispatch-id, --dispatch-surface, --agent-definition-path before advancing.\n`);
|
|
974
|
+
}
|
|
975
|
+
if (validation.delegation.legacyInferredCompletions.length > 0) {
|
|
976
|
+
io.stderr.write(`- legacy-inferred completions need rerecord: ${validation.delegation.legacyInferredCompletions.join(", ")}\n`);
|
|
977
|
+
io.stderr.write(` next action: \`node .cclaw/hooks/delegation-record.mjs --rerecord --span-id=<id> --dispatch-id=<id> --dispatch-surface=<surface> --agent-definition-path=<path>\`.\n`);
|
|
978
|
+
}
|
|
979
|
+
if (validation.delegation.corruptEventLines.length > 0) {
|
|
980
|
+
io.stderr.write(`- corrupt delegation-events.jsonl line(s): ${validation.delegation.corruptEventLines.slice(0, 3).join(", ")}${validation.delegation.corruptEventLines.length > 3 ? `, ... (+${validation.delegation.corruptEventLines.length - 3})` : ""}\n`);
|
|
981
|
+
for (const snippet of corruptSnippets) {
|
|
982
|
+
io.stderr.write(` sample: ${snippet}\n`);
|
|
983
|
+
}
|
|
935
984
|
}
|
|
936
985
|
if (validation.delegation.staleWorkers.length > 0) {
|
|
937
986
|
io.stderr.write(`- stale scheduled delegations: ${validation.delegation.staleWorkers.join(", ")}\n`);
|
|
987
|
+
io.stderr.write(` next action: emit a terminal row (completed/failed/stale) for the same span before advancing.\n`);
|
|
938
988
|
}
|
|
939
989
|
if (validation.gates.issues.length > 0) {
|
|
940
990
|
io.stderr.write(`- gate issues: ${validation.gates.issues.join(" | ")}\n`);
|