@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.
- package/CHANGELOG.md +82 -1
- package/README.md +40 -7
- package/docs/agents/wave-orchestrator-role.md +50 -0
- package/docs/agents/wave-planner-role.md +39 -0
- package/docs/context7/bundles.json +9 -0
- package/docs/context7/planner-agent/README.md +25 -0
- package/docs/context7/planner-agent/manifest.json +83 -0
- package/docs/context7/planner-agent/papers/cooperbench-why-coding-agents-cannot-be-your-teammates-yet.md +3283 -0
- package/docs/context7/planner-agent/papers/dova-deliberation-first-multi-agent-orchestration-for-autonomous-research-automation.md +1699 -0
- package/docs/context7/planner-agent/papers/dpbench-large-language-models-struggle-with-simultaneous-coordination.md +2251 -0
- package/docs/context7/planner-agent/papers/incremental-planning-to-control-a-blackboard-based-problem-solver.md +1729 -0
- package/docs/context7/planner-agent/papers/silo-bench-a-scalable-environment-for-evaluating-distributed-coordination-in-multi-agent-llm-systems.md +3747 -0
- package/docs/context7/planner-agent/papers/todoevolve-learning-to-architect-agent-planning-systems.md +1675 -0
- package/docs/context7/planner-agent/papers/verified-multi-agent-orchestration-a-plan-execute-verify-replan-framework-for-complex-query-resolution.md +1173 -0
- package/docs/context7/planner-agent/papers/why-do-multi-agent-llm-systems-fail.md +5211 -0
- package/docs/context7/planner-agent/topics/planning-and-orchestration.md +24 -0
- package/docs/evals/README.md +96 -1
- package/docs/evals/arm-templates/README.md +13 -0
- package/docs/evals/arm-templates/full-wave.json +15 -0
- package/docs/evals/arm-templates/single-agent.json +15 -0
- package/docs/evals/benchmark-catalog.json +7 -0
- package/docs/evals/cases/README.md +47 -0
- package/docs/evals/cases/wave-blackboard-inbox-targeting.json +73 -0
- package/docs/evals/cases/wave-contradiction-conflict.json +104 -0
- package/docs/evals/cases/wave-expert-routing-preservation.json +69 -0
- package/docs/evals/cases/wave-hidden-profile-private-evidence.json +81 -0
- package/docs/evals/cases/wave-premature-closure-guard.json +71 -0
- package/docs/evals/cases/wave-silo-cross-agent-state.json +77 -0
- package/docs/evals/cases/wave-simultaneous-lockstep.json +92 -0
- package/docs/evals/cooperbench/real-world-mitigation.md +341 -0
- package/docs/evals/external-benchmarks.json +85 -0
- package/docs/evals/external-command-config.sample.json +9 -0
- package/docs/evals/external-command-config.swe-bench-pro.json +8 -0
- package/docs/evals/pilots/README.md +47 -0
- package/docs/evals/pilots/swe-bench-pro-public-full-wave-review-10.json +64 -0
- package/docs/evals/pilots/swe-bench-pro-public-pilot.json +111 -0
- package/docs/evals/wave-benchmark-program.md +302 -0
- package/docs/guides/planner.md +67 -11
- package/docs/guides/terminal-surfaces.md +12 -0
- package/docs/plans/context7-wave-orchestrator.md +20 -0
- package/docs/plans/current-state.md +8 -1
- package/docs/plans/examples/wave-benchmark-improvement.md +108 -0
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/examples/wave-example-rollout-fidelity.md +340 -0
- package/docs/plans/migration.md +26 -0
- package/docs/plans/wave-orchestrator.md +60 -12
- package/docs/plans/waves/reviews/wave-1-benchmark-operator.md +118 -0
- package/docs/reference/cli-reference.md +547 -0
- package/docs/reference/coordination-and-closure.md +436 -0
- package/docs/reference/live-proof-waves.md +25 -3
- package/docs/reference/npmjs-trusted-publishing.md +3 -3
- package/docs/reference/proof-metrics.md +90 -0
- package/docs/reference/runtime-config/README.md +63 -2
- package/docs/reference/runtime-config/codex.md +2 -1
- package/docs/reference/sample-waves.md +29 -18
- package/docs/reference/wave-control.md +164 -0
- package/docs/reference/wave-planning-lessons.md +131 -0
- package/package.json +5 -4
- package/releases/manifest.json +40 -0
- package/scripts/research/agent-context-archive.mjs +18 -0
- package/scripts/research/manifests/agent-context-expanded-2026-03-22.mjs +17 -0
- package/scripts/research/sync-planner-context7-bundle.mjs +133 -0
- package/scripts/wave-orchestrator/agent-state.mjs +11 -2
- package/scripts/wave-orchestrator/artifact-schemas.mjs +232 -0
- package/scripts/wave-orchestrator/autonomous.mjs +7 -0
- package/scripts/wave-orchestrator/benchmark-cases.mjs +374 -0
- package/scripts/wave-orchestrator/benchmark-external.mjs +1384 -0
- package/scripts/wave-orchestrator/benchmark.mjs +972 -0
- package/scripts/wave-orchestrator/clarification-triage.mjs +78 -12
- package/scripts/wave-orchestrator/config.mjs +175 -0
- package/scripts/wave-orchestrator/control-cli.mjs +1216 -0
- package/scripts/wave-orchestrator/control-plane.mjs +697 -0
- package/scripts/wave-orchestrator/coord-cli.mjs +360 -2
- package/scripts/wave-orchestrator/coordination-store.mjs +211 -9
- package/scripts/wave-orchestrator/coordination.mjs +84 -0
- package/scripts/wave-orchestrator/dashboard-renderer.mjs +120 -5
- package/scripts/wave-orchestrator/dashboard-state.mjs +22 -0
- package/scripts/wave-orchestrator/evals.mjs +23 -0
- package/scripts/wave-orchestrator/executors.mjs +3 -2
- package/scripts/wave-orchestrator/feedback.mjs +55 -0
- package/scripts/wave-orchestrator/install.mjs +151 -2
- package/scripts/wave-orchestrator/launcher-closure.mjs +4 -1
- package/scripts/wave-orchestrator/launcher-runtime.mjs +33 -30
- package/scripts/wave-orchestrator/launcher.mjs +884 -36
- package/scripts/wave-orchestrator/planner-context.mjs +75 -0
- package/scripts/wave-orchestrator/planner.mjs +2270 -136
- package/scripts/wave-orchestrator/proof-cli.mjs +195 -0
- package/scripts/wave-orchestrator/proof-registry.mjs +317 -0
- package/scripts/wave-orchestrator/replay.mjs +10 -4
- package/scripts/wave-orchestrator/retry-cli.mjs +184 -0
- package/scripts/wave-orchestrator/retry-control.mjs +225 -0
- package/scripts/wave-orchestrator/shared.mjs +26 -0
- package/scripts/wave-orchestrator/swe-bench-pro-task.mjs +1004 -0
- package/scripts/wave-orchestrator/terminals.mjs +1 -1
- package/scripts/wave-orchestrator/traces.mjs +157 -2
- package/scripts/wave-orchestrator/wave-control-client.mjs +532 -0
- package/scripts/wave-orchestrator/wave-control-schema.mjs +309 -0
- package/scripts/wave-orchestrator/wave-files.mjs +144 -23
- package/scripts/wave.mjs +27 -0
- package/skills/repo-coding-rules/SKILL.md +1 -0
- package/skills/role-cont-eval/SKILL.md +1 -0
- package/skills/role-cont-qa/SKILL.md +13 -6
- package/skills/role-deploy/SKILL.md +1 -0
- package/skills/role-documentation/SKILL.md +4 -0
- package/skills/role-implementation/SKILL.md +4 -0
- package/skills/role-infra/SKILL.md +2 -1
- package/skills/role-integration/SKILL.md +15 -8
- package/skills/role-planner/SKILL.md +39 -0
- package/skills/role-planner/skill.json +21 -0
- package/skills/role-research/SKILL.md +1 -0
- package/skills/role-security/SKILL.md +2 -2
- package/skills/runtime-claude/SKILL.md +2 -1
- package/skills/runtime-codex/SKILL.md +1 -0
- package/skills/runtime-local/SKILL.md +2 -0
- package/skills/runtime-opencode/SKILL.md +1 -0
- package/skills/wave-core/SKILL.md +25 -6
- package/skills/wave-core/references/marker-syntax.md +16 -8
- 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"),
|