@chllming/wave-orchestration 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/README.md +44 -8
  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 +48 -11
  39. package/docs/plans/context7-wave-orchestrator.md +20 -0
  40. package/docs/plans/current-state.md +9 -1
  41. package/docs/plans/examples/wave-benchmark-improvement.md +108 -0
  42. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  43. package/docs/plans/examples/wave-example-rollout-fidelity.md +340 -0
  44. package/docs/plans/wave-orchestrator.md +73 -11
  45. package/docs/plans/waves/reviews/wave-1-benchmark-operator.md +118 -0
  46. package/docs/reference/coordination-and-closure.md +436 -0
  47. package/docs/reference/live-proof-waves.md +25 -3
  48. package/docs/reference/npmjs-trusted-publishing.md +3 -3
  49. package/docs/reference/proof-metrics.md +90 -0
  50. package/docs/reference/runtime-config/README.md +61 -0
  51. package/docs/reference/sample-waves.md +29 -18
  52. package/docs/reference/wave-control.md +164 -0
  53. package/docs/reference/wave-planning-lessons.md +131 -0
  54. package/package.json +5 -4
  55. package/releases/manifest.json +33 -0
  56. package/scripts/research/agent-context-archive.mjs +18 -0
  57. package/scripts/research/manifests/agent-context-expanded-2026-03-22.mjs +17 -0
  58. package/scripts/research/sync-planner-context7-bundle.mjs +133 -0
  59. package/scripts/wave-autonomous.mjs +2 -4
  60. package/scripts/wave-orchestrator/adhoc.mjs +32 -11
  61. package/scripts/wave-orchestrator/artifact-schemas.mjs +232 -0
  62. package/scripts/wave-orchestrator/autonomous.mjs +27 -6
  63. package/scripts/wave-orchestrator/benchmark-cases.mjs +374 -0
  64. package/scripts/wave-orchestrator/benchmark-external.mjs +1384 -0
  65. package/scripts/wave-orchestrator/benchmark.mjs +972 -0
  66. package/scripts/wave-orchestrator/clarification-triage.mjs +78 -12
  67. package/scripts/wave-orchestrator/config.mjs +175 -0
  68. package/scripts/wave-orchestrator/control-cli.mjs +1123 -0
  69. package/scripts/wave-orchestrator/control-plane.mjs +697 -0
  70. package/scripts/wave-orchestrator/coord-cli.mjs +360 -2
  71. package/scripts/wave-orchestrator/coordination-store.mjs +211 -9
  72. package/scripts/wave-orchestrator/coordination.mjs +84 -0
  73. package/scripts/wave-orchestrator/dashboard-renderer.mjs +38 -3
  74. package/scripts/wave-orchestrator/dashboard-state.mjs +22 -0
  75. package/scripts/wave-orchestrator/evals.mjs +23 -0
  76. package/scripts/wave-orchestrator/executors.mjs +3 -2
  77. package/scripts/wave-orchestrator/feedback.mjs +55 -0
  78. package/scripts/wave-orchestrator/install.mjs +253 -26
  79. package/scripts/wave-orchestrator/launcher-closure.mjs +4 -1
  80. package/scripts/wave-orchestrator/launcher-runtime.mjs +24 -21
  81. package/scripts/wave-orchestrator/launcher.mjs +800 -35
  82. package/scripts/wave-orchestrator/package-update-notice.mjs +230 -0
  83. package/scripts/wave-orchestrator/package-version.mjs +32 -0
  84. package/scripts/wave-orchestrator/planner-context.mjs +75 -0
  85. package/scripts/wave-orchestrator/planner.mjs +2270 -136
  86. package/scripts/wave-orchestrator/proof-cli.mjs +195 -0
  87. package/scripts/wave-orchestrator/proof-registry.mjs +317 -0
  88. package/scripts/wave-orchestrator/replay.mjs +10 -4
  89. package/scripts/wave-orchestrator/retry-cli.mjs +184 -0
  90. package/scripts/wave-orchestrator/retry-control.mjs +225 -0
  91. package/scripts/wave-orchestrator/shared.mjs +26 -0
  92. package/scripts/wave-orchestrator/swe-bench-pro-task.mjs +1004 -0
  93. package/scripts/wave-orchestrator/traces.mjs +157 -2
  94. package/scripts/wave-orchestrator/wave-control-client.mjs +532 -0
  95. package/scripts/wave-orchestrator/wave-control-schema.mjs +309 -0
  96. package/scripts/wave-orchestrator/wave-files.mjs +17 -5
  97. package/scripts/wave.mjs +39 -2
  98. package/skills/repo-coding-rules/SKILL.md +1 -0
  99. package/skills/role-cont-eval/SKILL.md +1 -0
  100. package/skills/role-cont-qa/SKILL.md +13 -6
  101. package/skills/role-deploy/SKILL.md +1 -0
  102. package/skills/role-documentation/SKILL.md +4 -0
  103. package/skills/role-implementation/SKILL.md +4 -0
  104. package/skills/role-infra/SKILL.md +2 -1
  105. package/skills/role-integration/SKILL.md +15 -8
  106. package/skills/role-planner/SKILL.md +39 -0
  107. package/skills/role-planner/skill.json +21 -0
  108. package/skills/role-research/SKILL.md +1 -0
  109. package/skills/role-security/SKILL.md +2 -2
  110. package/skills/runtime-claude/SKILL.md +2 -1
  111. package/skills/runtime-codex/SKILL.md +1 -0
  112. package/skills/runtime-local/SKILL.md +2 -0
  113. package/skills/runtime-opencode/SKILL.md +1 -0
  114. package/skills/wave-core/SKILL.md +25 -6
  115. package/skills/wave-core/references/marker-syntax.md +16 -8
  116. package/wave.config.json +45 -0
@@ -0,0 +1,184 @@
1
+ import path from "node:path";
2
+ import { parseWaveFiles } from "./wave-files.mjs";
3
+ import {
4
+ buildLanePaths,
5
+ parseNonNegativeInt,
6
+ readJsonOrNull,
7
+ REPO_ROOT,
8
+ sanitizeAdhocRunId,
9
+ sanitizeLaneName,
10
+ } from "./shared.mjs";
11
+ import {
12
+ clearWaveRetryOverride,
13
+ readWaveRelaunchPlanSnapshot,
14
+ readWaveRetryOverride,
15
+ resolveRetryOverrideAgentIds,
16
+ writeWaveRetryOverride,
17
+ } from "./retry-control.mjs";
18
+
19
+ function printUsage() {
20
+ console.log(`Usage:
21
+ pnpm exec wave retry show --lane <lane> --wave <n> [--json]
22
+ pnpm exec wave retry apply --lane <lane> --wave <n> [--agent <id> ...] [--clear-reuse <id> ...] [--preserve-reuse <id> ...] [--resume-phase <phase>] [--requested-by <name>] [--reason <text>] [--json]
23
+ pnpm exec wave retry clear --lane <lane> --wave <n>
24
+ pnpm exec wave retry <subcommand> --run <id> [--wave 0] ...
25
+ `);
26
+ }
27
+
28
+ function normalizeAgentList(values) {
29
+ return Array.from(
30
+ new Set(
31
+ values
32
+ .flatMap((value) => String(value || "").split(","))
33
+ .map((value) => value.trim())
34
+ .filter(Boolean),
35
+ ),
36
+ );
37
+ }
38
+
39
+ function parseArgs(argv) {
40
+ const args = argv[0] === "--" ? argv.slice(1) : argv;
41
+ const subcommand = String(args[0] || "").trim().toLowerCase();
42
+ const options = {
43
+ lane: "main",
44
+ wave: null,
45
+ runId: "",
46
+ json: false,
47
+ selectedAgentIds: [],
48
+ clearReusableAgentIds: [],
49
+ preserveReusableAgentIds: [],
50
+ resumePhase: "",
51
+ requestedBy: "",
52
+ reason: "",
53
+ };
54
+ for (let i = 1; i < args.length; i += 1) {
55
+ const arg = args[i];
56
+ if (arg === "--lane") {
57
+ options.lane = sanitizeLaneName(args[++i]);
58
+ } else if (arg === "--run") {
59
+ options.runId = sanitizeAdhocRunId(args[++i]);
60
+ } else if (arg === "--wave") {
61
+ options.wave = parseNonNegativeInt(args[++i], "--wave");
62
+ } else if (arg === "--agent" || arg === "--agents") {
63
+ options.selectedAgentIds.push(args[++i]);
64
+ } else if (arg === "--clear-reuse") {
65
+ options.clearReusableAgentIds.push(args[++i]);
66
+ } else if (arg === "--preserve-reuse") {
67
+ options.preserveReusableAgentIds.push(args[++i]);
68
+ } else if (arg === "--resume-phase") {
69
+ options.resumePhase = String(args[++i] || "").trim();
70
+ } else if (arg === "--requested-by") {
71
+ options.requestedBy = String(args[++i] || "").trim();
72
+ } else if (arg === "--reason") {
73
+ options.reason = String(args[++i] || "").trim();
74
+ } else if (arg === "--json") {
75
+ options.json = true;
76
+ } else if (arg === "--help" || arg === "-h") {
77
+ return { help: true, subcommand, options };
78
+ } else {
79
+ throw new Error(`Unknown argument: ${arg}`);
80
+ }
81
+ }
82
+ return { help: false, subcommand, options };
83
+ }
84
+
85
+ function resolveLaneForRun(runId, fallbackLane) {
86
+ return (
87
+ readJsonOrNull(path.join(REPO_ROOT, ".wave", "adhoc", "runs", runId, "result.json"))?.lane ||
88
+ fallbackLane
89
+ );
90
+ }
91
+
92
+ function loadWave(lanePaths, waveNumber) {
93
+ const waves = parseWaveFiles(lanePaths.wavesDir, { laneProfile: lanePaths.laneProfile });
94
+ const wave = waves.find((entry) => entry.wave === waveNumber);
95
+ if (!wave) {
96
+ throw new Error(`Wave ${waveNumber} not found in ${lanePaths.wavesDir}`);
97
+ }
98
+ return wave;
99
+ }
100
+
101
+ export async function runRetryCli(argv) {
102
+ const { help, subcommand, options } = parseArgs(argv);
103
+ if (help || !subcommand) {
104
+ printUsage();
105
+ return;
106
+ }
107
+ if (!["show", "apply", "clear"].includes(subcommand)) {
108
+ throw new Error("Expected subcommand: show | apply | clear");
109
+ }
110
+ if (options.runId) {
111
+ options.lane = resolveLaneForRun(options.runId, options.lane);
112
+ }
113
+ const lanePaths = buildLanePaths(options.lane, {
114
+ adhocRunId: options.runId || null,
115
+ });
116
+ if (options.wave === null && options.runId) {
117
+ options.wave = 0;
118
+ }
119
+ if (options.wave === null) {
120
+ throw new Error("--wave is required");
121
+ }
122
+ const wave = loadWave(lanePaths, options.wave);
123
+ if (subcommand === "clear") {
124
+ clearWaveRetryOverride(lanePaths, wave.wave);
125
+ console.log(`[wave-retry] cleared override for wave ${wave.wave}`);
126
+ return;
127
+ }
128
+
129
+ const existingOverride = readWaveRetryOverride(lanePaths, wave.wave);
130
+ const relaunchPlan = readWaveRelaunchPlanSnapshot(lanePaths, wave.wave);
131
+ if (subcommand === "show") {
132
+ const payload = {
133
+ wave: wave.wave,
134
+ lane: lanePaths.lane,
135
+ override: existingOverride,
136
+ effectiveSelectedAgentIds: resolveRetryOverrideAgentIds(wave, lanePaths, existingOverride),
137
+ relaunchPlan,
138
+ };
139
+ if (options.json) {
140
+ console.log(JSON.stringify(payload, null, 2));
141
+ } else {
142
+ console.log(JSON.stringify(payload, null, 2));
143
+ }
144
+ return;
145
+ }
146
+
147
+ const selectedAgentIds = normalizeAgentList(options.selectedAgentIds);
148
+ const clearReusableAgentIds = normalizeAgentList(options.clearReusableAgentIds);
149
+ const preserveReusableAgentIds = normalizeAgentList(options.preserveReusableAgentIds);
150
+ const knownAgentIds = new Set((wave.agents || []).map((agent) => agent.agentId));
151
+ const unknownAgentIds = [
152
+ ...selectedAgentIds,
153
+ ...clearReusableAgentIds,
154
+ ...preserveReusableAgentIds,
155
+ ].filter((agentId) => !knownAgentIds.has(agentId));
156
+ if (unknownAgentIds.length > 0) {
157
+ throw new Error(`Unknown wave agent ids: ${unknownAgentIds.join(", ")}`);
158
+ }
159
+ if (selectedAgentIds.length === 0 && !String(options.resumePhase || "").trim()) {
160
+ throw new Error("apply requires --agent/--agents or --resume-phase");
161
+ }
162
+ const override = writeWaveRetryOverride(lanePaths, wave.wave, {
163
+ lane: lanePaths.lane,
164
+ wave: wave.wave,
165
+ selectedAgentIds,
166
+ clearReusableAgentIds,
167
+ preserveReusableAgentIds,
168
+ resumePhase: options.resumePhase || null,
169
+ requestedBy: options.requestedBy || "human-operator",
170
+ reason: options.reason || null,
171
+ applyOnce: true,
172
+ });
173
+ const payload = {
174
+ wave: wave.wave,
175
+ lane: lanePaths.lane,
176
+ override,
177
+ effectiveSelectedAgentIds: resolveRetryOverrideAgentIds(wave, lanePaths, override),
178
+ };
179
+ if (options.json) {
180
+ console.log(JSON.stringify(payload, null, 2));
181
+ } else {
182
+ console.log(JSON.stringify(payload, null, 2));
183
+ }
184
+ }
@@ -0,0 +1,225 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {
4
+ readRetryOverride,
5
+ readRelaunchPlan,
6
+ writeRetryOverride,
7
+ } from "./artifact-schemas.mjs";
8
+ import {
9
+ appendWaveControlEvent,
10
+ readWaveControlPlaneState,
11
+ syncWaveControlPlaneProjections,
12
+ } from "./control-plane.mjs";
13
+ import { isSecurityReviewAgent } from "./role-helpers.mjs";
14
+ import { ensureDirectory, parseNonNegativeInt } from "./shared.mjs";
15
+
16
+ function uniqueAgentIds(values) {
17
+ return Array.from(
18
+ new Set(
19
+ (Array.isArray(values) ? values : [])
20
+ .map((value) => String(value || "").trim())
21
+ .filter(Boolean),
22
+ ),
23
+ );
24
+ }
25
+
26
+ function mergeRetryOverride(activeRequest, projectedOverride, lanePaths, waveNumber) {
27
+ const projected = projectedOverride || {};
28
+ return {
29
+ lane: lanePaths?.lane || projected.lane || null,
30
+ wave: waveNumber,
31
+ selectedAgentIds: uniqueAgentIds(
32
+ projected.selectedAgentIds?.length > 0
33
+ ? projected.selectedAgentIds
34
+ : activeRequest?.selectedAgentIds,
35
+ ),
36
+ reuseAttemptIds: uniqueAgentIds(
37
+ projected.reuseAttemptIds?.length > 0
38
+ ? projected.reuseAttemptIds
39
+ : activeRequest?.reuseAttemptIds,
40
+ ),
41
+ reuseProofBundleIds: uniqueAgentIds(
42
+ projected.reuseProofBundleIds?.length > 0
43
+ ? projected.reuseProofBundleIds
44
+ : activeRequest?.reuseProofBundleIds,
45
+ ),
46
+ reuseDerivedSummaries:
47
+ projected.reuseDerivedSummaries === false ? false : activeRequest?.reuseDerivedSummaries !== false,
48
+ invalidateComponentIds: uniqueAgentIds(
49
+ projected.invalidateComponentIds?.length > 0
50
+ ? projected.invalidateComponentIds
51
+ : activeRequest?.invalidateComponentIds,
52
+ ),
53
+ clearReusableAgentIds: uniqueAgentIds(
54
+ projected.clearReusableAgentIds?.length > 0
55
+ ? projected.clearReusableAgentIds
56
+ : activeRequest?.clearReusableAgentIds,
57
+ ),
58
+ preserveReusableAgentIds: uniqueAgentIds(
59
+ projected.preserveReusableAgentIds?.length > 0
60
+ ? projected.preserveReusableAgentIds
61
+ : activeRequest?.preserveReusableAgentIds,
62
+ ),
63
+ resumePhase: projected.resumePhase || activeRequest?.resumeCursor || null,
64
+ requestedBy: projected.requestedBy || activeRequest?.requestedBy || "human-operator",
65
+ reason: projected.reason || activeRequest?.reason || null,
66
+ applyOnce: projected.applyOnce === false ? false : activeRequest?.applyOnce !== false,
67
+ createdAt: projected.createdAt || activeRequest?.createdAt,
68
+ };
69
+ }
70
+
71
+ export function waveRetryOverridePath(lanePaths, waveNumber) {
72
+ return path.join(lanePaths.controlDir, `retry-override-wave-${parseNonNegativeInt(waveNumber, "wave")}.json`);
73
+ }
74
+
75
+ export function waveRelaunchPlanPath(lanePaths, waveNumber) {
76
+ return path.join(lanePaths.statusDir, `relaunch-plan-wave-${parseNonNegativeInt(waveNumber, "wave")}.json`);
77
+ }
78
+
79
+ export function readWaveRetryOverride(lanePaths, waveNumber) {
80
+ const state = readWaveControlPlaneState(lanePaths, waveNumber);
81
+ const activeRequest = state.activeRerunRequest;
82
+ const projectedOverride = readRetryOverride(waveRetryOverridePath(lanePaths, waveNumber), {
83
+ lane: lanePaths?.lane || null,
84
+ wave: waveNumber,
85
+ });
86
+ if (!activeRequest && state.rerunRequests.length === 0) {
87
+ return projectedOverride;
88
+ }
89
+ if (!activeRequest) {
90
+ return null;
91
+ }
92
+ return mergeRetryOverride(activeRequest, projectedOverride, lanePaths, waveNumber);
93
+ }
94
+
95
+ export function writeWaveRetryOverride(lanePaths, waveNumber, payload) {
96
+ const filePath = waveRetryOverridePath(lanePaths, waveNumber);
97
+ ensureDirectory(path.dirname(filePath));
98
+ const requestId =
99
+ String(payload?.requestId || "").trim() ||
100
+ `rerun-wave-${parseNonNegativeInt(waveNumber, "wave")}-${Date.now()}`;
101
+ appendWaveControlEvent(lanePaths, waveNumber, {
102
+ entityType: "rerun_request",
103
+ entityId: requestId,
104
+ action: "requested",
105
+ source: "operator",
106
+ actor: String(payload?.requestedBy || "human-operator"),
107
+ data: {
108
+ requestId,
109
+ state: "active",
110
+ selectedAgentIds: uniqueAgentIds(payload?.selectedAgentIds),
111
+ resumeCursor: String(payload?.resumeCursor || payload?.resumePhase || "").trim() || null,
112
+ reuseAttemptIds: uniqueAgentIds(payload?.reuseAttemptIds),
113
+ reuseProofBundleIds: uniqueAgentIds(payload?.reuseProofBundleIds),
114
+ reuseDerivedSummaries: payload?.reuseDerivedSummaries !== false,
115
+ invalidateComponentIds: uniqueAgentIds(payload?.invalidateComponentIds),
116
+ clearReusableAgentIds: uniqueAgentIds(payload?.clearReusableAgentIds),
117
+ preserveReusableAgentIds: uniqueAgentIds(payload?.preserveReusableAgentIds),
118
+ requestedBy: String(payload?.requestedBy || "human-operator"),
119
+ reason: String(payload?.reason || "").trim() || null,
120
+ applyOnce: payload?.applyOnce !== false,
121
+ createdAt: String(payload?.createdAt || "") || undefined,
122
+ },
123
+ });
124
+ const projections = syncWaveControlPlaneProjections(
125
+ lanePaths,
126
+ waveNumber,
127
+ readWaveControlPlaneState(lanePaths, waveNumber),
128
+ );
129
+ return writeRetryOverride(filePath, projections.retryOverride, {
130
+ lane: lanePaths?.lane || null,
131
+ wave: waveNumber,
132
+ });
133
+ }
134
+
135
+ export function clearWaveRetryOverride(lanePaths, waveNumber) {
136
+ const activeRequest = readWaveControlPlaneState(lanePaths, waveNumber).activeRerunRequest;
137
+ if (activeRequest?.requestId) {
138
+ appendWaveControlEvent(lanePaths, waveNumber, {
139
+ entityType: "rerun_request",
140
+ entityId: activeRequest.requestId,
141
+ action: "cleared",
142
+ source: "operator",
143
+ actor: "human-operator",
144
+ data: {
145
+ ...activeRequest,
146
+ state: "cleared",
147
+ updatedAt: undefined,
148
+ },
149
+ });
150
+ syncWaveControlPlaneProjections(
151
+ lanePaths,
152
+ waveNumber,
153
+ readWaveControlPlaneState(lanePaths, waveNumber),
154
+ );
155
+ }
156
+ try {
157
+ fs.rmSync(waveRetryOverridePath(lanePaths, waveNumber), { force: true });
158
+ } catch {
159
+ // no-op
160
+ }
161
+ }
162
+
163
+ export function readWaveRelaunchPlanSnapshot(lanePaths, waveNumber) {
164
+ return readRelaunchPlan(waveRelaunchPlanPath(lanePaths, waveNumber), {
165
+ wave: waveNumber,
166
+ });
167
+ }
168
+
169
+ export function resolveRetryOverrideAgentIds(waveDefinition, lanePaths, override) {
170
+ const selectedAgentIds = uniqueAgentIds(override?.selectedAgentIds);
171
+ if (selectedAgentIds.length > 0) {
172
+ return selectedAgentIds;
173
+ }
174
+ const resumePhase = String(override?.resumePhase || "")
175
+ .trim()
176
+ .toLowerCase();
177
+ if (!resumePhase) {
178
+ return [];
179
+ }
180
+ const agents = Array.isArray(waveDefinition?.agents) ? waveDefinition.agents : [];
181
+ const closureAgentIds = new Set(
182
+ [
183
+ lanePaths?.contEvalAgentId || "E0",
184
+ lanePaths?.integrationAgentId || "A8",
185
+ lanePaths?.documentationAgentId || "A9",
186
+ lanePaths?.contQaAgentId || "A0",
187
+ ].filter(Boolean),
188
+ );
189
+ if (resumePhase === "implementation") {
190
+ return agents
191
+ .filter((agent) => agent?.agentId && !closureAgentIds.has(agent.agentId) && !isSecurityReviewAgent(agent))
192
+ .map((agent) => agent.agentId);
193
+ }
194
+ if (resumePhase === "integrating") {
195
+ return [lanePaths?.integrationAgentId || "A8"];
196
+ }
197
+ if (resumePhase === "docs-closure") {
198
+ return [lanePaths?.documentationAgentId || "A9"];
199
+ }
200
+ if (resumePhase === "cont-qa-closure") {
201
+ return [lanePaths?.contQaAgentId || "A0"];
202
+ }
203
+ if (resumePhase === "cont-eval") {
204
+ return [lanePaths?.contEvalAgentId || "E0"];
205
+ }
206
+ return [];
207
+ }
208
+
209
+ export function resolveRetryOverrideRuns(agentRuns, override, lanePaths, waveDefinition) {
210
+ const selectedAgentIds = resolveRetryOverrideAgentIds(waveDefinition, lanePaths, override);
211
+ if (selectedAgentIds.length === 0) {
212
+ return {
213
+ runs: [],
214
+ selectedAgentIds: [],
215
+ unknownAgentIds: [],
216
+ };
217
+ }
218
+ const runsByAgentId = new Map((agentRuns || []).map((run) => [run?.agent?.agentId, run]));
219
+ const unknownAgentIds = selectedAgentIds.filter((agentId) => !runsByAgentId.has(agentId));
220
+ return {
221
+ runs: selectedAgentIds.map((agentId) => runsByAgentId.get(agentId)).filter(Boolean),
222
+ selectedAgentIds,
223
+ unknownAgentIds,
224
+ };
225
+ }
@@ -19,6 +19,9 @@ export const DEFAULT_AGENT_RATE_LIMIT_BASE_DELAY_SECONDS = 20;
19
19
  export const DEFAULT_AGENT_RATE_LIMIT_MAX_DELAY_SECONDS = 180;
20
20
  export const DEFAULT_AGENT_LAUNCH_STAGGER_MS = 1200;
21
21
  export const DEFAULT_WAIT_PROGRESS_INTERVAL_MS = 3000;
22
+ export const DEFAULT_LIVE_COORDINATION_REFRESH_MS = 15000;
23
+ export const DEFAULT_COORDINATION_ACK_TIMEOUT_MS = 5 * 60 * 1000;
24
+ export const DEFAULT_COORDINATION_RESOLUTION_STALE_MS = 30 * 60 * 1000;
22
25
  export const DEFAULT_REFRESH_MS = 2000;
23
26
  export const DEFAULT_WATCH_REFRESH_MS = 2000;
24
27
  export const DEFAULT_WAIT_TIMEOUT_SECONDS = 1800;
@@ -109,6 +112,21 @@ export function buildWorkspaceTmuxToken(workspaceRoot = REPO_ROOT) {
109
112
  return `${repoBase}_${repoHash}`;
110
113
  }
111
114
 
115
+ function buildTelemetryProjectId(config) {
116
+ return (
117
+ String(config?.waveControl?.projectId || config?.projectId || config?.projectName || path.basename(REPO_ROOT))
118
+ .trim()
119
+ .toLowerCase()
120
+ .replace(/[^a-z0-9._-]+/g, "-")
121
+ .replace(/-+/g, "-")
122
+ .replace(/^-+|-+$/g, "") || "wave"
123
+ );
124
+ }
125
+
126
+ function readRuntimeVersion() {
127
+ return String(readJsonOrNull(path.join(PACKAGE_ROOT, "package.json"))?.version || "").trim() || null;
128
+ }
129
+
112
130
  export function buildLanePaths(laneInput = DEFAULT_WAVE_LANE, options = {}) {
113
131
  const config = options.config || loadWaveConfig();
114
132
  const baseLaneProfile = resolveLaneProfile(config, laneInput || config.defaultLane);
@@ -176,10 +194,14 @@ export function buildLanePaths(laneInput = DEFAULT_WAVE_LANE, options = {}) {
176
194
  messageboardsDir: path.join(stateDir, "messageboards"),
177
195
  dashboardsDir: path.join(stateDir, "dashboards"),
178
196
  coordinationDir: path.join(stateDir, "coordination"),
197
+ controlDir: path.join(stateDir, "control"),
198
+ controlPlaneDir: path.join(stateDir, "control-plane"),
199
+ telemetryDir: path.join(stateDir, "control-plane", "telemetry"),
179
200
  assignmentsDir: path.join(stateDir, "assignments"),
180
201
  inboxesDir: path.join(stateDir, "inboxes"),
181
202
  ledgerDir: path.join(stateDir, "ledger"),
182
203
  integrationDir: path.join(stateDir, "integration"),
204
+ proofDir: path.join(stateDir, "proof"),
183
205
  securityDir: path.join(stateDir, "security"),
184
206
  dependencySnapshotsDir: path.join(stateDir, "dependencies"),
185
207
  docsQueueDir: path.join(stateDir, "docs-queue"),
@@ -224,6 +246,10 @@ export function buildLanePaths(laneInput = DEFAULT_WAVE_LANE, options = {}) {
224
246
  executors: laneProfile.executors,
225
247
  skills: laneProfile.skills,
226
248
  capabilityRouting: laneProfile.capabilityRouting,
249
+ projectId: buildTelemetryProjectId(config),
250
+ runtimeVersion: readRuntimeVersion(),
251
+ orchestratorId: null,
252
+ waveControl: laneProfile.waveControl,
227
253
  defaultManifestPath: path.join(stateDir, "waves.manifest.json"),
228
254
  defaultRunStatePath: path.join(stateDir, "run-state.json"),
229
255
  globalDashboardPath: path.join(stateDir, "dashboards", "global.json"),