@chllming/wave-orchestration 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/README.md +60 -11
  3. package/docs/README.md +8 -2
  4. package/docs/agents/wave-design-role.md +47 -0
  5. package/docs/concepts/what-is-a-wave.md +11 -7
  6. package/docs/guides/author-and-run-waves.md +24 -0
  7. package/docs/guides/planner.md +44 -0
  8. package/docs/plans/architecture-hardening-migration.md +8 -1
  9. package/docs/plans/current-state.md +19 -7
  10. package/docs/plans/end-state-architecture.md +88 -70
  11. package/docs/plans/examples/wave-example-design-handoff.md +262 -0
  12. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  13. package/docs/plans/migration.md +370 -64
  14. package/docs/plans/wave-orchestrator.md +49 -13
  15. package/docs/reference/cli-reference.md +46 -14
  16. package/docs/reference/coordination-and-closure.md +19 -6
  17. package/docs/reference/npmjs-trusted-publishing.md +5 -4
  18. package/docs/reference/sample-waves.md +14 -7
  19. package/docs/reference/skills.md +10 -0
  20. package/package.json +1 -1
  21. package/releases/manifest.json +39 -0
  22. package/scripts/wave-orchestrator/agent-state.mjs +64 -491
  23. package/scripts/wave-orchestrator/autonomous.mjs +10 -6
  24. package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
  25. package/scripts/wave-orchestrator/config.mjs +5 -0
  26. package/scripts/wave-orchestrator/coordination.mjs +42 -1
  27. package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
  28. package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +501 -141
  29. package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
  30. package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
  31. package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
  32. package/scripts/wave-orchestrator/install.mjs +3 -0
  33. package/scripts/wave-orchestrator/launcher-runtime.mjs +11 -6
  34. package/scripts/wave-orchestrator/launcher.mjs +324 -723
  35. package/scripts/wave-orchestrator/ledger.mjs +56 -27
  36. package/scripts/wave-orchestrator/local-executor.mjs +37 -0
  37. package/scripts/wave-orchestrator/planner.mjs +24 -4
  38. package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
  39. package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
  40. package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
  41. package/scripts/wave-orchestrator/replay.mjs +3 -1
  42. package/scripts/wave-orchestrator/result-envelope.mjs +620 -0
  43. package/scripts/wave-orchestrator/retry-control.mjs +22 -2
  44. package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +352 -18
  45. package/scripts/wave-orchestrator/role-helpers.mjs +124 -1
  46. package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
  47. package/scripts/wave-orchestrator/shared.mjs +2 -0
  48. package/scripts/wave-orchestrator/skills.mjs +1 -0
  49. package/scripts/wave-orchestrator/task-entity.mjs +65 -45
  50. package/scripts/wave-orchestrator/traces.mjs +10 -1
  51. package/scripts/wave-orchestrator/wave-files.mjs +96 -10
  52. package/scripts/wave-orchestrator/wave-state-reducer.mjs +76 -12
  53. package/skills/README.md +7 -0
  54. package/skills/role-design/SKILL.md +50 -0
  55. package/skills/role-design/skill.json +36 -0
  56. package/skills/tui-design/SKILL.md +77 -0
  57. package/skills/tui-design/references/tui-design.md +259 -0
  58. package/skills/tui-design/skill.json +36 -0
  59. package/wave.config.json +15 -1
@@ -5,8 +5,17 @@ import {
5
5
  setWaveDashboardAgent,
6
6
  updateWaveDashboardMessageBoard,
7
7
  } from "./dashboard-state.mjs";
8
+ import {
9
+ materializeAgentExecutionSummaryForRun as materializeAgentExecutionSummaryForRunDefault,
10
+ readWaveComponentMatrixGate as readWaveComponentMatrixGateDefault,
11
+ readWaveContEvalGate as readWaveContEvalGateDefault,
12
+ readWaveContQaGate as readWaveContQaGateDefault,
13
+ readWaveDocumentationGate as readWaveDocumentationGateDefault,
14
+ readWaveIntegrationBarrier as readWaveIntegrationBarrierDefault,
15
+ readWaveSecurityGate as readWaveSecurityGateDefault,
16
+ } from "./gate-engine.mjs";
8
17
  import { REPO_ROOT, toIsoTimestamp } from "./shared.mjs";
9
- import { isSecurityReviewAgent } from "./role-helpers.mjs";
18
+ import { isSecurityReviewAgent, resolveWaveRoleBindings } from "./role-helpers.mjs";
10
19
  import { summarizeResolvedSkills } from "./skills.mjs";
11
20
 
12
21
  function failureResultFromGate(gate, fallbackLogPath) {
@@ -71,76 +80,41 @@ export async function runClosureSweepPhase({
71
80
  materializeAgentExecutionSummaryForRunFn,
72
81
  monitorWaveHumanFeedbackFn,
73
82
  }) {
74
- const contQaAgentId = wave.contQaAgentId || "A0";
75
- const contEvalAgentId = wave.contEvalAgentId || lanePaths.contEvalAgentId || "E0";
76
- const integrationAgentId = wave.integrationAgentId || lanePaths.integrationAgentId || "A8";
77
- const documentationAgentId = wave.documentationAgentId || "A9";
78
- const stagedRuns = [
79
- {
80
- agentId: contEvalAgentId,
81
- label: "cont-EVAL gate",
82
- runs: closureRuns.filter((run) => run.agent.agentId === contEvalAgentId),
83
- validate: () =>
84
- readWaveContEvalGateFn(wave, closureRuns, {
85
- contEvalAgentId,
86
- mode: "live",
87
- evalTargets: wave.evalTargets,
88
- benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
89
- }),
90
- actionRequested:
91
- `Lane ${lanePaths.lane} owners should resolve cont-EVAL tuning gaps before integration closure.`,
92
- },
93
- {
94
- agentId: "security",
95
- label: "Security review",
96
- runs: closureRuns.filter((run) => isSecurityReviewAgent(run.agent)),
97
- validate: () => readWaveSecurityGateFn(wave, closureRuns),
98
- actionRequested:
99
- `Lane ${lanePaths.lane} owners should resolve blocked security findings or missing approvals before integration closure.`,
100
- },
101
- {
102
- agentId: integrationAgentId,
103
- label: "Integration gate",
104
- runs: closureRuns.filter((run) => run.agent.agentId === integrationAgentId),
105
- validate: () =>
106
- readWaveIntegrationBarrierFn(
107
- wave,
108
- closureRuns,
109
- refreshDerivedState?.(dashboardState?.attempt || 0),
110
- {
111
- integrationAgentId,
112
- requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
113
- },
114
- ),
115
- actionRequested:
116
- `Lane ${lanePaths.lane} owners should resolve integration contradictions or blockers before documentation and cont-QA closure.`,
117
- },
118
- {
119
- agentId: documentationAgentId,
120
- label: "Documentation closure",
121
- runs: closureRuns.filter((run) => run.agent.agentId === documentationAgentId),
122
- validate: () => {
123
- const documentationGate = readWaveDocumentationGateFn(wave, closureRuns);
124
- if (!documentationGate.ok) {
125
- return documentationGate;
126
- }
127
- return readWaveComponentMatrixGateFn(wave, closureRuns, {
128
- laneProfile: lanePaths.laneProfile,
129
- documentationAgentId,
130
- });
131
- },
132
- actionRequested:
133
- `Lane ${lanePaths.lane} owners should resolve the shared-plan or component-matrix closure state before cont-QA progression.`,
134
- },
135
- {
136
- agentId: contQaAgentId,
137
- label: "cont-QA gate",
138
- runs: closureRuns.filter((run) => run.agent.agentId === contQaAgentId),
139
- validate: () => readWaveContQaGateFn(wave, closureRuns, { contQaAgentId, mode: "live" }),
140
- actionRequested:
141
- `Lane ${lanePaths.lane} owners should resolve the cont-QA gate before wave progression.`,
142
- },
143
- ];
83
+ const materializeSummary =
84
+ typeof materializeAgentExecutionSummaryForRunFn === "function"
85
+ ? materializeAgentExecutionSummaryForRunFn
86
+ : materializeAgentExecutionSummaryForRunDefault;
87
+ const monitorHumanFeedback =
88
+ typeof monitorWaveHumanFeedbackFn === "function"
89
+ ? monitorWaveHumanFeedbackFn
90
+ : () => false;
91
+ const readContEvalGate =
92
+ typeof readWaveContEvalGateFn === "function"
93
+ ? readWaveContEvalGateFn
94
+ : readWaveContEvalGateDefault;
95
+ const readSecurityGate =
96
+ typeof readWaveSecurityGateFn === "function"
97
+ ? readWaveSecurityGateFn
98
+ : readWaveSecurityGateDefault;
99
+ const readIntegrationBarrier =
100
+ typeof readWaveIntegrationBarrierFn === "function"
101
+ ? readWaveIntegrationBarrierFn
102
+ : readWaveIntegrationBarrierDefault;
103
+ const readDocumentationGate =
104
+ typeof readWaveDocumentationGateFn === "function"
105
+ ? readWaveDocumentationGateFn
106
+ : readWaveDocumentationGateDefault;
107
+ const readComponentMatrixGate =
108
+ typeof readWaveComponentMatrixGateFn === "function"
109
+ ? readWaveComponentMatrixGateFn
110
+ : readWaveComponentMatrixGateDefault;
111
+ const readContQaGate =
112
+ typeof readWaveContQaGateFn === "function"
113
+ ? readWaveContQaGateFn
114
+ : readWaveContQaGateDefault;
115
+ const stagedRuns = planClosureStages({ lanePaths, wave, closureRuns });
116
+ const { contQaAgentId, contEvalAgentId, integrationAgentId, documentationAgentId } =
117
+ resolveWaveRoleBindings(wave, lanePaths);
144
118
  for (const stage of stagedRuns) {
145
119
  if (stage.runs.length === 0) {
146
120
  continue;
@@ -177,6 +151,11 @@ export async function runClosureSweepPhase({
177
151
  agentRateLimitBaseDelaySeconds: options.agentRateLimitBaseDelaySeconds,
178
152
  agentRateLimitMaxDelaySeconds: options.agentRateLimitMaxDelaySeconds,
179
153
  context7Enabled: options.context7Enabled,
154
+ attempt: dashboardState?.attempt || 1,
155
+ controlPlane: {
156
+ waveNumber: wave.wave,
157
+ attempt: dashboardState?.attempt || 1,
158
+ },
180
159
  });
181
160
  runInfo.lastLaunchAttempt = dashboardState?.attempt || null;
182
161
  runInfo.lastPromptHash = launchResult?.promptHash || null;
@@ -201,7 +180,7 @@ export async function runClosureSweepPhase({
201
180
  refreshWaveDashboardAgentStates(dashboardState, [runInfo], pendingAgentIds, (event) =>
202
181
  recordCombinedEvent(event),
203
182
  );
204
- const feedbackChanged = monitorWaveHumanFeedbackFn({
183
+ const feedbackChanged = monitorHumanFeedback({
205
184
  lanePaths,
206
185
  waveNumber: wave.wave,
207
186
  agentRuns: [runInfo],
@@ -217,14 +196,37 @@ export async function runClosureSweepPhase({
217
196
  updateWaveDashboardMessageBoard(dashboardState, runInfo.messageBoardPath);
218
197
  flushDashboards();
219
198
  },
199
+ {
200
+ controlPlane: {
201
+ waveNumber: wave.wave,
202
+ attempt: dashboardState?.attempt || 1,
203
+ },
204
+ },
220
205
  );
221
- materializeAgentExecutionSummaryForRunFn(wave, runInfo);
206
+ materializeSummary(wave, runInfo);
222
207
  refreshDerivedState?.(dashboardState?.attempt || 0);
223
208
  if (result.failures.length > 0) {
224
209
  return result;
225
210
  }
226
211
  }
227
- const gate = stage.validate();
212
+ const gate = evaluateClosureStage({
213
+ stage,
214
+ wave,
215
+ closureRuns,
216
+ lanePaths,
217
+ dashboardState,
218
+ refreshDerivedState,
219
+ readWaveContEvalGateFn: readContEvalGate,
220
+ readWaveSecurityGateFn: readSecurityGate,
221
+ readWaveIntegrationBarrierFn: readIntegrationBarrier,
222
+ readWaveDocumentationGateFn: readDocumentationGate,
223
+ readWaveComponentMatrixGateFn: readComponentMatrixGate,
224
+ readWaveContQaGateFn: readContQaGate,
225
+ contEvalAgentId,
226
+ integrationAgentId,
227
+ documentationAgentId,
228
+ contQaAgentId,
229
+ });
228
230
  if (!gate.ok) {
229
231
  recordClosureGateFailure({
230
232
  wave,
@@ -244,6 +246,120 @@ export async function runClosureSweepPhase({
244
246
  return { failures: [], timedOut: false };
245
247
  }
246
248
 
249
+ export function planClosureStages({ lanePaths, wave, closureRuns }) {
250
+ const { contQaAgentId, contEvalAgentId, integrationAgentId, documentationAgentId } =
251
+ resolveWaveRoleBindings(wave, lanePaths);
252
+ return [
253
+ {
254
+ key: "cont-eval",
255
+ agentId: contEvalAgentId,
256
+ label: "cont-EVAL gate",
257
+ runs: closureRuns.filter((run) => run.agent.agentId === contEvalAgentId),
258
+ actionRequested:
259
+ `Lane ${lanePaths.lane} owners should resolve cont-EVAL tuning gaps before integration closure.`,
260
+ },
261
+ {
262
+ key: "security-review",
263
+ agentId: "security",
264
+ label: "Security review",
265
+ runs: closureRuns.filter((run) => isSecurityReviewAgent(run.agent)),
266
+ actionRequested:
267
+ `Lane ${lanePaths.lane} owners should resolve blocked security findings or missing approvals before integration closure.`,
268
+ },
269
+ {
270
+ key: "integration",
271
+ agentId: integrationAgentId,
272
+ label: "Integration gate",
273
+ runs: closureRuns.filter((run) => run.agent.agentId === integrationAgentId),
274
+ actionRequested:
275
+ `Lane ${lanePaths.lane} owners should resolve integration contradictions or blockers before documentation and cont-QA closure.`,
276
+ },
277
+ {
278
+ key: "documentation",
279
+ agentId: documentationAgentId,
280
+ label: "Documentation closure",
281
+ runs: closureRuns.filter((run) => run.agent.agentId === documentationAgentId),
282
+ actionRequested:
283
+ `Lane ${lanePaths.lane} owners should resolve the shared-plan or component-matrix closure state before cont-QA progression.`,
284
+ },
285
+ {
286
+ key: "cont-qa",
287
+ agentId: contQaAgentId,
288
+ label: "cont-QA gate",
289
+ runs: closureRuns.filter((run) => run.agent.agentId === contQaAgentId),
290
+ actionRequested:
291
+ `Lane ${lanePaths.lane} owners should resolve the cont-QA gate before wave progression.`,
292
+ },
293
+ ];
294
+ }
295
+
296
+ function evaluateClosureStage({
297
+ stage,
298
+ wave,
299
+ closureRuns,
300
+ lanePaths,
301
+ dashboardState,
302
+ refreshDerivedState,
303
+ readWaveContEvalGateFn,
304
+ readWaveSecurityGateFn,
305
+ readWaveIntegrationBarrierFn,
306
+ readWaveDocumentationGateFn,
307
+ readWaveComponentMatrixGateFn,
308
+ readWaveContQaGateFn,
309
+ contEvalAgentId,
310
+ integrationAgentId,
311
+ documentationAgentId,
312
+ contQaAgentId,
313
+ }) {
314
+ switch (stage.key) {
315
+ case "cont-eval":
316
+ return readWaveContEvalGateFn(wave, closureRuns, {
317
+ contEvalAgentId,
318
+ mode: "live",
319
+ evalTargets: wave.evalTargets,
320
+ benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
321
+ });
322
+ case "security-review":
323
+ return readWaveSecurityGateFn(wave, closureRuns, { mode: "live" });
324
+ case "integration":
325
+ return readWaveIntegrationBarrierFn(
326
+ wave,
327
+ closureRuns,
328
+ refreshDerivedState?.(dashboardState?.attempt || 0),
329
+ {
330
+ integrationAgentId,
331
+ mode: "live",
332
+ requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
333
+ },
334
+ );
335
+ case "documentation": {
336
+ const documentationGate = readWaveDocumentationGateFn(wave, closureRuns, {
337
+ mode: "live",
338
+ });
339
+ if (!documentationGate.ok) {
340
+ return documentationGate;
341
+ }
342
+ return readWaveComponentMatrixGateFn(wave, closureRuns, {
343
+ laneProfile: lanePaths.laneProfile,
344
+ documentationAgentId,
345
+ });
346
+ }
347
+ case "cont-qa":
348
+ return readWaveContQaGateFn(wave, closureRuns, {
349
+ contQaAgentId,
350
+ mode: "live",
351
+ });
352
+ default:
353
+ return {
354
+ ok: true,
355
+ agentId: null,
356
+ statusCode: "pass",
357
+ detail: "No closure stage configured.",
358
+ logPath: null,
359
+ };
360
+ }
361
+ }
362
+
247
363
  const NON_BLOCKING_INFRA_SIGNAL_STATES = new Set([
248
364
  "conformant",
249
365
  "setup-required",
@@ -28,6 +28,7 @@ export const DEFAULT_INTEGRATION_ROLE_PROMPT_PATH = "docs/agents/wave-integratio
28
28
  export const DEFAULT_DOCUMENTATION_ROLE_PROMPT_PATH =
29
29
  "docs/agents/wave-documentation-role.md";
30
30
  export const DEFAULT_SECURITY_ROLE_PROMPT_PATH = "docs/agents/wave-security-role.md";
31
+ export const DEFAULT_DESIGN_ROLE_PROMPT_PATH = "docs/agents/wave-design-role.md";
31
32
  export const DEFAULT_TERMINALS_PATH = ".vscode/terminals.json";
32
33
  export const DEFAULT_DOCS_DIR = "docs";
33
34
  export const DEFAULT_STATE_ROOT = ".tmp";
@@ -348,6 +349,10 @@ function normalizeRoles(rawRoles = {}) {
348
349
  rawRoles.securityRolePromptPath || DEFAULT_SECURITY_ROLE_PROMPT_PATH,
349
350
  "roles.securityRolePromptPath",
350
351
  ),
352
+ designRolePromptPath: normalizeRepoRelativePath(
353
+ rawRoles.designRolePromptPath || DEFAULT_DESIGN_ROLE_PROMPT_PATH,
354
+ "roles.designRolePromptPath",
355
+ ),
351
356
  };
352
357
  }
353
358
 
@@ -17,6 +17,8 @@ import {
17
17
  import { resolveEvalTargetsAgainstCatalog } from "./evals.mjs";
18
18
  import {
19
19
  isContEvalImplementationOwningAgent,
20
+ isDesignAgent,
21
+ isImplementationOwningDesignAgent,
20
22
  isSecurityReviewAgent,
21
23
  } from "./role-helpers.mjs";
22
24
 
@@ -199,6 +201,8 @@ export function buildExecutionPrompt({
199
201
  evalTargets = null,
200
202
  benchmarkCatalogPath = null,
201
203
  sharedPlanDocs = null,
204
+ designPacketPaths = null,
205
+ designExecutionMode = null,
202
206
  contQaAgentId = "A0",
203
207
  contEvalAgentId = "E0",
204
208
  integrationAgentId = "A8",
@@ -222,6 +226,10 @@ export function buildExecutionPrompt({
222
226
  const contEvalImplementationOwning = isContEvalImplementationOwningAgent(agent, {
223
227
  contEvalAgentId,
224
228
  });
229
+ const hybridDesignAgent = isImplementationOwningDesignAgent(agent);
230
+ const designAgent = isDesignAgent(agent);
231
+ const designImplementationPass = designAgent && hybridDesignAgent && designExecutionMode === "implementation-pass";
232
+ const designPacketPass = designAgent && !designImplementationPass;
225
233
  const resolvedEvalTargets = (() => {
226
234
  try {
227
235
  return resolveEvalTargetsAgainstCatalog(evalTargets, { benchmarkCatalogPath }).targets;
@@ -269,6 +277,22 @@ export function buildExecutionPrompt({
269
277
  "- Use `clear` only when no unresolved findings or approvals remain. Use `blocked` only when the wave must stop before integration.",
270
278
  ]
271
279
  : [];
280
+ const designRequirements = designAgent
281
+ ? [
282
+ designImplementationPass
283
+ ? "- You are in the hybrid design steward's implementation follow-through pass. Keep the design packet current, implement only your explicit owned paths, and finish with both `[wave-design]` and the normal implementation proof markers."
284
+ : "- You are the wave's design steward. Stay packet-first and docs/spec-owned unless the wave explicitly assigns more.",
285
+ "- Leave one design packet with these sections in order: `Problem`, `Constraints`, `Decisions`, `Assumptions`, `Open Questions`, `Interface Impacts`, `Validation Plan`, `Implementation Handoff`.",
286
+ "- Emit one final structured design marker: `[wave-design] state=<ready-for-implementation|needs-clarification|blocked> decisions=<n> assumptions=<n> open_questions=<n> detail=<short-note>`.",
287
+ "- Use `ready-for-implementation` only when downstream implementation owners can start without unresolved design ambiguity.",
288
+ "- Use `needs-clarification` when the wave should stop for a specific question or decision before coding starts.",
289
+ ...(hybridDesignAgent && !designImplementationPass
290
+ ? [
291
+ "- This wave also assigns you explicit implementation-owned files, but this first pass is still design-only. Do not claim implementation proof yet; the code-owning pass starts only after the design packet is ready.",
292
+ ]
293
+ : []),
294
+ ]
295
+ : [];
272
296
  const coordinationCommand = [
273
297
  "pnpm exec wave coord post",
274
298
  `--lane ${lane}`,
@@ -280,6 +304,7 @@ export function buildExecutionPrompt({
280
304
  ].join(" ");
281
305
  const implementationRequirements =
282
306
  ![contQaAgentId, documentationAgentId].includes(agent.agentId) &&
307
+ (!designAgent || designImplementationPass) &&
283
308
  !isSecurityReviewAgent(agent) &&
284
309
  (agent.agentId !== contEvalAgentId || contEvalImplementationOwning)
285
310
  ? [
@@ -294,7 +319,8 @@ export function buildExecutionPrompt({
294
319
  `- Route unresolved architecture, integration, durability, ops, or docs issues through \`${coordinationCommand}\`. Do not append \`[wave-gap]\` lines after the final implementation markers.`,
295
320
  ]
296
321
  : [];
297
- const exitContractLines = agent.exitContract
322
+ const exitContractLines =
323
+ implementationRequirements.length > 0 && agent.exitContract
298
324
  ? [
299
325
  "Exit contract for this run:",
300
326
  `- completion: ${agent.exitContract.completion}`,
@@ -385,6 +411,7 @@ export function buildExecutionPrompt({
385
411
  : [];
386
412
  const ownedComponentLines =
387
413
  ![contQaAgentId, documentationAgentId].includes(agent.agentId) &&
414
+ (!designAgent || designImplementationPass) &&
388
415
  (agent.agentId !== contEvalAgentId || contEvalImplementationOwning) &&
389
416
  Array.isArray(agent.components) &&
390
417
  agent.components.length > 0
@@ -398,6 +425,7 @@ export function buildExecutionPrompt({
398
425
  ]
399
426
  : [];
400
427
  const deliverableLines =
428
+ (!designAgent || designImplementationPass) &&
401
429
  Array.isArray(agent.deliverables) && agent.deliverables.length > 0
402
430
  ? [
403
431
  "Deliverables required for this agent:",
@@ -405,7 +433,18 @@ export function buildExecutionPrompt({
405
433
  "",
406
434
  ]
407
435
  : [];
436
+ const designPacketLines =
437
+ !designAgent &&
438
+ Array.isArray(designPacketPaths) &&
439
+ designPacketPaths.length > 0
440
+ ? [
441
+ "Same-wave design packets to read before coding:",
442
+ ...designPacketPaths.map((designPacketPath) => `- ${designPacketPath}`),
443
+ "",
444
+ ]
445
+ : [];
408
446
  const proofArtifactLines =
447
+ implementationRequirements.length > 0 &&
409
448
  Array.isArray(agent.proofArtifacts) && agent.proofArtifacts.length > 0
410
449
  ? [
411
450
  "Proof artifacts required for this agent:",
@@ -473,6 +512,7 @@ export function buildExecutionPrompt({
473
512
  ...contEvalRequirements,
474
513
  ...docStewardRequirements,
475
514
  ...securityRequirements,
515
+ ...designRequirements,
476
516
  ...implementationRequirements,
477
517
  `- Update docs impacted by your implementation. If your work changes status, sequencing, ownership, or explicit proof expectations, update the relevant docs. If shared plan docs need changes outside your owned files, post the exact doc paths and exact delta needed for ${sharedPlanDocList} as a coordination record instead of leaving documentation drift for later cleanup.`,
478
518
  "- If the wave defines a documentation steward or other explicit owner for shared plan docs, coordinate those updates through that owner, notify them as soon as the delta is known, and stay engaged until they confirm `closed` or `no-change`. Do not treat the ownership boundary as the definition of done.",
@@ -503,6 +543,7 @@ export function buildExecutionPrompt({
503
543
  ...evalTargetLines,
504
544
  ...ownedComponentLines,
505
545
  ...deliverableLines,
546
+ ...designPacketLines,
506
547
  ...proofArtifactLines,
507
548
  ...skillLines,
508
549
  ...context7PromptLines,