@chllming/wave-orchestration 0.5.1

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 (68) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +549 -0
  3. package/docs/agents/wave-deploy-verifier-role.md +34 -0
  4. package/docs/agents/wave-documentation-role.md +30 -0
  5. package/docs/agents/wave-evaluator-role.md +43 -0
  6. package/docs/agents/wave-infra-role.md +34 -0
  7. package/docs/agents/wave-integration-role.md +32 -0
  8. package/docs/agents/wave-launcher-role.md +37 -0
  9. package/docs/context7/bundles.json +91 -0
  10. package/docs/plans/component-cutover-matrix.json +112 -0
  11. package/docs/plans/component-cutover-matrix.md +49 -0
  12. package/docs/plans/context7-wave-orchestrator.md +130 -0
  13. package/docs/plans/current-state.md +44 -0
  14. package/docs/plans/master-plan.md +16 -0
  15. package/docs/plans/migration.md +23 -0
  16. package/docs/plans/wave-orchestrator.md +254 -0
  17. package/docs/plans/waves/wave-0.md +165 -0
  18. package/docs/reference/github-packages-setup.md +52 -0
  19. package/docs/reference/migration-0.2-to-0.5.md +622 -0
  20. package/docs/reference/npmjs-trusted-publishing.md +55 -0
  21. package/docs/reference/repository-guidance.md +18 -0
  22. package/docs/reference/runtime-config/README.md +85 -0
  23. package/docs/reference/runtime-config/claude.md +105 -0
  24. package/docs/reference/runtime-config/codex.md +81 -0
  25. package/docs/reference/runtime-config/opencode.md +93 -0
  26. package/docs/research/agent-context-sources.md +57 -0
  27. package/docs/roadmap.md +626 -0
  28. package/package.json +53 -0
  29. package/releases/manifest.json +101 -0
  30. package/scripts/context7-api-check.sh +21 -0
  31. package/scripts/context7-export-env.sh +52 -0
  32. package/scripts/research/agent-context-archive.mjs +472 -0
  33. package/scripts/research/generate-agent-context-indexes.mjs +85 -0
  34. package/scripts/research/import-agent-context-archive.mjs +793 -0
  35. package/scripts/research/manifests/harness-and-blackboard-2026-03-21.mjs +201 -0
  36. package/scripts/wave-autonomous.mjs +13 -0
  37. package/scripts/wave-cli-bootstrap.mjs +27 -0
  38. package/scripts/wave-dashboard.mjs +11 -0
  39. package/scripts/wave-human-feedback.mjs +11 -0
  40. package/scripts/wave-launcher.mjs +11 -0
  41. package/scripts/wave-local-executor.mjs +13 -0
  42. package/scripts/wave-orchestrator/agent-state.mjs +416 -0
  43. package/scripts/wave-orchestrator/autonomous.mjs +367 -0
  44. package/scripts/wave-orchestrator/clarification-triage.mjs +605 -0
  45. package/scripts/wave-orchestrator/config.mjs +848 -0
  46. package/scripts/wave-orchestrator/context7.mjs +464 -0
  47. package/scripts/wave-orchestrator/coord-cli.mjs +286 -0
  48. package/scripts/wave-orchestrator/coordination-store.mjs +987 -0
  49. package/scripts/wave-orchestrator/coordination.mjs +768 -0
  50. package/scripts/wave-orchestrator/dashboard-renderer.mjs +254 -0
  51. package/scripts/wave-orchestrator/dashboard-state.mjs +473 -0
  52. package/scripts/wave-orchestrator/dep-cli.mjs +219 -0
  53. package/scripts/wave-orchestrator/docs-queue.mjs +75 -0
  54. package/scripts/wave-orchestrator/executors.mjs +385 -0
  55. package/scripts/wave-orchestrator/feedback.mjs +372 -0
  56. package/scripts/wave-orchestrator/install.mjs +540 -0
  57. package/scripts/wave-orchestrator/launcher.mjs +3879 -0
  58. package/scripts/wave-orchestrator/ledger.mjs +332 -0
  59. package/scripts/wave-orchestrator/local-executor.mjs +263 -0
  60. package/scripts/wave-orchestrator/replay.mjs +246 -0
  61. package/scripts/wave-orchestrator/roots.mjs +10 -0
  62. package/scripts/wave-orchestrator/routing-state.mjs +542 -0
  63. package/scripts/wave-orchestrator/shared.mjs +405 -0
  64. package/scripts/wave-orchestrator/terminals.mjs +209 -0
  65. package/scripts/wave-orchestrator/traces.mjs +1094 -0
  66. package/scripts/wave-orchestrator/wave-files.mjs +1923 -0
  67. package/scripts/wave.mjs +103 -0
  68. package/wave.config.json +115 -0
@@ -0,0 +1,416 @@
1
+ import path from "node:path";
2
+ import {
3
+ REPO_ROOT,
4
+ REPORT_VERDICT_REGEX,
5
+ WAVE_VERDICT_REGEX,
6
+ parseVerdictFromText,
7
+ readFileTail,
8
+ readJsonOrNull,
9
+ writeJsonAtomic,
10
+ } from "./shared.mjs";
11
+
12
+ export const EXIT_CONTRACT_COMPLETION_VALUES = ["contract", "integrated", "authoritative", "live"];
13
+ export const EXIT_CONTRACT_DURABILITY_VALUES = ["none", "ephemeral", "durable"];
14
+ export const EXIT_CONTRACT_PROOF_VALUES = ["unit", "integration", "live"];
15
+ export const EXIT_CONTRACT_DOC_IMPACT_VALUES = ["none", "owned", "shared-plan"];
16
+
17
+ const ORDER = (values) => Object.fromEntries(values.map((value, index) => [value, index]));
18
+ const COMPLETION_ORDER = ORDER(EXIT_CONTRACT_COMPLETION_VALUES);
19
+ const DURABILITY_ORDER = ORDER(EXIT_CONTRACT_DURABILITY_VALUES);
20
+ const PROOF_ORDER = ORDER(EXIT_CONTRACT_PROOF_VALUES);
21
+ const DOC_IMPACT_ORDER = ORDER(EXIT_CONTRACT_DOC_IMPACT_VALUES);
22
+
23
+ const WAVE_PROOF_REGEX =
24
+ /^\[wave-proof\]\s*completion=(contract|integrated|authoritative|live)\s+durability=(none|ephemeral|durable)\s+proof=(unit|integration|live)\s+state=(met|gap)\s*(?:detail=(.*))?$/gim;
25
+ const WAVE_DOC_DELTA_REGEX =
26
+ /^\[wave-doc-delta\]\s*state=(none|owned|shared-plan)(?:\s+paths=([^\n]*?))?(?:\s+detail=(.*))?$/gim;
27
+ const WAVE_DOC_CLOSURE_REGEX =
28
+ /^\[wave-doc-closure\]\s*state=(closed|no-change|delta)(?:\s+paths=([^\n]*?))?(?:\s+detail=(.*))?$/gim;
29
+ const WAVE_INTEGRATION_REGEX =
30
+ /^\[wave-integration\]\s*state=(ready-for-doc-closure|needs-more-work)\s+claims=(\d+)\s+conflicts=(\d+)\s+blockers=(\d+)\s*(?:detail=(.*))?$/gim;
31
+ const WAVE_GATE_REGEX =
32
+ /^\[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;
33
+ const WAVE_GAP_REGEX =
34
+ /^\[wave-gap\]\s*kind=(architecture|integration|durability|ops|docs)\s*(?:detail=(.*))?$/gim;
35
+ const WAVE_COMPONENT_REGEX =
36
+ /^\[wave-component\]\s*component=([a-z0-9._-]+)\s+level=([a-z0-9._-]+)\s+state=(met|gap)\s*(?:detail=(.*))?$/gim;
37
+
38
+ function cleanText(value) {
39
+ return String(value || "").trim();
40
+ }
41
+
42
+ function parsePaths(value) {
43
+ return cleanText(value)
44
+ .split(",")
45
+ .map((item) => item.trim())
46
+ .filter(Boolean);
47
+ }
48
+
49
+ function findLastMatch(text, regex, mapper) {
50
+ if (!text) {
51
+ return null;
52
+ }
53
+ regex.lastIndex = 0;
54
+ let match = regex.exec(text);
55
+ let result = null;
56
+ while (match !== null) {
57
+ result = mapper(match);
58
+ match = regex.exec(text);
59
+ }
60
+ return result;
61
+ }
62
+
63
+ function findAllMatches(text, regex, mapper) {
64
+ if (!text) {
65
+ return [];
66
+ }
67
+ regex.lastIndex = 0;
68
+ const out = [];
69
+ let match = regex.exec(text);
70
+ while (match !== null) {
71
+ out.push(mapper(match));
72
+ match = regex.exec(text);
73
+ }
74
+ return out;
75
+ }
76
+
77
+ function findLatestComponentMatches(text) {
78
+ const matches = findAllMatches(text, WAVE_COMPONENT_REGEX, (match) => ({
79
+ componentId: match[1],
80
+ level: match[2],
81
+ state: match[3],
82
+ detail: cleanText(match[4]),
83
+ }));
84
+ const byComponent = new Map();
85
+ for (const match of matches) {
86
+ byComponent.set(match.componentId, match);
87
+ }
88
+ return Array.from(byComponent.values());
89
+ }
90
+
91
+ function meetsOrExceeds(actual, required, orderMap) {
92
+ if (!required) {
93
+ return true;
94
+ }
95
+ if (!actual || !(actual in orderMap) || !(required in orderMap)) {
96
+ return false;
97
+ }
98
+ return orderMap[actual] >= orderMap[required];
99
+ }
100
+
101
+ export function normalizeExitContract(raw) {
102
+ if (!raw || typeof raw !== "object") {
103
+ return null;
104
+ }
105
+ const completion = cleanText(raw.completion);
106
+ const durability = cleanText(raw.durability);
107
+ const proof = cleanText(raw.proof);
108
+ const docImpact = cleanText(raw.docImpact || raw["doc-impact"]);
109
+ if (!completion && !durability && !proof && !docImpact) {
110
+ return null;
111
+ }
112
+ return {
113
+ completion: completion || null,
114
+ durability: durability || null,
115
+ proof: proof || null,
116
+ docImpact: docImpact || null,
117
+ };
118
+ }
119
+
120
+ export function validateExitContractShape(contract) {
121
+ if (!contract) {
122
+ return [];
123
+ }
124
+ const errors = [];
125
+ if (!EXIT_CONTRACT_COMPLETION_VALUES.includes(contract.completion)) {
126
+ errors.push(`completion must be one of ${EXIT_CONTRACT_COMPLETION_VALUES.join(", ")}`);
127
+ }
128
+ if (!EXIT_CONTRACT_DURABILITY_VALUES.includes(contract.durability)) {
129
+ errors.push(`durability must be one of ${EXIT_CONTRACT_DURABILITY_VALUES.join(", ")}`);
130
+ }
131
+ if (!EXIT_CONTRACT_PROOF_VALUES.includes(contract.proof)) {
132
+ errors.push(`proof must be one of ${EXIT_CONTRACT_PROOF_VALUES.join(", ")}`);
133
+ }
134
+ if (!EXIT_CONTRACT_DOC_IMPACT_VALUES.includes(contract.docImpact)) {
135
+ errors.push(`doc-impact must be one of ${EXIT_CONTRACT_DOC_IMPACT_VALUES.join(", ")}`);
136
+ }
137
+ return errors;
138
+ }
139
+
140
+ export function agentSummaryPathFromStatusPath(statusPath) {
141
+ return statusPath.endsWith(".status")
142
+ ? statusPath.replace(/\.status$/i, ".summary.json")
143
+ : `${statusPath}.summary.json`;
144
+ }
145
+
146
+ export function readAgentExecutionSummary(summaryPathOrStatusPath) {
147
+ const summaryPath = summaryPathOrStatusPath.endsWith(".summary.json")
148
+ ? summaryPathOrStatusPath
149
+ : agentSummaryPathFromStatusPath(summaryPathOrStatusPath);
150
+ const payload = readJsonOrNull(summaryPath);
151
+ return payload && typeof payload === "object" ? payload : null;
152
+ }
153
+
154
+ export function buildAgentExecutionSummary({ agent, statusRecord, logPath, reportPath = null }) {
155
+ const logText = readFileTail(logPath, 60000);
156
+ const reportText =
157
+ reportPath && readJsonOrNull(reportPath) === null
158
+ ? readFileTail(reportPath, 60000)
159
+ : reportPath
160
+ ? readFileTail(reportPath, 60000)
161
+ : "";
162
+ const reportVerdict = parseVerdictFromText(reportText, REPORT_VERDICT_REGEX);
163
+ const logVerdict = parseVerdictFromText(logText, WAVE_VERDICT_REGEX);
164
+ const verdict = reportVerdict.verdict ? reportVerdict : logVerdict;
165
+ return {
166
+ agentId: agent?.agentId || null,
167
+ promptHash: statusRecord?.promptHash || null,
168
+ exitCode: Number.isFinite(Number(statusRecord?.code)) ? Number(statusRecord.code) : null,
169
+ completedAt: statusRecord?.completedAt || null,
170
+ proof: findLastMatch(logText, WAVE_PROOF_REGEX, (match) => ({
171
+ completion: match[1],
172
+ durability: match[2],
173
+ proof: match[3],
174
+ state: match[4],
175
+ detail: cleanText(match[5]),
176
+ })),
177
+ docDelta: findLastMatch(logText, WAVE_DOC_DELTA_REGEX, (match) => ({
178
+ state: match[1],
179
+ paths: parsePaths(match[2]),
180
+ detail: cleanText(match[3]),
181
+ })),
182
+ docClosure: findLastMatch(logText, WAVE_DOC_CLOSURE_REGEX, (match) => ({
183
+ state: match[1],
184
+ paths: parsePaths(match[2]),
185
+ detail: cleanText(match[3]),
186
+ })),
187
+ integration: findLastMatch(logText, WAVE_INTEGRATION_REGEX, (match) => ({
188
+ state: match[1],
189
+ claims: Number.parseInt(String(match[2] || "0"), 10) || 0,
190
+ conflicts: Number.parseInt(String(match[3] || "0"), 10) || 0,
191
+ blockers: Number.parseInt(String(match[4] || "0"), 10) || 0,
192
+ detail: cleanText(match[5]),
193
+ })),
194
+ gate: findLastMatch(logText, WAVE_GATE_REGEX, (match) => ({
195
+ architecture: match[1],
196
+ integration: match[2],
197
+ durability: match[3],
198
+ live: match[4],
199
+ docs: match[5],
200
+ detail: cleanText(match[6]),
201
+ })),
202
+ components: findLatestComponentMatches(logText),
203
+ gaps: findAllMatches(logText, WAVE_GAP_REGEX, (match) => ({
204
+ kind: match[1],
205
+ detail: cleanText(match[2]),
206
+ })),
207
+ verdict: verdict.verdict
208
+ ? {
209
+ verdict: verdict.verdict,
210
+ detail: cleanText(verdict.detail),
211
+ }
212
+ : null,
213
+ logPath: path.relative(REPO_ROOT, logPath),
214
+ reportPath: reportPath ? path.relative(REPO_ROOT, reportPath) : null,
215
+ };
216
+ }
217
+
218
+ export function writeAgentExecutionSummary(summaryPathOrStatusPath, summary) {
219
+ const summaryPath = summaryPathOrStatusPath.endsWith(".summary.json")
220
+ ? summaryPathOrStatusPath
221
+ : agentSummaryPathFromStatusPath(summaryPathOrStatusPath);
222
+ writeJsonAtomic(summaryPath, summary);
223
+ return summaryPath;
224
+ }
225
+
226
+ export function validateImplementationSummary(agent, summary) {
227
+ const contract = normalizeExitContract(agent?.exitContract);
228
+ if (!contract) {
229
+ return { ok: true, statusCode: "pass", detail: "No exit contract declared." };
230
+ }
231
+ if (!summary) {
232
+ return {
233
+ ok: false,
234
+ statusCode: "missing-summary",
235
+ detail: `Missing execution summary for ${agent.agentId}.`,
236
+ };
237
+ }
238
+ if (!summary.proof) {
239
+ return {
240
+ ok: false,
241
+ statusCode: "missing-wave-proof",
242
+ detail: `Missing [wave-proof] marker for ${agent.agentId}.`,
243
+ };
244
+ }
245
+ if (summary.proof.state !== "met") {
246
+ return {
247
+ ok: false,
248
+ statusCode: "wave-proof-gap",
249
+ detail: `Agent ${agent.agentId} reported a proof gap${summary.proof.detail ? `: ${summary.proof.detail}` : "."}`,
250
+ };
251
+ }
252
+ if (!meetsOrExceeds(summary.proof.completion, contract.completion, COMPLETION_ORDER)) {
253
+ return {
254
+ ok: false,
255
+ statusCode: "completion-gap",
256
+ detail: `Agent ${agent.agentId} only proved ${summary.proof.completion}; exit contract requires ${contract.completion}.`,
257
+ };
258
+ }
259
+ if (!meetsOrExceeds(summary.proof.durability, contract.durability, DURABILITY_ORDER)) {
260
+ return {
261
+ ok: false,
262
+ statusCode: "durability-gap",
263
+ detail: `Agent ${agent.agentId} only proved ${summary.proof.durability} durability; exit contract requires ${contract.durability}.`,
264
+ };
265
+ }
266
+ if (!meetsOrExceeds(summary.proof.proof, contract.proof, PROOF_ORDER)) {
267
+ return {
268
+ ok: false,
269
+ statusCode: "proof-level-gap",
270
+ detail: `Agent ${agent.agentId} only proved ${summary.proof.proof}; exit contract requires ${contract.proof}.`,
271
+ };
272
+ }
273
+ if (!summary.docDelta) {
274
+ return {
275
+ ok: false,
276
+ statusCode: "missing-doc-delta",
277
+ detail: `Missing [wave-doc-delta] marker for ${agent.agentId}.`,
278
+ };
279
+ }
280
+ if (!meetsOrExceeds(summary.docDelta.state, contract.docImpact, DOC_IMPACT_ORDER)) {
281
+ return {
282
+ ok: false,
283
+ statusCode: "doc-impact-gap",
284
+ detail: `Agent ${agent.agentId} only reported ${summary.docDelta.state} doc impact; exit contract requires ${contract.docImpact}.`,
285
+ };
286
+ }
287
+ const ownedComponents = Array.isArray(agent?.components) ? agent.components : [];
288
+ if (ownedComponents.length > 0) {
289
+ const componentMarkers = new Map(
290
+ Array.isArray(summary.components)
291
+ ? summary.components.map((component) => [component.componentId, component])
292
+ : [],
293
+ );
294
+ for (const componentId of ownedComponents) {
295
+ const marker = componentMarkers.get(componentId);
296
+ if (!marker) {
297
+ return {
298
+ ok: false,
299
+ statusCode: "missing-wave-component",
300
+ detail: `Missing [wave-component] marker for ${agent.agentId} component ${componentId}.`,
301
+ };
302
+ }
303
+ const expectedLevel = agent?.componentTargets?.[componentId] || null;
304
+ if (expectedLevel && marker.level !== expectedLevel) {
305
+ return {
306
+ ok: false,
307
+ statusCode: "component-level-mismatch",
308
+ detail: `Agent ${agent.agentId} reported ${componentId} at ${marker.level}; wave requires ${expectedLevel}.`,
309
+ };
310
+ }
311
+ if (marker.state !== "met") {
312
+ return {
313
+ ok: false,
314
+ statusCode: "component-gap",
315
+ detail:
316
+ marker.detail ||
317
+ `Agent ${agent.agentId} reported a component gap for ${componentId}.`,
318
+ };
319
+ }
320
+ }
321
+ }
322
+ return {
323
+ ok: true,
324
+ statusCode: "pass",
325
+ detail: `Exit contract satisfied for ${agent.agentId}.`,
326
+ };
327
+ }
328
+
329
+ export function validateDocumentationClosureSummary(agent, summary) {
330
+ if (!summary?.docClosure) {
331
+ return {
332
+ ok: false,
333
+ statusCode: "missing-doc-closure",
334
+ detail: `Missing [wave-doc-closure] marker for ${agent?.agentId || "A9"}.`,
335
+ };
336
+ }
337
+ if (summary.docClosure.state === "delta") {
338
+ return {
339
+ ok: false,
340
+ statusCode: "doc-closure-open",
341
+ detail: `Documentation steward still reports open shared-plan delta${summary.docClosure.detail ? `: ${summary.docClosure.detail}` : "."}`,
342
+ };
343
+ }
344
+ return {
345
+ ok: true,
346
+ statusCode: "pass",
347
+ detail:
348
+ summary.docClosure.state === "closed"
349
+ ? "Documentation steward closed the shared-plan delta."
350
+ : "Documentation steward confirmed no shared-plan changes were needed.",
351
+ };
352
+ }
353
+
354
+ export function validateIntegrationSummary(agent, summary) {
355
+ if (!summary?.integration) {
356
+ return {
357
+ ok: false,
358
+ statusCode: "missing-wave-integration",
359
+ detail: `Missing [wave-integration] marker for ${agent?.agentId || "A8"}.`,
360
+ };
361
+ }
362
+ if (summary.integration.state !== "ready-for-doc-closure") {
363
+ return {
364
+ ok: false,
365
+ statusCode: "integration-needs-more-work",
366
+ detail:
367
+ summary.integration.detail ||
368
+ `Integration steward reported ${summary.integration.state}.`,
369
+ };
370
+ }
371
+ return {
372
+ ok: true,
373
+ statusCode: "pass",
374
+ detail: summary.integration.detail || "Integration summary is ready for doc closure.",
375
+ };
376
+ }
377
+
378
+ export function validateEvaluatorSummary(agent, summary) {
379
+ if (!summary?.gate) {
380
+ return {
381
+ ok: false,
382
+ statusCode: "missing-wave-gate",
383
+ detail: `Missing [wave-gate] marker for ${agent?.agentId || "A0"}.`,
384
+ };
385
+ }
386
+ if (!summary?.verdict?.verdict) {
387
+ return {
388
+ ok: false,
389
+ statusCode: "missing-evaluator-verdict",
390
+ detail: `Missing Verdict line or [wave-verdict] marker for ${agent?.agentId || "A0"}.`,
391
+ };
392
+ }
393
+ if (summary.verdict.verdict !== "pass") {
394
+ return {
395
+ ok: false,
396
+ statusCode: `evaluator-${summary.verdict.verdict}`,
397
+ detail: summary.verdict.detail || "Verdict read from evaluator report.",
398
+ };
399
+ }
400
+ for (const key of ["architecture", "integration", "durability", "live", "docs"]) {
401
+ if (summary.gate[key] !== "pass") {
402
+ return {
403
+ ok: false,
404
+ statusCode: `gate-${key}-${summary.gate[key]}`,
405
+ detail:
406
+ summary.gate.detail ||
407
+ `Final evaluator gate did not pass ${key}; got ${summary.gate[key]}.`,
408
+ };
409
+ }
410
+ }
411
+ return {
412
+ ok: true,
413
+ statusCode: "pass",
414
+ detail: summary.verdict.detail || summary.gate.detail || "Evaluator gate passed.",
415
+ };
416
+ }