@chllming/wave-orchestration 0.8.4 → 0.8.6

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 (60) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/README.md +31 -13
  3. package/docs/README.md +4 -0
  4. package/docs/agents/wave-design-role.md +47 -0
  5. package/docs/concepts/what-is-a-wave.md +11 -7
  6. package/docs/context7/bundles.json +19 -20
  7. package/docs/context7/planner-agent/README.md +4 -1
  8. package/docs/guides/author-and-run-waves.md +27 -0
  9. package/docs/guides/planner.md +46 -0
  10. package/docs/guides/signal-wrappers.md +165 -0
  11. package/docs/guides/terminal-surfaces.md +13 -0
  12. package/docs/plans/context7-wave-orchestrator.md +24 -7
  13. package/docs/plans/current-state.md +10 -2
  14. package/docs/plans/end-state-architecture.md +22 -5
  15. package/docs/plans/examples/wave-example-design-handoff.md +262 -0
  16. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  17. package/docs/plans/migration.md +301 -75
  18. package/docs/plans/wave-orchestrator.md +16 -3
  19. package/docs/reference/cli-reference.md +22 -1
  20. package/docs/reference/npmjs-trusted-publishing.md +2 -2
  21. package/docs/reference/sample-waves.md +14 -7
  22. package/docs/reference/skills.md +18 -0
  23. package/docs/reference/wave-control.md +2 -0
  24. package/package.json +1 -1
  25. package/releases/manifest.json +38 -0
  26. package/scripts/context7-api-check.sh +57 -13
  27. package/scripts/wave-orchestrator/agent-state.mjs +64 -0
  28. package/scripts/wave-orchestrator/config.mjs +5 -0
  29. package/scripts/wave-orchestrator/control-cli.mjs +19 -0
  30. package/scripts/wave-orchestrator/coordination.mjs +77 -1
  31. package/scripts/wave-orchestrator/gate-engine.mjs +106 -2
  32. package/scripts/wave-orchestrator/install.mjs +5 -0
  33. package/scripts/wave-orchestrator/launcher-runtime.mjs +18 -1
  34. package/scripts/wave-orchestrator/launcher.mjs +75 -1
  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/result-envelope.mjs +32 -1
  39. package/scripts/wave-orchestrator/retry-control.mjs +17 -2
  40. package/scripts/wave-orchestrator/retry-engine.mjs +85 -0
  41. package/scripts/wave-orchestrator/role-helpers.mjs +73 -1
  42. package/scripts/wave-orchestrator/session-supervisor.mjs +113 -0
  43. package/scripts/wave-orchestrator/shared.mjs +2 -0
  44. package/scripts/wave-orchestrator/signals.mjs +681 -0
  45. package/scripts/wave-orchestrator/skills.mjs +1 -0
  46. package/scripts/wave-orchestrator/task-entity.mjs +65 -45
  47. package/scripts/wave-orchestrator/wave-control-schema.mjs +2 -0
  48. package/scripts/wave-orchestrator/wave-files.mjs +85 -1
  49. package/scripts/wave-orchestrator/wave-state-reducer.mjs +24 -7
  50. package/scripts/wave-status.sh +200 -0
  51. package/scripts/wave-watch.sh +200 -0
  52. package/skills/README.md +10 -0
  53. package/skills/role-design/SKILL.md +50 -0
  54. package/skills/role-design/skill.json +36 -0
  55. package/skills/signal-hygiene/SKILL.md +51 -0
  56. package/skills/signal-hygiene/skill.json +20 -0
  57. package/skills/tui-design/SKILL.md +77 -0
  58. package/skills/tui-design/references/tui-design.md +259 -0
  59. package/skills/tui-design/skill.json +36 -0
  60. package/wave.config.json +15 -1
@@ -96,7 +96,7 @@ Unified operator control surface. Preferred over legacy `wave coord`, `wave retr
96
96
 
97
97
  ### wave control status
98
98
 
99
- Read-only view: blocking edges, logical agent state, tasks, dependencies, rerun intent, proof bundles, and next timers.
99
+ Read-only view: blocking edges, logical agent state, tasks, dependencies, rerun intent, proof bundles, next timers, and derived wave or agent signal snapshots.
100
100
 
101
101
  When a launcher attempt is already running, `wave control status` treats that active attempt as the authoritative current fan-out. Older relaunch plans or unrelated closure blockers remain visible in the payload, but they do not override the live attempt view.
102
102
 
@@ -104,6 +104,15 @@ When a launcher attempt is already running, `wave control status` treats that ac
104
104
  wave control status --lane <lane> --wave <n> [--agent <id>] [--run <id>] [--json]
105
105
  ```
106
106
 
107
+ The JSON payload now includes:
108
+
109
+ - `signals.wave`
110
+ Versioned wave-level signal state for wrappers and external operators.
111
+ - `signals.agents`
112
+ Versioned per-agent signal state, including `shouldWake` plus any observed ack metadata.
113
+
114
+ Starter repos also include `scripts/wave-status.sh` and `scripts/wave-watch.sh` as thin readers over this JSON payload. They use exit `0` for completed, `20` for input-required, `40` for failed, and `30` from `wave-watch.sh --until-change` when the signal changed but the wave stayed active. For the full wrapper contract, read [../guides/signal-wrappers.md](../guides/signal-wrappers.md).
115
+
107
116
  ### wave control telemetry
108
117
 
109
118
  Inspect and deliver the local Wave Control event queue.
@@ -534,6 +543,18 @@ wave draft --show-run <run-id>
534
543
  wave draft --apply-run <run-id>
535
544
  ```
536
545
 
546
+ Interactive draft currently offers worker role kinds:
547
+
548
+ - `design`
549
+ - `implementation`
550
+ - `qa`
551
+ - `infra`
552
+ - `deploy`
553
+ - `research`
554
+ - `security`
555
+
556
+ Agentic planner payloads also accept `workerAgents[].roleKind = "design"`. The shipped `0.8.6` surface uses `design-pass` as the default executor profile for that role and typically assigns a packet path like `docs/plans/waves/design/wave-<n>-<agentId>.md`. Interactive draft scaffolds the docs-first default; hybrid design stewards are authored by explicitly adding implementation-owned paths and the normal implementation contract sections.
557
+
537
558
  ## Ad-Hoc Task Commands
538
559
 
539
560
  **Plan and run ad-hoc tasks:**
@@ -2,7 +2,7 @@
2
2
 
3
3
  This repo now includes a dedicated npmjs publish workflow at [publish-npm.yml](../../.github/workflows/publish-npm.yml).
4
4
 
5
- The current `0.8.4` release procedure publishes through a repository Actions secret named `NPM_TOKEN`.
5
+ The current `0.8.6` release procedure publishes through a repository Actions secret named `NPM_TOKEN`.
6
6
 
7
7
  ## What This Repo Already Does
8
8
 
@@ -48,6 +48,6 @@ If this repo later needs private npm dependencies during CI, consider a separate
48
48
  2. Confirm `NPM_TOKEN` exists in the GitHub repo secrets.
49
49
  3. Confirm the package version has been bumped and committed.
50
50
  4. Confirm `README.md`, `CHANGELOG.md`, `releases/manifest.json`, and `docs/plans/migration.md` all describe the same release surface.
51
- 5. Push the release commit and release tag, for example `v0.8.4`.
51
+ 5. Push the release commit and release tag, for example `v0.8.6`.
52
52
  6. Verify both `publish-npm.yml` and `publish-package.yml` start from the tag push.
53
53
  7. Verify the npmjs publish completes successfully for the tagged source.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: "Sample Waves"
3
- summary: "Showcase-first sample waves that demonstrate the current 0.8.4 Wave surface."
3
+ summary: "Showcase-first sample waves that demonstrate the shipped 0.8.6 authored surface, including the optional design-role path."
4
4
  ---
5
5
 
6
6
  # Sample Waves
7
7
 
8
- This guide points to showcase-first sample waves that demonstrate the current `0.8.4` authored Wave surface.
8
+ This guide points to showcase-first sample waves that demonstrate the shipped `0.8.6` authored Wave surface.
9
9
 
10
10
  The examples are intentionally denser than typical production waves. Their job is to teach the current authoring and runtime surface quickly, not to be the smallest possible launch-ready files.
11
11
 
@@ -15,7 +15,10 @@ The examples are intentionally denser than typical production waves. Their job i
15
15
  Shows what a good `repo-landed` outcome looks like when one promoted component only closes honestly if desired-state records, reconcile-loop substrate, and cluster-view surfaces land together. It emphasizes maturity discipline, explicit deliverables, and shared-plan closure without drifting into `pilot-live` claims.
16
16
 
17
17
  - [Full modern sample wave](../plans/examples/wave-example-live-proof.md)
18
- Shows the combined `0.8.4` authored surface in one file: closure roles, `E0`, optional security review, delegated and pinned benchmark targets, richer executor config, `### Skills`, `### Capabilities`, `### Deliverables`, `### Exit contract`, `### Proof artifacts`, sticky retry, deploy environments, and proof-first live-wave structure.
18
+ Shows the combined `0.8.6` authored surface in one file: closure roles, `E0`, optional security review, delegated and pinned benchmark targets, richer executor config, `### Skills`, `### Capabilities`, `### Deliverables`, `### Exit contract`, `### Proof artifacts`, sticky retry, deploy environments, and proof-first live-wave structure.
19
+
20
+ - [Optional design-steward handoff wave](../plans/examples/wave-example-design-handoff.md)
21
+ Shows the shipped design-role surface: one pre-implementation design steward publishes a design packet, downstream implementation owners read that packet before coding, and normal closure roles still decide final completion. For terminal or operator-surface work, pair that shape with explicit `tui-design` in the design steward's `### Skills`. For the hybrid variant, explicitly give that same design agent implementation-owned paths and the normal implementation contract sections.
19
22
 
20
23
  ## What These Examples Teach
21
24
 
@@ -35,10 +38,11 @@ The examples are intentionally denser than typical production waves. Their job i
35
38
  - sticky retry for proof-bearing owners
36
39
  - deploy environments and provider-skill examples
37
40
  - infra and deploy-verifier specialist slices
41
+ - optional pre-implementation design packets and design-to-implementation handoff
38
42
 
39
43
  ## Feature Coverage Map
40
44
 
41
- Together these samples cover the main surfaces added or hardened for `0.8.4`:
45
+ Together these samples cover the main surfaces added or hardened through `0.8.6`:
42
46
 
43
47
  - repo-landed maturity discipline and anti-overclaim framing
44
48
  - explicit shared-plan closure for future-wave safety
@@ -56,6 +60,7 @@ Together these samples cover the main surfaces added or hardened for `0.8.4`:
56
60
  - proof-first live-wave prompts
57
61
  - deploy environments and deploy-kind-aware skills
58
62
  - integration, documentation, and cont-QA closure-role structure
63
+ - optional `design` worker role and `design-pass` executor profile
59
64
 
60
65
  ## When To Copy Literally Vs Adapt
61
66
 
@@ -76,6 +81,7 @@ Adapt more aggressively when:
76
81
  ## How This Example Maps To Other Docs
77
82
 
78
83
  - Use [docs/guides/planner.md](../guides/planner.md) for the planner-generated baseline, then use these samples to see how a human would enrich the generated draft for either repo-landed or proof-first work.
84
+ - Use [Optional design-steward handoff wave](../plans/examples/wave-example-design-handoff.md) when the wave should start with a reusable design packet before implementation begins.
79
85
  - Use [docs/evals/README.md](../evals/README.md) with the full modern sample when you need to see delegated and pinned benchmark targets in a real wave.
80
86
  - Use [docs/reference/live-proof-waves.md](./live-proof-waves.md) with the full modern sample when you need proof-first authoring for `pilot-live` and above.
81
87
  - Use [docs/plans/wave-orchestrator.md](../plans/wave-orchestrator.md) for the operational runbook that explains how the launcher interprets these sections.
@@ -83,9 +89,10 @@ Adapt more aggressively when:
83
89
  ## Suggested Reading Order
84
90
 
85
91
  1. Start with [High-fidelity repo-landed rollout wave](../plans/examples/wave-example-rollout-fidelity.md) if you want the clearest example of good closure-ready wave fidelity for a repo-only outcome.
86
- 2. Read [Full modern sample wave](../plans/examples/wave-example-live-proof.md) if you want the denser proof-first and eval-heavy surface.
87
- 3. Read [docs/evals/README.md](../evals/README.md) if you want more background on benchmark target selection.
88
- 4. Read [docs/reference/live-proof-waves.md](./live-proof-waves.md) if you want more detail on proof-first `pilot-live` authoring.
92
+ 2. Read [Full modern sample wave](../plans/examples/wave-example-live-proof.md) if you want the denser proof-first and eval-heavy `0.8.6` surface.
93
+ 3. Read [Optional design-steward handoff wave](../plans/examples/wave-example-design-handoff.md) if the task needs a design packet before implementation fan-out.
94
+ 4. Read [docs/evals/README.md](../evals/README.md) if you want more background on benchmark target selection.
95
+ 5. Read [docs/reference/live-proof-waves.md](./live-proof-waves.md) if you want more detail on proof-first `pilot-live` authoring.
89
96
 
90
97
  ## Why These Examples Live In `docs/plans/examples/`
91
98
 
@@ -109,6 +109,7 @@ Top-level and lane-local skill attachment use the same shape:
109
109
  "dir": "skills",
110
110
  "base": ["wave-core", "repo-coding-rules"],
111
111
  "byRole": {
112
+ "design": ["role-design"],
112
113
  "deploy": ["role-deploy"]
113
114
  },
114
115
  "byRuntime": {
@@ -123,6 +124,10 @@ Top-level and lane-local skill attachment use the same shape:
123
124
 
124
125
  Lane-local `lanes.<lane>.skills` extends the global config instead of replacing it.
125
126
 
127
+ Optional design workers in the shipped `0.8.6` surface normally attach `role-design`. That bundle is intended for docs/spec-first design packets and explicit implementation handoff work before implementation starts. When the design packet covers terminal UX, dashboards, or other operator surfaces, add `tui-design` explicitly in the wave's `### Skills`.
128
+
129
+ Long-running agents that should stay resident and react only to orchestrator signal changes can add `signal-hygiene` explicitly in `### Skills`. That bundle is not auto-attached and is not meant for normal one-shot implementation agents.
130
+
126
131
  ## Resolution Order
127
132
 
128
133
  Resolved skills are gathered in this order:
@@ -195,6 +200,18 @@ Runtime delivery:
195
200
 
196
201
  These runtime projections are guidance surfaces. They should stay aligned with the canonical authority model, but they are not replay inputs or decision state on their own.
197
202
 
203
+ For the optional `design` worker role, the default pattern is:
204
+
205
+ - `role-design` for the design packet contract
206
+ - `tui-design` only when the packet covers terminal UX, dashboards, or other operator surfaces
207
+ - no runtime-specific coding bundle unless the wave explicitly gives the design steward code ownership and makes it a hybrid design steward
208
+
209
+ For long-running watcher agents, the default pattern is:
210
+
211
+ - no special bundle by default
212
+ - add `signal-hygiene` only when the agent should stay alive and wait for signal-version changes
213
+ - use the provided signal state path plus signal ack path instead of inventing a second wakeup loop
214
+
198
215
  ## Generated Artifacts
199
216
 
200
217
  Executor overlay directories can contain:
@@ -225,3 +242,4 @@ Missing or malformed bundles are configuration errors, not silent no-ops.
225
242
  - Use explicit per-agent `### Skills` for true exceptions, not as a substitute for missing activation metadata.
226
243
  - Keep provider skills role-scoped unless every role genuinely needs the provider context.
227
244
  - Keep bundle ids stable so traces and prompt fingerprints remain intelligible across runs.
245
+ - Keep `role-design` docs/spec-first by default; add `tui-design` when terminal or operator-surface work is in scope, and only attach broader coding bundles when the wave explicitly assigns code ownership and expects the same design steward to return for implementation.
@@ -19,6 +19,8 @@ Wave Control normalizes these entity types:
19
19
 
20
20
  - `wave_run`
21
21
  - `agent_run`
22
+ - `wave_signal`
23
+ - `agent_signal`
22
24
  - `coordination_record`
23
25
  - `task`
24
26
  - `attempt`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chllming/wave-orchestration",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "license": "MIT",
5
5
  "description": "Generic wave-based multi-agent orchestration for repository work.",
6
6
  "repository": {
@@ -2,6 +2,44 @@
2
2
  "schemaVersion": 1,
3
3
  "packageName": "@chllming/wave-orchestration",
4
4
  "releases": [
5
+ {
6
+ "version": "0.8.6",
7
+ "date": "2026-03-25",
8
+ "summary": "Signal-hygiene starter surface, versioned signal wrappers, terminal watcher hardening, and 0.8.6 release-surface alignment.",
9
+ "features": [
10
+ "Versioned wave and agent signal snapshots now ship as part of the operator surface under `.tmp/<lane>-wave-launcher/signals/`, with resident-orchestrator and long-running-agent ack loops built on the same model.",
11
+ "Starter repos now include `skills/signal-hygiene/`, `scripts/wave-status.sh`, and `scripts/wave-watch.sh` for long-running watcher agents plus shell-friendly operator automation.",
12
+ "Wrapper exit semantics now expose terminal failure with exit `40`, while `wave-watch.sh --until-change` still returns `30` only when a signal changed and the wave stayed active.",
13
+ "Agent signal materialization now treats completed and failed as terminal even when stale answered feedback or old coordination tasks still exist in the materialized status payload.",
14
+ "The migration guide now covers fresh adoption plus upgrades from `0.8.5`, `0.8.4`, `0.8.3`, `0.8.0`-`0.8.4`, `0.6.x`-`0.7.x`, and `0.5.x` or earlier, including repo-owned sync guidance for `skills/signal-hygiene/`, the wrapper scripts, and the `planner-agentic` corpus."
15
+ ],
16
+ "manualSteps": [
17
+ "Run `pnpm exec wave doctor` and `pnpm exec wave launch --lane main --dry-run --no-dashboard` after upgrading so the repo validates against the `0.8.6` signal-hygiene, wrapper, and design-role behavior.",
18
+ "If your repo copied starter prompts, skills, scripts, or runbooks, sync `skills/signal-hygiene/`, `scripts/wave-status.sh`, `scripts/wave-watch.sh`, `docs/guides/signal-wrappers.md`, `docs/guides/terminal-surfaces.md`, `docs/reference/cli-reference.md`, and any local operator docs that describe waiting or failure handling.",
19
+ "If your repo uses planner workflows and copied the planner starter corpus, keep `docs/agents/wave-planner-role.md`, `skills/role-planner/`, `docs/context7/planner-agent/`, `docs/reference/wave-planning-lessons.md`, and the `planner-agentic` bundle entry in sync before relying on local planner docs.",
20
+ "If your repo uses long-running watcher agents or shell automation, update local loops so wrapper exit `40` is treated as terminal failure and confirm watchers can write their signal ack files under `.tmp/<lane>-wave-launcher/signals/`."
21
+ ],
22
+ "breaking": false
23
+ },
24
+ {
25
+ "version": "0.8.5",
26
+ "date": "2026-03-25",
27
+ "summary": "Shipped design-role support, hybrid design-steward execution, release-surface alignment, and a practical migration guide.",
28
+ "features": [
29
+ "The optional `design` worker role is now part of the published release surface, including the standing design prompt, `role-design`, and `tui-design` starter bundles.",
30
+ "Design stewards are docs-first by default, but waves can now explicitly give them implementation ownership so the same agent runs a design pass first and then rejoins implementation with normal proof obligations.",
31
+ "Design-aware validation, prompts, gates, retry or resume planning, reducer state, local-executor smoke behavior, and result-envelope projection now all agree on the same hybrid-design contract.",
32
+ "The migration guide now covers fresh adoption plus upgrades from `0.8.4`, `0.8.0`-`0.8.4`, `0.6.x`-`0.7.x`, and `0.5.x` or earlier, including repo-owned starter-surface sync guidance and `planner-agentic` corpus notes.",
33
+ "Shipped package metadata, README, current-state notes, sample-wave docs, and publishing guidance now point at the `0.8.5` release surface."
34
+ ],
35
+ "manualSteps": [
36
+ "Run `pnpm exec wave doctor` and `pnpm exec wave launch --lane main --dry-run --no-dashboard` after upgrading so the repo validates against the `0.8.5` design-role and hybrid-design behavior.",
37
+ "If your repo copied starter prompts, skills, or authoring docs, sync `docs/agents/wave-design-role.md`, `skills/role-design/`, `skills/tui-design/`, `wave.config.json` design-role keys, and any local planner or runbook pages that should describe the new design-steward model.",
38
+ "If a repo uses hybrid design stewards, make sure each one still owns a design packet path and that any explicit implementation ownership also carries the expected exit contract, deliverables, proof artifacts, and component declarations where your lane validation requires them.",
39
+ "If your repo uses planner workflows and copied the planner starter corpus, keep `docs/agents/wave-planner-role.md`, `skills/role-planner/`, `docs/context7/planner-agent/`, `docs/reference/wave-planning-lessons.md`, and the `planner-agentic` bundle entry in sync before relying on local planner docs."
40
+ ],
41
+ "breaking": false
42
+ },
5
43
  {
6
44
  "version": "0.8.4",
7
45
  "date": "2026-03-25",
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env bash
2
- # Minimal Context7 API smoke test (expects CONTEXT7_API_KEY in the environment).
3
2
  set -euo pipefail
4
3
 
5
4
  if [[ -z "${CONTEXT7_API_KEY:-}" ]]; then
@@ -7,15 +6,60 @@ if [[ -z "${CONTEXT7_API_KEY:-}" ]]; then
7
6
  exit 1
8
7
  fi
9
8
 
10
- URL='https://context7.com/api/v2/libs/search?libraryName=temporal&query=go%20workflow'
11
- echo "GET $URL" >&2
12
- RESP="$(curl -fsS "$URL" -H "Authorization: Bearer ${CONTEXT7_API_KEY}" -H "Accept: application/json")"
13
- RESP_JSON="$RESP" node -e "
14
- const j = JSON.parse(process.env.RESP_JSON || '{}');
15
- const list = Array.isArray(j) ? j : (j.results ?? j.items ?? []);
16
- const first = list[0];
17
- if (!first) { console.error('Unexpected response shape:', Object.keys(j)); process.exit(1); }
18
- const id = first.id ?? first.libraryId;
19
- const name = first.title ?? first.name;
20
- console.log('ok — first library:', id || name || JSON.stringify(first).slice(0, 120));
21
- "
9
+ node <<'NODE'
10
+ const fs = require("fs");
11
+ const path = require("path");
12
+
13
+ const apiKey = process.env.CONTEXT7_API_KEY || "";
14
+ const repoRoot = process.cwd();
15
+ const bundlePath = path.join(repoRoot, "docs/context7/bundles.json");
16
+ const payload = JSON.parse(fs.readFileSync(bundlePath, "utf8"));
17
+
18
+ const entries = [];
19
+ for (const [bundleId, bundle] of Object.entries(payload.bundles || {})) {
20
+ for (const library of bundle.libraries || []) {
21
+ if (!library.libraryId) {
22
+ throw new Error(
23
+ `Bundle "${bundleId}" must pin exact Context7 libraryId values. Found libraryName=${JSON.stringify(library.libraryName || "")}.`,
24
+ );
25
+ }
26
+ entries.push({
27
+ bundleId,
28
+ libraryId: String(library.libraryId),
29
+ queryHint: String(library.queryHint || "overview"),
30
+ });
31
+ }
32
+ }
33
+
34
+ const uniqueEntries = [...new Map(entries.map((entry) => [entry.libraryId, entry])).values()];
35
+
36
+ async function validate(entry) {
37
+ const url = new URL("https://context7.com/api/v2/context");
38
+ url.searchParams.set("libraryId", entry.libraryId);
39
+ url.searchParams.set("query", entry.queryHint);
40
+ url.searchParams.set("type", "txt");
41
+ const response = await fetch(url, {
42
+ headers: {
43
+ Authorization: "Bearer " + apiKey,
44
+ Accept: "text/plain, application/json",
45
+ },
46
+ });
47
+ const text = await response.text();
48
+ if (!response.ok) {
49
+ throw new Error(`Context7 ${entry.libraryId} failed (${response.status}): ${text.slice(0, 200)}`);
50
+ }
51
+ if (text.trim().length === 0) {
52
+ throw new Error(`Context7 ${entry.libraryId} returned empty context.`);
53
+ }
54
+ console.log(`ok -- ${entry.libraryId} (${entry.bundleId})`);
55
+ }
56
+
57
+ (async () => {
58
+ for (const entry of uniqueEntries) {
59
+ await validate(entry);
60
+ }
61
+ })().catch((error) => {
62
+ console.error(error instanceof Error ? error.message : String(error));
63
+ process.exit(1);
64
+ });
65
+ NODE
@@ -47,6 +47,8 @@ const WAVE_EVAL_REGEX =
47
47
  /^\[wave-eval\]\s*state=(satisfied|needs-more-work|blocked)\s+targets=(\d+)\s+benchmarks=(\d+)\s+regressions=(\d+)(?:\s+target_ids=([^\s]+))?(?:\s+benchmark_ids=([^\s]+))?\s*(?:detail=(.*))?$/gim;
48
48
  const WAVE_SECURITY_REGEX =
49
49
  /^\[wave-security\]\s*state=(clear|concerns|blocked)\s+findings=(\d+)\s+approvals=(\d+)\s*(?:detail=(.*))?$/gim;
50
+ const WAVE_DESIGN_REGEX =
51
+ /^\[wave-design\]\s*state=(ready-for-implementation|needs-clarification|blocked)\s+decisions=(\d+)\s+assumptions=(\d+)\s+open_questions=(\d+)\s*(?:detail=(.*))?$/gim;
50
52
  const WAVE_GATE_REGEX =
51
53
  /^\[wave-gate\]\s*architecture=(pass|concerns|blocked)\s+integration=(pass|concerns|blocked)\s+durability=(pass|concerns|blocked)\s+live=(pass|concerns|blocked)\s+docs=(pass|concerns|blocked)\s*(?:detail=(.*))?$/gim;
52
54
  const WAVE_GAP_REGEX =
@@ -64,6 +66,7 @@ const STRUCTURED_SIGNAL_KIND_BY_TAG = {
64
66
  integration: "integration",
65
67
  eval: "eval",
66
68
  security: "security",
69
+ design: "design",
67
70
  gate: "gate",
68
71
  gap: "gap",
69
72
  component: "component",
@@ -76,6 +79,7 @@ const STRUCTURED_SIGNAL_LINE_REGEX_BY_KIND = {
76
79
  integration: new RegExp(WAVE_INTEGRATION_REGEX.source, "i"),
77
80
  eval: new RegExp(WAVE_EVAL_REGEX.source, "i"),
78
81
  security: new RegExp(WAVE_SECURITY_REGEX.source, "i"),
82
+ design: new RegExp(WAVE_DESIGN_REGEX.source, "i"),
79
83
  gate: new RegExp(WAVE_GATE_REGEX.source, "i"),
80
84
  gap: new RegExp(WAVE_GAP_REGEX.source, "i"),
81
85
  component: new RegExp(WAVE_COMPONENT_REGEX.source, "i"),
@@ -89,6 +93,7 @@ function buildEmptyStructuredSignalDiagnostics() {
89
93
  integration: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
90
94
  eval: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
91
95
  security: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
96
+ design: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
92
97
  gate: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
93
98
  gap: { rawCount: 0, acceptedCount: 0, rejectedSamples: [] },
94
99
  component: { rawCount: 0, acceptedCount: 0, rejectedSamples: [], seenComponentIds: [] },
@@ -509,6 +514,13 @@ export function buildAgentExecutionSummary({ agent, statusRecord, logPath, repor
509
514
  approvals: Number.parseInt(String(match[3] || "0"), 10) || 0,
510
515
  detail: cleanText(match[4]),
511
516
  })),
517
+ design: findLastMatch(signalText, WAVE_DESIGN_REGEX, (match) => ({
518
+ state: match[1],
519
+ decisions: Number.parseInt(String(match[2] || "0"), 10) || 0,
520
+ assumptions: Number.parseInt(String(match[3] || "0"), 10) || 0,
521
+ openQuestions: Number.parseInt(String(match[4] || "0"), 10) || 0,
522
+ detail: cleanText(match[5]),
523
+ })),
512
524
  gate: findLastMatch(signalText, WAVE_GATE_REGEX, (match) => ({
513
525
  architecture: match[1],
514
526
  integration: match[2],
@@ -951,6 +963,58 @@ export function validateSecuritySummary(agent, summary) {
951
963
  };
952
964
  }
953
965
 
966
+ export function validateDesignSummary(agent, summary) {
967
+ if (!summary?.design) {
968
+ return {
969
+ ok: false,
970
+ statusCode: "missing-wave-design",
971
+ detail: appendTerminationHint(
972
+ `Missing [wave-design] marker for ${agent?.agentId || "D1"}.`,
973
+ summary,
974
+ ),
975
+ };
976
+ }
977
+ if (!summary.reportPath) {
978
+ return {
979
+ ok: false,
980
+ statusCode: "missing-design-packet",
981
+ detail: `Missing design packet path for ${agent?.agentId || "D1"}.`,
982
+ };
983
+ }
984
+ if (!fs.existsSync(path.resolve(REPO_ROOT, summary.reportPath))) {
985
+ return {
986
+ ok: false,
987
+ statusCode: "missing-design-packet",
988
+ detail: `Missing design packet at ${summary.reportPath}.`,
989
+ };
990
+ }
991
+ if (summary.design.state === "blocked") {
992
+ return {
993
+ ok: false,
994
+ statusCode: "design-blocked",
995
+ detail:
996
+ summary.design.detail ||
997
+ `Design packet reported blocked for ${agent?.agentId || "D1"}.`,
998
+ };
999
+ }
1000
+ if (summary.design.state === "needs-clarification") {
1001
+ return {
1002
+ ok: false,
1003
+ statusCode: "design-needs-clarification",
1004
+ detail:
1005
+ summary.design.detail ||
1006
+ `Design packet requested clarification for ${agent?.agentId || "D1"}.`,
1007
+ };
1008
+ }
1009
+ return {
1010
+ ok: true,
1011
+ statusCode: "pass",
1012
+ detail:
1013
+ summary.design.detail ||
1014
+ "Design packet is ready for implementation.",
1015
+ };
1016
+ }
1017
+
954
1018
  export function validateIntegrationSummary(agent, summary) {
955
1019
  if (!summary?.integration) {
956
1020
  return {
@@ -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
 
@@ -36,6 +36,10 @@ import { readWaveRelaunchPlanSnapshot, readWaveRetryOverride, resolveRetryOverri
36
36
  import { flushWaveControlQueue, readWaveControlQueueState } from "./wave-control-client.mjs";
37
37
  import { readAgentExecutionSummary, validateImplementationSummary } from "./agent-state.mjs";
38
38
  import { isContEvalReportOnlyAgent, isSecurityReviewAgent } from "./role-helpers.mjs";
39
+ import {
40
+ buildSignalStatusLine,
41
+ syncWaveSignalProjections,
42
+ } from "./signals.mjs";
39
43
 
40
44
  function printUsage() {
41
45
  console.log(`Usage:
@@ -676,6 +680,7 @@ export function buildControlStatusPayload({ lanePaths, wave, agentId = "" }) {
676
680
  proofBundles: (proofRegistry?.entries || []).filter(
677
681
  (entry) => !agentId || entry.agentId === agentId,
678
682
  ),
683
+ feedbackRequests,
679
684
  selectionSource: selection.source,
680
685
  rerunRequest,
681
686
  relaunchPlan,
@@ -690,6 +695,7 @@ function ensureWaveStateDirs(lanePaths) {
690
695
  ensureDirectory(lanePaths.controlPlaneDir);
691
696
  ensureDirectory(lanePaths.assignmentsDir);
692
697
  ensureDirectory(lanePaths.inboxesDir);
698
+ ensureDirectory(lanePaths.signalsDir);
693
699
  ensureDirectory(lanePaths.messageboardsDir);
694
700
  ensureDirectory(lanePaths.docsQueueDir);
695
701
  ensureDirectory(lanePaths.ledgerDir);
@@ -714,6 +720,9 @@ function printStatus(payload) {
714
720
  ? `${payload.blockingEdge.kind} ${payload.blockingEdge.id}: ${payload.blockingEdge.detail}`
715
721
  : "none";
716
722
  console.log(`lane=${payload.lane} wave=${payload.wave} phase=${payload.phase}`);
723
+ if (payload.signals?.wave) {
724
+ console.log(buildSignalStatusLine(payload.signals.wave, payload));
725
+ }
717
726
  console.log(`blocking=${blocking}`);
718
727
  if (payload.nextTimer) {
719
728
  console.log(`next-timer=${payload.nextTimer.kind} ${payload.nextTimer.taskId} at ${payload.nextTimer.at}`);
@@ -901,6 +910,16 @@ export async function runControlCli(argv) {
901
910
  wave,
902
911
  agentId: options.agent || "",
903
912
  });
913
+ const signalSync = syncWaveSignalProjections({
914
+ lanePaths,
915
+ wave,
916
+ statusPayload: payload,
917
+ includeResident: Boolean(options.orchestratorId),
918
+ });
919
+ payload.signals = {
920
+ wave: signalSync.wave?.snapshot || null,
921
+ agents: (signalSync.agents || []).map((entry) => entry.snapshot),
922
+ };
904
923
  if (options.json) {
905
924
  console.log(JSON.stringify(payload, null, 2));
906
925
  } else {