@chllming/wave-orchestration 0.8.3 → 0.8.5
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 +36 -1
- package/README.md +60 -11
- package/docs/README.md +8 -2
- package/docs/agents/wave-design-role.md +47 -0
- package/docs/concepts/what-is-a-wave.md +11 -7
- package/docs/guides/author-and-run-waves.md +24 -0
- package/docs/guides/planner.md +44 -0
- package/docs/plans/architecture-hardening-migration.md +8 -1
- package/docs/plans/current-state.md +19 -7
- package/docs/plans/end-state-architecture.md +88 -70
- package/docs/plans/examples/wave-example-design-handoff.md +262 -0
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +370 -64
- package/docs/plans/wave-orchestrator.md +49 -13
- package/docs/reference/cli-reference.md +46 -14
- package/docs/reference/coordination-and-closure.md +19 -6
- package/docs/reference/npmjs-trusted-publishing.md +5 -4
- package/docs/reference/sample-waves.md +14 -7
- package/docs/reference/skills.md +10 -0
- package/package.json +1 -1
- package/releases/manifest.json +39 -0
- package/scripts/wave-orchestrator/agent-state.mjs +64 -491
- package/scripts/wave-orchestrator/autonomous.mjs +10 -6
- package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
- package/scripts/wave-orchestrator/config.mjs +5 -0
- package/scripts/wave-orchestrator/coordination.mjs +42 -1
- package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
- package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +501 -141
- package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
- package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
- package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
- package/scripts/wave-orchestrator/install.mjs +3 -0
- package/scripts/wave-orchestrator/launcher-runtime.mjs +11 -6
- package/scripts/wave-orchestrator/launcher.mjs +324 -723
- package/scripts/wave-orchestrator/ledger.mjs +56 -27
- package/scripts/wave-orchestrator/local-executor.mjs +37 -0
- package/scripts/wave-orchestrator/planner.mjs +24 -4
- package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
- package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
- package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
- package/scripts/wave-orchestrator/replay.mjs +3 -1
- package/scripts/wave-orchestrator/result-envelope.mjs +620 -0
- package/scripts/wave-orchestrator/retry-control.mjs +22 -2
- package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +352 -18
- package/scripts/wave-orchestrator/role-helpers.mjs +124 -1
- package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
- package/scripts/wave-orchestrator/shared.mjs +2 -0
- package/scripts/wave-orchestrator/skills.mjs +1 -0
- package/scripts/wave-orchestrator/task-entity.mjs +65 -45
- package/scripts/wave-orchestrator/traces.mjs +10 -1
- package/scripts/wave-orchestrator/wave-files.mjs +96 -10
- package/scripts/wave-orchestrator/wave-state-reducer.mjs +76 -12
- package/skills/README.md +7 -0
- package/skills/role-design/SKILL.md +50 -0
- package/skills/role-design/skill.json +36 -0
- package/skills/tui-design/SKILL.md +77 -0
- package/skills/tui-design/references/tui-design.md +259 -0
- package/skills/tui-design/skill.json +36 -0
- package/wave.config.json +15 -1
|
@@ -47,6 +47,8 @@ const WAVE_EVAL_REGEX =
|
|
|
47
47
|
/^\[wave-eval\]\s*state=(satisfied|needs-more-work|blocked)\s+targets=(\d+)\s+benchmarks=(\d+)\s+regressions=(\d+)(?:\s+target_ids=([^\s]+))?(?:\s+benchmark_ids=([^\s]+))?\s*(?:detail=(.*))?$/gim;
|
|
48
48
|
const WAVE_SECURITY_REGEX =
|
|
49
49
|
/^\[wave-security\]\s*state=(clear|concerns|blocked)\s+findings=(\d+)\s+approvals=(\d+)\s*(?:detail=(.*))?$/gim;
|
|
50
|
+
const WAVE_DESIGN_REGEX =
|
|
51
|
+
/^\[wave-design\]\s*state=(ready-for-implementation|needs-clarification|blocked)\s+decisions=(\d+)\s+assumptions=(\d+)\s+open_questions=(\d+)\s*(?:detail=(.*))?$/gim;
|
|
50
52
|
const WAVE_GATE_REGEX =
|
|
51
53
|
/^\[wave-gate\]\s*architecture=(pass|concerns|blocked)\s+integration=(pass|concerns|blocked)\s+durability=(pass|concerns|blocked)\s+live=(pass|concerns|blocked)\s+docs=(pass|concerns|blocked)\s*(?:detail=(.*))?$/gim;
|
|
52
54
|
const WAVE_GAP_REGEX =
|
|
@@ -64,6 +66,7 @@ const STRUCTURED_SIGNAL_KIND_BY_TAG = {
|
|
|
64
66
|
integration: "integration",
|
|
65
67
|
eval: "eval",
|
|
66
68
|
security: "security",
|
|
69
|
+
design: "design",
|
|
67
70
|
gate: "gate",
|
|
68
71
|
gap: "gap",
|
|
69
72
|
component: "component",
|
|
@@ -76,6 +79,7 @@ const STRUCTURED_SIGNAL_LINE_REGEX_BY_KIND = {
|
|
|
76
79
|
integration: new RegExp(WAVE_INTEGRATION_REGEX.source, "i"),
|
|
77
80
|
eval: new RegExp(WAVE_EVAL_REGEX.source, "i"),
|
|
78
81
|
security: new RegExp(WAVE_SECURITY_REGEX.source, "i"),
|
|
82
|
+
design: new RegExp(WAVE_DESIGN_REGEX.source, "i"),
|
|
79
83
|
gate: new RegExp(WAVE_GATE_REGEX.source, "i"),
|
|
80
84
|
gap: new RegExp(WAVE_GAP_REGEX.source, "i"),
|
|
81
85
|
component: new RegExp(WAVE_COMPONENT_REGEX.source, "i"),
|
|
@@ -89,6 +93,7 @@ function buildEmptyStructuredSignalDiagnostics() {
|
|
|
89
93
|
integration: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
|
|
90
94
|
eval: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
|
|
91
95
|
security: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
|
|
96
|
+
design: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
|
|
92
97
|
gate: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
|
|
93
98
|
gap: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
|
|
94
99
|
component: { rawCount: 0, acceptedCount: 0, rejectedSamples: [], seenComponentIds: [] },
|
|
@@ -509,6 +514,13 @@ export function buildAgentExecutionSummary({ agent, statusRecord, logPath, repor
|
|
|
509
514
|
approvals: Number.parseInt(String(match[3] || "0"), 10) || 0,
|
|
510
515
|
detail: cleanText(match[4]),
|
|
511
516
|
})),
|
|
517
|
+
design: findLastMatch(signalText, WAVE_DESIGN_REGEX, (match) => ({
|
|
518
|
+
state: match[1],
|
|
519
|
+
decisions: Number.parseInt(String(match[2] || "0"), 10) || 0,
|
|
520
|
+
assumptions: Number.parseInt(String(match[3] || "0"), 10) || 0,
|
|
521
|
+
openQuestions: Number.parseInt(String(match[4] || "0"), 10) || 0,
|
|
522
|
+
detail: cleanText(match[5]),
|
|
523
|
+
})),
|
|
512
524
|
gate: findLastMatch(signalText, WAVE_GATE_REGEX, (match) => ({
|
|
513
525
|
architecture: match[1],
|
|
514
526
|
integration: match[2],
|
|
@@ -951,6 +963,58 @@ export function validateSecuritySummary(agent, summary) {
|
|
|
951
963
|
};
|
|
952
964
|
}
|
|
953
965
|
|
|
966
|
+
export function validateDesignSummary(agent, summary) {
|
|
967
|
+
if (!summary?.design) {
|
|
968
|
+
return {
|
|
969
|
+
ok: false,
|
|
970
|
+
statusCode: "missing-wave-design",
|
|
971
|
+
detail: appendTerminationHint(
|
|
972
|
+
`Missing [wave-design] marker for ${agent?.agentId || "D1"}.`,
|
|
973
|
+
summary,
|
|
974
|
+
),
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if (!summary.reportPath) {
|
|
978
|
+
return {
|
|
979
|
+
ok: false,
|
|
980
|
+
statusCode: "missing-design-packet",
|
|
981
|
+
detail: `Missing design packet path for ${agent?.agentId || "D1"}.`,
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
if (!fs.existsSync(path.resolve(REPO_ROOT, summary.reportPath))) {
|
|
985
|
+
return {
|
|
986
|
+
ok: false,
|
|
987
|
+
statusCode: "missing-design-packet",
|
|
988
|
+
detail: `Missing design packet at ${summary.reportPath}.`,
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
if (summary.design.state === "blocked") {
|
|
992
|
+
return {
|
|
993
|
+
ok: false,
|
|
994
|
+
statusCode: "design-blocked",
|
|
995
|
+
detail:
|
|
996
|
+
summary.design.detail ||
|
|
997
|
+
`Design packet reported blocked for ${agent?.agentId || "D1"}.`,
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
if (summary.design.state === "needs-clarification") {
|
|
1001
|
+
return {
|
|
1002
|
+
ok: false,
|
|
1003
|
+
statusCode: "design-needs-clarification",
|
|
1004
|
+
detail:
|
|
1005
|
+
summary.design.detail ||
|
|
1006
|
+
`Design packet requested clarification for ${agent?.agentId || "D1"}.`,
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
ok: true,
|
|
1011
|
+
statusCode: "pass",
|
|
1012
|
+
detail:
|
|
1013
|
+
summary.design.detail ||
|
|
1014
|
+
"Design packet is ready for implementation.",
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
|
|
954
1018
|
export function validateIntegrationSummary(agent, summary) {
|
|
955
1019
|
if (!summary?.integration) {
|
|
956
1020
|
return {
|
|
@@ -1180,494 +1244,3 @@ export function validateContQaSummary(agent, summary, options = {}) {
|
|
|
1180
1244
|
detail: summary.verdict.detail || summary.gate.detail || "cont-QA gate passed.",
|
|
1181
1245
|
};
|
|
1182
1246
|
}
|
|
1183
|
-
|
|
1184
|
-
// ---------------------------------------------------------------------------
|
|
1185
|
-
// Agent Result Envelope — P1-6 End-State (schemaVersion 2)
|
|
1186
|
-
// ---------------------------------------------------------------------------
|
|
1187
|
-
|
|
1188
|
-
import { toIsoTimestamp } from "./shared.mjs";
|
|
1189
|
-
|
|
1190
|
-
/**
|
|
1191
|
-
* Valid roles for the agent result envelope.
|
|
1192
|
-
*/
|
|
1193
|
-
export const ENVELOPE_VALID_ROLES = [
|
|
1194
|
-
"implementation",
|
|
1195
|
-
"integration",
|
|
1196
|
-
"documentation",
|
|
1197
|
-
"cont-qa",
|
|
1198
|
-
"cont-eval",
|
|
1199
|
-
"security",
|
|
1200
|
-
"deploy",
|
|
1201
|
-
];
|
|
1202
|
-
|
|
1203
|
-
function inferEnvelopeRole(agent, summary) {
|
|
1204
|
-
const candidate = String(agent?.role || summary?.role || "").trim().toLowerCase();
|
|
1205
|
-
if (candidate && ENVELOPE_VALID_ROLES.includes(candidate)) {
|
|
1206
|
-
return candidate;
|
|
1207
|
-
}
|
|
1208
|
-
if (summary?.integration) {
|
|
1209
|
-
return "integration";
|
|
1210
|
-
}
|
|
1211
|
-
if (summary?.docClosure) {
|
|
1212
|
-
return "documentation";
|
|
1213
|
-
}
|
|
1214
|
-
if (summary?.eval) {
|
|
1215
|
-
return "cont-eval";
|
|
1216
|
-
}
|
|
1217
|
-
if (summary?.security) {
|
|
1218
|
-
return "security";
|
|
1219
|
-
}
|
|
1220
|
-
if (summary?.gate || summary?.verdict) {
|
|
1221
|
-
return "cont-qa";
|
|
1222
|
-
}
|
|
1223
|
-
if (summary?.deploy) {
|
|
1224
|
-
return "deploy";
|
|
1225
|
-
}
|
|
1226
|
-
if (summary?.proof || summary?.docDelta || Array.isArray(summary?.components)) {
|
|
1227
|
-
return "implementation";
|
|
1228
|
-
}
|
|
1229
|
-
return null;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
function toSummaryRelativePath(filePath) {
|
|
1233
|
-
const normalized = String(filePath || "").trim();
|
|
1234
|
-
if (!normalized) {
|
|
1235
|
-
return null;
|
|
1236
|
-
}
|
|
1237
|
-
return path.isAbsolute(normalized) ? path.relative(REPO_ROOT, normalized) : normalized;
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
function toLegacyProofState(state) {
|
|
1241
|
-
if (state === "satisfied") {
|
|
1242
|
-
return "met";
|
|
1243
|
-
}
|
|
1244
|
-
if (state === "partial") {
|
|
1245
|
-
return "gap";
|
|
1246
|
-
}
|
|
1247
|
-
if (state === "failed") {
|
|
1248
|
-
return "failed";
|
|
1249
|
-
}
|
|
1250
|
-
return "not_applicable";
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
/**
|
|
1254
|
-
* Compute the attempt-scoped canonical envelope path.
|
|
1255
|
-
*
|
|
1256
|
-
* End-state path: .tmp/<lane>/results/wave-<N>/attempt-<A>/<agentId>.json
|
|
1257
|
-
*
|
|
1258
|
-
* @param {object} options - { lane, waveNumber, attempt, agentId }
|
|
1259
|
-
* @returns {string} The envelope file path
|
|
1260
|
-
*/
|
|
1261
|
-
export function agentEnvelopePath({ lane, waveNumber, attempt, agentId }) {
|
|
1262
|
-
const safeLane = lane || "main";
|
|
1263
|
-
const safeWave = waveNumber ?? 0;
|
|
1264
|
-
const safeAttempt = attempt ?? 1;
|
|
1265
|
-
const safeAgent = agentId || "unknown";
|
|
1266
|
-
return `.tmp/${safeLane}-wave-launcher/results/wave-${safeWave}/attempt-${safeAttempt}/${safeAgent}.json`;
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
/**
|
|
1270
|
-
* Legacy path derivation from status path.
|
|
1271
|
-
* Retained for backward compatibility during migration.
|
|
1272
|
-
*
|
|
1273
|
-
* @param {string} statusPath - Path to the .status or .summary file
|
|
1274
|
-
* @returns {string} The envelope file path
|
|
1275
|
-
*/
|
|
1276
|
-
export function agentEnvelopePathFromStatusPath(statusPath) {
|
|
1277
|
-
if (statusPath.endsWith(".summary.json")) {
|
|
1278
|
-
return statusPath.replace(/\.summary\.json$/i, ".envelope.json");
|
|
1279
|
-
}
|
|
1280
|
-
if (statusPath.endsWith(".status")) {
|
|
1281
|
-
return statusPath.replace(/\.status$/i, ".envelope.json");
|
|
1282
|
-
}
|
|
1283
|
-
return `${statusPath}.envelope.json`;
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
/**
|
|
1287
|
-
* Build a structured result envelope from an already-parsed execution summary.
|
|
1288
|
-
* Pure function — the envelope is a normalized projection of the summary.
|
|
1289
|
-
*
|
|
1290
|
-
* End-state P1-6: common header + role-specific typed optional payloads.
|
|
1291
|
-
* Absent role sections are NOT included (not null, not empty object).
|
|
1292
|
-
*
|
|
1293
|
-
* @param {object} agent - Agent definition from wave (must include .role)
|
|
1294
|
-
* @param {object} summary - Execution summary from buildAgentExecutionSummary
|
|
1295
|
-
* @param {object} [options] - { waveNumber, attempt, exitCode }
|
|
1296
|
-
* @returns {object} AgentResultEnvelope (schemaVersion 2)
|
|
1297
|
-
*/
|
|
1298
|
-
export function buildAgentResultEnvelope(agent, summary, options = {}) {
|
|
1299
|
-
const safeAgent = agent || {};
|
|
1300
|
-
const safeSummary = summary || {};
|
|
1301
|
-
const safeOptions = options || {};
|
|
1302
|
-
|
|
1303
|
-
const agentId = safeAgent.agentId || safeSummary.agentId || null;
|
|
1304
|
-
const role = inferEnvelopeRole(safeAgent, safeSummary);
|
|
1305
|
-
|
|
1306
|
-
// --- Common header ---
|
|
1307
|
-
const proof = safeSummary.proof || {};
|
|
1308
|
-
const proofSection = {
|
|
1309
|
-
state: proof.state === "met" ? "satisfied"
|
|
1310
|
-
: proof.state === "gap" ? "partial"
|
|
1311
|
-
: proof.state === "failed" ? "failed"
|
|
1312
|
-
: "not_applicable",
|
|
1313
|
-
completion: proof.completion || null,
|
|
1314
|
-
durability: proof.durability || null,
|
|
1315
|
-
proofLevel: proof.proof || null,
|
|
1316
|
-
detail: proof.detail || null,
|
|
1317
|
-
};
|
|
1318
|
-
|
|
1319
|
-
// Deliverables — with sha256
|
|
1320
|
-
const deliverables = Array.isArray(safeSummary.deliverables)
|
|
1321
|
-
? safeSummary.deliverables.map((d) => ({
|
|
1322
|
-
path: d.path || null,
|
|
1323
|
-
exists: d.exists === true,
|
|
1324
|
-
sha256: d.sha256 || null,
|
|
1325
|
-
}))
|
|
1326
|
-
: [];
|
|
1327
|
-
|
|
1328
|
-
// Proof artifacts — with sha256 and requiredFor
|
|
1329
|
-
const proofArtifacts = Array.isArray(safeSummary.proofArtifacts)
|
|
1330
|
-
? safeSummary.proofArtifacts.map((artifact) => ({
|
|
1331
|
-
path: artifact.path || null,
|
|
1332
|
-
kind: artifact.kind || null,
|
|
1333
|
-
exists: artifact.exists === true,
|
|
1334
|
-
sha256: artifact.sha256 || null,
|
|
1335
|
-
requiredFor: artifact.requiredFor || null,
|
|
1336
|
-
}))
|
|
1337
|
-
: [];
|
|
1338
|
-
|
|
1339
|
-
// Gaps
|
|
1340
|
-
const gaps = Array.isArray(safeSummary.gaps)
|
|
1341
|
-
? safeSummary.gaps.map((g) => ({
|
|
1342
|
-
kind: g.kind || null,
|
|
1343
|
-
detail: g.detail || null,
|
|
1344
|
-
}))
|
|
1345
|
-
: [];
|
|
1346
|
-
|
|
1347
|
-
// Unresolved blockers
|
|
1348
|
-
const unresolvedBlockers = Array.isArray(safeSummary.unresolvedBlockers)
|
|
1349
|
-
? safeSummary.unresolvedBlockers.map((b) =>
|
|
1350
|
-
typeof b === "object" ? { kind: b.kind || null, detail: b.detail || null, blocking: b.blocking || null } : { kind: null, detail: String(b), blocking: null },
|
|
1351
|
-
)
|
|
1352
|
-
: [];
|
|
1353
|
-
|
|
1354
|
-
// Risk notes
|
|
1355
|
-
const riskNotes = Array.isArray(safeSummary.riskNotes) ? safeSummary.riskNotes : [];
|
|
1356
|
-
|
|
1357
|
-
// Facts
|
|
1358
|
-
const facts = Array.isArray(safeSummary.facts)
|
|
1359
|
-
? safeSummary.facts.map((f) => ({
|
|
1360
|
-
factId: f.factId || null,
|
|
1361
|
-
kind: f.kind || null,
|
|
1362
|
-
content: f.content || null,
|
|
1363
|
-
}))
|
|
1364
|
-
: [];
|
|
1365
|
-
|
|
1366
|
-
const envelope = {
|
|
1367
|
-
schemaVersion: 2,
|
|
1368
|
-
agentId,
|
|
1369
|
-
waveNumber: safeOptions.waveNumber ?? safeSummary.waveNumber ?? null,
|
|
1370
|
-
attempt: safeOptions.attempt ?? safeSummary.attempt ?? null,
|
|
1371
|
-
completedAt: safeOptions.completedAt || toIsoTimestamp(),
|
|
1372
|
-
exitCode: typeof safeOptions.exitCode === "number" ? safeOptions.exitCode : (typeof safeSummary.exitCode === "number" ? safeSummary.exitCode : 0),
|
|
1373
|
-
role,
|
|
1374
|
-
proof: proofSection,
|
|
1375
|
-
deliverables,
|
|
1376
|
-
proofArtifacts,
|
|
1377
|
-
gaps,
|
|
1378
|
-
unresolvedBlockers,
|
|
1379
|
-
riskNotes,
|
|
1380
|
-
facts,
|
|
1381
|
-
};
|
|
1382
|
-
|
|
1383
|
-
// --- Role-specific typed payloads (absent when not applicable) ---
|
|
1384
|
-
|
|
1385
|
-
if (role === "implementation") {
|
|
1386
|
-
const docDelta = safeSummary.docDelta || {};
|
|
1387
|
-
const components = Array.isArray(safeSummary.components)
|
|
1388
|
-
? safeSummary.components.map((c) => ({
|
|
1389
|
-
componentId: c.componentId || null,
|
|
1390
|
-
level: c.level || null,
|
|
1391
|
-
state: c.state || null,
|
|
1392
|
-
detail: c.detail || null,
|
|
1393
|
-
}))
|
|
1394
|
-
: [];
|
|
1395
|
-
envelope.implementation = {
|
|
1396
|
-
docDelta: {
|
|
1397
|
-
state: docDelta.state || "none",
|
|
1398
|
-
paths: Array.isArray(docDelta.paths) ? docDelta.paths : [],
|
|
1399
|
-
detail: docDelta.detail || null,
|
|
1400
|
-
},
|
|
1401
|
-
components,
|
|
1402
|
-
};
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
if (role === "integration") {
|
|
1406
|
-
const integ = safeSummary.integration || {};
|
|
1407
|
-
envelope.integration = {
|
|
1408
|
-
state: integ.state || null,
|
|
1409
|
-
claims: integ.claims || 0,
|
|
1410
|
-
conflicts: integ.conflicts || 0,
|
|
1411
|
-
blockers: integ.blockers || 0,
|
|
1412
|
-
detail: integ.detail || null,
|
|
1413
|
-
};
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
if (role === "documentation") {
|
|
1417
|
-
const docDelta = safeSummary.docDelta || safeSummary.docClosure || {};
|
|
1418
|
-
envelope.documentation = {
|
|
1419
|
-
docClosure: {
|
|
1420
|
-
state: docDelta.state || "no-change",
|
|
1421
|
-
paths: Array.isArray(docDelta.paths) ? docDelta.paths : [],
|
|
1422
|
-
detail: docDelta.detail || null,
|
|
1423
|
-
},
|
|
1424
|
-
};
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
if (role === "cont-qa") {
|
|
1428
|
-
const verdict = safeSummary.verdict || {};
|
|
1429
|
-
const gate = safeSummary.gate || {};
|
|
1430
|
-
envelope.contQa = {
|
|
1431
|
-
verdict: {
|
|
1432
|
-
verdict: verdict.verdict || null,
|
|
1433
|
-
detail: verdict.detail || null,
|
|
1434
|
-
},
|
|
1435
|
-
gateClaims: {
|
|
1436
|
-
architecture: gate.architecture || null,
|
|
1437
|
-
integration: gate.integration || null,
|
|
1438
|
-
durability: gate.durability || null,
|
|
1439
|
-
live: gate.live || null,
|
|
1440
|
-
docs: gate.docs || null,
|
|
1441
|
-
},
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
if (role === "cont-eval") {
|
|
1446
|
-
const evalSection = safeSummary.eval || {};
|
|
1447
|
-
envelope.contEval = {
|
|
1448
|
-
state: evalSection.state || null,
|
|
1449
|
-
targets: evalSection.targets || 0,
|
|
1450
|
-
benchmarks: evalSection.benchmarks || 0,
|
|
1451
|
-
regressions: evalSection.regressions || 0,
|
|
1452
|
-
targetIds: Array.isArray(evalSection.targetIds) ? evalSection.targetIds : [],
|
|
1453
|
-
benchmarkIds: Array.isArray(evalSection.benchmarkIds) ? evalSection.benchmarkIds : [],
|
|
1454
|
-
detail: evalSection.detail || null,
|
|
1455
|
-
};
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
if (role === "security") {
|
|
1459
|
-
const sec = safeSummary.security || {};
|
|
1460
|
-
envelope.security = {
|
|
1461
|
-
state: sec.state || null,
|
|
1462
|
-
findings: sec.findings || 0,
|
|
1463
|
-
approvals: sec.approvals || 0,
|
|
1464
|
-
detail: sec.detail || null,
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
if (role === "deploy") {
|
|
1469
|
-
const dep = safeSummary.deploy || {};
|
|
1470
|
-
envelope.deploy = {
|
|
1471
|
-
state: dep.state || "not_applicable",
|
|
1472
|
-
environment: dep.environment || null,
|
|
1473
|
-
healthCheck: dep.healthCheck || null,
|
|
1474
|
-
rolloutArtifact: dep.rolloutArtifact || null,
|
|
1475
|
-
detail: dep.detail || null,
|
|
1476
|
-
};
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
return envelope;
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
/**
|
|
1483
|
-
* Build a v2 envelope from legacy parsed log markers.
|
|
1484
|
-
* Migration adapter: synthesizes the end-state envelope shape from the
|
|
1485
|
-
* output of buildAgentExecutionSummary (which parses log markers).
|
|
1486
|
-
*
|
|
1487
|
-
* This exists so the gate engine always sees a consistent v2 shape,
|
|
1488
|
-
* even when the agent emitted legacy log markers rather than a structured envelope.
|
|
1489
|
-
*
|
|
1490
|
-
* @param {object} agent - Agent definition (must include .agentId, .role)
|
|
1491
|
-
* @param {object} legacySummary - Result from buildAgentExecutionSummary
|
|
1492
|
-
* @param {object} [options] - { waveNumber, attempt, exitCode }
|
|
1493
|
-
* @returns {object} AgentResultEnvelope (schemaVersion 2)
|
|
1494
|
-
*/
|
|
1495
|
-
export function buildEnvelopeFromLegacySignals(agent, legacySummary, options = {}) {
|
|
1496
|
-
const envelope = buildAgentResultEnvelope(agent, legacySummary, options);
|
|
1497
|
-
envelope._synthesizedFromLegacy = true;
|
|
1498
|
-
return envelope;
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
export function buildExecutionSummaryFromEnvelope(envelope, options = {}) {
|
|
1502
|
-
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
1503
|
-
return null;
|
|
1504
|
-
}
|
|
1505
|
-
const role = inferEnvelopeRole(options.agent || {}, envelope);
|
|
1506
|
-
const proof = envelope.proof && typeof envelope.proof === "object"
|
|
1507
|
-
? {
|
|
1508
|
-
state: toLegacyProofState(envelope.proof.state),
|
|
1509
|
-
completion: envelope.proof.completion || null,
|
|
1510
|
-
durability: envelope.proof.durability || null,
|
|
1511
|
-
proof: envelope.proof.proofLevel || null,
|
|
1512
|
-
detail: envelope.proof.detail || null,
|
|
1513
|
-
}
|
|
1514
|
-
: null;
|
|
1515
|
-
const summary = {
|
|
1516
|
-
agentId: envelope.agentId || options.agent?.agentId || null,
|
|
1517
|
-
role,
|
|
1518
|
-
waveNumber: envelope.waveNumber ?? options.waveNumber ?? null,
|
|
1519
|
-
attempt: envelope.attempt ?? options.attempt ?? null,
|
|
1520
|
-
completedAt: envelope.completedAt || null,
|
|
1521
|
-
exitCode: typeof envelope.exitCode === "number" ? envelope.exitCode : 0,
|
|
1522
|
-
logPath: toSummaryRelativePath(options.logPath),
|
|
1523
|
-
reportPath: toSummaryRelativePath(options.reportPath),
|
|
1524
|
-
proof,
|
|
1525
|
-
deliverables: Array.isArray(envelope.deliverables)
|
|
1526
|
-
? envelope.deliverables.map((deliverable) => ({
|
|
1527
|
-
path: deliverable.path || null,
|
|
1528
|
-
exists: deliverable.exists === true,
|
|
1529
|
-
sha256: deliverable.sha256 || null,
|
|
1530
|
-
}))
|
|
1531
|
-
: [],
|
|
1532
|
-
proofArtifacts: Array.isArray(envelope.proofArtifacts)
|
|
1533
|
-
? envelope.proofArtifacts.map((artifact) => ({
|
|
1534
|
-
path: artifact.path || null,
|
|
1535
|
-
kind: artifact.kind || null,
|
|
1536
|
-
exists: artifact.exists === true,
|
|
1537
|
-
sha256: artifact.sha256 || null,
|
|
1538
|
-
requiredFor: artifact.requiredFor || null,
|
|
1539
|
-
}))
|
|
1540
|
-
: [],
|
|
1541
|
-
gaps: Array.isArray(envelope.gaps)
|
|
1542
|
-
? envelope.gaps.map((gap) => ({
|
|
1543
|
-
kind: gap.kind || null,
|
|
1544
|
-
detail: gap.detail || null,
|
|
1545
|
-
}))
|
|
1546
|
-
: [],
|
|
1547
|
-
unresolvedBlockers: Array.isArray(envelope.unresolvedBlockers)
|
|
1548
|
-
? envelope.unresolvedBlockers.map((blocker) => ({
|
|
1549
|
-
kind: blocker.kind || null,
|
|
1550
|
-
detail: blocker.detail || null,
|
|
1551
|
-
blocking: blocker.blocking ?? null,
|
|
1552
|
-
}))
|
|
1553
|
-
: [],
|
|
1554
|
-
riskNotes: Array.isArray(envelope.riskNotes) ? envelope.riskNotes.slice() : [],
|
|
1555
|
-
facts: Array.isArray(envelope.facts)
|
|
1556
|
-
? envelope.facts.map((fact) => ({
|
|
1557
|
-
factId: fact.factId || null,
|
|
1558
|
-
kind: fact.kind || null,
|
|
1559
|
-
content: fact.content || null,
|
|
1560
|
-
}))
|
|
1561
|
-
: [],
|
|
1562
|
-
};
|
|
1563
|
-
|
|
1564
|
-
if (envelope.implementation) {
|
|
1565
|
-
summary.docDelta = {
|
|
1566
|
-
state: envelope.implementation.docDelta?.state || "none",
|
|
1567
|
-
paths: Array.isArray(envelope.implementation.docDelta?.paths)
|
|
1568
|
-
? envelope.implementation.docDelta.paths
|
|
1569
|
-
: [],
|
|
1570
|
-
detail: envelope.implementation.docDelta?.detail || null,
|
|
1571
|
-
};
|
|
1572
|
-
summary.components = Array.isArray(envelope.implementation.components)
|
|
1573
|
-
? envelope.implementation.components.map((component) => ({
|
|
1574
|
-
componentId: component.componentId || null,
|
|
1575
|
-
level: component.level || null,
|
|
1576
|
-
state: component.state || null,
|
|
1577
|
-
detail: component.detail || null,
|
|
1578
|
-
}))
|
|
1579
|
-
: [];
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
if (envelope.documentation?.docClosure) {
|
|
1583
|
-
summary.docClosure = {
|
|
1584
|
-
state: envelope.documentation.docClosure.state || "no-change",
|
|
1585
|
-
paths: Array.isArray(envelope.documentation.docClosure.paths)
|
|
1586
|
-
? envelope.documentation.docClosure.paths
|
|
1587
|
-
: [],
|
|
1588
|
-
detail: envelope.documentation.docClosure.detail || null,
|
|
1589
|
-
};
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
if (envelope.integration) {
|
|
1593
|
-
summary.integration = {
|
|
1594
|
-
state: envelope.integration.state || null,
|
|
1595
|
-
claims: envelope.integration.claims || 0,
|
|
1596
|
-
conflicts: envelope.integration.conflicts || 0,
|
|
1597
|
-
blockers: envelope.integration.blockers || 0,
|
|
1598
|
-
detail: envelope.integration.detail || null,
|
|
1599
|
-
};
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
if (envelope.contEval) {
|
|
1603
|
-
summary.eval = {
|
|
1604
|
-
state: envelope.contEval.state || null,
|
|
1605
|
-
targets: envelope.contEval.targets || 0,
|
|
1606
|
-
benchmarks: envelope.contEval.benchmarks || 0,
|
|
1607
|
-
regressions: envelope.contEval.regressions || 0,
|
|
1608
|
-
targetIds: Array.isArray(envelope.contEval.targetIds) ? envelope.contEval.targetIds : [],
|
|
1609
|
-
benchmarkIds: Array.isArray(envelope.contEval.benchmarkIds) ? envelope.contEval.benchmarkIds : [],
|
|
1610
|
-
detail: envelope.contEval.detail || null,
|
|
1611
|
-
};
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
if (envelope.contQa) {
|
|
1615
|
-
summary.gate = {
|
|
1616
|
-
architecture: envelope.contQa.gateClaims?.architecture || null,
|
|
1617
|
-
integration: envelope.contQa.gateClaims?.integration || null,
|
|
1618
|
-
durability: envelope.contQa.gateClaims?.durability || null,
|
|
1619
|
-
live: envelope.contQa.gateClaims?.live || null,
|
|
1620
|
-
docs: envelope.contQa.gateClaims?.docs || null,
|
|
1621
|
-
detail: envelope.contQa.gateClaims?.detail || null,
|
|
1622
|
-
};
|
|
1623
|
-
summary.verdict = {
|
|
1624
|
-
verdict: envelope.contQa.verdict?.verdict || null,
|
|
1625
|
-
detail: envelope.contQa.verdict?.detail || null,
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
if (envelope.security) {
|
|
1630
|
-
summary.security = {
|
|
1631
|
-
state: envelope.security.state || null,
|
|
1632
|
-
findings: envelope.security.findings || 0,
|
|
1633
|
-
approvals: envelope.security.approvals || 0,
|
|
1634
|
-
detail: envelope.security.detail || null,
|
|
1635
|
-
};
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
if (envelope.deploy) {
|
|
1639
|
-
summary.deploy = {
|
|
1640
|
-
state: envelope.deploy.state || "not_applicable",
|
|
1641
|
-
environment: envelope.deploy.environment || null,
|
|
1642
|
-
healthCheck: envelope.deploy.healthCheck || null,
|
|
1643
|
-
rolloutArtifact: envelope.deploy.rolloutArtifact || null,
|
|
1644
|
-
detail: envelope.deploy.detail || null,
|
|
1645
|
-
};
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
return summary;
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
/**
|
|
1652
|
-
* Write an agent result envelope alongside the summary file.
|
|
1653
|
-
*
|
|
1654
|
-
* @param {string} statusPath - Path to the .status file
|
|
1655
|
-
* @param {object} envelope - Result from buildAgentResultEnvelope
|
|
1656
|
-
*/
|
|
1657
|
-
export function writeAgentResultEnvelope(statusPath, envelope) {
|
|
1658
|
-
const envelopePath = agentEnvelopePathFromStatusPath(statusPath);
|
|
1659
|
-
writeJsonAtomic(envelopePath, envelope);
|
|
1660
|
-
return envelopePath;
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
/**
|
|
1664
|
-
* Read an agent result envelope if it exists.
|
|
1665
|
-
*
|
|
1666
|
-
* @param {string} statusPath - Path to the .status file
|
|
1667
|
-
* @returns {object|null} The envelope or null
|
|
1668
|
-
*/
|
|
1669
|
-
export function readAgentResultEnvelope(statusPath) {
|
|
1670
|
-
const envelopePath = agentEnvelopePathFromStatusPath(statusPath);
|
|
1671
|
-
const payload = readJsonOrNull(envelopePath);
|
|
1672
|
-
return payload && typeof payload === "object" ? payload : null;
|
|
1673
|
-
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_CODEX_SANDBOX_MODE,
|
|
6
|
+
DEFAULT_EXECUTOR_MODE,
|
|
7
|
+
normalizeCodexSandboxMode,
|
|
8
|
+
normalizeExecutorMode,
|
|
9
|
+
SUPPORTED_EXECUTOR_MODES,
|
|
10
|
+
} from "./config.mjs";
|
|
5
11
|
import {
|
|
6
12
|
DEFAULT_AGENT_LAUNCH_STAGGER_MS,
|
|
7
13
|
DEFAULT_AGENT_RATE_LIMIT_BASE_DELAY_SECONDS,
|
|
@@ -17,10 +23,6 @@ import {
|
|
|
17
23
|
parsePositiveInt,
|
|
18
24
|
sanitizeLaneName,
|
|
19
25
|
} from "./shared.mjs";
|
|
20
|
-
import {
|
|
21
|
-
DEFAULT_CODEX_SANDBOX_MODE,
|
|
22
|
-
normalizeCodexSandboxMode,
|
|
23
|
-
} from "./launcher.mjs";
|
|
24
26
|
import {
|
|
25
27
|
maybeAnnouncePackageUpdate,
|
|
26
28
|
WAVE_SUPPRESS_UPDATE_NOTICE_ENV,
|
|
@@ -29,6 +31,8 @@ import { readRunState } from "./wave-files.mjs";
|
|
|
29
31
|
import { readDependencyTickets } from "./coordination-store.mjs";
|
|
30
32
|
import { readWaveLedger } from "./ledger.mjs";
|
|
31
33
|
|
|
34
|
+
const AUTONOMOUS_EXECUTOR_MODES = SUPPORTED_EXECUTOR_MODES.filter((mode) => mode !== "local");
|
|
35
|
+
|
|
32
36
|
function printUsage() {
|
|
33
37
|
console.log(`Usage: pnpm exec wave autonomous [options]
|
|
34
38
|
|
|
@@ -46,7 +50,7 @@ Options:
|
|
|
46
50
|
--agent-launch-stagger-ms <n> Delay between agent launches (default: ${DEFAULT_AGENT_LAUNCH_STAGGER_MS})
|
|
47
51
|
--orchestrator-id <id> Orchestrator ID for coordination board
|
|
48
52
|
--resident-orchestrator Launch a resident orchestrator session for each live wave
|
|
49
|
-
--executor <mode> Default executor passed to launcher: ${
|
|
53
|
+
--executor <mode> Default executor passed to launcher: ${AUTONOMOUS_EXECUTOR_MODES.join(" | ")} (default: lane config)
|
|
50
54
|
--codex-sandbox <mode> Default Codex sandbox mode passed to launcher (default: ${DEFAULT_CODEX_SANDBOX_MODE})
|
|
51
55
|
--dashboard Enable dashboards (default: disabled)
|
|
52
56
|
--keep-sessions Keep tmux sessions between waves
|