@chllming/wave-orchestration 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +82 -1
  2. package/README.md +40 -7
  3. package/docs/agents/wave-orchestrator-role.md +50 -0
  4. package/docs/agents/wave-planner-role.md +39 -0
  5. package/docs/context7/bundles.json +9 -0
  6. package/docs/context7/planner-agent/README.md +25 -0
  7. package/docs/context7/planner-agent/manifest.json +83 -0
  8. package/docs/context7/planner-agent/papers/cooperbench-why-coding-agents-cannot-be-your-teammates-yet.md +3283 -0
  9. package/docs/context7/planner-agent/papers/dova-deliberation-first-multi-agent-orchestration-for-autonomous-research-automation.md +1699 -0
  10. package/docs/context7/planner-agent/papers/dpbench-large-language-models-struggle-with-simultaneous-coordination.md +2251 -0
  11. package/docs/context7/planner-agent/papers/incremental-planning-to-control-a-blackboard-based-problem-solver.md +1729 -0
  12. package/docs/context7/planner-agent/papers/silo-bench-a-scalable-environment-for-evaluating-distributed-coordination-in-multi-agent-llm-systems.md +3747 -0
  13. package/docs/context7/planner-agent/papers/todoevolve-learning-to-architect-agent-planning-systems.md +1675 -0
  14. package/docs/context7/planner-agent/papers/verified-multi-agent-orchestration-a-plan-execute-verify-replan-framework-for-complex-query-resolution.md +1173 -0
  15. package/docs/context7/planner-agent/papers/why-do-multi-agent-llm-systems-fail.md +5211 -0
  16. package/docs/context7/planner-agent/topics/planning-and-orchestration.md +24 -0
  17. package/docs/evals/README.md +96 -1
  18. package/docs/evals/arm-templates/README.md +13 -0
  19. package/docs/evals/arm-templates/full-wave.json +15 -0
  20. package/docs/evals/arm-templates/single-agent.json +15 -0
  21. package/docs/evals/benchmark-catalog.json +7 -0
  22. package/docs/evals/cases/README.md +47 -0
  23. package/docs/evals/cases/wave-blackboard-inbox-targeting.json +73 -0
  24. package/docs/evals/cases/wave-contradiction-conflict.json +104 -0
  25. package/docs/evals/cases/wave-expert-routing-preservation.json +69 -0
  26. package/docs/evals/cases/wave-hidden-profile-private-evidence.json +81 -0
  27. package/docs/evals/cases/wave-premature-closure-guard.json +71 -0
  28. package/docs/evals/cases/wave-silo-cross-agent-state.json +77 -0
  29. package/docs/evals/cases/wave-simultaneous-lockstep.json +92 -0
  30. package/docs/evals/cooperbench/real-world-mitigation.md +341 -0
  31. package/docs/evals/external-benchmarks.json +85 -0
  32. package/docs/evals/external-command-config.sample.json +9 -0
  33. package/docs/evals/external-command-config.swe-bench-pro.json +8 -0
  34. package/docs/evals/pilots/README.md +47 -0
  35. package/docs/evals/pilots/swe-bench-pro-public-full-wave-review-10.json +64 -0
  36. package/docs/evals/pilots/swe-bench-pro-public-pilot.json +111 -0
  37. package/docs/evals/wave-benchmark-program.md +302 -0
  38. package/docs/guides/planner.md +67 -11
  39. package/docs/guides/terminal-surfaces.md +12 -0
  40. package/docs/plans/context7-wave-orchestrator.md +20 -0
  41. package/docs/plans/current-state.md +8 -1
  42. package/docs/plans/examples/wave-benchmark-improvement.md +108 -0
  43. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  44. package/docs/plans/examples/wave-example-rollout-fidelity.md +340 -0
  45. package/docs/plans/migration.md +26 -0
  46. package/docs/plans/wave-orchestrator.md +60 -12
  47. package/docs/plans/waves/reviews/wave-1-benchmark-operator.md +118 -0
  48. package/docs/reference/cli-reference.md +547 -0
  49. package/docs/reference/coordination-and-closure.md +436 -0
  50. package/docs/reference/live-proof-waves.md +25 -3
  51. package/docs/reference/npmjs-trusted-publishing.md +3 -3
  52. package/docs/reference/proof-metrics.md +90 -0
  53. package/docs/reference/runtime-config/README.md +63 -2
  54. package/docs/reference/runtime-config/codex.md +2 -1
  55. package/docs/reference/sample-waves.md +29 -18
  56. package/docs/reference/wave-control.md +164 -0
  57. package/docs/reference/wave-planning-lessons.md +131 -0
  58. package/package.json +5 -4
  59. package/releases/manifest.json +40 -0
  60. package/scripts/research/agent-context-archive.mjs +18 -0
  61. package/scripts/research/manifests/agent-context-expanded-2026-03-22.mjs +17 -0
  62. package/scripts/research/sync-planner-context7-bundle.mjs +133 -0
  63. package/scripts/wave-orchestrator/agent-state.mjs +11 -2
  64. package/scripts/wave-orchestrator/artifact-schemas.mjs +232 -0
  65. package/scripts/wave-orchestrator/autonomous.mjs +7 -0
  66. package/scripts/wave-orchestrator/benchmark-cases.mjs +374 -0
  67. package/scripts/wave-orchestrator/benchmark-external.mjs +1384 -0
  68. package/scripts/wave-orchestrator/benchmark.mjs +972 -0
  69. package/scripts/wave-orchestrator/clarification-triage.mjs +78 -12
  70. package/scripts/wave-orchestrator/config.mjs +175 -0
  71. package/scripts/wave-orchestrator/control-cli.mjs +1216 -0
  72. package/scripts/wave-orchestrator/control-plane.mjs +697 -0
  73. package/scripts/wave-orchestrator/coord-cli.mjs +360 -2
  74. package/scripts/wave-orchestrator/coordination-store.mjs +211 -9
  75. package/scripts/wave-orchestrator/coordination.mjs +84 -0
  76. package/scripts/wave-orchestrator/dashboard-renderer.mjs +120 -5
  77. package/scripts/wave-orchestrator/dashboard-state.mjs +22 -0
  78. package/scripts/wave-orchestrator/evals.mjs +23 -0
  79. package/scripts/wave-orchestrator/executors.mjs +3 -2
  80. package/scripts/wave-orchestrator/feedback.mjs +55 -0
  81. package/scripts/wave-orchestrator/install.mjs +151 -2
  82. package/scripts/wave-orchestrator/launcher-closure.mjs +4 -1
  83. package/scripts/wave-orchestrator/launcher-runtime.mjs +33 -30
  84. package/scripts/wave-orchestrator/launcher.mjs +884 -36
  85. package/scripts/wave-orchestrator/planner-context.mjs +75 -0
  86. package/scripts/wave-orchestrator/planner.mjs +2270 -136
  87. package/scripts/wave-orchestrator/proof-cli.mjs +195 -0
  88. package/scripts/wave-orchestrator/proof-registry.mjs +317 -0
  89. package/scripts/wave-orchestrator/replay.mjs +10 -4
  90. package/scripts/wave-orchestrator/retry-cli.mjs +184 -0
  91. package/scripts/wave-orchestrator/retry-control.mjs +225 -0
  92. package/scripts/wave-orchestrator/shared.mjs +26 -0
  93. package/scripts/wave-orchestrator/swe-bench-pro-task.mjs +1004 -0
  94. package/scripts/wave-orchestrator/terminals.mjs +1 -1
  95. package/scripts/wave-orchestrator/traces.mjs +157 -2
  96. package/scripts/wave-orchestrator/wave-control-client.mjs +532 -0
  97. package/scripts/wave-orchestrator/wave-control-schema.mjs +309 -0
  98. package/scripts/wave-orchestrator/wave-files.mjs +144 -23
  99. package/scripts/wave.mjs +27 -0
  100. package/skills/repo-coding-rules/SKILL.md +1 -0
  101. package/skills/role-cont-eval/SKILL.md +1 -0
  102. package/skills/role-cont-qa/SKILL.md +13 -6
  103. package/skills/role-deploy/SKILL.md +1 -0
  104. package/skills/role-documentation/SKILL.md +4 -0
  105. package/skills/role-implementation/SKILL.md +4 -0
  106. package/skills/role-infra/SKILL.md +2 -1
  107. package/skills/role-integration/SKILL.md +15 -8
  108. package/skills/role-planner/SKILL.md +39 -0
  109. package/skills/role-planner/skill.json +21 -0
  110. package/skills/role-research/SKILL.md +1 -0
  111. package/skills/role-security/SKILL.md +2 -2
  112. package/skills/runtime-claude/SKILL.md +2 -1
  113. package/skills/runtime-codex/SKILL.md +1 -0
  114. package/skills/runtime-local/SKILL.md +2 -0
  115. package/skills/runtime-opencode/SKILL.md +1 -0
  116. package/skills/wave-core/SKILL.md +25 -6
  117. package/skills/wave-core/references/marker-syntax.md +16 -8
  118. package/wave.config.json +45 -0
@@ -0,0 +1,1216 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { appendCoordinationRecord, clarificationClosureCondition, clarificationLinkedRequests, isOpenCoordinationStatus, readMaterializedCoordinationState, updateSeedRecords } from "./coordination-store.mjs";
4
+ import { answerFeedbackRequest, createFeedbackRequest } from "./feedback.mjs";
5
+ import { readWaveHumanFeedbackRequests } from "./coordination.mjs";
6
+ import { readWaveLedger } from "./ledger.mjs";
7
+ import { buildDependencySnapshot, buildRequestAssignments } from "./routing-state.mjs";
8
+ import { parseWaveFiles } from "./wave-files.mjs";
9
+ import {
10
+ buildLanePaths,
11
+ DEFAULT_COORDINATION_ACK_TIMEOUT_MS,
12
+ DEFAULT_COORDINATION_RESOLUTION_STALE_MS,
13
+ ensureDirectory,
14
+ parseNonNegativeInt,
15
+ readJsonOrNull,
16
+ readStatusRecordIfPresent,
17
+ REPO_ROOT,
18
+ sanitizeAdhocRunId,
19
+ sanitizeLaneName,
20
+ } from "./shared.mjs";
21
+ import {
22
+ appendWaveControlEvent,
23
+ buildTaskSnapshots,
24
+ nextTaskDeadline,
25
+ readWaveControlPlaneState,
26
+ syncWaveControlPlaneProjections,
27
+ } from "./control-plane.mjs";
28
+ import {
29
+ augmentSummaryWithProofRegistry,
30
+ readWaveProofRegistry,
31
+ registerWaveProofBundle,
32
+ waveProofRegistryPath,
33
+ } from "./proof-registry.mjs";
34
+ import { readWaveRelaunchPlanSnapshot, readWaveRetryOverride, resolveRetryOverrideAgentIds, writeWaveRetryOverride, clearWaveRetryOverride } from "./retry-control.mjs";
35
+ import { flushWaveControlQueue, readWaveControlQueueState } from "./wave-control-client.mjs";
36
+ import { readAgentExecutionSummary, validateImplementationSummary } from "./agent-state.mjs";
37
+ import { isContEvalReportOnlyAgent, isSecurityReviewAgent } from "./role-helpers.mjs";
38
+
39
+ function printUsage() {
40
+ console.log(`Usage:
41
+ wave control status --lane <lane> --wave <n> [--agent <id>] [--json]
42
+ wave control telemetry status --lane <lane> [--run <id>] [--json]
43
+ wave control telemetry flush --lane <lane> [--run <id>] [--json]
44
+
45
+ wave control task create --lane <lane> --wave <n> --agent <id> --kind <request|blocker|clarification|handoff|evidence|claim|decision|human-input> --summary <text> [options]
46
+ wave control task list --lane <lane> --wave <n> [--agent <id>] [--json]
47
+ wave control task get --lane <lane> --wave <n> --id <task-id> [--json]
48
+ wave control task act <start|resolve|dismiss|cancel|reassign|answer|escalate> --lane <lane> --wave <n> --id <task-id> [options]
49
+
50
+ wave control rerun request --lane <lane> --wave <n> [--agent <id> ...] [--resume-cursor <cursor>] [--reuse-attempt <id> ...] [--reuse-proof <id> ...] [--reuse-derived-summaries <true|false>] [--invalidate-component <id> ...] [--clear-reuse <id> ...] [--preserve-reuse <id> ...] [--requested-by <name>] [--reason <text>] [--json]
51
+ wave control rerun get --lane <lane> --wave <n> [--json]
52
+ wave control rerun clear --lane <lane> --wave <n>
53
+
54
+ wave control proof register --lane <lane> --wave <n> --agent <id> --artifact <path> [--artifact <path> ...] [--component <id[:level]> ...] [--authoritative] [--satisfy-owned-components] [--completion <level>] [--durability <level>] [--proof-level <level>] [--doc-delta <state>] [--operator <name>] [--detail <text>] [--json]
55
+ wave control proof get --lane <lane> --wave <n> [--agent <id>] [--id <bundle-id>] [--json]
56
+ wave control proof supersede --lane <lane> --wave <n> --id <bundle-id> --agent <id> --artifact <path> [--artifact <path> ...] [options]
57
+ wave control proof revoke --lane <lane> --wave <n> --id <bundle-id> [--operator <name>] [--detail <text>] [--json]
58
+ `);
59
+ }
60
+
61
+ function normalizeBooleanish(value, fallback = true) {
62
+ const normalized = String(value ?? "").trim().toLowerCase();
63
+ if (!normalized) {
64
+ return fallback;
65
+ }
66
+ if (["1", "true", "yes", "y", "on"].includes(normalized)) {
67
+ return true;
68
+ }
69
+ if (["0", "false", "no", "n", "off"].includes(normalized)) {
70
+ return false;
71
+ }
72
+ throw new Error(`Expected boolean value, got: ${value}`);
73
+ }
74
+
75
+ function parseArgs(argv) {
76
+ const args = argv[0] === "--" ? argv.slice(1) : argv;
77
+ const surface = String(args[0] || "").trim().toLowerCase();
78
+ const operation = String(args[1] || "").trim().toLowerCase();
79
+ const action = String(args[2] || "").trim().toLowerCase();
80
+ const options = {
81
+ lane: "main",
82
+ wave: null,
83
+ runId: "",
84
+ dryRun: false,
85
+ json: false,
86
+ agent: "",
87
+ kind: "",
88
+ summary: "",
89
+ detail: "",
90
+ targets: [],
91
+ priority: "normal",
92
+ dependsOn: [],
93
+ artifactRefs: [],
94
+ status: "open",
95
+ id: "",
96
+ to: "",
97
+ response: "",
98
+ operator: "human-operator",
99
+ selectedAgentIds: [],
100
+ reuseAttemptIds: [],
101
+ reuseProofBundleIds: [],
102
+ invalidateComponentIds: [],
103
+ clearReusableAgentIds: [],
104
+ preserveReusableAgentIds: [],
105
+ requestedBy: "",
106
+ reason: "",
107
+ resumeCursor: "",
108
+ reuseDerivedSummaries: true,
109
+ componentIds: [],
110
+ authoritative: false,
111
+ satisfyOwnedComponents: false,
112
+ completion: "",
113
+ durability: "",
114
+ proofLevel: "",
115
+ docDeltaState: "",
116
+ };
117
+ const startIndex =
118
+ surface === "status"
119
+ ? 1
120
+ : surface === "telemetry"
121
+ ? 2
122
+ : surface === "task" || surface === "rerun" || surface === "proof"
123
+ ? operation === "act"
124
+ ? 3
125
+ : 2
126
+ : 0;
127
+ for (let i = startIndex; i < args.length; i += 1) {
128
+ const arg = args[i];
129
+ if (i < startIndex) {
130
+ continue;
131
+ }
132
+ if (arg === "--lane") {
133
+ options.lane = sanitizeLaneName(args[++i]);
134
+ } else if (arg === "--run") {
135
+ options.runId = sanitizeAdhocRunId(args[++i]);
136
+ } else if (arg === "--wave") {
137
+ options.wave = parseNonNegativeInt(args[++i], "--wave");
138
+ } else if (arg === "--agent" || arg === "--agents") {
139
+ options.selectedAgentIds.push(String(args[++i] || "").trim());
140
+ if (!options.agent) {
141
+ options.agent = options.selectedAgentIds.at(-1) || "";
142
+ }
143
+ } else if (arg === "--kind") {
144
+ options.kind = String(args[++i] || "").trim();
145
+ } else if (arg === "--summary") {
146
+ options.summary = String(args[++i] || "").trim();
147
+ } else if (arg === "--detail") {
148
+ options.detail = String(args[++i] || "").trim();
149
+ } else if (arg === "--target") {
150
+ options.targets.push(String(args[++i] || "").trim());
151
+ } else if (arg === "--priority") {
152
+ options.priority = String(args[++i] || "").trim();
153
+ } else if (arg === "--depends-on") {
154
+ options.dependsOn.push(String(args[++i] || "").trim());
155
+ } else if (arg === "--artifact") {
156
+ options.artifactRefs.push(String(args[++i] || "").trim());
157
+ } else if (arg === "--status") {
158
+ options.status = String(args[++i] || "").trim();
159
+ } else if (arg === "--id") {
160
+ options.id = String(args[++i] || "").trim();
161
+ } else if (arg === "--to") {
162
+ options.to = String(args[++i] || "").trim();
163
+ } else if (arg === "--response") {
164
+ options.response = String(args[++i] || "").trim();
165
+ } else if (arg === "--operator") {
166
+ options.operator = String(args[++i] || "").trim() || "human-operator";
167
+ } else if (arg === "--requested-by") {
168
+ options.requestedBy = String(args[++i] || "").trim();
169
+ } else if (arg === "--reason") {
170
+ options.reason = String(args[++i] || "").trim();
171
+ } else if (arg === "--resume-cursor" || arg === "--resume-phase") {
172
+ options.resumeCursor = String(args[++i] || "").trim();
173
+ } else if (arg === "--reuse-attempt") {
174
+ options.reuseAttemptIds.push(String(args[++i] || "").trim());
175
+ } else if (arg === "--reuse-proof") {
176
+ options.reuseProofBundleIds.push(String(args[++i] || "").trim());
177
+ } else if (arg === "--reuse-derived-summaries") {
178
+ options.reuseDerivedSummaries = normalizeBooleanish(args[++i], true);
179
+ } else if (arg === "--invalidate-component") {
180
+ options.invalidateComponentIds.push(String(args[++i] || "").trim());
181
+ } else if (arg === "--clear-reuse") {
182
+ options.clearReusableAgentIds.push(String(args[++i] || "").trim());
183
+ } else if (arg === "--preserve-reuse") {
184
+ options.preserveReusableAgentIds.push(String(args[++i] || "").trim());
185
+ } else if (arg === "--component") {
186
+ options.componentIds.push(String(args[++i] || "").trim());
187
+ } else if (arg === "--authoritative") {
188
+ options.authoritative = true;
189
+ } else if (arg === "--satisfy-owned-components") {
190
+ options.satisfyOwnedComponents = true;
191
+ } else if (arg === "--completion") {
192
+ options.completion = String(args[++i] || "").trim();
193
+ } else if (arg === "--durability") {
194
+ options.durability = String(args[++i] || "").trim();
195
+ } else if (arg === "--proof-level") {
196
+ options.proofLevel = String(args[++i] || "").trim();
197
+ } else if (arg === "--doc-delta") {
198
+ options.docDeltaState = String(args[++i] || "").trim();
199
+ } else if (arg === "--json") {
200
+ options.json = true;
201
+ } else if (arg === "--dry-run") {
202
+ options.dryRun = true;
203
+ } else if (arg === "--help" || arg === "-h") {
204
+ return { help: true, surface, operation, action, options };
205
+ } else if (arg && arg !== "--") {
206
+ throw new Error(`Unknown argument: ${arg}`);
207
+ }
208
+ }
209
+ return { help: false, surface, operation, action, options };
210
+ }
211
+
212
+ function resolveLaneForRun(runId, fallbackLane) {
213
+ return (
214
+ readJsonOrNull(path.join(REPO_ROOT, ".wave", "adhoc", "runs", runId, "result.json"))?.lane ||
215
+ fallbackLane
216
+ );
217
+ }
218
+
219
+ function loadWave(lanePaths, waveNumber) {
220
+ const waves = parseWaveFiles(lanePaths.wavesDir, { laneProfile: lanePaths.laneProfile });
221
+ const wave = waves.find((entry) => entry.wave === waveNumber);
222
+ if (!wave) {
223
+ throw new Error(`Wave ${waveNumber} not found in ${lanePaths.wavesDir}`);
224
+ }
225
+ return wave;
226
+ }
227
+
228
+ function coordinationLogPath(lanePaths, waveNumber) {
229
+ return path.join(lanePaths.coordinationDir, `wave-${waveNumber}.jsonl`);
230
+ }
231
+
232
+ function ledgerPath(lanePaths, waveNumber) {
233
+ return path.join(lanePaths.ledgerDir, `wave-${waveNumber}.json`);
234
+ }
235
+
236
+ function targetAgentId(target) {
237
+ const value = String(target || "").trim();
238
+ return value.startsWith("agent:") ? value.slice("agent:".length) : value;
239
+ }
240
+
241
+ function recordTargetsAgent(record, agentId) {
242
+ return (
243
+ String(record?.agentId || "").trim() === agentId ||
244
+ (Array.isArray(record?.targets) &&
245
+ record.targets.some((target) => targetAgentId(target) === agentId))
246
+ );
247
+ }
248
+
249
+ function statusPathForAgent(lanePaths, wave, agent) {
250
+ return path.join(lanePaths.statusDir, `wave-${wave.wave}-${agent.slug}.status`);
251
+ }
252
+
253
+ const BLOCKING_TASK_TYPES = new Set([
254
+ "request",
255
+ "blocker",
256
+ "clarification",
257
+ "human-input",
258
+ "escalation",
259
+ ]);
260
+
261
+ function taskBlocksAgent(task) {
262
+ return BLOCKING_TASK_TYPES.has(String(task?.taskType || "").trim().toLowerCase());
263
+ }
264
+
265
+ function assignmentRelevantToAgent(assignment, agentId = "") {
266
+ return (
267
+ !agentId ||
268
+ assignment?.assignedAgentId === agentId ||
269
+ assignment?.sourceAgentId === agentId
270
+ );
271
+ }
272
+
273
+ function buildEffectiveSelection(lanePaths, wave, { activeAttempt = null, rerunRequest = null, relaunchPlan = null } = {}) {
274
+ const activeAttemptSelected = Array.isArray(activeAttempt?.selectedAgentIds)
275
+ ? Array.from(new Set(activeAttempt.selectedAgentIds.filter(Boolean)))
276
+ : [];
277
+ if (activeAttemptSelected.length > 0) {
278
+ return {
279
+ source: "active-attempt",
280
+ selectedAgentIds: activeAttemptSelected,
281
+ detail: activeAttempt?.detail || null,
282
+ };
283
+ }
284
+ const rerunSelected = rerunRequest?.selectedAgentIds?.length
285
+ ? rerunRequest.selectedAgentIds
286
+ : resolveRetryOverrideAgentIds(wave, lanePaths, rerunRequest);
287
+ if (rerunSelected.length > 0) {
288
+ return {
289
+ source: "rerun-request",
290
+ selectedAgentIds: rerunSelected,
291
+ detail: rerunRequest?.reason || null,
292
+ };
293
+ }
294
+ const relaunchSelected = Array.isArray(relaunchPlan?.selectedAgentIds)
295
+ ? Array.from(new Set(relaunchPlan.selectedAgentIds.filter(Boolean)))
296
+ : [];
297
+ if (relaunchSelected.length > 0) {
298
+ return {
299
+ source: "relaunch-plan",
300
+ selectedAgentIds: relaunchSelected,
301
+ detail: null,
302
+ };
303
+ }
304
+ return {
305
+ source: "none",
306
+ selectedAgentIds: [],
307
+ detail: null,
308
+ };
309
+ }
310
+
311
+ function buildLogicalAgents({ lanePaths, wave, tasks, dependencySnapshot, capabilityAssignments, selection, proofRegistry }) {
312
+ const selectedAgentIds = new Set(selection?.selectedAgentIds || []);
313
+ const helperAssignments = Array.isArray(capabilityAssignments) ? capabilityAssignments : [];
314
+ const openInbound = dependencySnapshot?.openInbound || [];
315
+ return wave.agents.map((agent) => {
316
+ const statusPath = statusPathForAgent(lanePaths, wave, agent);
317
+ const statusRecord = readStatusRecordIfPresent(statusPath);
318
+ const summary = augmentSummaryWithProofRegistry(
319
+ agent,
320
+ readAgentExecutionSummary(statusPath),
321
+ proofRegistry || { entries: [] },
322
+ );
323
+ const proofValidation =
324
+ !isSecurityReviewAgent(agent) && !isContEvalReportOnlyAgent(agent, { contEvalAgentId: lanePaths.contEvalAgentId })
325
+ ? validateImplementationSummary(agent, summary ? summary : null)
326
+ : { ok: statusRecord?.code === 0, statusCode: statusRecord?.code === 0 ? "pass" : "pending" };
327
+ const targetedTasks = tasks.filter(
328
+ (task) =>
329
+ task.ownerAgentId === agent.agentId ||
330
+ task.assigneeAgentId === agent.agentId,
331
+ );
332
+ const targetedOpenTasks = targetedTasks.filter((task) =>
333
+ ["open", "working", "input-required"].includes(task.state),
334
+ );
335
+ const targetedBlockingTasks = targetedOpenTasks.filter((task) => taskBlocksAgent(task));
336
+ const helperAssignment = helperAssignments.find(
337
+ (assignment) => assignment.blocking && assignment.assignedAgentId === agent.agentId,
338
+ );
339
+ const dependency = openInbound.find((record) => record.assignedAgentId === agent.agentId);
340
+ let state = "planned";
341
+ let reason = "";
342
+ if (selection?.source === "active-attempt" && selectedAgentIds.has(agent.agentId)) {
343
+ state = "working";
344
+ reason = selection?.detail || "Selected by the active launcher attempt.";
345
+ } else if (selectedAgentIds.has(agent.agentId)) {
346
+ state = "needs-rerun";
347
+ reason =
348
+ selection?.source === "relaunch-plan"
349
+ ? "Selected by the persisted relaunch plan."
350
+ : "Selected by active rerun request.";
351
+ } else if (targetedBlockingTasks.some((task) => task.state === "working")) {
352
+ state = "working";
353
+ reason = targetedBlockingTasks.find((task) => task.state === "working")?.title || "";
354
+ } else if (targetedBlockingTasks.length > 0 || helperAssignment || dependency) {
355
+ state = "blocked";
356
+ reason =
357
+ targetedBlockingTasks[0]?.title ||
358
+ helperAssignment?.assignmentDetail ||
359
+ helperAssignment?.summary ||
360
+ dependency?.summary ||
361
+ "";
362
+ } else if (statusRecord?.code === 0 && (proofValidation.ok || isSecurityReviewAgent(agent) || isContEvalReportOnlyAgent(agent, { contEvalAgentId: lanePaths.contEvalAgentId }))) {
363
+ state = [
364
+ lanePaths.contEvalAgentId || "E0",
365
+ lanePaths.integrationAgentId || "A8",
366
+ lanePaths.documentationAgentId || "A9",
367
+ lanePaths.contQaAgentId || "A0",
368
+ ].includes(agent.agentId) || isSecurityReviewAgent(agent)
369
+ ? "closed"
370
+ : "satisfied";
371
+ reason = "Latest attempt satisfied current control-plane state.";
372
+ } else if (Number.isInteger(statusRecord?.code) && statusRecord.code !== 0) {
373
+ state = "needs-rerun";
374
+ reason = `Latest attempt exited with code ${statusRecord.code}.`;
375
+ }
376
+ return {
377
+ agentId: agent.agentId,
378
+ state,
379
+ reason: reason || null,
380
+ taskIds: targetedTasks.map((task) => task.taskId),
381
+ selectedForRerun: selectedAgentIds.has(agent.agentId) && selection?.source !== "active-attempt",
382
+ selectedForActiveAttempt: selection?.source === "active-attempt" && selectedAgentIds.has(agent.agentId),
383
+ activeProofBundleIds: (proofRegistry?.entries || [])
384
+ .filter(
385
+ (entry) =>
386
+ entry.agentId === agent.agentId &&
387
+ !["revoked", "superseded"].includes(String(entry.state || "").trim().toLowerCase()),
388
+ )
389
+ .map((entry) => entry.id),
390
+ };
391
+ });
392
+ }
393
+
394
+ function selectionTargetsAgent(agentId, selectionSet) {
395
+ return Boolean(agentId) && selectionSet.has(agentId);
396
+ }
397
+
398
+ function buildBlockingEdge({ tasks, capabilityAssignments, dependencySnapshot, activeAttempt, rerunRequest, relaunchPlan, agentId = "" }) {
399
+ const attemptSelection = new Set(activeAttempt?.selectedAgentIds || []);
400
+ const scopeToActiveAttempt = !agentId && attemptSelection.size > 0;
401
+ const scopedTasks = (agentId
402
+ ? tasks.filter((task) => task.ownerAgentId === agentId || task.assigneeAgentId === agentId)
403
+ : tasks
404
+ ).filter((task) => {
405
+ if (!scopeToActiveAttempt) {
406
+ return true;
407
+ }
408
+ return (
409
+ selectionTargetsAgent(task.ownerAgentId, attemptSelection) ||
410
+ selectionTargetsAgent(task.assigneeAgentId, attemptSelection)
411
+ );
412
+ });
413
+ const pendingHuman = scopedTasks.find((task) => task.state === "input-required");
414
+ if (pendingHuman) {
415
+ return {
416
+ kind: "human-input",
417
+ id: pendingHuman.taskId,
418
+ agentId: pendingHuman.assigneeAgentId || pendingHuman.ownerAgentId || null,
419
+ detail: pendingHuman.title,
420
+ };
421
+ }
422
+ const escalation = scopedTasks.find(
423
+ (task) => task.taskType === "escalation" && ["open", "working"].includes(task.state),
424
+ );
425
+ if (escalation) {
426
+ return {
427
+ kind: "human-escalation",
428
+ id: escalation.taskId,
429
+ agentId: escalation.assigneeAgentId || escalation.ownerAgentId || null,
430
+ detail: escalation.title,
431
+ };
432
+ }
433
+ const clarification = scopedTasks.find(
434
+ (task) => task.taskType === "clarification" && ["open", "working"].includes(task.state),
435
+ );
436
+ if (clarification) {
437
+ return {
438
+ kind: "clarification",
439
+ id: clarification.taskId,
440
+ agentId: clarification.assigneeAgentId || clarification.ownerAgentId || null,
441
+ detail: clarification.title,
442
+ };
443
+ }
444
+ const scopedAssignments = (capabilityAssignments || []).filter((assignment) => {
445
+ if (!scopeToActiveAttempt) {
446
+ return assignmentRelevantToAgent(assignment, agentId);
447
+ }
448
+ return (
449
+ selectionTargetsAgent(assignment.assignedAgentId, attemptSelection) ||
450
+ selectionTargetsAgent(assignment.sourceAgentId, attemptSelection)
451
+ );
452
+ });
453
+ const unresolvedAssignment = scopedAssignments.find(
454
+ (assignment) =>
455
+ assignment.blocking &&
456
+ !assignment.assignedAgentId,
457
+ );
458
+ if (unresolvedAssignment) {
459
+ return {
460
+ kind: "helper-assignment-unresolved",
461
+ id: unresolvedAssignment.requestId,
462
+ agentId: unresolvedAssignment.sourceAgentId || null,
463
+ detail: unresolvedAssignment.assignmentDetail || unresolvedAssignment.summary || unresolvedAssignment.requestId,
464
+ };
465
+ }
466
+ const blockingAssignment = scopedAssignments.find((assignment) => assignment.blocking);
467
+ if (blockingAssignment) {
468
+ return {
469
+ kind: "helper-assignment",
470
+ id: blockingAssignment.requestId,
471
+ agentId: blockingAssignment.assignedAgentId || blockingAssignment.sourceAgentId || null,
472
+ detail: blockingAssignment.assignmentDetail || blockingAssignment.summary || blockingAssignment.requestId,
473
+ };
474
+ }
475
+ const dependency = [
476
+ ...(dependencySnapshot?.openInbound || []),
477
+ ...(dependencySnapshot?.openOutbound || []),
478
+ ].find((record) => {
479
+ if (agentId) {
480
+ return record.assignedAgentId === agentId || record.agentId === agentId;
481
+ }
482
+ if (!scopeToActiveAttempt) {
483
+ return true;
484
+ }
485
+ return (
486
+ selectionTargetsAgent(record.assignedAgentId, attemptSelection) ||
487
+ selectionTargetsAgent(record.agentId, attemptSelection)
488
+ );
489
+ });
490
+ if (dependency) {
491
+ return {
492
+ kind: "dependency",
493
+ id: dependency.id,
494
+ agentId: dependency.assignedAgentId || dependency.agentId || null,
495
+ detail: dependency.summary || dependency.detail || dependency.id,
496
+ };
497
+ }
498
+ if (!scopeToActiveAttempt && rerunRequest) {
499
+ return {
500
+ kind: "rerun-request",
501
+ id: rerunRequest.requestId || "active-rerun",
502
+ agentId: null,
503
+ detail: rerunRequest.reason || "Active rerun request controls next attempt selection.",
504
+ };
505
+ }
506
+ if (!scopeToActiveAttempt && relaunchPlan) {
507
+ return {
508
+ kind: "relaunch-plan",
509
+ id: `wave-${relaunchPlan.wave ?? "unknown"}-relaunch-plan`,
510
+ agentId: null,
511
+ detail: "Persisted relaunch plan controls the next safe launcher selection.",
512
+ };
513
+ }
514
+ const blocker = scopedTasks.find(
515
+ (task) => task.taskType === "blocker" && ["open", "working"].includes(task.state),
516
+ );
517
+ if (blocker) {
518
+ return {
519
+ kind: "blocker",
520
+ id: blocker.taskId,
521
+ agentId: blocker.ownerAgentId || null,
522
+ detail: blocker.title,
523
+ };
524
+ }
525
+ const request = scopedTasks.find(
526
+ (task) => task.taskType === "request" && ["open", "working"].includes(task.state),
527
+ );
528
+ if (request) {
529
+ return {
530
+ kind: "request",
531
+ id: request.taskId,
532
+ agentId: request.assigneeAgentId || request.ownerAgentId || null,
533
+ detail: request.title,
534
+ };
535
+ }
536
+ return null;
537
+ }
538
+
539
+ export function buildControlStatusPayload({ lanePaths, wave, agentId = "" }) {
540
+ const logPath = coordinationLogPath(lanePaths, wave.wave);
541
+ const coordinationState = readMaterializedCoordinationState(logPath);
542
+ const ledger = readWaveLedger(ledgerPath(lanePaths, wave.wave)) || { phase: "planned" };
543
+ const capabilityAssignments = buildRequestAssignments({
544
+ coordinationState,
545
+ agents: wave.agents,
546
+ ledger,
547
+ capabilityRouting: lanePaths.capabilityRouting,
548
+ });
549
+ const dependencySnapshot = buildDependencySnapshot({
550
+ dirPath: lanePaths.crossLaneDependenciesDir,
551
+ lane: lanePaths.lane,
552
+ waveNumber: wave.wave,
553
+ agents: wave.agents,
554
+ ledger,
555
+ capabilityRouting: lanePaths.capabilityRouting,
556
+ });
557
+ const feedbackRequests = readWaveHumanFeedbackRequests({
558
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
559
+ lane: lanePaths.lane,
560
+ waveNumber: wave.wave,
561
+ agentIds: wave.agents.map((agent) => agent.agentId),
562
+ orchestratorId: "",
563
+ });
564
+ const tasks = buildTaskSnapshots({
565
+ coordinationState,
566
+ feedbackRequests,
567
+ ackTimeoutMs: DEFAULT_COORDINATION_ACK_TIMEOUT_MS,
568
+ resolutionStaleMs: DEFAULT_COORDINATION_RESOLUTION_STALE_MS,
569
+ }).filter((task) => !agentId || task.ownerAgentId === agentId || task.assigneeAgentId === agentId);
570
+ const controlState = readWaveControlPlaneState(lanePaths, wave.wave);
571
+ const proofRegistry = readWaveProofRegistry(lanePaths, wave.wave) || { entries: [] };
572
+ const relaunchPlan = readWaveRelaunchPlanSnapshot(lanePaths, wave.wave);
573
+ const rerunRequest = controlState.activeRerunRequest
574
+ ? {
575
+ ...controlState.activeRerunRequest,
576
+ selectedAgentIds:
577
+ controlState.activeRerunRequest.selectedAgentIds.length > 0
578
+ ? controlState.activeRerunRequest.selectedAgentIds
579
+ : resolveRetryOverrideAgentIds(wave, lanePaths, {
580
+ selectedAgentIds: controlState.activeRerunRequest.selectedAgentIds,
581
+ resumePhase: controlState.activeRerunRequest.resumeCursor,
582
+ }),
583
+ }
584
+ : null;
585
+ const selection = buildEffectiveSelection(lanePaths, wave, {
586
+ activeAttempt: controlState.activeAttempt,
587
+ rerunRequest,
588
+ relaunchPlan,
589
+ });
590
+ return {
591
+ lane: lanePaths.lane,
592
+ wave: wave.wave,
593
+ phase: ledger.phase || "unknown",
594
+ agentId: agentId || null,
595
+ blockingEdge: buildBlockingEdge({
596
+ tasks,
597
+ capabilityAssignments,
598
+ dependencySnapshot,
599
+ activeAttempt: controlState.activeAttempt,
600
+ rerunRequest,
601
+ relaunchPlan,
602
+ agentId,
603
+ }),
604
+ logicalAgents: buildLogicalAgents({
605
+ lanePaths,
606
+ wave,
607
+ tasks,
608
+ dependencySnapshot,
609
+ capabilityAssignments,
610
+ selection,
611
+ proofRegistry,
612
+ }).filter((agent) => !agentId || agent.agentId === agentId),
613
+ tasks,
614
+ helperAssignments: (capabilityAssignments || []).filter(
615
+ (assignment) => assignment.blocking && assignmentRelevantToAgent(assignment, agentId),
616
+ ),
617
+ dependencies: [
618
+ ...(dependencySnapshot?.openInbound || []).filter(
619
+ (record) => !agentId || record.assignedAgentId === agentId,
620
+ ),
621
+ ...(dependencySnapshot?.openOutbound || []).filter(
622
+ (record) => !agentId || record.agentId === agentId,
623
+ ),
624
+ ],
625
+ proofBundles: (proofRegistry?.entries || []).filter(
626
+ (entry) => !agentId || entry.agentId === agentId,
627
+ ),
628
+ selectionSource: selection.source,
629
+ rerunRequest,
630
+ relaunchPlan,
631
+ nextTimer: nextTaskDeadline(tasks),
632
+ activeAttempt: controlState.activeAttempt,
633
+ };
634
+ }
635
+
636
+ function ensureWaveStateDirs(lanePaths) {
637
+ ensureDirectory(lanePaths.coordinationDir);
638
+ ensureDirectory(lanePaths.controlDir);
639
+ ensureDirectory(lanePaths.controlPlaneDir);
640
+ ensureDirectory(lanePaths.assignmentsDir);
641
+ ensureDirectory(lanePaths.inboxesDir);
642
+ ensureDirectory(lanePaths.messageboardsDir);
643
+ ensureDirectory(lanePaths.docsQueueDir);
644
+ ensureDirectory(lanePaths.ledgerDir);
645
+ ensureDirectory(lanePaths.integrationDir);
646
+ ensureDirectory(lanePaths.proofDir);
647
+ ensureDirectory(lanePaths.dependencySnapshotsDir);
648
+ }
649
+
650
+ function kindForTaskCreate(input) {
651
+ const normalized = String(input || "").trim().toLowerCase();
652
+ if (normalized === "clarification") {
653
+ return "clarification-request";
654
+ }
655
+ if (normalized === "human-input") {
656
+ return "human-feedback";
657
+ }
658
+ return normalized;
659
+ }
660
+
661
+ function printStatus(payload) {
662
+ const blocking = payload.blockingEdge
663
+ ? `${payload.blockingEdge.kind} ${payload.blockingEdge.id}: ${payload.blockingEdge.detail}`
664
+ : "none";
665
+ console.log(`lane=${payload.lane} wave=${payload.wave} phase=${payload.phase}`);
666
+ console.log(`blocking=${blocking}`);
667
+ if (payload.nextTimer) {
668
+ console.log(`next-timer=${payload.nextTimer.kind} ${payload.nextTimer.taskId} at ${payload.nextTimer.at}`);
669
+ }
670
+ if (payload.logicalAgents.length > 0) {
671
+ console.log("logical-agents:");
672
+ for (const agent of payload.logicalAgents) {
673
+ console.log(`- ${agent.agentId} ${agent.state}${agent.reason ? `: ${agent.reason}` : ""}`);
674
+ }
675
+ }
676
+ }
677
+
678
+ function appendCoordinationStatusUpdate(logPath, record, status, options = {}) {
679
+ return appendCoordinationRecord(logPath, {
680
+ ...record,
681
+ status,
682
+ summary: options.summary || record.summary,
683
+ detail: options.detail || record.detail,
684
+ source: options.source || "operator",
685
+ });
686
+ }
687
+
688
+ function appendTaskCoordinationEvent(logPath, lanePaths, wave, record, action, options) {
689
+ if (action === "start") {
690
+ return appendCoordinationStatusUpdate(logPath, record, "in_progress", {
691
+ detail: options.detail || record.detail,
692
+ summary: options.summary || record.summary,
693
+ });
694
+ }
695
+ if (action === "resolve") {
696
+ return appendCoordinationStatusUpdate(logPath, record, "resolved", {
697
+ detail: options.detail || record.detail,
698
+ summary: options.summary || record.summary,
699
+ });
700
+ }
701
+ if (action === "dismiss" || action === "cancel") {
702
+ return appendCoordinationStatusUpdate(logPath, record, "cancelled", {
703
+ detail: options.detail || record.detail,
704
+ summary: options.summary || record.summary,
705
+ });
706
+ }
707
+ if (action === "reassign") {
708
+ if (!options.to) {
709
+ throw new Error("reassign requires --to");
710
+ }
711
+ const closureCondition =
712
+ record.kind === "clarification-request"
713
+ ? clarificationClosureCondition(record.id)
714
+ : record.closureCondition || "";
715
+ appendCoordinationStatusUpdate(logPath, record, "superseded", {
716
+ detail: options.detail || `${record.id} re-assigned to ${options.to}.`,
717
+ summary: record.summary,
718
+ });
719
+ const rerouted = appendCoordinationRecord(logPath, {
720
+ lane: lanePaths.lane,
721
+ wave: wave.wave,
722
+ agentId: options.agent || "operator",
723
+ kind: "request",
724
+ targets: [`agent:${options.to}`],
725
+ priority: record.priority,
726
+ artifactRefs: record.artifactRefs,
727
+ dependsOn:
728
+ record.kind === "clarification-request"
729
+ ? [record.id]
730
+ : Array.from(new Set([record.id, ...(record.dependsOn || [])])),
731
+ closureCondition,
732
+ summary: record.summary,
733
+ detail: options.detail || `${record.summary} reassigned to ${options.to}.`,
734
+ status: "open",
735
+ source: "operator",
736
+ });
737
+ if (record.kind === "clarification-request") {
738
+ appendCoordinationStatusUpdate(logPath, record, "in_progress", {
739
+ detail: `Awaiting routed follow-up from ${options.to}.`,
740
+ summary: record.summary,
741
+ });
742
+ }
743
+ return rerouted;
744
+ }
745
+ if (action === "escalate") {
746
+ return appendCoordinationRecord(logPath, {
747
+ id: `escalation-${record.id}`,
748
+ lane: lanePaths.lane,
749
+ wave: wave.wave,
750
+ agentId: options.agent || "operator",
751
+ kind: "human-escalation",
752
+ targets: record.targets,
753
+ priority: "high",
754
+ artifactRefs: record.artifactRefs,
755
+ dependsOn: [record.id],
756
+ closureCondition:
757
+ record.kind === "clarification-request"
758
+ ? clarificationClosureCondition(record.id)
759
+ : record.closureCondition || "",
760
+ summary: record.summary,
761
+ detail: options.detail || record.detail,
762
+ status: "open",
763
+ source: "operator",
764
+ });
765
+ }
766
+ throw new Error(`Unsupported task action: ${action}`);
767
+ }
768
+
769
+ function appendAttemptEvent(lanePaths, waveNumber, payload) {
770
+ const attemptId = payload.attemptId || `attempt-${payload.attemptNumber || 0}`;
771
+ return appendWaveControlEvent(lanePaths, waveNumber, {
772
+ entityType: "attempt",
773
+ entityId: attemptId,
774
+ action: payload.state || "running",
775
+ source: "launcher",
776
+ actor: "launcher",
777
+ data: {
778
+ attemptId,
779
+ attemptNumber: payload.attemptNumber || 0,
780
+ state: payload.state || "running",
781
+ selectedAgentIds: payload.selectedAgentIds || [],
782
+ detail: payload.detail || null,
783
+ createdAt: payload.createdAt || undefined,
784
+ },
785
+ });
786
+ }
787
+
788
+ export async function runControlCli(argv) {
789
+ const { help, surface, operation, action, options } = parseArgs(argv);
790
+ if (help || !surface) {
791
+ printUsage();
792
+ return;
793
+ }
794
+ if (surface !== "status" && !["telemetry", "task", "rerun", "proof"].includes(surface)) {
795
+ throw new Error("Expected control surface: status | telemetry | task | rerun | proof");
796
+ }
797
+ if (options.runId) {
798
+ options.lane = resolveLaneForRun(options.runId, options.lane);
799
+ }
800
+ const lanePaths = buildLanePaths(options.lane, {
801
+ runVariant: options.dryRun ? "dry-run" : undefined,
802
+ adhocRunId: options.runId || null,
803
+ });
804
+ if (surface === "telemetry") {
805
+ if (!["status", "flush"].includes(operation)) {
806
+ throw new Error("Expected telemetry operation: status | flush");
807
+ }
808
+ const payload =
809
+ operation === "flush"
810
+ ? await flushWaveControlQueue(lanePaths)
811
+ : readWaveControlQueueState(lanePaths);
812
+ if (options.json) {
813
+ console.log(JSON.stringify(payload, null, 2));
814
+ } else {
815
+ console.log(JSON.stringify(payload, null, 2));
816
+ }
817
+ return;
818
+ }
819
+ if (options.wave === null && options.runId) {
820
+ options.wave = 0;
821
+ }
822
+ if (options.wave === null) {
823
+ throw new Error("--wave is required");
824
+ }
825
+ const wave = loadWave(lanePaths, options.wave);
826
+ ensureWaveStateDirs(lanePaths);
827
+ const logPath = coordinationLogPath(lanePaths, wave.wave);
828
+ updateSeedRecords(logPath, {
829
+ lane: lanePaths.lane,
830
+ wave: wave.wave,
831
+ agents: wave.agents,
832
+ componentPromotions: wave.componentPromotions,
833
+ sharedPlanDocs: lanePaths.sharedPlanDocs,
834
+ contQaAgentId: lanePaths.contQaAgentId,
835
+ contEvalAgentId: lanePaths.contEvalAgentId,
836
+ integrationAgentId: lanePaths.integrationAgentId,
837
+ documentationAgentId: lanePaths.documentationAgentId,
838
+ feedbackRequests: readWaveHumanFeedbackRequests({
839
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
840
+ lane: lanePaths.lane,
841
+ waveNumber: wave.wave,
842
+ agentIds: wave.agents.map((agent) => agent.agentId),
843
+ orchestratorId: "",
844
+ }),
845
+ });
846
+
847
+ if (surface === "status") {
848
+ const payload = buildControlStatusPayload({
849
+ lanePaths,
850
+ wave,
851
+ agentId: options.agent || "",
852
+ });
853
+ if (options.json) {
854
+ console.log(JSON.stringify(payload, null, 2));
855
+ } else {
856
+ printStatus(payload);
857
+ }
858
+ return;
859
+ }
860
+
861
+ if (surface === "task") {
862
+ const coordinationState = readMaterializedCoordinationState(logPath);
863
+ if (operation === "create") {
864
+ if (!options.agent || !options.kind || !options.summary) {
865
+ throw new Error("task create requires --agent, --kind, and --summary");
866
+ }
867
+ const kind = kindForTaskCreate(options.kind);
868
+ if (kind === "human-feedback") {
869
+ const created = createFeedbackRequest({
870
+ feedbackStateDir: lanePaths.feedbackStateDir,
871
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
872
+ lane: lanePaths.lane,
873
+ wave: wave.wave,
874
+ agentId: options.agent,
875
+ orchestratorId: "",
876
+ question: options.summary,
877
+ context: options.detail,
878
+ });
879
+ appendWaveControlEvent(lanePaths, wave.wave, {
880
+ entityType: "human_input",
881
+ entityId: created.requestId,
882
+ action: "requested",
883
+ source: "operator",
884
+ actor: options.operator,
885
+ data: {
886
+ humanInputId: created.requestId,
887
+ requestId: created.requestId,
888
+ state: "pending",
889
+ createdAt: created.payload.createdAt,
890
+ },
891
+ });
892
+ console.log(JSON.stringify(created.payload, null, 2));
893
+ return;
894
+ }
895
+ const record = appendCoordinationRecord(logPath, {
896
+ lane: lanePaths.lane,
897
+ wave: wave.wave,
898
+ agentId: options.agent,
899
+ kind,
900
+ summary: options.summary,
901
+ detail: options.detail,
902
+ targets: options.targets,
903
+ priority: options.priority,
904
+ dependsOn: options.dependsOn,
905
+ artifactRefs: options.artifactRefs,
906
+ status: options.status,
907
+ source: "operator",
908
+ });
909
+ console.log(JSON.stringify(record, null, 2));
910
+ return;
911
+ }
912
+ if (operation === "list") {
913
+ const feedbackRequests = readWaveHumanFeedbackRequests({
914
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
915
+ lane: lanePaths.lane,
916
+ waveNumber: wave.wave,
917
+ agentIds: wave.agents.map((agent) => agent.agentId),
918
+ orchestratorId: "",
919
+ });
920
+ const tasks = buildTaskSnapshots({
921
+ coordinationState,
922
+ feedbackRequests,
923
+ }).filter((task) => !options.agent || task.ownerAgentId === options.agent || task.assigneeAgentId === options.agent);
924
+ if (options.json) {
925
+ console.log(JSON.stringify(tasks, null, 2));
926
+ } else {
927
+ for (const task of tasks) {
928
+ console.log(`${task.taskId} ${task.taskType}/${task.state} ${task.title}`);
929
+ }
930
+ }
931
+ return;
932
+ }
933
+ if (operation === "get") {
934
+ if (!options.id) {
935
+ throw new Error("task get requires --id");
936
+ }
937
+ const feedbackRequests = readWaveHumanFeedbackRequests({
938
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
939
+ lane: lanePaths.lane,
940
+ waveNumber: wave.wave,
941
+ agentIds: wave.agents.map((agent) => agent.agentId),
942
+ orchestratorId: "",
943
+ });
944
+ const task = buildTaskSnapshots({
945
+ coordinationState,
946
+ feedbackRequests,
947
+ }).find((entry) => entry.taskId === options.id);
948
+ if (!task) {
949
+ throw new Error(`Task not found: ${options.id}`);
950
+ }
951
+ console.log(JSON.stringify(task, null, 2));
952
+ return;
953
+ }
954
+ if (operation === "act") {
955
+ if (!action || !options.id) {
956
+ throw new Error("task act requires an action and --id");
957
+ }
958
+ if (action === "answer") {
959
+ if (!options.response) {
960
+ throw new Error("task act answer requires --response");
961
+ }
962
+ const answered = answerFeedbackRequest({
963
+ feedbackStateDir: lanePaths.feedbackStateDir,
964
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
965
+ requestId: options.id,
966
+ response: options.response,
967
+ operator: options.operator,
968
+ force: true,
969
+ });
970
+ appendWaveControlEvent(lanePaths, wave.wave, {
971
+ entityType: "human_input",
972
+ entityId: options.id,
973
+ action: "answered",
974
+ source: "operator",
975
+ actor: options.operator,
976
+ data: {
977
+ humanInputId: options.id,
978
+ requestId: options.id,
979
+ state: "answered",
980
+ operator: options.operator,
981
+ response: options.response,
982
+ createdAt: answered.createdAt,
983
+ },
984
+ });
985
+ console.log(JSON.stringify(answered, null, 2));
986
+ return;
987
+ }
988
+ const record = coordinationState.byId.get(options.id);
989
+ if (!record) {
990
+ throw new Error(`Task not found: ${options.id}`);
991
+ }
992
+ const updated = appendTaskCoordinationEvent(logPath, lanePaths, wave, record, action, options);
993
+ if (record.kind === "clarification-request" && ["resolve", "dismiss"].includes(action)) {
994
+ const nextStatus = action === "resolve" ? "resolved" : "cancelled";
995
+ for (const linked of clarificationLinkedRequests(coordinationState, record.id).filter((entry) =>
996
+ isOpenCoordinationStatus(entry.status),
997
+ )) {
998
+ appendCoordinationStatusUpdate(logPath, linked, nextStatus, {
999
+ detail: `${action === "resolve" ? "Resolved" : "Cancelled"} via clarification ${record.id}.`,
1000
+ summary: linked.summary,
1001
+ });
1002
+ }
1003
+ }
1004
+ console.log(JSON.stringify(updated, null, 2));
1005
+ return;
1006
+ }
1007
+ throw new Error("Expected task operation: create | list | get | act");
1008
+ }
1009
+
1010
+ if (surface === "rerun") {
1011
+ if (operation === "get") {
1012
+ const payload = {
1013
+ lane: lanePaths.lane,
1014
+ wave: wave.wave,
1015
+ rerunRequest: readWaveRetryOverride(lanePaths, wave.wave),
1016
+ effectiveSelectedAgentIds: resolveRetryOverrideAgentIds(
1017
+ wave,
1018
+ lanePaths,
1019
+ readWaveRetryOverride(lanePaths, wave.wave),
1020
+ ),
1021
+ relaunchPlan: readWaveRelaunchPlanSnapshot(lanePaths, wave.wave),
1022
+ };
1023
+ console.log(JSON.stringify(payload, null, 2));
1024
+ return;
1025
+ }
1026
+ if (operation === "clear") {
1027
+ clearWaveRetryOverride(lanePaths, wave.wave);
1028
+ console.log(`[wave-control] cleared rerun request for wave ${wave.wave}`);
1029
+ return;
1030
+ }
1031
+ if (operation === "request") {
1032
+ const selectedAgentIds = Array.from(new Set(options.selectedAgentIds.filter(Boolean)));
1033
+ const request = writeWaveRetryOverride(lanePaths, wave.wave, {
1034
+ lane: lanePaths.lane,
1035
+ wave: wave.wave,
1036
+ selectedAgentIds,
1037
+ resumeCursor: options.resumeCursor || null,
1038
+ reuseAttemptIds: options.reuseAttemptIds,
1039
+ reuseProofBundleIds: options.reuseProofBundleIds,
1040
+ reuseDerivedSummaries: options.reuseDerivedSummaries,
1041
+ invalidateComponentIds: options.invalidateComponentIds,
1042
+ clearReusableAgentIds: options.clearReusableAgentIds,
1043
+ preserveReusableAgentIds: options.preserveReusableAgentIds,
1044
+ requestedBy: options.requestedBy || "human-operator",
1045
+ reason: options.reason || null,
1046
+ applyOnce: true,
1047
+ });
1048
+ console.log(JSON.stringify({
1049
+ lane: lanePaths.lane,
1050
+ wave: wave.wave,
1051
+ rerunRequest: request,
1052
+ effectiveSelectedAgentIds: resolveRetryOverrideAgentIds(wave, lanePaths, request),
1053
+ }, null, 2));
1054
+ return;
1055
+ }
1056
+ throw new Error("Expected rerun operation: request | get | clear");
1057
+ }
1058
+
1059
+ if (surface === "proof") {
1060
+ if (operation === "get") {
1061
+ const registry = readWaveProofRegistry(lanePaths, wave.wave);
1062
+ const entries = (registry?.entries || []).filter((entry) => {
1063
+ if (options.id && entry.id !== options.id) {
1064
+ return false;
1065
+ }
1066
+ if (options.agent && entry.agentId !== options.agent) {
1067
+ return false;
1068
+ }
1069
+ return true;
1070
+ });
1071
+ console.log(JSON.stringify({
1072
+ lane: lanePaths.lane,
1073
+ wave: wave.wave,
1074
+ entries,
1075
+ registryPath: waveProofRegistryPath(lanePaths, wave.wave),
1076
+ }, null, 2));
1077
+ return;
1078
+ }
1079
+ if (["register", "supersede"].includes(operation) && !options.agent) {
1080
+ throw new Error(`proof ${operation} requires --agent`);
1081
+ }
1082
+ const agent = options.agent
1083
+ ? (wave.agents || []).find((entry) => entry.agentId === options.agent)
1084
+ : null;
1085
+ if (options.agent && !agent) {
1086
+ throw new Error(`Unknown wave agent id: ${options.agent}`);
1087
+ }
1088
+ if (operation === "register") {
1089
+ if (options.artifactRefs.length === 0) {
1090
+ throw new Error("proof register requires at least one --artifact");
1091
+ }
1092
+ const result = registerWaveProofBundle({
1093
+ lanePaths,
1094
+ wave,
1095
+ agent,
1096
+ artifactPaths: options.artifactRefs,
1097
+ componentIds: options.componentIds,
1098
+ authoritative: options.authoritative,
1099
+ satisfyOwnedComponents: options.satisfyOwnedComponents,
1100
+ completion: options.completion || null,
1101
+ durability: options.durability || null,
1102
+ proofLevel: options.proofLevel || null,
1103
+ docDeltaState: options.docDeltaState || null,
1104
+ detail: options.detail || "",
1105
+ recordedBy: options.operator || "human-operator",
1106
+ });
1107
+ const payload = {
1108
+ lane: lanePaths.lane,
1109
+ wave: wave.wave,
1110
+ entry: result.entry,
1111
+ registry: result.registry,
1112
+ };
1113
+ console.log(JSON.stringify(payload, null, 2));
1114
+ return;
1115
+ }
1116
+ if (operation === "supersede") {
1117
+ if (!options.id) {
1118
+ throw new Error("proof supersede requires --id");
1119
+ }
1120
+ const state = readWaveControlPlaneState(lanePaths, wave.wave);
1121
+ const current = state.proofBundlesById.get(options.id);
1122
+ if (!current) {
1123
+ throw new Error(`Proof bundle not found: ${options.id}`);
1124
+ }
1125
+ appendWaveControlEvent(lanePaths, wave.wave, {
1126
+ entityType: "proof_bundle",
1127
+ entityId: options.id,
1128
+ action: "superseded",
1129
+ source: "operator",
1130
+ actor: options.operator,
1131
+ data: {
1132
+ ...current,
1133
+ state: "superseded",
1134
+ },
1135
+ });
1136
+ const result = registerWaveProofBundle({
1137
+ lanePaths,
1138
+ wave,
1139
+ agent,
1140
+ artifactPaths: options.artifactRefs.length > 0 ? options.artifactRefs : current.artifacts.map((artifact) => artifact.path),
1141
+ componentIds: options.componentIds.length > 0 ? options.componentIds : current.components.map((component) => component.componentId),
1142
+ authoritative: options.authoritative || current.authoritative,
1143
+ satisfyOwnedComponents: options.satisfyOwnedComponents || current.satisfyOwnedComponents,
1144
+ completion: options.completion || current.proof?.completion || null,
1145
+ durability: options.durability || current.proof?.durability || null,
1146
+ proofLevel: options.proofLevel || current.proof?.proof || null,
1147
+ docDeltaState: options.docDeltaState || current.docDelta?.state || null,
1148
+ detail: options.detail || current.detail || "",
1149
+ recordedBy: options.operator || "human-operator",
1150
+ });
1151
+ appendWaveControlEvent(lanePaths, wave.wave, {
1152
+ entityType: "proof_bundle",
1153
+ entityId: result.entry.id,
1154
+ action: "linked-supersession",
1155
+ source: "operator",
1156
+ actor: options.operator,
1157
+ data: {
1158
+ ...state.proofBundlesById.get(result.entry.id),
1159
+ supersedes: options.id,
1160
+ },
1161
+ });
1162
+ syncWaveControlPlaneProjections(
1163
+ lanePaths,
1164
+ wave.wave,
1165
+ readWaveControlPlaneState(lanePaths, wave.wave),
1166
+ );
1167
+ console.log(JSON.stringify({
1168
+ lane: lanePaths.lane,
1169
+ wave: wave.wave,
1170
+ superseded: options.id,
1171
+ entry: result.entry,
1172
+ registry: result.registry,
1173
+ }, null, 2));
1174
+ return;
1175
+ }
1176
+ if (operation === "revoke") {
1177
+ if (!options.id) {
1178
+ throw new Error("proof revoke requires --id");
1179
+ }
1180
+ const state = readWaveControlPlaneState(lanePaths, wave.wave);
1181
+ const current = state.proofBundlesById.get(options.id);
1182
+ if (!current) {
1183
+ throw new Error(`Proof bundle not found: ${options.id}`);
1184
+ }
1185
+ appendWaveControlEvent(lanePaths, wave.wave, {
1186
+ entityType: "proof_bundle",
1187
+ entityId: options.id,
1188
+ action: "revoked",
1189
+ source: "operator",
1190
+ actor: options.operator,
1191
+ data: {
1192
+ ...current,
1193
+ state: "revoked",
1194
+ detail: options.detail || current.detail || "Revoked by operator.",
1195
+ },
1196
+ });
1197
+ const projections = syncWaveControlPlaneProjections(
1198
+ lanePaths,
1199
+ wave.wave,
1200
+ readWaveControlPlaneState(lanePaths, wave.wave),
1201
+ );
1202
+ console.log(JSON.stringify({
1203
+ lane: lanePaths.lane,
1204
+ wave: wave.wave,
1205
+ revokedId: options.id,
1206
+ registry: projections.proofRegistry,
1207
+ }, null, 2));
1208
+ return;
1209
+ }
1210
+ throw new Error("Expected proof operation: register | get | supersede | revoke");
1211
+ }
1212
+
1213
+ throw new Error(`Unknown control surface: ${surface}`);
1214
+ }
1215
+
1216
+ export { appendAttemptEvent };