@chllming/wave-orchestration 0.9.0 → 0.9.2
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 +57 -0
- package/LICENSE.md +21 -0
- package/README.md +133 -20
- package/docs/README.md +12 -4
- package/docs/agents/wave-security-role.md +1 -0
- package/docs/architecture/README.md +1498 -0
- package/docs/concepts/operating-modes.md +2 -2
- package/docs/guides/author-and-run-waves.md +14 -4
- package/docs/guides/planner.md +2 -2
- package/docs/guides/{recommendations-0.9.0.md → recommendations-0.9.2.md} +8 -7
- package/docs/guides/sandboxed-environments.md +158 -0
- package/docs/guides/terminal-surfaces.md +14 -12
- package/docs/plans/current-state.md +11 -3
- package/docs/plans/end-state-architecture.md +3 -1
- package/docs/plans/examples/wave-example-design-handoff.md +1 -1
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +70 -19
- package/docs/plans/sandbox-end-state-architecture.md +153 -0
- package/docs/reference/cli-reference.md +71 -7
- package/docs/reference/coordination-and-closure.md +18 -1
- package/docs/reference/corridor.md +225 -0
- package/docs/reference/github-packages-setup.md +1 -1
- package/docs/reference/migration-0.2-to-0.5.md +9 -7
- package/docs/reference/npmjs-token-publishing.md +53 -0
- package/docs/reference/npmjs-trusted-publishing.md +4 -50
- package/docs/reference/package-publishing-flow.md +272 -0
- package/docs/reference/runtime-config/README.md +61 -3
- package/docs/reference/sample-waves.md +5 -5
- package/docs/reference/skills.md +1 -1
- package/docs/reference/wave-control.md +358 -27
- package/docs/roadmap.md +39 -204
- package/package.json +1 -1
- package/releases/manifest.json +38 -0
- package/scripts/wave-cli-bootstrap.mjs +52 -1
- package/scripts/wave-orchestrator/agent-process-runner.mjs +344 -0
- package/scripts/wave-orchestrator/agent-state.mjs +0 -1
- package/scripts/wave-orchestrator/artifact-schemas.mjs +7 -0
- package/scripts/wave-orchestrator/autonomous.mjs +47 -14
- package/scripts/wave-orchestrator/closure-engine.mjs +138 -17
- package/scripts/wave-orchestrator/config.mjs +199 -3
- package/scripts/wave-orchestrator/context7.mjs +231 -29
- package/scripts/wave-orchestrator/control-cli.mjs +42 -5
- package/scripts/wave-orchestrator/coordination.mjs +14 -0
- package/scripts/wave-orchestrator/corridor.mjs +363 -0
- package/scripts/wave-orchestrator/dashboard-renderer.mjs +115 -43
- package/scripts/wave-orchestrator/derived-state-engine.mjs +44 -4
- package/scripts/wave-orchestrator/gate-engine.mjs +126 -38
- package/scripts/wave-orchestrator/install.mjs +46 -0
- package/scripts/wave-orchestrator/launcher-progress.mjs +91 -0
- package/scripts/wave-orchestrator/launcher-runtime.mjs +290 -75
- package/scripts/wave-orchestrator/launcher.mjs +201 -53
- package/scripts/wave-orchestrator/ledger.mjs +7 -2
- package/scripts/wave-orchestrator/planner.mjs +1 -0
- package/scripts/wave-orchestrator/projection-writer.mjs +36 -1
- package/scripts/wave-orchestrator/provider-runtime.mjs +104 -0
- package/scripts/wave-orchestrator/reducer-snapshot.mjs +6 -0
- package/scripts/wave-orchestrator/retry-control.mjs +3 -3
- package/scripts/wave-orchestrator/retry-engine.mjs +93 -6
- package/scripts/wave-orchestrator/role-helpers.mjs +30 -0
- package/scripts/wave-orchestrator/session-supervisor.mjs +94 -85
- package/scripts/wave-orchestrator/shared.mjs +1 -0
- package/scripts/wave-orchestrator/supervisor-cli.mjs +1306 -0
- package/scripts/wave-orchestrator/terminals.mjs +12 -32
- package/scripts/wave-orchestrator/tmux-adapter.mjs +300 -0
- package/scripts/wave-orchestrator/traces.mjs +25 -0
- package/scripts/wave-orchestrator/wave-control-client.mjs +14 -1
- package/scripts/wave-orchestrator/wave-files.mjs +38 -5
- package/scripts/wave.mjs +13 -0
|
@@ -74,6 +74,7 @@ import {
|
|
|
74
74
|
appendTerminalEntries,
|
|
75
75
|
createGlobalDashboardTerminalEntry,
|
|
76
76
|
createTemporaryTerminalEntries,
|
|
77
|
+
createWaveAgentSessionName,
|
|
77
78
|
killTmuxSessionIfExists,
|
|
78
79
|
normalizeTerminalSurface,
|
|
79
80
|
pruneOrphanLaneTemporaryTerminalEntries,
|
|
@@ -144,7 +145,7 @@ import {
|
|
|
144
145
|
summarizeResolvedSkills,
|
|
145
146
|
} from "./skills.mjs";
|
|
146
147
|
import {
|
|
147
|
-
|
|
148
|
+
applyLaunchResultToRun,
|
|
148
149
|
launchAgentSession as launchAgentSessionImpl,
|
|
149
150
|
refreshResolvedSkillsForRun,
|
|
150
151
|
waitForWaveCompletion as waitForWaveCompletionImpl,
|
|
@@ -200,7 +201,7 @@ import {
|
|
|
200
201
|
acquireLauncherLock,
|
|
201
202
|
releaseLauncherLock,
|
|
202
203
|
reconcileStaleLauncherArtifacts,
|
|
203
|
-
|
|
204
|
+
collectUnexpectedSessionWarnings,
|
|
204
205
|
launchAgentSession,
|
|
205
206
|
waitForWaveCompletion,
|
|
206
207
|
monitorWaveHumanFeedback,
|
|
@@ -208,10 +209,10 @@ import {
|
|
|
208
209
|
monitorResidentOrchestratorSession,
|
|
209
210
|
launchWaveDashboardSession,
|
|
210
211
|
cleanupLaneTmuxSessions,
|
|
212
|
+
cleanupLaunchedRun,
|
|
211
213
|
pruneDryRunExecutorPreviewDirs,
|
|
212
214
|
recordAttemptState,
|
|
213
215
|
recordWaveRunState,
|
|
214
|
-
runTmux,
|
|
215
216
|
syncLiveWaveSignals,
|
|
216
217
|
} from "./session-supervisor.mjs";
|
|
217
218
|
import { buildControlStatusPayload } from "./control-cli.mjs";
|
|
@@ -230,6 +231,10 @@ import {
|
|
|
230
231
|
formatReconcilePreservedWaveLine,
|
|
231
232
|
} from "./reconcile-format.mjs";
|
|
232
233
|
import { computeReducerSnapshot } from "./reducer-snapshot.mjs";
|
|
234
|
+
import {
|
|
235
|
+
launcherProgressPathForRun,
|
|
236
|
+
updateLauncherProgress,
|
|
237
|
+
} from "./launcher-progress.mjs";
|
|
233
238
|
|
|
234
239
|
function printUsage(lanePaths, terminalSurface) {
|
|
235
240
|
console.log(`Usage: pnpm exec wave launch [options]
|
|
@@ -255,7 +260,7 @@ Options:
|
|
|
255
260
|
--agent-launch-stagger-ms <n>
|
|
256
261
|
Delay between agent launches (default: ${DEFAULT_AGENT_LAUNCH_STAGGER_MS})
|
|
257
262
|
--executor <mode> Default agent executor mode: ${SUPPORTED_EXECUTOR_MODES.join(" | ")} (default: ${lanePaths.executors.default})
|
|
258
|
-
--codex-sandbox <mode> Codex sandbox mode: ${CODEX_SANDBOX_MODES.join(" | ")} (default:
|
|
263
|
+
--codex-sandbox <mode> Codex sandbox mode override: ${CODEX_SANDBOX_MODES.join(" | ")} (default: lane config)
|
|
259
264
|
--manifest-out <path> Write parsed wave manifest JSON (default: ${path.relative(REPO_ROOT, lanePaths.defaultManifestPath)})
|
|
260
265
|
--dry-run Parse waves and update manifest only
|
|
261
266
|
--terminal-surface <mode>
|
|
@@ -298,7 +303,7 @@ function parseArgs(argv) {
|
|
|
298
303
|
agentRateLimitMaxDelaySeconds: DEFAULT_AGENT_RATE_LIMIT_MAX_DELAY_SECONDS,
|
|
299
304
|
agentLaunchStaggerMs: DEFAULT_AGENT_LAUNCH_STAGGER_MS,
|
|
300
305
|
executorMode: lanePaths.executors.default,
|
|
301
|
-
codexSandboxMode:
|
|
306
|
+
codexSandboxMode: null,
|
|
302
307
|
manifestOut: lanePaths.defaultManifestPath,
|
|
303
308
|
dryRun: false,
|
|
304
309
|
terminalSurface: resolveDefaultTerminalSurface(
|
|
@@ -319,6 +324,7 @@ function parseArgs(argv) {
|
|
|
319
324
|
let manifestOutProvided = false;
|
|
320
325
|
let orchestratorBoardProvided = false;
|
|
321
326
|
let executorProvided = false;
|
|
327
|
+
let terminalSurfaceProvided = false;
|
|
322
328
|
|
|
323
329
|
for (let i = 0; i < argv.length; i += 1) {
|
|
324
330
|
const arg = argv[i];
|
|
@@ -332,6 +338,7 @@ function parseArgs(argv) {
|
|
|
332
338
|
options.dryRun = true;
|
|
333
339
|
} else if (arg === "--terminal-surface") {
|
|
334
340
|
options.terminalSurface = normalizeTerminalSurface(argv[++i], "--terminal-surface");
|
|
341
|
+
terminalSurfaceProvided = true;
|
|
335
342
|
} else if (arg === "--no-dashboard") {
|
|
336
343
|
options.dashboard = false;
|
|
337
344
|
} else if (arg === "--cleanup-sessions") {
|
|
@@ -360,9 +367,11 @@ function parseArgs(argv) {
|
|
|
360
367
|
project: options.project,
|
|
361
368
|
adhocRunId: options.adhocRunId,
|
|
362
369
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
370
|
+
if (!terminalSurfaceProvided) {
|
|
371
|
+
options.terminalSurface = resolveDefaultTerminalSurface(
|
|
372
|
+
readProjectProfile({ config, project: options.project }),
|
|
373
|
+
);
|
|
374
|
+
}
|
|
366
375
|
} else if (arg === "--lane") {
|
|
367
376
|
options.lane = String(argv[++i] || "").trim();
|
|
368
377
|
lanePaths = buildLanePaths(options.lane, {
|
|
@@ -654,7 +663,7 @@ function recoverableFailureReason(failure, summary = null) {
|
|
|
654
663
|
return statusCode;
|
|
655
664
|
}
|
|
656
665
|
const terminationReason = String(summary?.terminationReason || "").trim().toLowerCase();
|
|
657
|
-
if (["timeout", "max-turns"
|
|
666
|
+
if (["timeout", "max-turns"].includes(terminationReason)) {
|
|
658
667
|
return terminationReason;
|
|
659
668
|
}
|
|
660
669
|
const detailText = `${failure?.detail || ""} ${summary?.terminationHint || ""}`.toLowerCase();
|
|
@@ -747,6 +756,23 @@ export async function runLauncherCli(argv) {
|
|
|
747
756
|
return;
|
|
748
757
|
}
|
|
749
758
|
const { lanePaths, options } = parsed;
|
|
759
|
+
const supervisorRunId = String(process.env.WAVE_SUPERVISOR_RUN_ID || "").trim() || null;
|
|
760
|
+
const launcherProgressPath = launcherProgressPathForRun(lanePaths, supervisorRunId);
|
|
761
|
+
const writeLauncherRunProgress = (patch = {}) => {
|
|
762
|
+
if (!launcherProgressPath || !supervisorRunId) {
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
return updateLauncherProgress(
|
|
766
|
+
launcherProgressPath,
|
|
767
|
+
{
|
|
768
|
+
runId: supervisorRunId,
|
|
769
|
+
...patch,
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
runId: supervisorRunId,
|
|
773
|
+
},
|
|
774
|
+
);
|
|
775
|
+
};
|
|
750
776
|
if (!options.reconcileStatus) {
|
|
751
777
|
await maybeAnnouncePackageUpdate();
|
|
752
778
|
}
|
|
@@ -824,7 +850,7 @@ export async function runLauncherCli(argv) {
|
|
|
824
850
|
}
|
|
825
851
|
|
|
826
852
|
try {
|
|
827
|
-
const staleArtifactCleanup = reconcileStaleLauncherArtifacts(lanePaths, {
|
|
853
|
+
const staleArtifactCleanup = await reconcileStaleLauncherArtifacts(lanePaths, {
|
|
828
854
|
terminalSurface: options.terminalSurface,
|
|
829
855
|
});
|
|
830
856
|
const context7BundleIndex = loadContext7BundleIndex(lanePaths.context7BundleIndexPath);
|
|
@@ -1036,6 +1062,18 @@ export async function runLauncherCli(argv) {
|
|
|
1036
1062
|
feedbackRequestsDir: lanePaths.feedbackRequestsDir,
|
|
1037
1063
|
});
|
|
1038
1064
|
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
1065
|
+
writeLauncherRunProgress({
|
|
1066
|
+
phase: "starting",
|
|
1067
|
+
waveNumber: null,
|
|
1068
|
+
attemptNumber: null,
|
|
1069
|
+
selectedAgentIds: [],
|
|
1070
|
+
launchedAgentIds: [],
|
|
1071
|
+
completedAgentIds: [],
|
|
1072
|
+
resumeFromPhase: null,
|
|
1073
|
+
forwardedClosureGaps: [],
|
|
1074
|
+
finalized: false,
|
|
1075
|
+
finalDisposition: null,
|
|
1076
|
+
});
|
|
1039
1077
|
|
|
1040
1078
|
if (terminalRegistryEnabled && !options.keepTerminals) {
|
|
1041
1079
|
const removed = removeLaneTemporaryTerminalEntries(lanePaths.terminalsPath, lanePaths);
|
|
@@ -1047,7 +1085,7 @@ export async function runLauncherCli(argv) {
|
|
|
1047
1085
|
}
|
|
1048
1086
|
|
|
1049
1087
|
if (options.cleanupSessions) {
|
|
1050
|
-
const killed = cleanupLaneTmuxSessions(lanePaths);
|
|
1088
|
+
const killed = await cleanupLaneTmuxSessions(lanePaths);
|
|
1051
1089
|
if (killed.length > 0) {
|
|
1052
1090
|
recordGlobalDashboardEvent(globalDashboard, {
|
|
1053
1091
|
message: `Pre-run cleanup removed ${killed.length} stale tmux sessions for lane ${lanePaths.lane}.`,
|
|
@@ -1070,7 +1108,7 @@ export async function runLauncherCli(argv) {
|
|
|
1070
1108
|
globalDashboardTerminalAppended = true;
|
|
1071
1109
|
currentWaveDashboardTerminalAppended = true;
|
|
1072
1110
|
}
|
|
1073
|
-
launchWaveDashboardSession(lanePaths, {
|
|
1111
|
+
await launchWaveDashboardSession(lanePaths, {
|
|
1074
1112
|
sessionName: globalDashboardTerminalEntry.sessionName,
|
|
1075
1113
|
dashboardPath: lanePaths.globalDashboardPath,
|
|
1076
1114
|
});
|
|
@@ -1154,36 +1192,18 @@ export async function runLauncherCli(argv) {
|
|
|
1154
1192
|
};
|
|
1155
1193
|
|
|
1156
1194
|
try {
|
|
1157
|
-
terminalEntries = createTemporaryTerminalEntries(
|
|
1158
|
-
lanePaths,
|
|
1159
|
-
wave.wave,
|
|
1160
|
-
wave.agents,
|
|
1161
|
-
runTag,
|
|
1162
|
-
false,
|
|
1163
|
-
);
|
|
1164
|
-
if (terminalRegistryEnabled) {
|
|
1165
|
-
appendTerminalEntries(lanePaths.terminalsPath, terminalEntries);
|
|
1166
|
-
terminalsAppended = true;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
1195
|
const agentRuns = wave.agents.map((agent) => {
|
|
1170
1196
|
const safeName = `wave-${wave.wave}-${agent.slug}`;
|
|
1171
|
-
const terminalName = `${lanePaths.terminalNamePrefix}${wave.wave}-${agent.slug}`;
|
|
1172
|
-
const sessionName = terminalEntries.find(
|
|
1173
|
-
(entry) => entry.terminalName === terminalName,
|
|
1174
|
-
)?.sessionName;
|
|
1175
|
-
if (!sessionName) {
|
|
1176
|
-
throw new Error(`Failed to resolve session name for ${agent.agentId}`);
|
|
1177
|
-
}
|
|
1178
1197
|
return {
|
|
1179
1198
|
agent,
|
|
1180
1199
|
lane: lanePaths.lane,
|
|
1181
1200
|
wave: wave.wave,
|
|
1182
1201
|
resultsDir: lanePaths.resultsDir,
|
|
1183
|
-
sessionName,
|
|
1202
|
+
sessionName: createWaveAgentSessionName(lanePaths, wave.wave, agent.slug),
|
|
1184
1203
|
promptPath: path.join(lanePaths.promptsDir, `${safeName}.prompt.md`),
|
|
1185
1204
|
logPath: path.join(lanePaths.logsDir, `${safeName}.log`),
|
|
1186
1205
|
statusPath: path.join(lanePaths.statusDir, `${safeName}.status`),
|
|
1206
|
+
runtimePath: path.join(lanePaths.statusDir, `${safeName}.runtime.json`),
|
|
1187
1207
|
previewPath: path.join(
|
|
1188
1208
|
lanePaths.executorOverlaysDir,
|
|
1189
1209
|
`wave-${wave.wave}`,
|
|
@@ -1198,6 +1218,17 @@ export async function runLauncherCli(argv) {
|
|
|
1198
1218
|
inboxText: derivedState.inboxesByAgentId[agent.agentId]?.text || "",
|
|
1199
1219
|
};
|
|
1200
1220
|
});
|
|
1221
|
+
terminalEntries = createTemporaryTerminalEntries(
|
|
1222
|
+
lanePaths,
|
|
1223
|
+
wave.wave,
|
|
1224
|
+
agentRuns,
|
|
1225
|
+
runTag,
|
|
1226
|
+
false,
|
|
1227
|
+
);
|
|
1228
|
+
if (terminalRegistryEnabled) {
|
|
1229
|
+
appendTerminalEntries(lanePaths.terminalsPath, terminalEntries);
|
|
1230
|
+
terminalsAppended = true;
|
|
1231
|
+
}
|
|
1201
1232
|
const roleBindings = resolveWaveRoleBindings(wave, lanePaths, wave.agents);
|
|
1202
1233
|
|
|
1203
1234
|
const refreshDerivedState = (attemptNumber = 0) => {
|
|
@@ -1207,7 +1238,12 @@ export async function runLauncherCli(argv) {
|
|
|
1207
1238
|
}
|
|
1208
1239
|
const summariesByAgentId = Object.fromEntries(
|
|
1209
1240
|
agentRuns
|
|
1210
|
-
.map((run) => [
|
|
1241
|
+
.map((run) => [
|
|
1242
|
+
run.agent.agentId,
|
|
1243
|
+
readRunExecutionSummary(run, wave, {
|
|
1244
|
+
securityRolePromptPath: lanePaths.securityRolePromptPath,
|
|
1245
|
+
}),
|
|
1246
|
+
])
|
|
1211
1247
|
.filter(([, summary]) => summary),
|
|
1212
1248
|
);
|
|
1213
1249
|
const feedbackRequests = readWaveHumanFeedbackRequests({
|
|
@@ -1396,7 +1432,7 @@ export async function runLauncherCli(argv) {
|
|
|
1396
1432
|
syncWaveSignals();
|
|
1397
1433
|
|
|
1398
1434
|
if (options.dashboard && currentWaveDashboardTerminalEntry) {
|
|
1399
|
-
launchWaveDashboardSession(lanePaths, {
|
|
1435
|
+
await launchWaveDashboardSession(lanePaths, {
|
|
1400
1436
|
sessionName: currentWaveDashboardTerminalEntry.sessionName,
|
|
1401
1437
|
dashboardPath,
|
|
1402
1438
|
messageBoardPath,
|
|
@@ -1431,6 +1467,7 @@ export async function runLauncherCli(argv) {
|
|
|
1431
1467
|
promptPath: residentOrchestratorRun.promptPath,
|
|
1432
1468
|
logPath: residentOrchestratorRun.logPath,
|
|
1433
1469
|
statusPath: residentOrchestratorRun.statusPath,
|
|
1470
|
+
runtimePath: residentOrchestratorRun.runtimePath,
|
|
1434
1471
|
messageBoardPath: derivedState.messageBoardPath,
|
|
1435
1472
|
messageBoardSnapshot: derivedState.messageBoardText,
|
|
1436
1473
|
sharedSummaryPath: derivedState.sharedSummaryPath,
|
|
@@ -1444,18 +1481,19 @@ export async function runLauncherCli(argv) {
|
|
|
1444
1481
|
agentRateLimitMaxDelaySeconds: options.agentRateLimitMaxDelaySeconds,
|
|
1445
1482
|
context7Enabled: options.context7Enabled,
|
|
1446
1483
|
});
|
|
1447
|
-
residentOrchestratorRun
|
|
1448
|
-
|
|
1449
|
-
|
|
1484
|
+
applyLaunchResultToRun(residentOrchestratorRun, launchResult, {
|
|
1485
|
+
fallbackExecutorId: residentOrchestratorRun.agent.executorResolved?.id || null,
|
|
1486
|
+
fallbackSkills: summarizeResolvedSkills(residentOrchestratorRun.agent.skillsResolved),
|
|
1487
|
+
});
|
|
1450
1488
|
recordCombinedEvent({
|
|
1451
1489
|
agentId: residentOrchestratorRun.agent.agentId,
|
|
1452
|
-
message: `Resident orchestrator launched
|
|
1490
|
+
message: `Resident orchestrator launched via ${launchResult?.sessionBackend || "process"} backend`,
|
|
1453
1491
|
});
|
|
1454
1492
|
appendCoordination({
|
|
1455
1493
|
event: "resident_orchestrator_start",
|
|
1456
1494
|
waves: [wave.wave],
|
|
1457
1495
|
status: "running",
|
|
1458
|
-
details: `session=${residentOrchestratorRun.sessionName}; executor=${residentOrchestratorRun.lastExecutorId || "unknown"}`,
|
|
1496
|
+
details: `backend=${launchResult?.sessionBackend || "process"}; session=${residentOrchestratorRun.sessionName}; executor=${residentOrchestratorRun.lastExecutorId || "unknown"}`,
|
|
1459
1497
|
actionRequested: "None",
|
|
1460
1498
|
});
|
|
1461
1499
|
syncWaveSignals();
|
|
@@ -1497,12 +1535,36 @@ export async function runLauncherCli(argv) {
|
|
|
1497
1535
|
let traceAttempt = 1;
|
|
1498
1536
|
let completionGateSnapshot = null;
|
|
1499
1537
|
let completionTraceDir = null;
|
|
1538
|
+
const terminalAgentIdsForWave = () =>
|
|
1539
|
+
agentRuns
|
|
1540
|
+
.filter((run) => readStatusRecordIfPresent(run.statusPath))
|
|
1541
|
+
.map((run) => run.agent.agentId);
|
|
1500
1542
|
recordWaveRunState(lanePaths, wave.wave, "started", {
|
|
1501
1543
|
agentIds: wave.agents.map((agent) => agent.agentId),
|
|
1502
1544
|
runVariant: lanePaths.runVariant || "live",
|
|
1503
1545
|
});
|
|
1546
|
+
writeLauncherRunProgress({
|
|
1547
|
+
waveNumber: wave.wave,
|
|
1548
|
+
attemptNumber: 0,
|
|
1549
|
+
phase: "wave-started",
|
|
1550
|
+
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
1551
|
+
launchedAgentIds: [],
|
|
1552
|
+
completedAgentIds: terminalAgentIdsForWave(),
|
|
1553
|
+
finalized: false,
|
|
1554
|
+
finalDisposition: null,
|
|
1555
|
+
});
|
|
1504
1556
|
|
|
1505
1557
|
while (attempt <= options.maxRetriesPerWave + 1) {
|
|
1558
|
+
writeLauncherRunProgress({
|
|
1559
|
+
waveNumber: wave.wave,
|
|
1560
|
+
attemptNumber: attempt,
|
|
1561
|
+
phase: "attempt-starting",
|
|
1562
|
+
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
1563
|
+
launchedAgentIds: [],
|
|
1564
|
+
completedAgentIds: [],
|
|
1565
|
+
finalized: false,
|
|
1566
|
+
finalDisposition: null,
|
|
1567
|
+
});
|
|
1506
1568
|
refreshDerivedState(attempt - 1);
|
|
1507
1569
|
lastLiveCoordinationRefreshAt = Date.now();
|
|
1508
1570
|
dashboardState.attempt = attempt;
|
|
@@ -1569,6 +1631,7 @@ export async function runLauncherCli(argv) {
|
|
|
1569
1631
|
promptPath: runInfo.promptPath,
|
|
1570
1632
|
logPath: runInfo.logPath,
|
|
1571
1633
|
statusPath: runInfo.statusPath,
|
|
1634
|
+
runtimePath: runInfo.runtimePath,
|
|
1572
1635
|
messageBoardPath: runInfo.messageBoardPath,
|
|
1573
1636
|
messageBoardSnapshot: runInfo.messageBoardSnapshot || "",
|
|
1574
1637
|
sharedSummaryPath: runInfo.sharedSummaryPath,
|
|
@@ -1596,19 +1659,27 @@ export async function runLauncherCli(argv) {
|
|
|
1596
1659
|
attempt,
|
|
1597
1660
|
},
|
|
1598
1661
|
});
|
|
1599
|
-
runInfo
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1662
|
+
applyLaunchResultToRun(runInfo, launchResult, {
|
|
1663
|
+
attempt,
|
|
1664
|
+
fallbackExecutorId: runInfo.agent.executorResolved?.id || null,
|
|
1665
|
+
fallbackSkills: summarizeResolvedSkills(runInfo.agent.skillsResolved),
|
|
1666
|
+
});
|
|
1667
|
+
writeLauncherRunProgress({
|
|
1668
|
+
waveNumber: wave.wave,
|
|
1669
|
+
attemptNumber: attempt,
|
|
1670
|
+
phase: "attempt-running",
|
|
1671
|
+
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
1672
|
+
launchedAgentIds: runsToLaunch
|
|
1673
|
+
.filter((run) => run.lastLaunchAttempt === attempt)
|
|
1674
|
+
.map((run) => run.agent.agentId),
|
|
1675
|
+
});
|
|
1605
1676
|
setWaveDashboardAgent(dashboardState, runInfo.agent.agentId, {
|
|
1606
1677
|
state: "running",
|
|
1607
1678
|
detail: "Session launched",
|
|
1608
1679
|
});
|
|
1609
1680
|
recordCombinedEvent({
|
|
1610
1681
|
agentId: runInfo.agent.agentId,
|
|
1611
|
-
message: `Launched
|
|
1682
|
+
message: `Launched via ${launchResult?.sessionBackend || "process"} backend`,
|
|
1612
1683
|
});
|
|
1613
1684
|
const context7Mode = launchResult?.context7?.mode || "none";
|
|
1614
1685
|
if (runInfo.agent.context7Resolved?.bundleId !== "none") {
|
|
@@ -1678,9 +1749,23 @@ export async function runLauncherCli(argv) {
|
|
|
1678
1749
|
timedOut = waitResult.timedOut;
|
|
1679
1750
|
}
|
|
1680
1751
|
|
|
1681
|
-
materializeAgentExecutionSummaries(wave, agentRuns
|
|
1752
|
+
materializeAgentExecutionSummaries(wave, agentRuns, {
|
|
1753
|
+
securityRolePromptPath: lanePaths.securityRolePromptPath,
|
|
1754
|
+
});
|
|
1682
1755
|
failures = annotateFailuresWithRecoveryHints(failures, agentRuns);
|
|
1683
1756
|
refreshDerivedState(attempt);
|
|
1757
|
+
const reducerDecisionForProgress = latestReducerSnapshot || refreshReducerSnapshot(attempt);
|
|
1758
|
+
writeLauncherRunProgress({
|
|
1759
|
+
waveNumber: wave.wave,
|
|
1760
|
+
attemptNumber: attempt,
|
|
1761
|
+
phase: failures.length === 0 ? "attempt-succeeded" : "attempt-failed",
|
|
1762
|
+
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
1763
|
+
launchedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
1764
|
+
completedAgentIds: terminalAgentIdsForWave(),
|
|
1765
|
+
resumeFromPhase: reducerDecisionForProgress?.resumePlan?.resumeFromPhase || null,
|
|
1766
|
+
forwardedClosureGaps: reducerDecisionForProgress?.resumePlan?.forwardedClosureGaps || [],
|
|
1767
|
+
gateSnapshotSummary: reducerDecisionForProgress?.reducerState?.gateSnapshot?.overall || null,
|
|
1768
|
+
});
|
|
1684
1769
|
syncWaveSignals();
|
|
1685
1770
|
lastLiveCoordinationRefreshAt = Date.now();
|
|
1686
1771
|
emitCoordinationAlertEvents(derivedState);
|
|
@@ -1765,7 +1850,9 @@ export async function runLauncherCli(argv) {
|
|
|
1765
1850
|
}
|
|
1766
1851
|
}
|
|
1767
1852
|
if (failures.length === 0) {
|
|
1768
|
-
const implementationGate = readWaveImplementationGate(wave, agentRuns
|
|
1853
|
+
const implementationGate = readWaveImplementationGate(wave, agentRuns, {
|
|
1854
|
+
securityRolePromptPath: lanePaths.securityRolePromptPath,
|
|
1855
|
+
});
|
|
1769
1856
|
if (!implementationGate.ok) {
|
|
1770
1857
|
failures = [
|
|
1771
1858
|
{
|
|
@@ -1889,7 +1976,9 @@ export async function runLauncherCli(argv) {
|
|
|
1889
1976
|
});
|
|
1890
1977
|
failures = closureResult.failures;
|
|
1891
1978
|
timedOut = timedOut || closureResult.timedOut;
|
|
1892
|
-
materializeAgentExecutionSummaries(wave, agentRuns
|
|
1979
|
+
materializeAgentExecutionSummaries(wave, agentRuns, {
|
|
1980
|
+
securityRolePromptPath: lanePaths.securityRolePromptPath,
|
|
1981
|
+
});
|
|
1893
1982
|
failures = annotateFailuresWithRecoveryHints(failures, agentRuns);
|
|
1894
1983
|
refreshDerivedState(attempt);
|
|
1895
1984
|
}
|
|
@@ -2097,6 +2186,19 @@ export async function runLauncherCli(argv) {
|
|
|
2097
2186
|
runs: runsToLaunch,
|
|
2098
2187
|
failures,
|
|
2099
2188
|
derivedState,
|
|
2189
|
+
resumePlan: (latestReducerSnapshot || refreshReducerSnapshot(attempt))?.resumePlan || null,
|
|
2190
|
+
});
|
|
2191
|
+
writeLauncherRunProgress({
|
|
2192
|
+
waveNumber: wave.wave,
|
|
2193
|
+
attemptNumber: attempt,
|
|
2194
|
+
phase: "waiting-shared-component",
|
|
2195
|
+
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2196
|
+
launchedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2197
|
+
completedAgentIds: terminalAgentIdsForWave(),
|
|
2198
|
+
resumeFromPhase:
|
|
2199
|
+
(latestReducerSnapshot || refreshReducerSnapshot(attempt))?.resumePlan?.resumeFromPhase || null,
|
|
2200
|
+
forwardedClosureGaps:
|
|
2201
|
+
(latestReducerSnapshot || refreshReducerSnapshot(attempt))?.resumePlan?.forwardedClosureGaps || [],
|
|
2100
2202
|
});
|
|
2101
2203
|
flushDashboards();
|
|
2102
2204
|
traceAttempt += 1;
|
|
@@ -2121,6 +2223,16 @@ export async function runLauncherCli(argv) {
|
|
|
2121
2223
|
updateWaveDashboardMessageBoard(dashboardState, messageBoardPath);
|
|
2122
2224
|
flushDashboards();
|
|
2123
2225
|
await flushWaveControlTelemetry();
|
|
2226
|
+
writeLauncherRunProgress({
|
|
2227
|
+
waveNumber: wave.wave,
|
|
2228
|
+
attemptNumber: attempt,
|
|
2229
|
+
phase: "wave-completed",
|
|
2230
|
+
selectedAgentIds: [],
|
|
2231
|
+
launchedAgentIds: [],
|
|
2232
|
+
completedAgentIds: terminalAgentIdsForWave(),
|
|
2233
|
+
resumeFromPhase: "completed",
|
|
2234
|
+
forwardedClosureGaps: [],
|
|
2235
|
+
});
|
|
2124
2236
|
break;
|
|
2125
2237
|
}
|
|
2126
2238
|
|
|
@@ -2179,6 +2291,7 @@ export async function runLauncherCli(argv) {
|
|
|
2179
2291
|
runs: recoveryPlan.selectedRuns,
|
|
2180
2292
|
failures,
|
|
2181
2293
|
derivedState,
|
|
2294
|
+
resumePlan: reducerDecision?.resumePlan || null,
|
|
2182
2295
|
});
|
|
2183
2296
|
}
|
|
2184
2297
|
recordAttemptState(lanePaths, wave.wave, attempt, "failed", {
|
|
@@ -2218,6 +2331,16 @@ export async function runLauncherCli(argv) {
|
|
|
2218
2331
|
actionRequested:
|
|
2219
2332
|
`Lane ${lanePaths.lane} owners should resume the queued targeted recovery or let autonomous relaunch the selected agents.`,
|
|
2220
2333
|
});
|
|
2334
|
+
writeLauncherRunProgress({
|
|
2335
|
+
waveNumber: wave.wave,
|
|
2336
|
+
attemptNumber: attempt,
|
|
2337
|
+
phase: "recovery-queued",
|
|
2338
|
+
selectedAgentIds: recoverySelectedAgentIds,
|
|
2339
|
+
launchedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2340
|
+
completedAgentIds: terminalAgentIdsForWave(),
|
|
2341
|
+
resumeFromPhase: reducerDecision?.resumePlan?.resumeFromPhase || null,
|
|
2342
|
+
forwardedClosureGaps: reducerDecision?.resumePlan?.forwardedClosureGaps || [],
|
|
2343
|
+
});
|
|
2221
2344
|
await flushWaveControlTelemetry();
|
|
2222
2345
|
const error = new Error(
|
|
2223
2346
|
`Wave ${wave.wave} queued targeted recovery request ${queuedRecovery.requestId} after recoverable execution failures.`,
|
|
@@ -2386,6 +2509,19 @@ export async function runLauncherCli(argv) {
|
|
|
2386
2509
|
runs: runsToLaunch,
|
|
2387
2510
|
failures,
|
|
2388
2511
|
derivedState,
|
|
2512
|
+
resumePlan: (latestReducerSnapshot || refreshReducerSnapshot(attempt))?.resumePlan || null,
|
|
2513
|
+
});
|
|
2514
|
+
writeLauncherRunProgress({
|
|
2515
|
+
waveNumber: wave.wave,
|
|
2516
|
+
attemptNumber: attempt + 1,
|
|
2517
|
+
phase: "retry-queued",
|
|
2518
|
+
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2519
|
+
launchedAgentIds: [],
|
|
2520
|
+
completedAgentIds: terminalAgentIdsForWave(),
|
|
2521
|
+
resumeFromPhase:
|
|
2522
|
+
(latestReducerSnapshot || refreshReducerSnapshot(attempt))?.resumePlan?.resumeFromPhase || null,
|
|
2523
|
+
forwardedClosureGaps:
|
|
2524
|
+
(latestReducerSnapshot || refreshReducerSnapshot(attempt))?.resumePlan?.forwardedClosureGaps || [],
|
|
2389
2525
|
});
|
|
2390
2526
|
flushDashboards();
|
|
2391
2527
|
attempt += 1;
|
|
@@ -2418,7 +2554,7 @@ export async function runLauncherCli(argv) {
|
|
|
2418
2554
|
});
|
|
2419
2555
|
} finally {
|
|
2420
2556
|
if (residentOrchestratorRun) {
|
|
2421
|
-
|
|
2557
|
+
await cleanupLaunchedRun(lanePaths, residentOrchestratorRun);
|
|
2422
2558
|
}
|
|
2423
2559
|
if (terminalsAppended && !options.keepTerminals) {
|
|
2424
2560
|
removeTerminalEntries(lanePaths.terminalsPath, terminalEntries);
|
|
@@ -2431,7 +2567,7 @@ export async function runLauncherCli(argv) {
|
|
|
2431
2567
|
if (currentWaveDashboardTerminalEntry) {
|
|
2432
2568
|
excludeSessionNames.add(currentWaveDashboardTerminalEntry.sessionName);
|
|
2433
2569
|
}
|
|
2434
|
-
cleanupLaneTmuxSessions(lanePaths, { excludeSessionNames });
|
|
2570
|
+
await cleanupLaneTmuxSessions(lanePaths, { excludeSessionNames });
|
|
2435
2571
|
}
|
|
2436
2572
|
if (globalWave && globalWave.status === "running") {
|
|
2437
2573
|
globalWave.status = dashboardState?.status || "failed";
|
|
@@ -2446,6 +2582,12 @@ export async function runLauncherCli(argv) {
|
|
|
2446
2582
|
globalDashboard.status = "completed";
|
|
2447
2583
|
recordGlobalDashboardEvent(globalDashboard, { message: "All selected waves completed." });
|
|
2448
2584
|
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
2585
|
+
writeLauncherRunProgress({
|
|
2586
|
+
phase: "completed",
|
|
2587
|
+
finalized: true,
|
|
2588
|
+
finalDisposition: "completed",
|
|
2589
|
+
exitCode: 0,
|
|
2590
|
+
});
|
|
2449
2591
|
appendCoordination({
|
|
2450
2592
|
event: "launcher_finish",
|
|
2451
2593
|
waves: selectedWavesForCoordination,
|
|
@@ -2460,6 +2602,12 @@ export async function runLauncherCli(argv) {
|
|
|
2460
2602
|
appendCoordination,
|
|
2461
2603
|
error,
|
|
2462
2604
|
);
|
|
2605
|
+
writeLauncherRunProgress({
|
|
2606
|
+
phase: "failed",
|
|
2607
|
+
finalized: true,
|
|
2608
|
+
finalDisposition: "failed",
|
|
2609
|
+
exitCode: Number.isInteger(error?.exitCode) ? error.exitCode : 1,
|
|
2610
|
+
});
|
|
2463
2611
|
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
2464
2612
|
throw error;
|
|
2465
2613
|
} finally {
|
|
@@ -2475,14 +2623,14 @@ export async function runLauncherCli(argv) {
|
|
|
2475
2623
|
}
|
|
2476
2624
|
if (options.cleanupSessions && globalDashboardTerminalEntry) {
|
|
2477
2625
|
try {
|
|
2478
|
-
killTmuxSessionIfExists(lanePaths.tmuxSocketName, globalDashboardTerminalEntry.sessionName);
|
|
2626
|
+
await killTmuxSessionIfExists(lanePaths.tmuxSocketName, globalDashboardTerminalEntry.sessionName);
|
|
2479
2627
|
} catch {
|
|
2480
2628
|
// no-op
|
|
2481
2629
|
}
|
|
2482
2630
|
}
|
|
2483
2631
|
if (options.cleanupSessions && currentWaveDashboardTerminalEntry) {
|
|
2484
2632
|
try {
|
|
2485
|
-
killTmuxSessionIfExists(
|
|
2633
|
+
await killTmuxSessionIfExists(
|
|
2486
2634
|
lanePaths.tmuxSocketName,
|
|
2487
2635
|
currentWaveDashboardTerminalEntry.sessionName,
|
|
2488
2636
|
);
|
|
@@ -54,6 +54,7 @@ export function buildSeedWaveLedger({
|
|
|
54
54
|
contEvalAgentId = DEFAULT_CONT_EVAL_AGENT_ID,
|
|
55
55
|
integrationAgentId = DEFAULT_INTEGRATION_AGENT_ID,
|
|
56
56
|
documentationAgentId = DEFAULT_DOCUMENTATION_AGENT_ID,
|
|
57
|
+
securityRolePromptPath = null,
|
|
57
58
|
}) {
|
|
58
59
|
const tasks = [];
|
|
59
60
|
for (const agent of wave.agents) {
|
|
@@ -69,7 +70,7 @@ export function buildSeedWaveLedger({
|
|
|
69
70
|
? "documentation"
|
|
70
71
|
: isDesignAgent(agent)
|
|
71
72
|
? "design"
|
|
72
|
-
: isSecurityReviewAgent(agent)
|
|
73
|
+
: isSecurityReviewAgent(agent, { securityRolePromptPath })
|
|
73
74
|
? "security"
|
|
74
75
|
: "implementation";
|
|
75
76
|
const runtime = agent.executorResolved
|
|
@@ -220,6 +221,7 @@ export function deriveWaveLedger({
|
|
|
220
221
|
benchmarkCatalogPath = null,
|
|
221
222
|
capabilityAssignments = [],
|
|
222
223
|
dependencySnapshot = null,
|
|
224
|
+
securityRolePromptPath = null,
|
|
223
225
|
}) {
|
|
224
226
|
const seed = buildSeedWaveLedger({
|
|
225
227
|
lane,
|
|
@@ -228,6 +230,7 @@ export function deriveWaveLedger({
|
|
|
228
230
|
contEvalAgentId,
|
|
229
231
|
integrationAgentId,
|
|
230
232
|
documentationAgentId,
|
|
233
|
+
securityRolePromptPath,
|
|
231
234
|
});
|
|
232
235
|
const primaryTasks = seed.tasks.map((task) => {
|
|
233
236
|
const agent = wave.agents.find((item) => item.agentId === task.owner);
|
|
@@ -343,7 +346,9 @@ export function deriveWaveLedger({
|
|
|
343
346
|
const docAgent = wave.agents.find((agent) => agent.agentId === documentationAgentId);
|
|
344
347
|
const contEvalAgent = wave.agents.find((agent) => agent.agentId === contEvalAgentId);
|
|
345
348
|
const contQaAgent = wave.agents.find((agent) => agent.agentId === contQaAgentId);
|
|
346
|
-
const securityAgents = (wave.agents || []).filter((agent) =>
|
|
349
|
+
const securityAgents = (wave.agents || []).filter((agent) =>
|
|
350
|
+
isSecurityReviewAgent(agent, { securityRolePromptPath }),
|
|
351
|
+
);
|
|
347
352
|
const contEvalValidation = (() => {
|
|
348
353
|
if (!contEvalAgent) {
|
|
349
354
|
return { ok: true };
|
|
@@ -2625,6 +2625,7 @@ async function runAgenticDraftFlow(options = {}) {
|
|
|
2625
2625
|
request,
|
|
2626
2626
|
});
|
|
2627
2627
|
const plannerContext7Prefetch = await prefetchContext7ForSelection(plannerContext7Selection, {
|
|
2628
|
+
lanePaths,
|
|
2628
2629
|
cacheDir: lanePaths.context7CacheDir,
|
|
2629
2630
|
});
|
|
2630
2631
|
const promptText = buildPlannerPromptText({
|