@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.
- package/CHANGELOG.md +36 -1
- package/README.md +60 -11
- package/docs/README.md +8 -2
- package/docs/agents/wave-design-role.md +47 -0
- package/docs/concepts/what-is-a-wave.md +11 -7
- package/docs/guides/author-and-run-waves.md +24 -0
- package/docs/guides/planner.md +44 -0
- package/docs/plans/architecture-hardening-migration.md +8 -1
- package/docs/plans/current-state.md +19 -7
- package/docs/plans/end-state-architecture.md +88 -70
- package/docs/plans/examples/wave-example-design-handoff.md +262 -0
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +370 -64
- package/docs/plans/wave-orchestrator.md +49 -13
- package/docs/reference/cli-reference.md +46 -14
- package/docs/reference/coordination-and-closure.md +19 -6
- package/docs/reference/npmjs-trusted-publishing.md +5 -4
- package/docs/reference/sample-waves.md +14 -7
- package/docs/reference/skills.md +10 -0
- package/package.json +1 -1
- package/releases/manifest.json +39 -0
- package/scripts/wave-orchestrator/agent-state.mjs +64 -491
- package/scripts/wave-orchestrator/autonomous.mjs +10 -6
- package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
- package/scripts/wave-orchestrator/config.mjs +5 -0
- package/scripts/wave-orchestrator/coordination.mjs +42 -1
- package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
- package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +501 -141
- package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
- package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
- package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
- package/scripts/wave-orchestrator/install.mjs +3 -0
- package/scripts/wave-orchestrator/launcher-runtime.mjs +11 -6
- package/scripts/wave-orchestrator/launcher.mjs +324 -723
- package/scripts/wave-orchestrator/ledger.mjs +56 -27
- package/scripts/wave-orchestrator/local-executor.mjs +37 -0
- package/scripts/wave-orchestrator/planner.mjs +24 -4
- package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
- package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
- package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
- package/scripts/wave-orchestrator/replay.mjs +3 -1
- package/scripts/wave-orchestrator/result-envelope.mjs +620 -0
- package/scripts/wave-orchestrator/retry-control.mjs +22 -2
- package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +352 -18
- package/scripts/wave-orchestrator/role-helpers.mjs +124 -1
- package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
- package/scripts/wave-orchestrator/shared.mjs +2 -0
- package/scripts/wave-orchestrator/skills.mjs +1 -0
- package/scripts/wave-orchestrator/task-entity.mjs +65 -45
- package/scripts/wave-orchestrator/traces.mjs +10 -1
- package/scripts/wave-orchestrator/wave-files.mjs +96 -10
- package/scripts/wave-orchestrator/wave-state-reducer.mjs +76 -12
- package/skills/README.md +7 -0
- package/skills/role-design/SKILL.md +50 -0
- package/skills/role-design/skill.json +36 -0
- package/skills/tui-design/SKILL.md +77 -0
- package/skills/tui-design/references/tui-design.md +259 -0
- package/skills/tui-design/skill.json +36 -0
- package/wave.config.json +15 -1
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "./config.mjs";
|
|
7
7
|
import {
|
|
8
8
|
validateContEvalSummary,
|
|
9
|
+
validateDesignSummary,
|
|
9
10
|
validateDocumentationClosureSummary,
|
|
10
11
|
validateContQaSummary,
|
|
11
12
|
validateImplementationSummary,
|
|
@@ -13,6 +14,8 @@ import {
|
|
|
13
14
|
} from "./agent-state.mjs";
|
|
14
15
|
import {
|
|
15
16
|
isContEvalImplementationOwningAgent,
|
|
17
|
+
isDesignAgent,
|
|
18
|
+
isImplementationOwningDesignAgent,
|
|
16
19
|
isSecurityReviewAgent,
|
|
17
20
|
} from "./role-helpers.mjs";
|
|
18
21
|
import { openClarificationLinkedRequests } from "./coordination-store.mjs";
|
|
@@ -54,6 +57,7 @@ export function buildSeedWaveLedger({
|
|
|
54
57
|
}) {
|
|
55
58
|
const tasks = [];
|
|
56
59
|
for (const agent of wave.agents) {
|
|
60
|
+
const hybridDesignAgent = isImplementationOwningDesignAgent(agent);
|
|
57
61
|
const kind =
|
|
58
62
|
agent.agentId === contQaAgentId
|
|
59
63
|
? "cont-qa"
|
|
@@ -63,35 +67,46 @@ export function buildSeedWaveLedger({
|
|
|
63
67
|
? "integration"
|
|
64
68
|
: agent.agentId === documentationAgentId
|
|
65
69
|
? "documentation"
|
|
70
|
+
: isDesignAgent(agent)
|
|
71
|
+
? "design"
|
|
66
72
|
: isSecurityReviewAgent(agent)
|
|
67
73
|
? "security"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
74
|
+
: "implementation";
|
|
75
|
+
const runtime = agent.executorResolved
|
|
76
|
+
? {
|
|
77
|
+
executorId: agent.executorResolved.id,
|
|
78
|
+
role: agent.executorResolved.role,
|
|
79
|
+
profile: agent.executorResolved.profile,
|
|
80
|
+
selectedBy: agent.executorResolved.selectedBy,
|
|
81
|
+
retryPolicy: agent.executorResolved.retryPolicy || null,
|
|
82
|
+
allowFallbackOnRetry: agent.executorResolved.allowFallbackOnRetry !== false,
|
|
83
|
+
fallbacks: agent.executorResolved.fallbacks || [],
|
|
84
|
+
fallbackUsed: agent.executorResolved.fallbackUsed === true,
|
|
85
|
+
}
|
|
86
|
+
: null;
|
|
87
|
+
const pushTask = (taskKind) => {
|
|
88
|
+
tasks.push({
|
|
89
|
+
id: taskId(taskKind, agent.agentId),
|
|
90
|
+
title: `${agent.agentId}: ${agent.title}`,
|
|
91
|
+
owner: agent.agentId,
|
|
92
|
+
kind: taskKind,
|
|
93
|
+
dependsOn: [],
|
|
94
|
+
state: "planned",
|
|
95
|
+
proofState: "pending",
|
|
96
|
+
docState: "pending",
|
|
97
|
+
infraState: "n/a",
|
|
98
|
+
priority:
|
|
99
|
+
taskKind === "implementation" ? "normal" : taskKind === "integration" ? "high" : "high",
|
|
100
|
+
artifactRefs: agent.ownedPaths || [],
|
|
101
|
+
runtime,
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
if (hybridDesignAgent && kind === "design") {
|
|
105
|
+
pushTask("design");
|
|
106
|
+
pushTask("implementation");
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
pushTask(kind);
|
|
95
110
|
}
|
|
96
111
|
for (const promotion of wave.componentPromotions || []) {
|
|
97
112
|
tasks.push({
|
|
@@ -163,6 +178,11 @@ function derivePhase({
|
|
|
163
178
|
return blockingHelperTasks.some((task) => task.state === "blocked") ? "blocked" : "running";
|
|
164
179
|
}
|
|
165
180
|
const implementationTasks = tasks.filter((task) => task.kind === "implementation");
|
|
181
|
+
const designTasks = tasks.filter((task) => task.kind === "design");
|
|
182
|
+
const allDesignDone = designTasks.every((task) => task.state === "done");
|
|
183
|
+
if (!allDesignDone && designTasks.length > 0) {
|
|
184
|
+
return "design";
|
|
185
|
+
}
|
|
166
186
|
const allImplementationDone = implementationTasks.every((task) => task.state === "done");
|
|
167
187
|
if (!allImplementationDone) {
|
|
168
188
|
return "running";
|
|
@@ -221,6 +241,15 @@ export function deriveWaveLedger({
|
|
|
221
241
|
docState: summary?.docDelta?.state || "pending",
|
|
222
242
|
};
|
|
223
243
|
}
|
|
244
|
+
if (task.kind === "design" && agent) {
|
|
245
|
+
const validation = validateDesignSummary(agent, summary);
|
|
246
|
+
return {
|
|
247
|
+
...task,
|
|
248
|
+
state: taskStateFromValidation(validation),
|
|
249
|
+
proofState: validation.ok ? "met" : "gap",
|
|
250
|
+
docState: validation.ok ? "met" : "gap",
|
|
251
|
+
};
|
|
252
|
+
}
|
|
224
253
|
if (task.kind === "documentation" && agent) {
|
|
225
254
|
const validation = validateDocumentationClosureSummary(agent, summary);
|
|
226
255
|
return {
|
|
@@ -173,6 +173,11 @@ function formatWaveEvalLine(evalMarker, detail) {
|
|
|
173
173
|
return `[wave-eval] state=satisfied targets=${targetIds.length} benchmarks=${benchmarkIds.length} regressions=0${targetIdSegment}${benchmarkIdSegment} detail=${detail}`;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
function isDesignAgentPrompt(rawPrompt) {
|
|
177
|
+
const text = String(rawPrompt || "");
|
|
178
|
+
return /\[wave-design\]/i.test(text) || /\bwave design\b/i.test(text);
|
|
179
|
+
}
|
|
180
|
+
|
|
176
181
|
export function resolveRepoOwnedDeliverablePath(relPath) {
|
|
177
182
|
if (!relPath || path.isAbsolute(relPath)) {
|
|
178
183
|
throw new Error(`Unsafe deliverable path: ${String(relPath || "")}`);
|
|
@@ -277,6 +282,8 @@ export function runLocalExecutorCli(argv) {
|
|
|
277
282
|
const contQaAgent = agentId === contQaAgentId;
|
|
278
283
|
const contEvalAgent = agentId === contEvalAgentId;
|
|
279
284
|
const integrationAgent = agentId === integrationAgentId;
|
|
285
|
+
const designAgent = isDesignAgentPrompt(rawPrompt);
|
|
286
|
+
const implementationMarkersRequired = /\[wave-proof\]/i.test(rawPrompt);
|
|
280
287
|
const ownedComponents = extractOwnedComponents(rawPrompt);
|
|
281
288
|
const assignedPrompt = extractAssignedPrompt(rawPrompt);
|
|
282
289
|
const ownedPaths = extractFileOwnershipPaths(assignedPrompt);
|
|
@@ -304,6 +311,21 @@ export function runLocalExecutorCli(argv) {
|
|
|
304
311
|
console.log(
|
|
305
312
|
"[wave-integration] state=ready-for-doc-closure claims=0 conflicts=0 blockers=0 detail=local-executor-no-deliverables",
|
|
306
313
|
);
|
|
314
|
+
} else if (designAgent) {
|
|
315
|
+
console.log(
|
|
316
|
+
"[wave-design] state=ready-for-implementation decisions=1 assumptions=1 open_questions=0 detail=local-executor-no-deliverables",
|
|
317
|
+
);
|
|
318
|
+
if (implementationMarkersRequired) {
|
|
319
|
+
console.log(
|
|
320
|
+
"[wave-proof] completion=contract durability=none proof=unit state=met detail=local-executor-no-deliverables",
|
|
321
|
+
);
|
|
322
|
+
console.log("[wave-doc-delta] state=none detail=local-executor-no-deliverables");
|
|
323
|
+
for (const component of ownedComponents) {
|
|
324
|
+
console.log(
|
|
325
|
+
`[wave-component] component=${component.componentId} level=${component.level || "repo-landed"} state=met detail=local-executor-no-deliverables`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
307
329
|
} else if (agentId === documentationAgentId) {
|
|
308
330
|
console.log("[wave-doc-closure] state=no-change detail=local-executor-no-deliverables");
|
|
309
331
|
} else if (agentId) {
|
|
@@ -348,6 +370,21 @@ export function runLocalExecutorCli(argv) {
|
|
|
348
370
|
console.log(
|
|
349
371
|
"[wave-integration] state=ready-for-doc-closure claims=0 conflicts=0 blockers=0 detail=local-executor-smoke",
|
|
350
372
|
);
|
|
373
|
+
} else if (designAgent) {
|
|
374
|
+
console.log(
|
|
375
|
+
"[wave-design] state=ready-for-implementation decisions=2 assumptions=1 open_questions=0 detail=local-executor-smoke",
|
|
376
|
+
);
|
|
377
|
+
if (implementationMarkersRequired) {
|
|
378
|
+
console.log(
|
|
379
|
+
"[wave-proof] completion=contract durability=none proof=unit state=met detail=local-executor-smoke",
|
|
380
|
+
);
|
|
381
|
+
console.log("[wave-doc-delta] state=owned detail=local-executor-smoke");
|
|
382
|
+
for (const component of ownedComponents) {
|
|
383
|
+
console.log(
|
|
384
|
+
`[wave-component] component=${component.componentId} level=${component.level || "repo-landed"} state=met detail=local-executor-smoke`,
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
351
388
|
} else if (agentId === documentationAgentId) {
|
|
352
389
|
console.log("[wave-doc-closure] state=no-change detail=local-executor-smoke");
|
|
353
390
|
} else if (agentId) {
|
|
@@ -317,6 +317,9 @@ function defaultTargetLevel(template) {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
function defaultExecutorProfile(roleKind) {
|
|
320
|
+
if (roleKind === "design") {
|
|
321
|
+
return "design-pass";
|
|
322
|
+
}
|
|
320
323
|
if (roleKind === "infra" || roleKind === "deploy" || roleKind === "research") {
|
|
321
324
|
return "ops-triage";
|
|
322
325
|
}
|
|
@@ -327,7 +330,7 @@ function defaultExecutorProfile(roleKind) {
|
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
function defaultExitContract(roleKind) {
|
|
330
|
-
if (roleKind === "security") {
|
|
333
|
+
if (roleKind === "security" || roleKind === "design") {
|
|
331
334
|
return null;
|
|
332
335
|
}
|
|
333
336
|
if (roleKind === "infra" || roleKind === "deploy") {
|
|
@@ -355,6 +358,9 @@ function defaultExitContract(roleKind) {
|
|
|
355
358
|
}
|
|
356
359
|
|
|
357
360
|
function buildDefaultValidationCommand(template, roleKind) {
|
|
361
|
+
if (roleKind === "design") {
|
|
362
|
+
return "Manual review of the design packet against the wave scope, constraints, and downstream ownership.";
|
|
363
|
+
}
|
|
358
364
|
if (roleKind === "security") {
|
|
359
365
|
return "Manual review of the changed security-sensitive surfaces plus required proofs.";
|
|
360
366
|
}
|
|
@@ -368,6 +374,9 @@ function buildDefaultValidationCommand(template, roleKind) {
|
|
|
368
374
|
}
|
|
369
375
|
|
|
370
376
|
function buildDefaultOutputSummary(template, roleKind) {
|
|
377
|
+
if (roleKind === "design") {
|
|
378
|
+
return "Summarize the design packet, key decisions, assumptions, open questions, and exact implementation handoff.";
|
|
379
|
+
}
|
|
371
380
|
if (roleKind === "security") {
|
|
372
381
|
return "Summarize the threat model, findings, required approvals, requested fixes, and final security disposition.";
|
|
373
382
|
}
|
|
@@ -381,6 +390,9 @@ function buildDefaultOutputSummary(template, roleKind) {
|
|
|
381
390
|
}
|
|
382
391
|
|
|
383
392
|
function buildDefaultPrimaryGoal(template, roleKind, title) {
|
|
393
|
+
if (roleKind === "design") {
|
|
394
|
+
return `Produce an implementation-ready design packet for the ${title.toLowerCase()} slice before coding starts.`;
|
|
395
|
+
}
|
|
384
396
|
if (roleKind === "security") {
|
|
385
397
|
return `Review the ${title.toLowerCase()} slice for security risks and route exact fixes before integration.`;
|
|
386
398
|
}
|
|
@@ -1067,6 +1079,9 @@ function buildWorkerAgentSpec({
|
|
|
1067
1079
|
if (roleKind === "research" && !capabilities.includes("research")) {
|
|
1068
1080
|
capabilities.push("research");
|
|
1069
1081
|
}
|
|
1082
|
+
if (roleKind === "design" && !capabilities.includes("design")) {
|
|
1083
|
+
capabilities.push("design");
|
|
1084
|
+
}
|
|
1070
1085
|
return {
|
|
1071
1086
|
agentId,
|
|
1072
1087
|
title,
|
|
@@ -1075,6 +1090,8 @@ function buildWorkerAgentSpec({
|
|
|
1075
1090
|
? values.rolePromptPaths
|
|
1076
1091
|
: roleKind === "security"
|
|
1077
1092
|
? [lanePaths.securityRolePromptPath]
|
|
1093
|
+
: roleKind === "design"
|
|
1094
|
+
? [lanePaths.designRolePromptPath]
|
|
1078
1095
|
: [],
|
|
1079
1096
|
skills: values.skills || [],
|
|
1080
1097
|
executor: {
|
|
@@ -1934,6 +1951,7 @@ function normalizePlannerContext7Bundle(bundle, bundleIndex) {
|
|
|
1934
1951
|
function normalizePlannerWorkerAgent(rawAgent, context) {
|
|
1935
1952
|
const agentId = cleanText(rawAgent?.agentId) || `A${context.index + 1}`;
|
|
1936
1953
|
const roleKind = [
|
|
1954
|
+
"design",
|
|
1937
1955
|
"implementation",
|
|
1938
1956
|
"qa",
|
|
1939
1957
|
"infra",
|
|
@@ -3067,12 +3085,12 @@ async function collectWorkerAgents({
|
|
|
3067
3085
|
const title = cleanText(await prompt.ask(`Worker ${agentId} title`, defaults.title));
|
|
3068
3086
|
const roleKind = await prompt.askChoice(
|
|
3069
3087
|
`Worker ${agentId} role kind`,
|
|
3070
|
-
["implementation", "qa", "infra", "deploy", "research", "security"],
|
|
3088
|
+
["design", "implementation", "qa", "infra", "deploy", "research", "security"],
|
|
3071
3089
|
defaultRoleKind,
|
|
3072
3090
|
);
|
|
3073
3091
|
const executorProfile = await prompt.askChoice(
|
|
3074
3092
|
`Worker ${agentId} executor profile`,
|
|
3075
|
-
["implement-fast", "deep-review", "eval-tuning", "docs-pass", "ops-triage", "security-review"],
|
|
3093
|
+
["implement-fast", "design-pass", "deep-review", "eval-tuning", "docs-pass", "ops-triage", "security-review"],
|
|
3076
3094
|
defaultExecutorProfile(roleKind),
|
|
3077
3095
|
);
|
|
3078
3096
|
const ownedPaths = normalizeRepoPathList(
|
|
@@ -3081,6 +3099,8 @@ async function collectWorkerAgents({
|
|
|
3081
3099
|
`Worker ${agentId} owned paths (comma or | separated)`,
|
|
3082
3100
|
roleKind === "security"
|
|
3083
3101
|
? `.tmp/${lane}-wave-launcher/security/wave-${waveNumber}-review.md`
|
|
3102
|
+
: roleKind === "design"
|
|
3103
|
+
? `docs/plans/waves/design/wave-${waveNumber}-${agentId}.md`
|
|
3084
3104
|
: template === "infra"
|
|
3085
3105
|
? "scripts/,docs/plans/"
|
|
3086
3106
|
: template === "release"
|
|
@@ -3093,7 +3113,7 @@ async function collectWorkerAgents({
|
|
|
3093
3113
|
const components = normalizeListText(
|
|
3094
3114
|
await prompt.ask(
|
|
3095
3115
|
`Worker ${agentId} component ids (comma or | separated)`,
|
|
3096
|
-
roleKind === "security"
|
|
3116
|
+
roleKind === "security" || roleKind === "design"
|
|
3097
3117
|
? ""
|
|
3098
3118
|
: componentPromotions.map((promotion) => promotion.componentId).join(", "),
|
|
3099
3119
|
),
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
writeAssignmentSnapshot,
|
|
4
|
+
writeDependencySnapshot,
|
|
5
|
+
} from "./artifact-schemas.mjs";
|
|
6
|
+
import {
|
|
7
|
+
syncGlobalWaveFromWaveDashboard,
|
|
8
|
+
writeGlobalDashboard,
|
|
9
|
+
writeWaveDashboard,
|
|
10
|
+
} from "./dashboard-state.mjs";
|
|
11
|
+
import { writeDocsQueue } from "./docs-queue.mjs";
|
|
12
|
+
import { writeWaveLedger } from "./ledger.mjs";
|
|
13
|
+
import { writeDependencySnapshotMarkdown } from "./routing-state.mjs";
|
|
14
|
+
import {
|
|
15
|
+
writeCompiledInbox,
|
|
16
|
+
writeCoordinationBoardProjection,
|
|
17
|
+
writeJsonArtifact,
|
|
18
|
+
} from "./coordination-store.mjs";
|
|
19
|
+
import { parseStructuredSignalsFromLog } from "./dashboard-state.mjs";
|
|
20
|
+
import { readRunExecutionSummary } from "./gate-engine.mjs";
|
|
21
|
+
import { waveProofRegistryPath } from "./proof-registry.mjs";
|
|
22
|
+
import { relaunchReasonBuckets, writeWaveRelaunchPlan } from "./retry-engine.mjs";
|
|
23
|
+
import { toIsoTimestamp, writeTextAtomic } from "./shared.mjs";
|
|
24
|
+
import { buildQualityMetrics, writeTraceBundle } from "./traces.mjs";
|
|
25
|
+
|
|
26
|
+
export function writeWaveDerivedProjections({ lanePaths, wave, derivedState }) {
|
|
27
|
+
if (!derivedState) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
writeAssignmentSnapshot(derivedState.assignmentSnapshotPath, derivedState.capabilityAssignments, {
|
|
31
|
+
lane: lanePaths.lane,
|
|
32
|
+
wave: wave.wave,
|
|
33
|
+
});
|
|
34
|
+
writeDependencySnapshot(
|
|
35
|
+
derivedState.dependencySnapshotPath,
|
|
36
|
+
derivedState.dependencySnapshot,
|
|
37
|
+
{
|
|
38
|
+
lane: lanePaths.lane,
|
|
39
|
+
wave: wave.wave,
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
writeDependencySnapshotMarkdown(
|
|
43
|
+
derivedState.dependencySnapshotMarkdownPath,
|
|
44
|
+
derivedState.dependencySnapshot,
|
|
45
|
+
);
|
|
46
|
+
writeDocsQueue(derivedState.docsQueuePath, derivedState.docsQueue);
|
|
47
|
+
writeJsonArtifact(derivedState.securitySummaryPath, derivedState.securitySummary);
|
|
48
|
+
writeTextAtomic(
|
|
49
|
+
derivedState.securityMarkdownPath,
|
|
50
|
+
`${derivedState.securitySummary ? renderWaveSecuritySummaryMarkdown(derivedState.securitySummary) : ""}\n`,
|
|
51
|
+
);
|
|
52
|
+
writeJsonArtifact(derivedState.integrationSummaryPath, derivedState.integrationSummary);
|
|
53
|
+
writeTextAtomic(
|
|
54
|
+
derivedState.integrationMarkdownPath,
|
|
55
|
+
`${derivedState.integrationSummary ? renderIntegrationSummaryMarkdown(derivedState.integrationSummary) : ""}\n`,
|
|
56
|
+
);
|
|
57
|
+
writeWaveLedger(derivedState.ledgerPath, derivedState.ledger);
|
|
58
|
+
writeCompiledInbox(derivedState.sharedSummaryPath, derivedState.sharedSummaryText);
|
|
59
|
+
for (const inbox of Object.values(derivedState.inboxesByAgentId || {})) {
|
|
60
|
+
writeCompiledInbox(inbox.path, inbox.text);
|
|
61
|
+
}
|
|
62
|
+
writeCoordinationBoardProjection(derivedState.messageBoardPath, {
|
|
63
|
+
wave: wave.wave,
|
|
64
|
+
waveFile: wave.file,
|
|
65
|
+
agents: wave.agents,
|
|
66
|
+
state: derivedState.coordinationState,
|
|
67
|
+
capabilityAssignments: derivedState.capabilityAssignments,
|
|
68
|
+
dependencySnapshot: derivedState.dependencySnapshot,
|
|
69
|
+
});
|
|
70
|
+
return derivedState;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function writeDashboardProjections({
|
|
74
|
+
lanePaths,
|
|
75
|
+
globalDashboard = null,
|
|
76
|
+
dashboardState = null,
|
|
77
|
+
dashboardPath = null,
|
|
78
|
+
}) {
|
|
79
|
+
if (dashboardState && dashboardPath) {
|
|
80
|
+
writeWaveDashboard(dashboardPath, dashboardState);
|
|
81
|
+
}
|
|
82
|
+
if (globalDashboard && dashboardState) {
|
|
83
|
+
syncGlobalWaveFromWaveDashboard(globalDashboard, dashboardState);
|
|
84
|
+
}
|
|
85
|
+
if (globalDashboard) {
|
|
86
|
+
writeGlobalDashboard(lanePaths.globalDashboardPath, globalDashboard);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function writeWaveAttemptTraceProjection({
|
|
91
|
+
lanePaths,
|
|
92
|
+
wave,
|
|
93
|
+
attempt,
|
|
94
|
+
launcherOptions,
|
|
95
|
+
derivedState,
|
|
96
|
+
manifest,
|
|
97
|
+
agentRuns,
|
|
98
|
+
gateSnapshot,
|
|
99
|
+
tracesDir,
|
|
100
|
+
}) {
|
|
101
|
+
const structuredSignals = Object.fromEntries(
|
|
102
|
+
agentRuns.map((run) => [run.agent.agentId, parseStructuredSignalsFromLog(run.logPath)]),
|
|
103
|
+
);
|
|
104
|
+
const summariesByAgentId = Object.fromEntries(
|
|
105
|
+
agentRuns
|
|
106
|
+
.map((run) => [run.agent.agentId, readRunExecutionSummary(run, wave, { mode: "compat" })])
|
|
107
|
+
.filter(([, summary]) => summary),
|
|
108
|
+
);
|
|
109
|
+
const traceDir = writeTraceBundle({
|
|
110
|
+
tracesDir,
|
|
111
|
+
lanePaths,
|
|
112
|
+
launcherOptions,
|
|
113
|
+
wave,
|
|
114
|
+
attempt,
|
|
115
|
+
manifest,
|
|
116
|
+
coordinationLogPath: derivedState.coordinationLogPath,
|
|
117
|
+
coordinationState: derivedState.coordinationState,
|
|
118
|
+
ledger: derivedState.ledger,
|
|
119
|
+
docsQueue: derivedState.docsQueue,
|
|
120
|
+
capabilityAssignments: derivedState.capabilityAssignments,
|
|
121
|
+
dependencySnapshot: derivedState.dependencySnapshot,
|
|
122
|
+
securitySummary: derivedState.securitySummary,
|
|
123
|
+
integrationSummary: derivedState.integrationSummary,
|
|
124
|
+
integrationMarkdownPath: derivedState.integrationMarkdownPath,
|
|
125
|
+
proofRegistryPath: lanePaths.proofDir ? waveProofRegistryPath(lanePaths, wave.wave) : null,
|
|
126
|
+
controlPlanePath: path.join(lanePaths.controlPlaneDir, `wave-${wave.wave}.jsonl`),
|
|
127
|
+
clarificationTriage: derivedState.clarificationTriage,
|
|
128
|
+
agentRuns,
|
|
129
|
+
structuredSignals,
|
|
130
|
+
gateSnapshot,
|
|
131
|
+
quality: buildQualityMetrics({
|
|
132
|
+
tracesDir,
|
|
133
|
+
wave,
|
|
134
|
+
coordinationState: derivedState.coordinationState,
|
|
135
|
+
integrationSummary: derivedState.integrationSummary,
|
|
136
|
+
ledger: derivedState.ledger,
|
|
137
|
+
docsQueue: derivedState.docsQueue,
|
|
138
|
+
capabilityAssignments: derivedState.capabilityAssignments,
|
|
139
|
+
dependencySnapshot: derivedState.dependencySnapshot,
|
|
140
|
+
summariesByAgentId,
|
|
141
|
+
agentRuns,
|
|
142
|
+
gateSnapshot,
|
|
143
|
+
attempt,
|
|
144
|
+
coordinationLogPath: derivedState.coordinationLogPath,
|
|
145
|
+
}),
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
traceDir,
|
|
149
|
+
structuredSignals,
|
|
150
|
+
summariesByAgentId,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function writeWaveRelaunchProjection({
|
|
155
|
+
lanePaths,
|
|
156
|
+
wave,
|
|
157
|
+
attempt,
|
|
158
|
+
runs,
|
|
159
|
+
failures,
|
|
160
|
+
derivedState,
|
|
161
|
+
}) {
|
|
162
|
+
writeWaveRelaunchPlan(lanePaths, wave.wave, {
|
|
163
|
+
wave: wave.wave,
|
|
164
|
+
attempt,
|
|
165
|
+
phase: derivedState?.ledger?.phase || null,
|
|
166
|
+
selectedAgentIds: runs.map((run) => run.agent.agentId),
|
|
167
|
+
reasonBuckets: relaunchReasonBuckets(runs, failures, derivedState),
|
|
168
|
+
executorStates: Object.fromEntries(
|
|
169
|
+
runs.map((run) => [run.agent.agentId, run.agent.executorResolved || null]),
|
|
170
|
+
),
|
|
171
|
+
fallbackHistory: Object.fromEntries(
|
|
172
|
+
runs.map((run) => [
|
|
173
|
+
run.agent.agentId,
|
|
174
|
+
run.agent.executorResolved?.executorHistory || [],
|
|
175
|
+
]),
|
|
176
|
+
),
|
|
177
|
+
createdAt: toIsoTimestamp(),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function renderWaveSecuritySummaryMarkdown(securitySummary) {
|
|
182
|
+
return [
|
|
183
|
+
`# Wave ${securitySummary.wave} Security Summary`,
|
|
184
|
+
"",
|
|
185
|
+
`- State: ${securitySummary.overallState || "unknown"}`,
|
|
186
|
+
`- Detail: ${securitySummary.detail || "n/a"}`,
|
|
187
|
+
`- Total findings: ${securitySummary.totalFindings || 0}`,
|
|
188
|
+
`- Total approvals: ${securitySummary.totalApprovals || 0}`,
|
|
189
|
+
`- Reviewers: ${(securitySummary.agents || []).length}`,
|
|
190
|
+
"",
|
|
191
|
+
"## Reviews",
|
|
192
|
+
...((securitySummary.agents || []).length > 0
|
|
193
|
+
? securitySummary.agents.map(
|
|
194
|
+
(entry) =>
|
|
195
|
+
`- ${entry.agentId}: state=${entry.state || "unknown"} findings=${entry.findings || 0} approvals=${entry.approvals || 0}${entry.reportPath ? ` report=${entry.reportPath}` : ""}${entry.detail ? ` detail=${entry.detail}` : ""}`,
|
|
196
|
+
)
|
|
197
|
+
: ["- None."]),
|
|
198
|
+
"",
|
|
199
|
+
].join("\n");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function renderIntegrationSection(title, items) {
|
|
203
|
+
return [
|
|
204
|
+
title,
|
|
205
|
+
...((items || []).length > 0 ? items.map((item) => `- ${item}`) : ["- None."]),
|
|
206
|
+
"",
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function renderIntegrationSummaryMarkdown(integrationSummary) {
|
|
211
|
+
return [
|
|
212
|
+
`# Wave ${integrationSummary.wave} Integration Summary`,
|
|
213
|
+
"",
|
|
214
|
+
`- Recommendation: ${integrationSummary.recommendation || "unknown"}`,
|
|
215
|
+
`- Detail: ${integrationSummary.detail || "n/a"}`,
|
|
216
|
+
`- Open claims: ${(integrationSummary.openClaims || []).length}`,
|
|
217
|
+
`- Conflicting claims: ${(integrationSummary.conflictingClaims || []).length}`,
|
|
218
|
+
`- Unresolved blockers: ${(integrationSummary.unresolvedBlockers || []).length}`,
|
|
219
|
+
`- Changed interfaces: ${(integrationSummary.changedInterfaces || []).length}`,
|
|
220
|
+
`- Cross-component impacts: ${(integrationSummary.crossComponentImpacts || []).length}`,
|
|
221
|
+
`- Proof gaps: ${(integrationSummary.proofGaps || []).length}`,
|
|
222
|
+
`- Deploy risks: ${(integrationSummary.deployRisks || []).length}`,
|
|
223
|
+
`- Documentation gaps: ${(integrationSummary.docGaps || []).length}`,
|
|
224
|
+
`- Security review: ${integrationSummary.securityState || "not-applicable"}`,
|
|
225
|
+
`- Security findings: ${(integrationSummary.securityFindings || []).length}`,
|
|
226
|
+
`- Security approvals: ${(integrationSummary.securityApprovals || []).length}`,
|
|
227
|
+
`- Inbound dependencies: ${(integrationSummary.inboundDependencies || []).length}`,
|
|
228
|
+
`- Outbound dependencies: ${(integrationSummary.outboundDependencies || []).length}`,
|
|
229
|
+
`- Helper assignments: ${(integrationSummary.helperAssignments || []).length}`,
|
|
230
|
+
"",
|
|
231
|
+
...renderIntegrationSection("## Open Claims", integrationSummary.openClaims),
|
|
232
|
+
...renderIntegrationSection("## Conflicting Claims", integrationSummary.conflictingClaims),
|
|
233
|
+
...renderIntegrationSection("## Unresolved Blockers", integrationSummary.unresolvedBlockers),
|
|
234
|
+
...renderIntegrationSection("## Changed Interfaces", integrationSummary.changedInterfaces),
|
|
235
|
+
...renderIntegrationSection(
|
|
236
|
+
"## Cross-Component Impacts",
|
|
237
|
+
integrationSummary.crossComponentImpacts,
|
|
238
|
+
),
|
|
239
|
+
...renderIntegrationSection("## Proof Gaps", integrationSummary.proofGaps),
|
|
240
|
+
...renderIntegrationSection("## Deploy Risks", integrationSummary.deployRisks),
|
|
241
|
+
...renderIntegrationSection("## Security Findings", integrationSummary.securityFindings),
|
|
242
|
+
...renderIntegrationSection("## Security Approvals", integrationSummary.securityApprovals),
|
|
243
|
+
...renderIntegrationSection("## Inbound Dependencies", integrationSummary.inboundDependencies),
|
|
244
|
+
...renderIntegrationSection("## Outbound Dependencies", integrationSummary.outboundDependencies),
|
|
245
|
+
...renderIntegrationSection("## Helper Assignments", integrationSummary.helperAssignments),
|
|
246
|
+
"## Runtime Assignments",
|
|
247
|
+
...((integrationSummary.runtimeAssignments || []).length > 0
|
|
248
|
+
? integrationSummary.runtimeAssignments.map(
|
|
249
|
+
(assignment) =>
|
|
250
|
+
`- ${assignment.agentId}: executor=${assignment.executorId || "n/a"} role=${assignment.role || "n/a"} profile=${assignment.profile || "none"} fallback_used=${assignment.fallbackUsed ? "yes" : "no"}`,
|
|
251
|
+
)
|
|
252
|
+
: ["- None."]),
|
|
253
|
+
"",
|
|
254
|
+
...renderIntegrationSection("## Documentation Gaps", integrationSummary.docGaps),
|
|
255
|
+
].join("\n");
|
|
256
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { compactSingleLine } from "./shared.mjs";
|
|
2
|
+
|
|
3
|
+
export function formatReconcileBlockedWaveLine(blockedWave) {
|
|
4
|
+
const parts = Array.isArray(blockedWave?.reasons)
|
|
5
|
+
? blockedWave.reasons
|
|
6
|
+
.map((reason) => {
|
|
7
|
+
const code = compactSingleLine(reason?.code || "", 80);
|
|
8
|
+
const detail = compactSingleLine(reason?.detail || "", 240);
|
|
9
|
+
return code && detail ? `${code}=${detail}` : "";
|
|
10
|
+
})
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
: [];
|
|
13
|
+
return `[reconcile] wave ${blockedWave?.wave ?? "unknown"} not reconstructable: ${
|
|
14
|
+
parts.join("; ") || "unknown reason"
|
|
15
|
+
}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function formatReconcilePreservedWaveLine(preservedWave) {
|
|
19
|
+
const parts = Array.isArray(preservedWave?.reasons)
|
|
20
|
+
? preservedWave.reasons
|
|
21
|
+
.map((reason) => {
|
|
22
|
+
const code = compactSingleLine(reason?.code || "", 80);
|
|
23
|
+
const detail = compactSingleLine(reason?.detail || "", 240);
|
|
24
|
+
return code && detail ? `${code}=${detail}` : "";
|
|
25
|
+
})
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
: [];
|
|
28
|
+
const previousState = compactSingleLine(preservedWave?.previousState || "completed", 80);
|
|
29
|
+
return `[reconcile] wave ${preservedWave?.wave ?? "unknown"} preserved as ${previousState}: ${
|
|
30
|
+
parts.join("; ") || "unknown reason"
|
|
31
|
+
}`;
|
|
32
|
+
}
|