@chllming/wave-orchestration 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/README.md +44 -8
  3. package/docs/agents/wave-orchestrator-role.md +50 -0
  4. package/docs/agents/wave-planner-role.md +39 -0
  5. package/docs/context7/bundles.json +9 -0
  6. package/docs/context7/planner-agent/README.md +25 -0
  7. package/docs/context7/planner-agent/manifest.json +83 -0
  8. package/docs/context7/planner-agent/papers/cooperbench-why-coding-agents-cannot-be-your-teammates-yet.md +3283 -0
  9. package/docs/context7/planner-agent/papers/dova-deliberation-first-multi-agent-orchestration-for-autonomous-research-automation.md +1699 -0
  10. package/docs/context7/planner-agent/papers/dpbench-large-language-models-struggle-with-simultaneous-coordination.md +2251 -0
  11. package/docs/context7/planner-agent/papers/incremental-planning-to-control-a-blackboard-based-problem-solver.md +1729 -0
  12. package/docs/context7/planner-agent/papers/silo-bench-a-scalable-environment-for-evaluating-distributed-coordination-in-multi-agent-llm-systems.md +3747 -0
  13. package/docs/context7/planner-agent/papers/todoevolve-learning-to-architect-agent-planning-systems.md +1675 -0
  14. package/docs/context7/planner-agent/papers/verified-multi-agent-orchestration-a-plan-execute-verify-replan-framework-for-complex-query-resolution.md +1173 -0
  15. package/docs/context7/planner-agent/papers/why-do-multi-agent-llm-systems-fail.md +5211 -0
  16. package/docs/context7/planner-agent/topics/planning-and-orchestration.md +24 -0
  17. package/docs/evals/README.md +96 -1
  18. package/docs/evals/arm-templates/README.md +13 -0
  19. package/docs/evals/arm-templates/full-wave.json +15 -0
  20. package/docs/evals/arm-templates/single-agent.json +15 -0
  21. package/docs/evals/benchmark-catalog.json +7 -0
  22. package/docs/evals/cases/README.md +47 -0
  23. package/docs/evals/cases/wave-blackboard-inbox-targeting.json +73 -0
  24. package/docs/evals/cases/wave-contradiction-conflict.json +104 -0
  25. package/docs/evals/cases/wave-expert-routing-preservation.json +69 -0
  26. package/docs/evals/cases/wave-hidden-profile-private-evidence.json +81 -0
  27. package/docs/evals/cases/wave-premature-closure-guard.json +71 -0
  28. package/docs/evals/cases/wave-silo-cross-agent-state.json +77 -0
  29. package/docs/evals/cases/wave-simultaneous-lockstep.json +92 -0
  30. package/docs/evals/cooperbench/real-world-mitigation.md +341 -0
  31. package/docs/evals/external-benchmarks.json +85 -0
  32. package/docs/evals/external-command-config.sample.json +9 -0
  33. package/docs/evals/external-command-config.swe-bench-pro.json +8 -0
  34. package/docs/evals/pilots/README.md +47 -0
  35. package/docs/evals/pilots/swe-bench-pro-public-full-wave-review-10.json +64 -0
  36. package/docs/evals/pilots/swe-bench-pro-public-pilot.json +111 -0
  37. package/docs/evals/wave-benchmark-program.md +302 -0
  38. package/docs/guides/planner.md +48 -11
  39. package/docs/plans/context7-wave-orchestrator.md +20 -0
  40. package/docs/plans/current-state.md +9 -1
  41. package/docs/plans/examples/wave-benchmark-improvement.md +108 -0
  42. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  43. package/docs/plans/examples/wave-example-rollout-fidelity.md +340 -0
  44. package/docs/plans/wave-orchestrator.md +73 -11
  45. package/docs/plans/waves/reviews/wave-1-benchmark-operator.md +118 -0
  46. package/docs/reference/coordination-and-closure.md +436 -0
  47. package/docs/reference/live-proof-waves.md +25 -3
  48. package/docs/reference/npmjs-trusted-publishing.md +3 -3
  49. package/docs/reference/proof-metrics.md +90 -0
  50. package/docs/reference/runtime-config/README.md +61 -0
  51. package/docs/reference/sample-waves.md +29 -18
  52. package/docs/reference/wave-control.md +164 -0
  53. package/docs/reference/wave-planning-lessons.md +131 -0
  54. package/package.json +5 -4
  55. package/releases/manifest.json +33 -0
  56. package/scripts/research/agent-context-archive.mjs +18 -0
  57. package/scripts/research/manifests/agent-context-expanded-2026-03-22.mjs +17 -0
  58. package/scripts/research/sync-planner-context7-bundle.mjs +133 -0
  59. package/scripts/wave-autonomous.mjs +2 -4
  60. package/scripts/wave-orchestrator/adhoc.mjs +32 -11
  61. package/scripts/wave-orchestrator/artifact-schemas.mjs +232 -0
  62. package/scripts/wave-orchestrator/autonomous.mjs +27 -6
  63. package/scripts/wave-orchestrator/benchmark-cases.mjs +374 -0
  64. package/scripts/wave-orchestrator/benchmark-external.mjs +1384 -0
  65. package/scripts/wave-orchestrator/benchmark.mjs +972 -0
  66. package/scripts/wave-orchestrator/clarification-triage.mjs +78 -12
  67. package/scripts/wave-orchestrator/config.mjs +175 -0
  68. package/scripts/wave-orchestrator/control-cli.mjs +1123 -0
  69. package/scripts/wave-orchestrator/control-plane.mjs +697 -0
  70. package/scripts/wave-orchestrator/coord-cli.mjs +360 -2
  71. package/scripts/wave-orchestrator/coordination-store.mjs +211 -9
  72. package/scripts/wave-orchestrator/coordination.mjs +84 -0
  73. package/scripts/wave-orchestrator/dashboard-renderer.mjs +38 -3
  74. package/scripts/wave-orchestrator/dashboard-state.mjs +22 -0
  75. package/scripts/wave-orchestrator/evals.mjs +23 -0
  76. package/scripts/wave-orchestrator/executors.mjs +3 -2
  77. package/scripts/wave-orchestrator/feedback.mjs +55 -0
  78. package/scripts/wave-orchestrator/install.mjs +253 -26
  79. package/scripts/wave-orchestrator/launcher-closure.mjs +4 -1
  80. package/scripts/wave-orchestrator/launcher-runtime.mjs +24 -21
  81. package/scripts/wave-orchestrator/launcher.mjs +800 -35
  82. package/scripts/wave-orchestrator/package-update-notice.mjs +230 -0
  83. package/scripts/wave-orchestrator/package-version.mjs +32 -0
  84. package/scripts/wave-orchestrator/planner-context.mjs +75 -0
  85. package/scripts/wave-orchestrator/planner.mjs +2270 -136
  86. package/scripts/wave-orchestrator/proof-cli.mjs +195 -0
  87. package/scripts/wave-orchestrator/proof-registry.mjs +317 -0
  88. package/scripts/wave-orchestrator/replay.mjs +10 -4
  89. package/scripts/wave-orchestrator/retry-cli.mjs +184 -0
  90. package/scripts/wave-orchestrator/retry-control.mjs +225 -0
  91. package/scripts/wave-orchestrator/shared.mjs +26 -0
  92. package/scripts/wave-orchestrator/swe-bench-pro-task.mjs +1004 -0
  93. package/scripts/wave-orchestrator/traces.mjs +157 -2
  94. package/scripts/wave-orchestrator/wave-control-client.mjs +532 -0
  95. package/scripts/wave-orchestrator/wave-control-schema.mjs +309 -0
  96. package/scripts/wave-orchestrator/wave-files.mjs +17 -5
  97. package/scripts/wave.mjs +39 -2
  98. package/skills/repo-coding-rules/SKILL.md +1 -0
  99. package/skills/role-cont-eval/SKILL.md +1 -0
  100. package/skills/role-cont-qa/SKILL.md +13 -6
  101. package/skills/role-deploy/SKILL.md +1 -0
  102. package/skills/role-documentation/SKILL.md +4 -0
  103. package/skills/role-implementation/SKILL.md +4 -0
  104. package/skills/role-infra/SKILL.md +2 -1
  105. package/skills/role-integration/SKILL.md +15 -8
  106. package/skills/role-planner/SKILL.md +39 -0
  107. package/skills/role-planner/skill.json +21 -0
  108. package/skills/role-research/SKILL.md +1 -0
  109. package/skills/role-security/SKILL.md +2 -2
  110. package/skills/runtime-claude/SKILL.md +2 -1
  111. package/skills/runtime-codex/SKILL.md +1 -0
  112. package/skills/runtime-local/SKILL.md +2 -0
  113. package/skills/runtime-opencode/SKILL.md +1 -0
  114. package/skills/wave-core/SKILL.md +25 -6
  115. package/skills/wave-core/references/marker-syntax.md +16 -8
  116. package/wave.config.json +45 -0
@@ -5,9 +5,7 @@ import { bootstrapWaveArgs } from "./wave-cli-bootstrap.mjs";
5
5
  const argv = bootstrapWaveArgs(process.argv.slice(2));
6
6
  const { runAutonomousCli } = await import("./wave-orchestrator/autonomous.mjs");
7
7
 
8
- try {
9
- runAutonomousCli(argv);
10
- } catch (error) {
8
+ runAutonomousCli(argv).catch((error) => {
11
9
  console.error(`[wave-autonomous] ${error instanceof Error ? error.message : String(error)}`);
12
10
  process.exit(1);
13
- }
11
+ });
@@ -8,6 +8,10 @@ import {
8
8
  buildDefaultProjectProfile,
9
9
  readProjectProfile,
10
10
  } from "./project-profile.mjs";
11
+ import {
12
+ maybeAnnouncePackageUpdate,
13
+ WAVE_SUPPRESS_UPDATE_NOTICE_ENV,
14
+ } from "./package-update-notice.mjs";
11
15
  import { runLauncherCli } from "./launcher.mjs";
12
16
  import { renderWaveMarkdown } from "./planner.mjs";
13
17
  import {
@@ -187,6 +191,20 @@ function buildAdhocRunId() {
187
191
  return sanitizeAdhocRunId(`adhoc-${stamp}-${random}`);
188
192
  }
189
193
 
194
+ async function withSuppressedNestedUpdateNotice(fn) {
195
+ const previousValue = process.env[WAVE_SUPPRESS_UPDATE_NOTICE_ENV];
196
+ process.env[WAVE_SUPPRESS_UPDATE_NOTICE_ENV] = "1";
197
+ try {
198
+ return await fn();
199
+ } finally {
200
+ if (previousValue === undefined) {
201
+ delete process.env[WAVE_SUPPRESS_UPDATE_NOTICE_ENV];
202
+ } else {
203
+ process.env[WAVE_SUPPRESS_UPDATE_NOTICE_ENV] = previousValue;
204
+ }
205
+ }
206
+ }
207
+
190
208
  function readEffectiveProjectProfile(config) {
191
209
  return readProjectProfile({ config }) || buildDefaultProjectProfile(config);
192
210
  }
@@ -1135,6 +1153,7 @@ export async function runAdhocCli(argv) {
1135
1153
  if (options.tasks.length === 0) {
1136
1154
  throw new Error("At least one --task is required for `wave adhoc run`.");
1137
1155
  }
1156
+ await maybeAnnouncePackageUpdate();
1138
1157
  const stored = createStoredRun({ config, options });
1139
1158
  const summary = summarizePlan(stored.spec, stored.lanePaths);
1140
1159
  if (options.json) {
@@ -1157,17 +1176,19 @@ export async function runAdhocCli(argv) {
1157
1176
  writeJsonAtomic(stored.lanePaths.adhocResultPath, runningResult);
1158
1177
  upsertAdhocIndexEntry(stored.lanePaths.adhocIndexPath, runningResult);
1159
1178
  try {
1160
- await runLauncherCli([
1161
- "--lane",
1162
- stored.lanePaths.lane,
1163
- "--adhoc-run",
1164
- stored.lanePaths.runId,
1165
- "--start-wave",
1166
- String(ADHOC_WAVE_NUMBER),
1167
- "--end-wave",
1168
- String(ADHOC_WAVE_NUMBER),
1169
- ...options.launcherArgs,
1170
- ]);
1179
+ await withSuppressedNestedUpdateNotice(() =>
1180
+ runLauncherCli([
1181
+ "--lane",
1182
+ stored.lanePaths.lane,
1183
+ "--adhoc-run",
1184
+ stored.lanePaths.runId,
1185
+ "--start-wave",
1186
+ String(ADHOC_WAVE_NUMBER),
1187
+ "--end-wave",
1188
+ String(ADHOC_WAVE_NUMBER),
1189
+ ...options.launcherArgs,
1190
+ ]),
1191
+ );
1171
1192
  const completedResult = buildResultRecord(
1172
1193
  stored.lanePaths,
1173
1194
  stored.request,
@@ -1,20 +1,30 @@
1
1
  import { readJsonOrNull, toIsoTimestamp, writeJsonAtomic } from "./shared.mjs";
2
+ import {
3
+ normalizeWaveControlReportMode,
4
+ normalizeWaveControlRunKind,
5
+ } from "./wave-control-schema.mjs";
2
6
 
3
7
  export const MANIFEST_SCHEMA_VERSION = 1;
4
8
  export const GLOBAL_DASHBOARD_SCHEMA_VERSION = 1;
5
9
  export const WAVE_DASHBOARD_SCHEMA_VERSION = 1;
6
10
  export const RELAUNCH_PLAN_SCHEMA_VERSION = 1;
11
+ export const RETRY_OVERRIDE_SCHEMA_VERSION = 1;
7
12
  export const ASSIGNMENT_SNAPSHOT_SCHEMA_VERSION = 1;
8
13
  export const DEPENDENCY_SNAPSHOT_SCHEMA_VERSION = 1;
14
+ export const PROOF_REGISTRY_SCHEMA_VERSION = 1;
9
15
  export const RUN_STATE_SCHEMA_VERSION = 2;
16
+ export const WAVE_CONTROL_DELIVERY_STATE_SCHEMA_VERSION = 1;
10
17
 
11
18
  export const MANIFEST_KIND = "wave-manifest";
12
19
  export const GLOBAL_DASHBOARD_KIND = "global-dashboard";
13
20
  export const WAVE_DASHBOARD_KIND = "wave-dashboard";
14
21
  export const RELAUNCH_PLAN_KIND = "wave-relaunch-plan";
22
+ export const RETRY_OVERRIDE_KIND = "wave-retry-override";
15
23
  export const ASSIGNMENT_SNAPSHOT_KIND = "wave-assignment-snapshot";
16
24
  export const DEPENDENCY_SNAPSHOT_KIND = "wave-dependency-snapshot";
25
+ export const PROOF_REGISTRY_KIND = "wave-proof-registry";
17
26
  export const RUN_STATE_KIND = "wave-run-state";
27
+ export const WAVE_CONTROL_DELIVERY_STATE_KIND = "wave-control-delivery-state";
18
28
 
19
29
  function isPlainObject(value) {
20
30
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -25,6 +35,11 @@ function normalizeInteger(value, fallback = null) {
25
35
  return Number.isFinite(parsed) ? parsed : fallback;
26
36
  }
27
37
 
38
+ function normalizeNonNegativeInteger(value, fallback = 0) {
39
+ const parsed = Number.parseInt(String(value ?? ""), 10);
40
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
41
+ }
42
+
28
43
  function normalizeText(value, fallback = null) {
29
44
  const normalized = String(value ?? "").trim();
30
45
  return normalized || fallback;
@@ -34,6 +49,19 @@ function cloneJson(value) {
34
49
  return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
35
50
  }
36
51
 
52
+ function normalizeStringArray(values) {
53
+ if (!Array.isArray(values)) {
54
+ return [];
55
+ }
56
+ return Array.from(
57
+ new Set(
58
+ values
59
+ .map((value) => normalizeText(value, null))
60
+ .filter(Boolean),
61
+ ),
62
+ );
63
+ }
64
+
37
65
  export function normalizeManifest(payload) {
38
66
  const source = isPlainObject(payload) ? payload : {};
39
67
  return {
@@ -94,6 +122,42 @@ export function writeRelaunchPlan(filePath, payload, defaults = {}) {
94
122
  return normalized;
95
123
  }
96
124
 
125
+ export function normalizeRetryOverride(payload, defaults = {}) {
126
+ const source = isPlainObject(payload) ? payload : {};
127
+ return {
128
+ schemaVersion: RETRY_OVERRIDE_SCHEMA_VERSION,
129
+ kind: RETRY_OVERRIDE_KIND,
130
+ lane: normalizeText(source.lane, normalizeText(defaults.lane, null)),
131
+ wave: normalizeInteger(source.wave, normalizeInteger(defaults.wave, null)),
132
+ selectedAgentIds: normalizeStringArray(source.selectedAgentIds),
133
+ reuseAttemptIds: normalizeStringArray(source.reuseAttemptIds),
134
+ reuseProofBundleIds: normalizeStringArray(source.reuseProofBundleIds),
135
+ reuseDerivedSummaries: source.reuseDerivedSummaries !== false,
136
+ invalidateComponentIds: normalizeStringArray(source.invalidateComponentIds),
137
+ clearReusableAgentIds: normalizeStringArray(source.clearReusableAgentIds),
138
+ preserveReusableAgentIds: normalizeStringArray(source.preserveReusableAgentIds),
139
+ resumePhase: normalizeText(source.resumePhase, null),
140
+ requestedBy: normalizeText(source.requestedBy, normalizeText(defaults.requestedBy, null)),
141
+ reason: normalizeText(source.reason, null),
142
+ applyOnce: source.applyOnce !== false,
143
+ createdAt: normalizeText(source.createdAt, toIsoTimestamp()),
144
+ };
145
+ }
146
+
147
+ export function readRetryOverride(filePath, defaults = {}) {
148
+ const payload = readJsonOrNull(filePath);
149
+ if (!payload) {
150
+ return null;
151
+ }
152
+ return normalizeRetryOverride(payload, defaults);
153
+ }
154
+
155
+ export function writeRetryOverride(filePath, payload, defaults = {}) {
156
+ const normalized = normalizeRetryOverride(payload, defaults);
157
+ writeJsonAtomic(filePath, normalized);
158
+ return normalized;
159
+ }
160
+
97
161
  export function normalizeAssignmentSnapshot(payload, defaults = {}) {
98
162
  if (Array.isArray(payload)) {
99
163
  return {
@@ -168,6 +232,174 @@ export function writeDependencySnapshot(filePath, payload, defaults = {}) {
168
232
  return normalized;
169
233
  }
170
234
 
235
+ function normalizeProofArtifactEntry(entry) {
236
+ const source = isPlainObject(entry) ? entry : {};
237
+ return {
238
+ path: normalizeText(source.path, null),
239
+ kind: normalizeText(source.kind, null),
240
+ requiredFor: normalizeStringArray(source.requiredFor),
241
+ exists: source.exists === true,
242
+ sha256: normalizeText(source.sha256, null),
243
+ };
244
+ }
245
+
246
+ function normalizeProofComponentEntry(entry) {
247
+ const source = isPlainObject(entry) ? entry : {};
248
+ return {
249
+ componentId: normalizeText(source.componentId, null),
250
+ level: normalizeText(source.level, null),
251
+ state: normalizeText(source.state, null),
252
+ detail: normalizeText(source.detail, null),
253
+ };
254
+ }
255
+
256
+ function normalizeProofSummaryEntry(entry) {
257
+ const source = isPlainObject(entry) ? entry : {};
258
+ const state = normalizeText(source.state, null);
259
+ const completion = normalizeText(source.completion, null);
260
+ const durability = normalizeText(source.durability, null);
261
+ const proof = normalizeText(source.proof, null);
262
+ if (!state && !completion && !durability && !proof) {
263
+ return null;
264
+ }
265
+ return {
266
+ state,
267
+ completion,
268
+ durability,
269
+ proof,
270
+ detail: normalizeText(source.detail, null),
271
+ };
272
+ }
273
+
274
+ function normalizeDocDeltaEntry(entry) {
275
+ const source = isPlainObject(entry) ? entry : {};
276
+ const state = normalizeText(source.state, null);
277
+ if (!state) {
278
+ return null;
279
+ }
280
+ return {
281
+ state,
282
+ detail: normalizeText(source.detail, null),
283
+ };
284
+ }
285
+
286
+ function normalizeProofRegistryEntry(entry) {
287
+ const source = isPlainObject(entry) ? entry : {};
288
+ return {
289
+ id: normalizeText(source.id, null),
290
+ agentId: normalizeText(source.agentId, null),
291
+ state: normalizeText(source.state, null),
292
+ authoritative: source.authoritative === true,
293
+ recordedAt: normalizeText(source.recordedAt, toIsoTimestamp()),
294
+ recordedBy: normalizeText(source.recordedBy, null),
295
+ detail: normalizeText(source.detail, null),
296
+ summary: normalizeText(source.summary, null),
297
+ satisfyOwnedComponents: source.satisfyOwnedComponents === true,
298
+ proof: normalizeProofSummaryEntry(source.proof),
299
+ docDelta: normalizeDocDeltaEntry(source.docDelta),
300
+ components: (Array.isArray(source.components) ? source.components : [])
301
+ .map((item) => normalizeProofComponentEntry(item))
302
+ .filter((item) => item.componentId),
303
+ artifacts: (Array.isArray(source.artifacts) ? source.artifacts : [])
304
+ .map((item) => normalizeProofArtifactEntry(item))
305
+ .filter((item) => item.path),
306
+ scope: normalizeText(source.scope, null),
307
+ attestation: isPlainObject(source.attestation) ? cloneJson(source.attestation) : null,
308
+ satisfies: normalizeStringArray(source.satisfies),
309
+ supersedes: normalizeText(source.supersedes, null),
310
+ supersededBy: normalizeText(source.supersededBy, null),
311
+ };
312
+ }
313
+
314
+ export function normalizeProofRegistry(payload, defaults = {}) {
315
+ const source = isPlainObject(payload) ? payload : {};
316
+ return {
317
+ schemaVersion: PROOF_REGISTRY_SCHEMA_VERSION,
318
+ kind: PROOF_REGISTRY_KIND,
319
+ lane: normalizeText(source.lane, normalizeText(defaults.lane, null)),
320
+ wave: normalizeInteger(source.wave, normalizeInteger(defaults.wave, null)),
321
+ updatedAt: normalizeText(source.updatedAt, toIsoTimestamp()),
322
+ entries: (Array.isArray(source.entries) ? source.entries : [])
323
+ .map((entry) => normalizeProofRegistryEntry(entry))
324
+ .filter((entry) => entry.id && entry.agentId),
325
+ };
326
+ }
327
+
328
+ export function readProofRegistry(filePath, defaults = {}) {
329
+ const payload = readJsonOrNull(filePath);
330
+ if (!payload) {
331
+ return null;
332
+ }
333
+ return normalizeProofRegistry(payload, defaults);
334
+ }
335
+
336
+ export function writeProofRegistry(filePath, payload, defaults = {}) {
337
+ const normalized = normalizeProofRegistry(payload, defaults);
338
+ writeJsonAtomic(filePath, normalized);
339
+ return normalized;
340
+ }
341
+
342
+ export function normalizeWaveControlDeliveryState(payload, defaults = {}) {
343
+ const source = isPlainObject(payload) ? payload : {};
344
+ return {
345
+ schemaVersion: WAVE_CONTROL_DELIVERY_STATE_SCHEMA_VERSION,
346
+ kind: WAVE_CONTROL_DELIVERY_STATE_KIND,
347
+ workspaceId: normalizeText(source.workspaceId, normalizeText(defaults.workspaceId, null)),
348
+ lane: normalizeText(source.lane, normalizeText(defaults.lane, null)),
349
+ runId: normalizeText(source.runId, normalizeText(defaults.runId, null)),
350
+ runKind: normalizeWaveControlRunKind(
351
+ source.runKind,
352
+ "waveControlDeliveryState.runKind",
353
+ normalizeText(defaults.runKind, "unknown"),
354
+ ),
355
+ reportMode: normalizeWaveControlReportMode(
356
+ source.reportMode,
357
+ "waveControlDeliveryState.reportMode",
358
+ normalizeText(defaults.reportMode, "metadata-plus-selected"),
359
+ ),
360
+ endpoint: normalizeText(source.endpoint, normalizeText(defaults.endpoint, null)),
361
+ queuePath: normalizeText(source.queuePath, normalizeText(defaults.queuePath, null)),
362
+ eventsPath: normalizeText(source.eventsPath, normalizeText(defaults.eventsPath, null)),
363
+ pendingCount: normalizeNonNegativeInteger(
364
+ source.pendingCount,
365
+ normalizeNonNegativeInteger(defaults.pendingCount, 0),
366
+ ),
367
+ sentCount: normalizeNonNegativeInteger(
368
+ source.sentCount,
369
+ normalizeNonNegativeInteger(defaults.sentCount, 0),
370
+ ),
371
+ failedCount: normalizeNonNegativeInteger(
372
+ source.failedCount,
373
+ normalizeNonNegativeInteger(defaults.failedCount, 0),
374
+ ),
375
+ lastEnqueuedAt: normalizeText(source.lastEnqueuedAt, normalizeText(defaults.lastEnqueuedAt, null)),
376
+ lastFlushAt: normalizeText(source.lastFlushAt, normalizeText(defaults.lastFlushAt, null)),
377
+ lastSuccessAt: normalizeText(source.lastSuccessAt, normalizeText(defaults.lastSuccessAt, null)),
378
+ lastError:
379
+ source.lastError === undefined
380
+ ? defaults.lastError ?? null
381
+ : isPlainObject(source.lastError)
382
+ ? source.lastError
383
+ : normalizeText(source.lastError, null),
384
+ recentEventIds: normalizeStringArray(source.recentEventIds ?? defaults.recentEventIds),
385
+ updatedAt: normalizeText(source.updatedAt, normalizeText(defaults.updatedAt, toIsoTimestamp())),
386
+ };
387
+ }
388
+
389
+ export function readWaveControlDeliveryState(filePath, defaults = {}) {
390
+ const payload = readJsonOrNull(filePath);
391
+ if (!payload) {
392
+ return null;
393
+ }
394
+ return normalizeWaveControlDeliveryState(payload, defaults);
395
+ }
396
+
397
+ export function writeWaveControlDeliveryState(filePath, payload, defaults = {}) {
398
+ const normalized = normalizeWaveControlDeliveryState(payload, defaults);
399
+ writeJsonAtomic(filePath, normalized);
400
+ return normalized;
401
+ }
402
+
171
403
  export function cloneArtifactPayload(value) {
172
404
  return cloneJson(value);
173
405
  }
@@ -21,6 +21,10 @@ import {
21
21
  DEFAULT_CODEX_SANDBOX_MODE,
22
22
  normalizeCodexSandboxMode,
23
23
  } from "./launcher.mjs";
24
+ import {
25
+ maybeAnnouncePackageUpdate,
26
+ WAVE_SUPPRESS_UPDATE_NOTICE_ENV,
27
+ } from "./package-update-notice.mjs";
24
28
  import { readRunState } from "./wave-files.mjs";
25
29
  import { readDependencyTickets } from "./coordination-store.mjs";
26
30
  import { readWaveLedger } from "./ledger.mjs";
@@ -41,6 +45,7 @@ Options:
41
45
  Max backoff delay for 429 retries (default: ${DEFAULT_AGENT_RATE_LIMIT_MAX_DELAY_SECONDS})
42
46
  --agent-launch-stagger-ms <n> Delay between agent launches (default: ${DEFAULT_AGENT_LAUNCH_STAGGER_MS})
43
47
  --orchestrator-id <id> Orchestrator ID for coordination board
48
+ --resident-orchestrator Launch a resident orchestrator session for each live wave
44
49
  --executor <mode> Default executor passed to launcher: ${SUPPORTED_EXECUTOR_MODES.join(" | ")} (default: lane config)
45
50
  --codex-sandbox <mode> Default Codex sandbox mode passed to launcher (default: ${DEFAULT_CODEX_SANDBOX_MODE})
46
51
  --dashboard Enable dashboards (default: disabled)
@@ -60,6 +65,7 @@ export function parseArgs(argv) {
60
65
  agentRateLimitMaxDelaySeconds: DEFAULT_AGENT_RATE_LIMIT_MAX_DELAY_SECONDS,
61
66
  agentLaunchStaggerMs: DEFAULT_AGENT_LAUNCH_STAGGER_MS,
62
67
  orchestratorId: null,
68
+ residentOrchestrator: false,
63
69
  executorMode: DEFAULT_EXECUTOR_MODE,
64
70
  codexSandboxMode: DEFAULT_CODEX_SANDBOX_MODE,
65
71
  noDashboard: true,
@@ -99,6 +105,8 @@ export function parseArgs(argv) {
99
105
  options.agentLaunchStaggerMs = parseNonNegativeInt(argv[++i], "--agent-launch-stagger-ms");
100
106
  } else if (arg === "--orchestrator-id") {
101
107
  options.orchestratorId = String(argv[++i] || "").trim();
108
+ } else if (arg === "--resident-orchestrator") {
109
+ options.residentOrchestrator = true;
102
110
  } else if (arg === "--executor") {
103
111
  options.executorMode = normalizeExecutorMode(argv[++i], "--executor");
104
112
  executorProvided = true;
@@ -155,21 +163,30 @@ export function nextIncompleteWave(allWaves, completed) {
155
163
  return null;
156
164
  }
157
165
 
158
- function runCommand(args) {
166
+ function runCommand(args, envOverrides = {}) {
159
167
  const result = spawnSync("node", args, {
160
168
  cwd: REPO_ROOT,
161
169
  stdio: "inherit",
162
- env: process.env,
170
+ env: {
171
+ ...process.env,
172
+ ...envOverrides,
173
+ },
163
174
  });
164
175
  return Number.isInteger(result.status) ? result.status : 1;
165
176
  }
166
177
 
167
178
  function reconcile(lane) {
168
- return runCommand([path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"), "--lane", lane, "--reconcile-status"]);
179
+ return runCommand(
180
+ [path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"), "--lane", lane, "--reconcile-status"],
181
+ { [WAVE_SUPPRESS_UPDATE_NOTICE_ENV]: "1" },
182
+ );
169
183
  }
170
184
 
171
185
  function dryRun(lane) {
172
- return runCommand([path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"), "--lane", lane, "--dry-run", "--no-dashboard"]);
186
+ return runCommand(
187
+ [path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"), "--lane", lane, "--dry-run", "--no-dashboard"],
188
+ { [WAVE_SUPPRESS_UPDATE_NOTICE_ENV]: "1" },
189
+ );
173
190
  }
174
191
 
175
192
  function listPendingFeedback(lane) {
@@ -215,7 +232,10 @@ function launchSingleWave(params) {
215
232
  if (params.keepTerminals) {
216
233
  args.push("--keep-terminals");
217
234
  }
218
- return runCommand(args);
235
+ if (params.residentOrchestrator) {
236
+ args.push("--resident-orchestrator");
237
+ }
238
+ return runCommand(args, { [WAVE_SUPPRESS_UPDATE_NOTICE_ENV]: "1" });
219
239
  }
220
240
 
221
241
  function requiredInboundDependenciesOpen(lanePaths, lane) {
@@ -291,12 +311,13 @@ export function readAutonomousBarrier(lanePaths, lane, wave = null) {
291
311
  return null;
292
312
  }
293
313
 
294
- export function runAutonomousCli(argv) {
314
+ export async function runAutonomousCli(argv) {
295
315
  const parsed = parseArgs(argv);
296
316
  if (parsed.help) {
297
317
  printUsage();
298
318
  return;
299
319
  }
320
+ await maybeAnnouncePackageUpdate();
300
321
  const options = parsed.options;
301
322
  const allWaves = getWaveNumbers(options.lane);
302
323
  console.log(`[autonomous] lane=${options.lane} orchestrator=${options.orchestratorId}`);