@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
@@ -0,0 +1,297 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {
4
+ isOpenCoordinationStatus,
5
+ openClarificationLinkedRequests,
6
+ readMaterializedCoordinationState,
7
+ } from "./coordination-store.mjs";
8
+ import { readWaveHumanFeedbackRequests } from "./coordination.mjs";
9
+ import { readControlPlaneEvents } from "./control-plane.mjs";
10
+ import {
11
+ readWaveAssignmentBarrier,
12
+ readWaveDependencyBarrier,
13
+ readRunResultEnvelope,
14
+ } from "./gate-engine.mjs";
15
+ import { buildResumePlan } from "./retry-engine.mjs";
16
+ import { reduceWaveState } from "./wave-state-reducer.mjs";
17
+ import { resolveWaveRoleBindings } from "./role-helpers.mjs";
18
+ import {
19
+ readWaveStateSnapshot,
20
+ writeWaveStateSnapshot,
21
+ } from "./artifact-schemas.mjs";
22
+ import { ensureDirectory } from "./shared.mjs";
23
+
24
+ function normalizeShadowGate(gate) {
25
+ if (!gate || typeof gate !== "object") {
26
+ return null;
27
+ }
28
+ return {
29
+ ok: gate.ok === true,
30
+ agentId: gate.agentId || null,
31
+ componentId: gate.componentId || null,
32
+ statusCode: gate.statusCode || null,
33
+ detail: gate.detail || null,
34
+ waitingOnAgentIds: Array.isArray(gate.waitingOnAgentIds)
35
+ ? [...new Set(gate.waitingOnAgentIds.filter(Boolean))].sort()
36
+ : [],
37
+ };
38
+ }
39
+
40
+ function normalizeShadowIdList(values) {
41
+ return [...new Set((values || []).filter(Boolean))].sort();
42
+ }
43
+
44
+ function shadowSlice(compatibility, reducer) {
45
+ return {
46
+ matches: JSON.stringify(compatibility) === JSON.stringify(reducer),
47
+ compatibility,
48
+ reducer,
49
+ };
50
+ }
51
+
52
+ function contradictionIds(value) {
53
+ if (value instanceof Map) {
54
+ return [...value.keys()];
55
+ }
56
+ if (Array.isArray(value)) {
57
+ return value.map((entry) => entry?.contradictionId || entry?.id).filter(Boolean);
58
+ }
59
+ if (value && typeof value === "object") {
60
+ return Object.keys(value);
61
+ }
62
+ return [];
63
+ }
64
+
65
+ function compatibilityBlockerIds(derivedState) {
66
+ const coordinationState = derivedState?.coordinationState || {};
67
+ return normalizeShadowIdList([
68
+ ...(coordinationState.blockers || [])
69
+ .filter((record) => isOpenCoordinationStatus(record.status))
70
+ .map((record) => record.id),
71
+ ...(coordinationState.clarifications || [])
72
+ .filter((record) => isOpenCoordinationStatus(record.status))
73
+ .map((record) => record.id),
74
+ ...openClarificationLinkedRequests(coordinationState).map((record) => record.id),
75
+ ...(coordinationState.humanFeedback || [])
76
+ .filter((record) => isOpenCoordinationStatus(record.status))
77
+ .map((record) => record.id),
78
+ ...(coordinationState.humanEscalations || [])
79
+ .filter((record) => isOpenCoordinationStatus(record.status))
80
+ .map((record) => record.id),
81
+ ...((derivedState?.capabilityAssignments || [])
82
+ .filter((assignment) => assignment.blocking)
83
+ .map((assignment) => assignment.requestId || assignment.id)),
84
+ ...((derivedState?.dependencySnapshot?.requiredInbound || []).map((record) => record.id)),
85
+ ...((derivedState?.dependencySnapshot?.requiredOutbound || []).map((record) => record.id)),
86
+ ...((derivedState?.dependencySnapshot?.unresolvedInboundAssignments || []).map((record) => record.id)),
87
+ ]);
88
+ }
89
+
90
+ function buildReducerShadowDiff({
91
+ derivedState,
92
+ compatibilityGateSnapshot = null,
93
+ compatibilityRelaunchResolution = null,
94
+ reducerState,
95
+ resumePlan,
96
+ }) {
97
+ const helperCompatibility = compatibilityGateSnapshot
98
+ ? normalizeShadowGate(compatibilityGateSnapshot.helperAssignmentBarrier)
99
+ : normalizeShadowGate(readWaveAssignmentBarrier(derivedState));
100
+ const dependencyCompatibility = compatibilityGateSnapshot
101
+ ? normalizeShadowGate(compatibilityGateSnapshot.dependencyBarrier)
102
+ : normalizeShadowGate(readWaveDependencyBarrier(derivedState));
103
+ const overallCompatibility = compatibilityGateSnapshot
104
+ ? normalizeShadowGate(compatibilityGateSnapshot.overall)
105
+ : null;
106
+ const retryCompatibility = compatibilityRelaunchResolution
107
+ ? {
108
+ selectedAgentIds: normalizeShadowIdList(
109
+ (compatibilityRelaunchResolution.runs || []).map((run) => run.agent.agentId),
110
+ ),
111
+ barrier: compatibilityRelaunchResolution.barrier
112
+ ? {
113
+ statusCode: compatibilityRelaunchResolution.barrier.statusCode || null,
114
+ detail: compatibilityRelaunchResolution.barrier.detail || null,
115
+ }
116
+ : null,
117
+ }
118
+ : null;
119
+ const blockerCompatibility = compatibilityBlockerIds(derivedState);
120
+ const contradictionCompatibility = normalizeShadowIdList(
121
+ contradictionIds(derivedState?.contradictions),
122
+ );
123
+ const blockerReducer = normalizeShadowIdList(
124
+ (reducerState?.openBlockers || []).map(
125
+ (blocker) => blocker.id || blocker.taskId || blocker.title || blocker.detail,
126
+ ),
127
+ );
128
+ const contradictionReducer = normalizeShadowIdList(
129
+ contradictionIds(reducerState?.contradictions),
130
+ );
131
+ const retryReducer = {
132
+ selectedAgentIds: normalizeShadowIdList(
133
+ reducerState?.retryTargetSet?.agentIds || resumePlan?.invalidatedAgentIds || [],
134
+ ),
135
+ barrier:
136
+ reducerState?.gateSnapshot?.helperAssignmentBarrier?.ok === false
137
+ ? {
138
+ statusCode: reducerState.gateSnapshot.helperAssignmentBarrier.statusCode || null,
139
+ detail: reducerState.gateSnapshot.helperAssignmentBarrier.detail || null,
140
+ }
141
+ : reducerState?.gateSnapshot?.dependencyBarrier?.ok === false
142
+ ? {
143
+ statusCode: reducerState.gateSnapshot.dependencyBarrier.statusCode || null,
144
+ detail: reducerState.gateSnapshot.dependencyBarrier.detail || null,
145
+ }
146
+ : null,
147
+ resumeFromPhase: resumePlan?.resumeFromPhase || null,
148
+ };
149
+ const shadowDiff = {
150
+ helperAssignmentBarrier: shadowSlice(
151
+ helperCompatibility,
152
+ normalizeShadowGate(reducerState?.gateSnapshot?.helperAssignmentBarrier),
153
+ ),
154
+ dependencyBarrier: shadowSlice(
155
+ dependencyCompatibility,
156
+ normalizeShadowGate(reducerState?.gateSnapshot?.dependencyBarrier),
157
+ ),
158
+ overallGate: shadowSlice(
159
+ overallCompatibility,
160
+ normalizeShadowGate(reducerState?.gateSnapshot?.overall),
161
+ ),
162
+ blockers: shadowSlice(blockerCompatibility, blockerReducer),
163
+ contradictions: shadowSlice(contradictionCompatibility, contradictionReducer),
164
+ closureReadiness: shadowSlice(
165
+ overallCompatibility
166
+ ? { allGatesPass: overallCompatibility.ok === true }
167
+ : null,
168
+ {
169
+ allGatesPass: reducerState?.closureEligibility?.allGatesPass === true,
170
+ waveMayClose: reducerState?.closureEligibility?.waveMayClose === true,
171
+ pendingAgentIds: normalizeShadowIdList(
172
+ reducerState?.closureEligibility?.pendingAgentIds || [],
173
+ ),
174
+ },
175
+ ),
176
+ retryPlan: shadowSlice(retryCompatibility, retryReducer),
177
+ };
178
+ const comparedSlices = Object.values(shadowDiff).filter(
179
+ (slice) => slice.compatibility !== null && slice.reducer !== null,
180
+ );
181
+ return {
182
+ comparedSliceCount: comparedSlices.length,
183
+ matches: comparedSlices.every((slice) => slice.matches),
184
+ slices: shadowDiff,
185
+ };
186
+ }
187
+
188
+ export function computeReducerSnapshot({
189
+ lanePaths,
190
+ wave,
191
+ agentRuns,
192
+ derivedState,
193
+ attempt,
194
+ options = {},
195
+ compatibilityGateSnapshot = null,
196
+ compatibilityRelaunchResolution = null,
197
+ }) {
198
+ const agentEnvelopes = {};
199
+ for (const run of agentRuns) {
200
+ const envelopeResult = readRunResultEnvelope(run, wave, { mode: "live" });
201
+ if (envelopeResult?.valid && envelopeResult.envelope) {
202
+ agentEnvelopes[run.agent.agentId] = envelopeResult.envelope;
203
+ }
204
+ }
205
+
206
+ const controlPlaneLogPath = path.join(
207
+ lanePaths.controlPlaneDir,
208
+ `wave-${wave.wave}.jsonl`,
209
+ );
210
+ const controlPlaneEvents = fs.existsSync(controlPlaneLogPath)
211
+ ? readControlPlaneEvents(controlPlaneLogPath)
212
+ : [];
213
+
214
+ const coordinationLogPath = path.join(
215
+ lanePaths.coordinationDir,
216
+ `wave-${wave.wave}.jsonl`,
217
+ );
218
+ const coordinationRecords = fs.existsSync(coordinationLogPath)
219
+ ? readMaterializedCoordinationState(coordinationLogPath)
220
+ : null;
221
+
222
+ const feedbackRequests = readWaveHumanFeedbackRequests({
223
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
224
+ lane: lanePaths.lane,
225
+ waveNumber: wave.wave,
226
+ agentIds: (agentRuns || []).map((run) => run.agent.agentId),
227
+ orchestratorId: options.orchestratorId,
228
+ });
229
+ const roleBindings = resolveWaveRoleBindings(wave, lanePaths, wave.agents);
230
+
231
+ const reducerState = reduceWaveState({
232
+ controlPlaneEvents,
233
+ coordinationRecords: coordinationRecords?.latestRecords || [],
234
+ agentEnvelopes,
235
+ waveDefinition: wave,
236
+ dependencyTickets: derivedState?.dependencySnapshot || null,
237
+ feedbackRequests: feedbackRequests || [],
238
+ laneConfig: {
239
+ lane: lanePaths.lane,
240
+ contQaAgentId: roleBindings.contQaAgentId,
241
+ contEvalAgentId: roleBindings.contEvalAgentId,
242
+ integrationAgentId: roleBindings.integrationAgentId,
243
+ documentationAgentId: roleBindings.documentationAgentId,
244
+ validationMode: "live",
245
+ evalTargets: wave.evalTargets,
246
+ benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
247
+ laneProfile: lanePaths.laneProfile,
248
+ requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
249
+ capabilityRouting: lanePaths.capabilityRouting,
250
+ },
251
+ });
252
+
253
+ const resumePlan = buildResumePlan(reducerState, {
254
+ waveDefinition: wave,
255
+ lanePaths,
256
+ });
257
+ const shadowDiff = buildReducerShadowDiff({
258
+ derivedState,
259
+ compatibilityGateSnapshot,
260
+ compatibilityRelaunchResolution,
261
+ reducerState,
262
+ resumePlan,
263
+ });
264
+
265
+ const stateDir = path.join(lanePaths.stateDir, "reducer");
266
+ ensureDirectory(stateDir);
267
+ const snapshotPath = path.join(stateDir, `wave-${wave.wave}.json`);
268
+ writeWaveStateSnapshot(
269
+ snapshotPath,
270
+ {
271
+ ...reducerState,
272
+ attempt,
273
+ resumePlan,
274
+ shadowDiff,
275
+ },
276
+ {
277
+ lane: lanePaths.lane,
278
+ wave: wave.wave,
279
+ },
280
+ );
281
+
282
+ return {
283
+ reducerState,
284
+ resumePlan,
285
+ shadowDiff,
286
+ snapshotPath,
287
+ };
288
+ }
289
+
290
+ export function readPersistedReducerSnapshot(lanePaths, waveNumber) {
291
+ const stateDir = path.join(lanePaths.stateDir, "reducer");
292
+ const snapshotPath = path.join(stateDir, `wave-${waveNumber}.json`);
293
+ return readWaveStateSnapshot(snapshotPath, {
294
+ lane: lanePaths.lane,
295
+ wave: waveNumber,
296
+ });
297
+ }
@@ -1,7 +1,8 @@
1
1
  import path from "node:path";
2
2
  import { augmentSummaryWithProofRegistry } from "./proof-registry.mjs";
3
3
  import { readJsonOrNull } from "./shared.mjs";
4
- import { buildGateSnapshot } from "./launcher.mjs";
4
+ import { buildGateSnapshot } from "./gate-engine.mjs";
5
+ import { materializeContradictionsFromControlPlaneEvents } from "./contradiction-entity.mjs";
5
6
  import {
6
7
  buildQualityMetrics,
7
8
  loadTraceBundle,
@@ -188,6 +189,7 @@ export function replayTraceBundle(dir) {
188
189
  capabilityAssignments: bundle.capabilityAssignments || [],
189
190
  dependencySnapshot: bundle.dependencySnapshot || null,
190
191
  integrationSummary: bundle.integrationSummary,
192
+ contradictions: materializeContradictionsFromControlPlaneEvents(bundle.controlPlaneEvents),
191
193
  };
192
194
  const gateSnapshot = normalizeGateSnapshotForBundle(
193
195
  buildGateSnapshot({