@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/README.md +60 -11
  3. package/docs/README.md +8 -2
  4. package/docs/agents/wave-design-role.md +47 -0
  5. package/docs/concepts/what-is-a-wave.md +11 -7
  6. package/docs/guides/author-and-run-waves.md +24 -0
  7. package/docs/guides/planner.md +44 -0
  8. package/docs/plans/architecture-hardening-migration.md +8 -1
  9. package/docs/plans/current-state.md +19 -7
  10. package/docs/plans/end-state-architecture.md +88 -70
  11. package/docs/plans/examples/wave-example-design-handoff.md +262 -0
  12. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  13. package/docs/plans/migration.md +370 -64
  14. package/docs/plans/wave-orchestrator.md +49 -13
  15. package/docs/reference/cli-reference.md +46 -14
  16. package/docs/reference/coordination-and-closure.md +19 -6
  17. package/docs/reference/npmjs-trusted-publishing.md +5 -4
  18. package/docs/reference/sample-waves.md +14 -7
  19. package/docs/reference/skills.md +10 -0
  20. package/package.json +1 -1
  21. package/releases/manifest.json +39 -0
  22. package/scripts/wave-orchestrator/agent-state.mjs +64 -491
  23. package/scripts/wave-orchestrator/autonomous.mjs +10 -6
  24. package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
  25. package/scripts/wave-orchestrator/config.mjs +5 -0
  26. package/scripts/wave-orchestrator/coordination.mjs +42 -1
  27. package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
  28. package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +501 -141
  29. package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
  30. package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
  31. package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
  32. package/scripts/wave-orchestrator/install.mjs +3 -0
  33. package/scripts/wave-orchestrator/launcher-runtime.mjs +11 -6
  34. package/scripts/wave-orchestrator/launcher.mjs +324 -723
  35. package/scripts/wave-orchestrator/ledger.mjs +56 -27
  36. package/scripts/wave-orchestrator/local-executor.mjs +37 -0
  37. package/scripts/wave-orchestrator/planner.mjs +24 -4
  38. package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
  39. package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
  40. package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
  41. package/scripts/wave-orchestrator/replay.mjs +3 -1
  42. package/scripts/wave-orchestrator/result-envelope.mjs +620 -0
  43. package/scripts/wave-orchestrator/retry-control.mjs +22 -2
  44. package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +352 -18
  45. package/scripts/wave-orchestrator/role-helpers.mjs +124 -1
  46. package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
  47. package/scripts/wave-orchestrator/shared.mjs +2 -0
  48. package/scripts/wave-orchestrator/skills.mjs +1 -0
  49. package/scripts/wave-orchestrator/task-entity.mjs +65 -45
  50. package/scripts/wave-orchestrator/traces.mjs +10 -1
  51. package/scripts/wave-orchestrator/wave-files.mjs +96 -10
  52. package/scripts/wave-orchestrator/wave-state-reducer.mjs +76 -12
  53. package/skills/README.md +7 -0
  54. package/skills/role-design/SKILL.md +50 -0
  55. package/skills/role-design/skill.json +36 -0
  56. package/skills/tui-design/SKILL.md +77 -0
  57. package/skills/tui-design/references/tui-design.md +259 -0
  58. package/skills/tui-design/skill.json +36 -0
  59. 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 { DEFAULT_EXECUTOR_MODE, normalizeExecutorMode, SUPPORTED_EXECUTOR_MODES } from "./config.mjs";
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: ${SUPPORTED_EXECUTOR_MODES.join(" | ")} (default: lane config)
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