@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,987 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import {
5
+ REPO_ROOT,
6
+ compactSingleLine,
7
+ ensureDirectory,
8
+ readJsonOrNull,
9
+ toIsoTimestamp,
10
+ truncate,
11
+ writeTextAtomic,
12
+ } from "./shared.mjs";
13
+
14
+ export const COORDINATION_KIND_VALUES = [
15
+ "request",
16
+ "ack",
17
+ "claim",
18
+ "evidence",
19
+ "decision",
20
+ "blocker",
21
+ "handoff",
22
+ "clarification-request",
23
+ "orchestrator-guidance",
24
+ "resolved-by-policy",
25
+ "human-escalation",
26
+ "human-feedback",
27
+ "integration-summary",
28
+ ];
29
+
30
+ export const COORDINATION_STATUS_VALUES = [
31
+ "open",
32
+ "acknowledged",
33
+ "in_progress",
34
+ "resolved",
35
+ "closed",
36
+ "superseded",
37
+ "cancelled",
38
+ ];
39
+
40
+ export const COORDINATION_PRIORITY_VALUES = ["low", "normal", "high", "urgent"];
41
+ export const COORDINATION_CONFIDENCE_VALUES = ["low", "medium", "high"];
42
+ const OPEN_COORDINATION_STATUSES = new Set(["open", "acknowledged", "in_progress"]);
43
+ export const CLARIFICATION_CLOSURE_PREFIX = "clarification:";
44
+
45
+ function normalizeString(value, fallback = "") {
46
+ const normalized = String(value ?? "")
47
+ .trim();
48
+ return normalized || fallback;
49
+ }
50
+
51
+ function normalizeStringArray(values) {
52
+ if (!Array.isArray(values)) {
53
+ return [];
54
+ }
55
+ return Array.from(
56
+ new Set(
57
+ values
58
+ .map((value) => normalizeString(value))
59
+ .filter(Boolean),
60
+ ),
61
+ );
62
+ }
63
+
64
+ function validateEnum(value, allowed, label) {
65
+ if (!allowed.includes(value)) {
66
+ throw new Error(`${label} must be one of ${allowed.join(", ")} (got: ${value || "empty"})`);
67
+ }
68
+ }
69
+
70
+ function stableId(prefix) {
71
+ return `${prefix}-${crypto.randomBytes(4).toString("hex")}`;
72
+ }
73
+
74
+ export function normalizeCoordinationRecord(rawRecord, defaults = {}) {
75
+ if (!rawRecord || typeof rawRecord !== "object" || Array.isArray(rawRecord)) {
76
+ throw new Error("Coordination record must be an object");
77
+ }
78
+ const now = toIsoTimestamp();
79
+ const id =
80
+ normalizeString(rawRecord.id) ||
81
+ normalizeString(defaults.id) ||
82
+ stableId(`coord-${normalizeString(rawRecord.kind || defaults.kind || "record", "record")}`);
83
+ const kind = normalizeString(rawRecord.kind || defaults.kind).toLowerCase();
84
+ const lane = normalizeString(rawRecord.lane || defaults.lane);
85
+ const wave = Number.parseInt(String(rawRecord.wave ?? defaults.wave ?? ""), 10);
86
+ const agentId = normalizeString(rawRecord.agentId || defaults.agentId);
87
+ const status = normalizeString(rawRecord.status || defaults.status || "open").toLowerCase();
88
+ const priority = normalizeString(rawRecord.priority || defaults.priority || "normal").toLowerCase();
89
+ const confidence = normalizeString(rawRecord.confidence || defaults.confidence || "medium").toLowerCase();
90
+ const createdAt = normalizeString(rawRecord.createdAt || defaults.createdAt || now);
91
+ const updatedAt = normalizeString(rawRecord.updatedAt || defaults.updatedAt || createdAt);
92
+ validateEnum(kind, COORDINATION_KIND_VALUES, "Coordination kind");
93
+ validateEnum(status, COORDINATION_STATUS_VALUES, "Coordination status");
94
+ validateEnum(priority, COORDINATION_PRIORITY_VALUES, "Coordination priority");
95
+ validateEnum(confidence, COORDINATION_CONFIDENCE_VALUES, "Coordination confidence");
96
+ if (!lane) {
97
+ throw new Error("Coordination lane is required");
98
+ }
99
+ if (!Number.isFinite(wave) || wave < 0) {
100
+ throw new Error(`Coordination wave must be a non-negative integer (got: ${rawRecord.wave})`);
101
+ }
102
+ if (!agentId) {
103
+ throw new Error("Coordination agentId is required");
104
+ }
105
+ return {
106
+ recordVersion: 1,
107
+ id,
108
+ kind,
109
+ wave,
110
+ lane,
111
+ agentId,
112
+ targets: normalizeStringArray(rawRecord.targets ?? defaults.targets),
113
+ status,
114
+ priority,
115
+ artifactRefs: normalizeStringArray(rawRecord.artifactRefs ?? defaults.artifactRefs),
116
+ dependsOn: normalizeStringArray(rawRecord.dependsOn ?? defaults.dependsOn),
117
+ closureCondition: normalizeString(rawRecord.closureCondition ?? defaults.closureCondition, ""),
118
+ createdAt,
119
+ updatedAt,
120
+ confidence,
121
+ summary: normalizeString(rawRecord.summary ?? defaults.summary),
122
+ detail: normalizeString(rawRecord.detail ?? defaults.detail),
123
+ attempt:
124
+ rawRecord.attempt === null || rawRecord.attempt === undefined || rawRecord.attempt === ""
125
+ ? defaults.attempt ?? null
126
+ : Number.parseInt(String(rawRecord.attempt), 10),
127
+ source: normalizeString(rawRecord.source ?? defaults.source, "launcher"),
128
+ executorId: normalizeString(rawRecord.executorId ?? defaults.executorId, ""),
129
+ requesterLane: normalizeString(rawRecord.requesterLane ?? defaults.requesterLane, ""),
130
+ ownerLane: normalizeString(rawRecord.ownerLane ?? defaults.ownerLane, ""),
131
+ requesterWave:
132
+ rawRecord.requesterWave === null || rawRecord.requesterWave === undefined || rawRecord.requesterWave === ""
133
+ ? defaults.requesterWave ?? null
134
+ : Number.parseInt(String(rawRecord.requesterWave), 10),
135
+ ownerWave:
136
+ rawRecord.ownerWave === null || rawRecord.ownerWave === undefined || rawRecord.ownerWave === ""
137
+ ? defaults.ownerWave ?? null
138
+ : Number.parseInt(String(rawRecord.ownerWave), 10),
139
+ required:
140
+ rawRecord.required === undefined
141
+ ? Boolean(defaults.required)
142
+ : Boolean(rawRecord.required),
143
+ };
144
+ }
145
+
146
+ export function appendCoordinationRecord(filePath, rawRecord, defaults = {}) {
147
+ const record = normalizeCoordinationRecord(rawRecord, defaults);
148
+ ensureDirectory(path.dirname(filePath));
149
+ fs.appendFileSync(filePath, `${JSON.stringify(record)}\n`, "utf8");
150
+ return record;
151
+ }
152
+
153
+ export function readCoordinationLog(filePath) {
154
+ if (!fs.existsSync(filePath)) {
155
+ return [];
156
+ }
157
+ const lines = fs
158
+ .readFileSync(filePath, "utf8")
159
+ .split(/\r?\n/)
160
+ .map((line) => line.trim())
161
+ .filter(Boolean);
162
+ const records = [];
163
+ for (const line of lines) {
164
+ const parsed = JSON.parse(line);
165
+ records.push(normalizeCoordinationRecord(parsed));
166
+ }
167
+ return records;
168
+ }
169
+
170
+ function coordinationSort(a, b) {
171
+ const updatedDiff = Date.parse(a.updatedAt) - Date.parse(b.updatedAt);
172
+ if (updatedDiff !== 0) {
173
+ return updatedDiff;
174
+ }
175
+ return String(a.id).localeCompare(String(b.id));
176
+ }
177
+
178
+ export function materializeCoordinationState(records) {
179
+ const ordered = [...records].sort(coordinationSort);
180
+ const byId = new Map();
181
+ for (const record of ordered) {
182
+ const existing = byId.get(record.id);
183
+ byId.set(record.id, existing ? { ...existing, ...record, id: existing.id, createdAt: existing.createdAt } : record);
184
+ }
185
+ const latestRecords = Array.from(byId.values()).sort(coordinationSort);
186
+ const openRecords = latestRecords.filter((record) => OPEN_COORDINATION_STATUSES.has(record.status));
187
+ const recordsByAgentId = new Map();
188
+ const recordsByTarget = new Map();
189
+ for (const record of latestRecords) {
190
+ const agentList = recordsByAgentId.get(record.agentId) || [];
191
+ agentList.push(record);
192
+ recordsByAgentId.set(record.agentId, agentList);
193
+ for (const target of record.targets || []) {
194
+ const targetList = recordsByTarget.get(target) || [];
195
+ targetList.push(record);
196
+ recordsByTarget.set(target, targetList);
197
+ }
198
+ }
199
+ return {
200
+ records: ordered,
201
+ latestRecords,
202
+ openRecords,
203
+ byId,
204
+ recordsByAgentId,
205
+ recordsByTarget,
206
+ requests: latestRecords.filter((record) => record.kind === "request"),
207
+ blockers: latestRecords.filter((record) => record.kind === "blocker"),
208
+ claims: latestRecords.filter((record) => record.kind === "claim"),
209
+ evidence: latestRecords.filter((record) => record.kind === "evidence"),
210
+ decisions: latestRecords.filter((record) => record.kind === "decision"),
211
+ handoffs: latestRecords.filter((record) => record.kind === "handoff"),
212
+ clarifications: latestRecords.filter((record) => record.kind === "clarification-request"),
213
+ orchestratorGuidance: latestRecords.filter(
214
+ (record) => record.kind === "orchestrator-guidance",
215
+ ),
216
+ resolvedByPolicy: latestRecords.filter((record) => record.kind === "resolved-by-policy"),
217
+ humanEscalations: latestRecords.filter((record) => record.kind === "human-escalation"),
218
+ humanFeedback: latestRecords.filter((record) => record.kind === "human-feedback"),
219
+ integrationSummaries: latestRecords.filter((record) => record.kind === "integration-summary"),
220
+ };
221
+ }
222
+
223
+ export function isOpenCoordinationStatus(status) {
224
+ return OPEN_COORDINATION_STATUSES.has(String(status || "").trim().toLowerCase());
225
+ }
226
+
227
+ export function clarificationClosureCondition(clarificationId) {
228
+ return `${CLARIFICATION_CLOSURE_PREFIX}${String(clarificationId || "").trim()}`;
229
+ }
230
+
231
+ export function clarificationIdFromClosureCondition(value) {
232
+ const normalized = String(value || "").trim();
233
+ if (!normalized.startsWith(CLARIFICATION_CLOSURE_PREFIX)) {
234
+ return null;
235
+ }
236
+ const clarificationId = normalized.slice(CLARIFICATION_CLOSURE_PREFIX.length).trim();
237
+ return clarificationId || null;
238
+ }
239
+
240
+ export function isClarificationLinkedRequest(record, clarificationIds = null) {
241
+ const clarificationIdSet =
242
+ clarificationIds instanceof Set
243
+ ? clarificationIds
244
+ : clarificationIds === null
245
+ ? null
246
+ : new Set(Array.isArray(clarificationIds) ? clarificationIds : []);
247
+ const closureClarificationId = clarificationIdFromClosureCondition(record?.closureCondition);
248
+ if (closureClarificationId) {
249
+ return clarificationIdSet === null
250
+ ? true
251
+ : clarificationIdSet.has(closureClarificationId);
252
+ }
253
+ if (clarificationIdSet === null) {
254
+ return false;
255
+ }
256
+ return Array.isArray(record?.dependsOn)
257
+ ? record.dependsOn.some((dependencyId) => clarificationIdSet.has(String(dependencyId || "").trim()))
258
+ : false;
259
+ }
260
+
261
+ export function clarificationLinkedRequests(state, clarificationId = null) {
262
+ const clarificationIds =
263
+ clarificationId === null
264
+ ? new Set((state?.clarifications || []).map((record) => String(record.id || "").trim()))
265
+ : new Set([String(clarificationId || "").trim()]);
266
+ return (state?.requests || []).filter((record) =>
267
+ isClarificationLinkedRequest(record, clarificationIds),
268
+ );
269
+ }
270
+
271
+ export function openClarificationLinkedRequests(state, clarificationId = null) {
272
+ return clarificationLinkedRequests(state, clarificationId).filter((record) =>
273
+ isOpenCoordinationStatus(record.status),
274
+ );
275
+ }
276
+
277
+ export function readMaterializedCoordinationState(filePath) {
278
+ return materializeCoordinationState(readCoordinationLog(filePath));
279
+ }
280
+
281
+ export function serializeCoordinationState(state) {
282
+ return {
283
+ records: state?.records || [],
284
+ latestRecords: state?.latestRecords || [],
285
+ openRecords: state?.openRecords || [],
286
+ byId: Object.fromEntries(state?.byId?.entries?.() || []),
287
+ recordsByAgentId: Object.fromEntries(
288
+ Array.from(state?.recordsByAgentId?.entries?.() || []).map(([agentId, records]) => [
289
+ agentId,
290
+ records,
291
+ ]),
292
+ ),
293
+ recordsByTarget: Object.fromEntries(
294
+ Array.from(state?.recordsByTarget?.entries?.() || []).map(([target, records]) => [
295
+ target,
296
+ records,
297
+ ]),
298
+ ),
299
+ requests: state?.requests || [],
300
+ blockers: state?.blockers || [],
301
+ claims: state?.claims || [],
302
+ evidence: state?.evidence || [],
303
+ decisions: state?.decisions || [],
304
+ handoffs: state?.handoffs || [],
305
+ clarifications: state?.clarifications || [],
306
+ orchestratorGuidance: state?.orchestratorGuidance || [],
307
+ resolvedByPolicy: state?.resolvedByPolicy || [],
308
+ humanEscalations: state?.humanEscalations || [],
309
+ humanFeedback: state?.humanFeedback || [],
310
+ integrationSummaries: state?.integrationSummaries || [],
311
+ };
312
+ }
313
+
314
+ function renderOpenRecord(record) {
315
+ const targets = record.targets.length > 0 ? ` -> ${record.targets.join(", ")}` : "";
316
+ const artifacts =
317
+ record.artifactRefs.length > 0 ? ` [artifacts: ${record.artifactRefs.join(", ")}]` : "";
318
+ return `- [${record.priority}] ${record.kind}/${record.status} ${record.agentId}${targets}: ${compactSingleLine(record.summary || record.detail || "no summary", 160)}${artifacts}`;
319
+ }
320
+
321
+ function renderActivityRecord(record) {
322
+ const targets = record.targets.length > 0 ? ` -> ${record.targets.join(", ")}` : "";
323
+ const summary = compactSingleLine(record.summary || record.detail || "no summary", 180);
324
+ return `- ${record.updatedAt} | ${record.agentId} | ${record.kind}/${record.status}${targets} | ${summary}`;
325
+ }
326
+
327
+ function renderIntegrationItems(title, items, options = {}) {
328
+ const normalized = Array.isArray(items)
329
+ ? items.map((item) => compactSingleLine(item, options.maxChars || 180)).filter(Boolean)
330
+ : [];
331
+ const visible = normalized.slice(0, options.maxItems || 4);
332
+ return [
333
+ title,
334
+ ...(visible.length > 0 ? visible.map((item) => `- ${item}`) : ["- None."]),
335
+ ...(normalized.length > visible.length
336
+ ? [`- ... ${normalized.length - visible.length} more item(s)`]
337
+ : []),
338
+ ];
339
+ }
340
+
341
+ export function renderCoordinationBoardProjection({
342
+ wave,
343
+ waveFile,
344
+ agents,
345
+ state,
346
+ capabilityAssignments = [],
347
+ dependencySnapshot = null,
348
+ }) {
349
+ const latestRecords = Array.isArray(state?.latestRecords) ? state.latestRecords : [];
350
+ const openRecords = latestRecords.filter((record) => OPEN_COORDINATION_STATUSES.has(record.status));
351
+ const activityRecords = [...latestRecords].sort(coordinationSort);
352
+ const openAssignments = (capabilityAssignments || []).filter((assignment) => assignment.blocking);
353
+ const openInboundDependencies = dependencySnapshot?.openInbound || [];
354
+ const openOutboundDependencies = dependencySnapshot?.openOutbound || [];
355
+ return [
356
+ `# Wave ${wave} Message Board`,
357
+ "",
358
+ `- Wave file: \`${waveFile}\``,
359
+ `- Agents: ${(agents || []).map((agent) => agent.agentId).join(", ")}`,
360
+ `- Generated: ${toIsoTimestamp()}`,
361
+ "",
362
+ "## Open Coordination State",
363
+ ...(openRecords.length > 0
364
+ ? openRecords.map((record) => renderOpenRecord(record))
365
+ : ["- None."]),
366
+ "",
367
+ "## Helper Assignments",
368
+ ...(openAssignments.length > 0
369
+ ? openAssignments.map(
370
+ (assignment) =>
371
+ `- [${assignment.priority || "normal"}] ${assignment.requestId} -> ${assignment.target}${assignment.assignedAgentId ? ` => ${assignment.assignedAgentId}` : " => unresolved"} (${assignment.assignmentReason || "n/a"})`,
372
+ )
373
+ : ["- None."]),
374
+ "",
375
+ "## Cross-Lane Dependencies",
376
+ ...(openInboundDependencies.length + openOutboundDependencies.length > 0
377
+ ? [
378
+ ...openInboundDependencies.map(
379
+ (record) =>
380
+ `- [inbound${record.required ? ", required" : ""}] ${record.id}: ${compactSingleLine(record.summary || record.detail || "dependency", 160)}${record.assignedAgentId ? ` -> ${record.assignedAgentId}` : ""}`,
381
+ ),
382
+ ...openOutboundDependencies.map(
383
+ (record) =>
384
+ `- [outbound${record.required ? ", required" : ""}] ${record.id}: ${compactSingleLine(record.summary || record.detail || "dependency", 160)}`,
385
+ ),
386
+ ]
387
+ : ["- None."]),
388
+ "",
389
+ "## Activity Feed",
390
+ ...(activityRecords.length > 0
391
+ ? activityRecords.map((record) => renderActivityRecord(record))
392
+ : ["- No activity yet."]),
393
+ "",
394
+ ].join("\n");
395
+ }
396
+
397
+ function isTargetedToAgent(record, agent) {
398
+ const targets = Array.isArray(record.targets) ? record.targets : [];
399
+ if (targets.length === 0) {
400
+ return false;
401
+ }
402
+ const agentTargets = new Set([agent.agentId, `agent:${agent.agentId}`]);
403
+ for (const target of targets) {
404
+ if (agentTargets.has(target)) {
405
+ return true;
406
+ }
407
+ if (String(target).startsWith("capability:")) {
408
+ const capability = String(target).slice("capability:".length);
409
+ if (Array.isArray(agent.capabilities) && agent.capabilities.includes(capability)) {
410
+ return true;
411
+ }
412
+ }
413
+ }
414
+ return false;
415
+ }
416
+
417
+ function normalizeOwnedReference(value) {
418
+ return String(value || "").trim().replace(/\/+$/, "");
419
+ }
420
+
421
+ function matchesOwnedPathArtifact(artifactRef, ownedPath) {
422
+ const normalizedArtifact = normalizeOwnedReference(artifactRef);
423
+ const normalizedOwnedPath = normalizeOwnedReference(ownedPath);
424
+ if (!normalizedArtifact || !normalizedOwnedPath) {
425
+ return false;
426
+ }
427
+ return (
428
+ normalizedArtifact === normalizedOwnedPath ||
429
+ normalizedArtifact.startsWith(`${normalizedOwnedPath}/`)
430
+ );
431
+ }
432
+
433
+ function isArtifactRelevantToAgent(record, agent) {
434
+ const artifactRefs = Array.isArray(record?.artifactRefs) ? record.artifactRefs : [];
435
+ if (artifactRefs.length === 0) {
436
+ return false;
437
+ }
438
+ const ownedPaths = Array.isArray(agent?.ownedPaths) ? agent.ownedPaths : [];
439
+ const ownedComponents = Array.isArray(agent?.components) ? agent.components : [];
440
+ return artifactRefs.some((artifactRef) => {
441
+ const normalizedArtifact = normalizeOwnedReference(artifactRef);
442
+ if (!normalizedArtifact) {
443
+ return false;
444
+ }
445
+ if (ownedComponents.some((componentId) => normalizedArtifact === String(componentId || "").trim())) {
446
+ return true;
447
+ }
448
+ return ownedPaths.some((ownedPath) => matchesOwnedPathArtifact(normalizedArtifact, ownedPath));
449
+ });
450
+ }
451
+
452
+ export function compileSharedSummary({
453
+ wave,
454
+ state,
455
+ ledger = null,
456
+ integrationSummary = null,
457
+ capabilityAssignments = [],
458
+ dependencySnapshot = null,
459
+ maxChars = 4000,
460
+ }) {
461
+ const openBlockers = state.blockers.filter((record) => OPEN_COORDINATION_STATUSES.has(record.status));
462
+ const openRequests = state.requests.filter((record) => OPEN_COORDINATION_STATUSES.has(record.status));
463
+ const openClarifications = state.clarifications.filter((record) =>
464
+ OPEN_COORDINATION_STATUSES.has(record.status),
465
+ );
466
+ const openHumanEscalations = state.humanEscalations.filter((record) =>
467
+ OPEN_COORDINATION_STATUSES.has(record.status),
468
+ );
469
+ const openHelperAssignments = (capabilityAssignments || []).filter((assignment) => assignment.blocking);
470
+ const openInboundDependencies = dependencySnapshot?.openInbound || [];
471
+ const openOutboundDependencies = dependencySnapshot?.openOutbound || [];
472
+ const summary = [
473
+ `# Wave ${wave.wave} Shared Summary`,
474
+ "",
475
+ `- Open requests: ${openRequests.length}`,
476
+ `- Open blockers: ${openBlockers.length}`,
477
+ `- Open clarifications: ${openClarifications.length}`,
478
+ `- Open human escalations: ${openHumanEscalations.length}`,
479
+ `- Open coordination items: ${state.openRecords.length}`,
480
+ `- Open helper assignments: ${openHelperAssignments.length}`,
481
+ `- Open inbound dependencies: ${openInboundDependencies.length}`,
482
+ `- Open outbound dependencies: ${openOutboundDependencies.length}`,
483
+ ...(integrationSummary
484
+ ? [`- Integration recommendation: ${integrationSummary.recommendation || "n/a"}`]
485
+ : []),
486
+ ...(integrationSummary
487
+ ? [
488
+ `- Integration conflicts: ${(integrationSummary.conflictingClaims || []).length}`,
489
+ `- Integration proof gaps: ${(integrationSummary.proofGaps || []).length}`,
490
+ `- Integration deploy risks: ${(integrationSummary.deployRisks || []).length}`,
491
+ `- Integration doc gaps: ${(integrationSummary.docGaps || []).length}`,
492
+ ]
493
+ : []),
494
+ ...(ledger ? [`- Ledger phase: ${ledger.phase || "n/a"}`] : []),
495
+ "",
496
+ "## Current blockers",
497
+ ...(openBlockers.length > 0
498
+ ? openBlockers.map((record) => renderOpenRecord(record))
499
+ : ["- None."]),
500
+ "",
501
+ "## Current clarifications",
502
+ ...(openClarifications.length > 0
503
+ ? openClarifications.map((record) => renderOpenRecord(record))
504
+ : ["- None."]),
505
+ "",
506
+ "## Helper assignments",
507
+ ...(openHelperAssignments.length > 0
508
+ ? openHelperAssignments.map(
509
+ (assignment) =>
510
+ `- ${assignment.requestId}: ${assignment.target}${assignment.assignedAgentId ? ` -> ${assignment.assignedAgentId}` : " -> unresolved"} (${assignment.assignmentReason || "n/a"})`,
511
+ )
512
+ : ["- None."]),
513
+ "",
514
+ "## Cross-lane dependencies",
515
+ ...(openInboundDependencies.length + openOutboundDependencies.length > 0
516
+ ? [
517
+ ...openInboundDependencies.map(
518
+ (item) =>
519
+ `- inbound${item.required ? " required" : ""}: ${compactSingleLine(item.summary || item.detail || item.id, 160)}${item.assignedAgentId ? ` -> ${item.assignedAgentId}` : ""}`,
520
+ ),
521
+ ...openOutboundDependencies.map(
522
+ (item) =>
523
+ `- outbound${item.required ? " required" : ""}: ${compactSingleLine(item.summary || item.detail || item.id, 160)}`,
524
+ ),
525
+ ]
526
+ : ["- None."]),
527
+ "",
528
+ "## Current decisions",
529
+ ...(state.decisions.length > 0
530
+ ? state.decisions.slice(-5).map((record) => renderActivityRecord(record))
531
+ : ["- None."]),
532
+ ...(integrationSummary
533
+ ? [
534
+ "",
535
+ ...renderIntegrationItems("## Integration conflicts", integrationSummary.conflictingClaims),
536
+ "",
537
+ ...renderIntegrationItems("## Changed interfaces", integrationSummary.changedInterfaces),
538
+ "",
539
+ ...renderIntegrationItems(
540
+ "## Cross-component impacts",
541
+ integrationSummary.crossComponentImpacts,
542
+ ),
543
+ "",
544
+ ...renderIntegrationItems("## Proof gaps", integrationSummary.proofGaps),
545
+ "",
546
+ ...renderIntegrationItems("## Deploy risks", integrationSummary.deployRisks),
547
+ "",
548
+ ...renderIntegrationItems("## Documentation gaps", integrationSummary.docGaps),
549
+ ]
550
+ : []),
551
+ ...(Array.isArray(integrationSummary?.runtimeAssignments) &&
552
+ integrationSummary.runtimeAssignments.length > 0
553
+ ? [
554
+ "",
555
+ "## Runtime assignments",
556
+ ...integrationSummary.runtimeAssignments.map(
557
+ (assignment) =>
558
+ `- ${assignment.agentId}: ${assignment.executorId || "n/a"} (${assignment.role || "n/a"})${assignment.profile ? ` profile=${assignment.profile}` : ""}${assignment.fallbackUsed ? " fallback-used" : ""}`,
559
+ ),
560
+ ]
561
+ : []),
562
+ "",
563
+ ].join("\n");
564
+ if (summary.length <= maxChars) {
565
+ return { text: summary, truncated: false };
566
+ }
567
+ const suffix = "\n\n[Shared summary truncated; see generated artifact for full details]";
568
+ return {
569
+ text: `${summary.slice(0, Math.max(0, maxChars - suffix.length))}${suffix}`,
570
+ truncated: true,
571
+ };
572
+ }
573
+
574
+ export function compileAgentInbox({
575
+ wave,
576
+ agent,
577
+ state,
578
+ ledger = null,
579
+ docsQueue = null,
580
+ integrationSummary = null,
581
+ capabilityAssignments = [],
582
+ dependencySnapshot = null,
583
+ maxChars = 8000,
584
+ }) {
585
+ const targetedRecords = state.openRecords.filter((record) => isTargetedToAgent(record, agent));
586
+ const ownedRecords = (state.recordsByAgentId.get(agent.agentId) || []).filter((record) =>
587
+ OPEN_COORDINATION_STATUSES.has(record.status),
588
+ );
589
+ const clarificationRecords = state.clarifications.filter((record) =>
590
+ OPEN_COORDINATION_STATUSES.has(record.status) &&
591
+ (record.agentId === agent.agentId || isTargetedToAgent(record, agent)),
592
+ );
593
+ const excludedRecordIds = new Set([
594
+ ...targetedRecords.map((record) => record.id),
595
+ ...ownedRecords.map((record) => record.id),
596
+ ...clarificationRecords.map((record) => record.id),
597
+ ]);
598
+ const relevantRecords = state.openRecords.filter(
599
+ (record) =>
600
+ !excludedRecordIds.has(record.id) &&
601
+ record.kind !== "clarification-request" &&
602
+ isArtifactRelevantToAgent(record, agent),
603
+ );
604
+ const docsItems =
605
+ Array.isArray(docsQueue?.items) && docsQueue.items.length > 0
606
+ ? docsQueue.items.filter(
607
+ (item) =>
608
+ item.ownerAgentId === agent.agentId ||
609
+ item.agentId === agent.agentId ||
610
+ (Array.isArray(item.targets) && item.targets.includes(agent.agentId)),
611
+ )
612
+ : [];
613
+ const ledgerTasks =
614
+ Array.isArray(ledger?.tasks) && ledger.tasks.length > 0
615
+ ? ledger.tasks.filter((task) => task.owner === agent.agentId)
616
+ : [];
617
+ const helperAssignments = (capabilityAssignments || []).filter(
618
+ (assignment) => assignment.blocking && assignment.assignedAgentId === agent.agentId,
619
+ );
620
+ const dependencyItems = [
621
+ ...((dependencySnapshot?.inbound || []).filter(
622
+ (record) =>
623
+ isOpenCoordinationStatus(record.status) &&
624
+ (record.assignedAgentId === agent.agentId ||
625
+ isArtifactRelevantToAgent(record, agent) ||
626
+ isTargetedToAgent(record, agent)),
627
+ )),
628
+ ...((dependencySnapshot?.outbound || []).filter(
629
+ (record) =>
630
+ isOpenCoordinationStatus(record.status) &&
631
+ (isArtifactRelevantToAgent(record, agent) || isTargetedToAgent(record, agent)),
632
+ )),
633
+ ];
634
+ const text = [
635
+ `# Wave ${wave.wave} Inbox for ${agent.agentId}`,
636
+ "",
637
+ "## Targeted open coordination",
638
+ ...(targetedRecords.length > 0
639
+ ? targetedRecords.map((record) => renderOpenRecord(record))
640
+ : ["- None."]),
641
+ "",
642
+ "## Your open coordination items",
643
+ ...(ownedRecords.length > 0
644
+ ? ownedRecords.map((record) => renderOpenRecord(record))
645
+ : ["- None."]),
646
+ "",
647
+ "## Clarifications",
648
+ ...(clarificationRecords.length > 0
649
+ ? clarificationRecords.map((record) => renderOpenRecord(record))
650
+ : ["- None."]),
651
+ "",
652
+ "## Relevant open coordination",
653
+ ...(relevantRecords.length > 0
654
+ ? relevantRecords.map((record) => renderOpenRecord(record))
655
+ : ["- None."]),
656
+ "",
657
+ "## Helper assignments",
658
+ ...(helperAssignments.length > 0
659
+ ? helperAssignments.map(
660
+ (assignment) =>
661
+ `- [${assignment.priority || "normal"}] ${compactSingleLine(assignment.summary || assignment.requestId, 140)} (${assignment.target}${assignment.assignmentReason ? `; ${assignment.assignmentReason}` : ""})`,
662
+ )
663
+ : ["- None."]),
664
+ "",
665
+ "## Cross-lane dependencies",
666
+ ...(dependencyItems.length > 0
667
+ ? dependencyItems.map(
668
+ (record) =>
669
+ `- [${record.priority || "normal"}] ${record.direction || "dependency"}${record.required ? " required" : ""}: ${compactSingleLine(record.summary || record.detail || record.id, 140)}${record.assignedAgentId ? ` -> ${record.assignedAgentId}` : ""}`,
670
+ )
671
+ : ["- None."]),
672
+ "",
673
+ "## Ledger tasks",
674
+ ...(ledgerTasks.length > 0
675
+ ? ledgerTasks.map(
676
+ (task) =>
677
+ `- [${task.priority || "normal"}] ${task.id}: ${compactSingleLine(task.title || task.kind || "task", 140)} (${task.state || "unknown"})`,
678
+ )
679
+ : ["- None."]),
680
+ "",
681
+ "## Documentation obligations",
682
+ ...(docsItems.length > 0
683
+ ? docsItems.map(
684
+ (item) =>
685
+ `- ${item.kind || "doc"}: ${compactSingleLine(item.summary || item.path || item.detail || "update required", 140)}`,
686
+ )
687
+ : ["- None."]),
688
+ ...(integrationSummary
689
+ ? [
690
+ "",
691
+ "## Integration note",
692
+ `- Recommendation: ${integrationSummary.recommendation || "n/a"}`,
693
+ `- Detail: ${compactSingleLine(integrationSummary.detail || "n/a", 180)}`,
694
+ `- Conflicts: ${(integrationSummary.conflictingClaims || []).length}`,
695
+ `- Proof gaps: ${(integrationSummary.proofGaps || []).length}`,
696
+ `- Deploy risks: ${(integrationSummary.deployRisks || []).length}`,
697
+ `- Documentation gaps: ${(integrationSummary.docGaps || []).length}`,
698
+ ...renderIntegrationItems(
699
+ "- Changed interfaces",
700
+ integrationSummary.changedInterfaces,
701
+ { maxItems: 3 },
702
+ ),
703
+ ...renderIntegrationItems(
704
+ "- Cross-component impacts",
705
+ integrationSummary.crossComponentImpacts,
706
+ { maxItems: 3 },
707
+ ),
708
+ ...renderIntegrationItems("- Proof gaps", integrationSummary.proofGaps, {
709
+ maxItems: 3,
710
+ }),
711
+ ...renderIntegrationItems("- Deploy risks", integrationSummary.deployRisks, {
712
+ maxItems: 3,
713
+ }),
714
+ ...renderIntegrationItems("- Documentation gaps", integrationSummary.docGaps, {
715
+ maxItems: 3,
716
+ }),
717
+ ...(Array.isArray(integrationSummary.runtimeAssignments) &&
718
+ integrationSummary.runtimeAssignments.length > 0
719
+ ? [
720
+ "- Runtime assignments:",
721
+ ...integrationSummary.runtimeAssignments.map(
722
+ (assignment) =>
723
+ ` ${assignment.agentId}: ${assignment.executorId || "n/a"} (${assignment.role || "n/a"})`,
724
+ ),
725
+ ]
726
+ : []),
727
+ ]
728
+ : []),
729
+ "",
730
+ ].join("\n");
731
+ if (text.length <= maxChars) {
732
+ return { text, truncated: false };
733
+ }
734
+ const suffix = "\n\n[Inbox truncated; see generated artifact for full details]";
735
+ return {
736
+ text: `${text.slice(0, Math.max(0, maxChars - suffix.length))}${suffix}`,
737
+ truncated: true,
738
+ };
739
+ }
740
+
741
+ export function writeCoordinationBoardProjection(filePath, params) {
742
+ writeTextAtomic(filePath, `${renderCoordinationBoardProjection(params)}\n`);
743
+ }
744
+
745
+ export function writeCompiledInbox(filePath, payload) {
746
+ writeTextAtomic(filePath, `${String(payload || "")}\n`);
747
+ }
748
+
749
+ function baseRecord({
750
+ id,
751
+ kind,
752
+ lane,
753
+ wave,
754
+ agentId,
755
+ targets = [],
756
+ priority = "normal",
757
+ summary,
758
+ detail = "",
759
+ artifactRefs = [],
760
+ status = "open",
761
+ }) {
762
+ return normalizeCoordinationRecord({
763
+ id,
764
+ kind,
765
+ lane,
766
+ wave,
767
+ agentId,
768
+ targets,
769
+ priority,
770
+ summary,
771
+ detail,
772
+ artifactRefs,
773
+ status,
774
+ confidence: "medium",
775
+ source: "launcher",
776
+ });
777
+ }
778
+
779
+ export function buildSeedCoordinationRecords({
780
+ lane,
781
+ wave,
782
+ agents,
783
+ componentPromotions = [],
784
+ sharedPlanDocs = [],
785
+ evaluatorAgentId = "A0",
786
+ integrationAgentId = "A8",
787
+ documentationAgentId = "A9",
788
+ feedbackRequests = [],
789
+ }) {
790
+ const records = [];
791
+ for (const agent of agents) {
792
+ const targets =
793
+ agent.agentId === evaluatorAgentId || agent.agentId === documentationAgentId || agent.agentId === integrationAgentId
794
+ ? []
795
+ : [`agent:${agent.agentId}`];
796
+ records.push(
797
+ baseRecord({
798
+ id: `wave-${wave}-agent-${agent.agentId}-request`,
799
+ kind: "request",
800
+ lane,
801
+ wave,
802
+ agentId: "launcher",
803
+ targets,
804
+ priority:
805
+ agent.agentId === evaluatorAgentId || agent.agentId === documentationAgentId
806
+ ? "high"
807
+ : "normal",
808
+ summary: `Wave ${wave} assigned to ${agent.agentId}: ${agent.title}`,
809
+ detail: agent.promptOverlay || agent.prompt || agent.title,
810
+ artifactRefs: agent.ownedPaths || [],
811
+ }),
812
+ );
813
+ }
814
+ for (const promotion of componentPromotions) {
815
+ records.push(
816
+ baseRecord({
817
+ id: `wave-${wave}-component-${promotion.componentId}`,
818
+ kind: "decision",
819
+ lane,
820
+ wave,
821
+ agentId: "launcher",
822
+ summary: `Promote ${promotion.componentId} to ${promotion.targetLevel}`,
823
+ detail: `Wave ${wave} requires component ${promotion.componentId} at ${promotion.targetLevel}.`,
824
+ artifactRefs: [promotion.componentId],
825
+ priority: "high",
826
+ status: "in_progress",
827
+ }),
828
+ );
829
+ }
830
+ if (sharedPlanDocs.length > 0) {
831
+ records.push(
832
+ baseRecord({
833
+ id: `wave-${wave}-shared-plan-docs`,
834
+ kind: "request",
835
+ lane,
836
+ wave,
837
+ agentId: "launcher",
838
+ targets: [`agent:${documentationAgentId}`],
839
+ priority: "high",
840
+ summary: `Reconcile shared-plan documentation for wave ${wave}`,
841
+ detail: `Documentation steward must reconcile ${sharedPlanDocs.join(", ")}`,
842
+ artifactRefs: sharedPlanDocs,
843
+ }),
844
+ );
845
+ }
846
+ if (agents.some((agent) => agent.agentId === integrationAgentId)) {
847
+ records.push(
848
+ baseRecord({
849
+ id: `wave-${wave}-integration-summary`,
850
+ kind: "integration-summary",
851
+ lane,
852
+ wave,
853
+ agentId: "launcher",
854
+ targets: [`agent:${integrationAgentId}`],
855
+ priority: "high",
856
+ summary: `Synthesize wave ${wave} before documentation and evaluator closure`,
857
+ detail: "Integration steward must reconcile open claims, blockers, interfaces, and release risk.",
858
+ }),
859
+ );
860
+ }
861
+ for (const request of feedbackRequests) {
862
+ records.push(
863
+ baseRecord({
864
+ id: request.id,
865
+ kind: "human-feedback",
866
+ lane,
867
+ wave,
868
+ agentId: request.agentId || "human",
869
+ targets: request.agentId ? [`agent:${request.agentId}`] : [],
870
+ priority: "high",
871
+ summary: request.question || "Human feedback requested",
872
+ detail: request.context || "",
873
+ status: request.status === "answered" ? "resolved" : "open",
874
+ }),
875
+ );
876
+ }
877
+ return records;
878
+ }
879
+
880
+ export function updateSeedRecords(filePath, params) {
881
+ const existing = readCoordinationLog(filePath);
882
+ const latestById = materializeCoordinationState(existing).byId;
883
+ const seed = buildSeedCoordinationRecords(params);
884
+ const comparableKeys = [
885
+ "kind",
886
+ "wave",
887
+ "lane",
888
+ "agentId",
889
+ "targets",
890
+ "status",
891
+ "priority",
892
+ "artifactRefs",
893
+ "dependsOn",
894
+ "closureCondition",
895
+ "confidence",
896
+ "summary",
897
+ "detail",
898
+ "attempt",
899
+ "source",
900
+ "executorId",
901
+ "requesterLane",
902
+ "ownerLane",
903
+ "requesterWave",
904
+ "ownerWave",
905
+ "required",
906
+ ];
907
+ for (const record of seed) {
908
+ const existingRecord = latestById.get(record.id);
909
+ const unchanged =
910
+ existingRecord &&
911
+ comparableKeys.every((key) => JSON.stringify(existingRecord[key]) === JSON.stringify(record[key]));
912
+ if (!unchanged) {
913
+ appendCoordinationRecord(filePath, record, {
914
+ createdAt: existingRecord?.createdAt || record.createdAt,
915
+ });
916
+ }
917
+ }
918
+ return readCoordinationLog(filePath);
919
+ }
920
+
921
+ export function deriveIntegrationSummaryFromState({
922
+ lane,
923
+ wave,
924
+ state,
925
+ attempt = null,
926
+ }) {
927
+ const openClaims = state.claims.filter((record) => OPEN_COORDINATION_STATUSES.has(record.status));
928
+ const unresolvedBlockers = state.blockers.filter((record) =>
929
+ OPEN_COORDINATION_STATUSES.has(record.status),
930
+ );
931
+ const conflictingClaims = openClaims.filter((record) =>
932
+ /conflict|contradict/i.test(record.detail || record.summary || ""),
933
+ );
934
+ const changedInterfaces = (state.latestRecords || [])
935
+ .filter(
936
+ (record) =>
937
+ !["cancelled", "superseded"].includes(String(record?.status || "").trim().toLowerCase()) &&
938
+ /interface|contract|api|schema|migration|signature/i.test(
939
+ [record.summary, record.detail, ...(record.artifactRefs || [])].join("\n"),
940
+ ),
941
+ )
942
+ .map((record) => summarizeIntegrationRecord(record));
943
+ return {
944
+ wave,
945
+ lane,
946
+ agentId: "launcher",
947
+ attempt,
948
+ openClaims: openClaims.map((record) => summarizeIntegrationRecord(record)),
949
+ conflictingClaims: conflictingClaims.map((record) => summarizeIntegrationRecord(record)),
950
+ unresolvedBlockers: unresolvedBlockers.map((record) => summarizeIntegrationRecord(record)),
951
+ changedInterfaces,
952
+ crossComponentImpacts: [],
953
+ proofGaps: [],
954
+ docGaps: [],
955
+ deployRisks: [],
956
+ recommendation:
957
+ unresolvedBlockers.length > 0 || conflictingClaims.length > 0
958
+ ? "needs-more-work"
959
+ : "ready-for-doc-closure",
960
+ detail:
961
+ unresolvedBlockers.length > 0
962
+ ? `${unresolvedBlockers.length} unresolved blocker(s) remain.`
963
+ : conflictingClaims.length > 0
964
+ ? `${conflictingClaims.length} conflicting claim(s) remain.`
965
+ : "No unresolved blockers or conflicting claims remain in coordination state.",
966
+ createdAt: toIsoTimestamp(),
967
+ updatedAt: toIsoTimestamp(),
968
+ };
969
+ }
970
+
971
+ export function readDependencyTickets(dirPath, lane) {
972
+ const filePath = path.join(dirPath, `${lane}.jsonl`);
973
+ return readCoordinationLog(filePath);
974
+ }
975
+
976
+ export function appendDependencyTicket(dirPath, lane, record) {
977
+ const filePath = path.join(dirPath, `${lane}.jsonl`);
978
+ return appendCoordinationRecord(filePath, record);
979
+ }
980
+
981
+ export function writeJsonArtifact(filePath, payload) {
982
+ writeTextAtomic(filePath, `${JSON.stringify(payload, null, 2)}\n`);
983
+ }
984
+
985
+ export function readJsonArtifact(filePath) {
986
+ return readJsonOrNull(filePath);
987
+ }