@hegemonart/get-design-done 1.26.0 → 1.27.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 (34) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +74 -0
  4. package/README.md +10 -8
  5. package/SKILL.md +3 -0
  6. package/agents/README.md +29 -0
  7. package/package.json +2 -2
  8. package/reference/peer-cli-capabilities.md +151 -0
  9. package/reference/peer-protocols.md +266 -0
  10. package/reference/registry.json +14 -0
  11. package/reference/runtime-models.md +3 -3
  12. package/scripts/install.cjs +100 -1
  13. package/scripts/lib/bandit-router.cjs +214 -7
  14. package/scripts/lib/budget-enforcer.cjs +69 -1
  15. package/scripts/lib/event-stream/index.ts +14 -1
  16. package/scripts/lib/event-stream/types.ts +125 -1
  17. package/scripts/lib/install/runtimes.cjs +58 -0
  18. package/scripts/lib/peer-cli/acp-client.cjs +375 -0
  19. package/scripts/lib/peer-cli/adapters/codex.cjs +101 -0
  20. package/scripts/lib/peer-cli/adapters/copilot.cjs +79 -0
  21. package/scripts/lib/peer-cli/adapters/cursor.cjs +78 -0
  22. package/scripts/lib/peer-cli/adapters/gemini.cjs +81 -0
  23. package/scripts/lib/peer-cli/adapters/qwen.cjs +72 -0
  24. package/scripts/lib/peer-cli/asp-client.cjs +587 -0
  25. package/scripts/lib/peer-cli/broker-lifecycle.cjs +406 -0
  26. package/scripts/lib/peer-cli/registry.cjs +434 -0
  27. package/scripts/lib/peer-cli/spawn-cmd.cjs +149 -0
  28. package/scripts/lib/runtime-detect.cjs +1 -1
  29. package/scripts/lib/session-runner/index.ts +362 -0
  30. package/scripts/lib/session-runner/types.ts +60 -0
  31. package/scripts/validate-frontmatter.ts +159 -1
  32. package/skills/peer-cli-add/SKILL.md +170 -0
  33. package/skills/peer-cli-customize/SKILL.md +110 -0
  34. package/skills/peers/SKILL.md +101 -0
@@ -0,0 +1,266 @@
1
+ # Peer-CLI Protocols — ACP + ASP Cheat Sheet
2
+
3
+ **Phase 27 (v1.27.0).** This file is the protocol-level reference for gdd's peer-CLI delegation layer. If you're authoring a new peer adapter or debugging a protocol-level issue, start here.
4
+
5
+ For ops-level guidance (when delegation fires, how to enable/disable, fallback diagnostics), see `docs/PEER-DELEGATION.md`.
6
+
7
+ Protocol shapes are adapted from [`greenpolo/cc-multi-cli-plugin`](https://github.com/greenpolo/cc-multi-cli-plugin) under Apache 2.0 — see `NOTICE` for full attribution.
8
+
9
+ ---
10
+
11
+ ## Two protocols, two transports
12
+
13
+ | Protocol | Used by | Transport | Lifecycle |
14
+ |----------|---------|-----------|-----------|
15
+ | **ACP** (Agent Client Protocol) | Gemini, Cursor, Copilot, Qwen | Line-delimited JSON-RPC over stdio | Per-prompt request/response |
16
+ | **ASP** (App Server Protocol) | Codex | Line-delimited JSON-RPC over stdio | Thread-oriented, multi-turn |
17
+
18
+ Both protocols use the same line-delimited JSON-RPC framing (one JSON message per `\n`-terminated line on stdin/stdout). Both can be wrapped by gdd's broker (`scripts/lib/peer-cli/broker-lifecycle.cjs`) for long-lived sessions per `(peer, workspace)`.
19
+
20
+ Line-buffer overflow guard: 16 MiB per line (both clients reject lines longer than this with a structured error).
21
+
22
+ ---
23
+
24
+ ## ACP — Agent Client Protocol
25
+
26
+ ### Initialize handshake
27
+
28
+ Client → server, first message after spawn:
29
+
30
+ ```json
31
+ {
32
+ "id": 1,
33
+ "jsonrpc": "2.0",
34
+ "method": "initialize",
35
+ "params": {
36
+ "protocolVersion": "2025-06-18",
37
+ "clientCapabilities": {}
38
+ }
39
+ }
40
+ ```
41
+
42
+ Server → client (reply correlated by `id`):
43
+
44
+ ```json
45
+ {
46
+ "id": 1,
47
+ "jsonrpc": "2.0",
48
+ "result": {
49
+ "protocolVersion": "2025-06-18",
50
+ "serverCapabilities": { "...": "..." }
51
+ }
52
+ }
53
+ ```
54
+
55
+ If `serverCapabilities.protocolVersion` does not match the client's, the client logs a `protocol_mismatch` event and aborts the session.
56
+
57
+ ### Prompt method
58
+
59
+ Client → server:
60
+
61
+ ```json
62
+ {
63
+ "id": 2,
64
+ "jsonrpc": "2.0",
65
+ "method": "prompt",
66
+ "params": {
67
+ "text": "Research best React state libs"
68
+ }
69
+ }
70
+ ```
71
+
72
+ Server → client streams notifications (no `id`, no `result`) until the final `result` for the prompt's `id`:
73
+
74
+ ```json
75
+ { "jsonrpc": "2.0", "method": "agent_message_chunk", "params": { "text": "..." } }
76
+ { "jsonrpc": "2.0", "method": "tool_call", "params": { "tool": "...", "input": "..." } }
77
+ { "jsonrpc": "2.0", "method": "file_change", "params": { "path": "...", "diff": "..." } }
78
+ { "id": 2, "jsonrpc": "2.0", "result": { "content": "...", "finish_reason": "stop", "usage": { "input_tokens": 1234, "output_tokens": 5678 } } }
79
+ ```
80
+
81
+ Notifications are surfaced via the `onNotification` callback the gdd caller passes:
82
+
83
+ ```js
84
+ const result = await acpClient.prompt('Research ...', {
85
+ onNotification: (n) => console.log(n.method, n.params),
86
+ });
87
+ ```
88
+
89
+ ### Per-peer ACP entry points
90
+
91
+ Each peer documents its own way to enter ACP mode:
92
+
93
+ - **Gemini**: `gemini acp` (subcommand).
94
+ - **Cursor**: `cursor-agent acp` (subcommand on the CLI binary, not the IDE).
95
+ - **Copilot**: `copilot --acp` (flag).
96
+ - **Qwen**: `qwen acp` (subcommand).
97
+
98
+ Verify via the `peer-cli-add` skill's verification ladder (Step 1) before adding a new peer.
99
+
100
+ ---
101
+
102
+ ## ASP — App Server Protocol (Codex)
103
+
104
+ ### Service identification
105
+
106
+ Client → server, declared during initial communication:
107
+
108
+ - `service_name = "gdd_peer_delegation"` (the canonical service identifier gdd uses)
109
+ - `experimentalRawEvents = false` (we don't want raw model-token events; just structured turn output)
110
+
111
+ These fields appear in both `threadStart` params and (where relevant) in handshake metadata.
112
+
113
+ ### Thread lifecycle
114
+
115
+ ASP is thread-oriented. Each conversation has a `threadId`; turns happen within a thread.
116
+
117
+ #### threadStart
118
+
119
+ Client → server:
120
+
121
+ ```json
122
+ {
123
+ "id": 1,
124
+ "jsonrpc": "2.0",
125
+ "method": "threadStart",
126
+ "params": {
127
+ "service_name": "gdd_peer_delegation",
128
+ "experimentalRawEvents": false
129
+ }
130
+ }
131
+ ```
132
+
133
+ Server → client:
134
+
135
+ ```json
136
+ {
137
+ "id": 1,
138
+ "jsonrpc": "2.0",
139
+ "result": {
140
+ "threadId": "thread-abc123"
141
+ }
142
+ }
143
+ ```
144
+
145
+ #### threadResume
146
+
147
+ Useful for cross-cycle conversation continuity (out of scope for v1.27.0 — gdd always creates fresh threads per delegated call — but the API surface exists):
148
+
149
+ ```json
150
+ {
151
+ "id": 2,
152
+ "jsonrpc": "2.0",
153
+ "method": "threadResume",
154
+ "params": { "threadId": "thread-abc123" }
155
+ }
156
+ ```
157
+
158
+ Server replies with the thread's current state (turn history, last-known result).
159
+
160
+ #### turn
161
+
162
+ Client → server:
163
+
164
+ ```json
165
+ {
166
+ "id": 3,
167
+ "jsonrpc": "2.0",
168
+ "method": "turn",
169
+ "params": {
170
+ "threadId": "thread-abc123",
171
+ "text": "Execute the build command"
172
+ }
173
+ }
174
+ ```
175
+
176
+ Server streams turn-progress notifications, ends with a structured result:
177
+
178
+ **Completion path:**
179
+
180
+ ```json
181
+ {
182
+ "id": 3,
183
+ "jsonrpc": "2.0",
184
+ "result": {
185
+ "threadId": "thread-abc123",
186
+ "turnId": "turn-xyz",
187
+ "status": "complete",
188
+ "content": "...",
189
+ "usage": { "input_tokens": 1234, "output_tokens": 5678 }
190
+ }
191
+ }
192
+ ```
193
+
194
+ **Error path** (does NOT throw on the client side — resolves with the error structure):
195
+
196
+ ```json
197
+ {
198
+ "id": 3,
199
+ "jsonrpc": "2.0",
200
+ "result": {
201
+ "threadId": "thread-abc123",
202
+ "turnId": "turn-xyz",
203
+ "status": "error",
204
+ "error": {
205
+ "code": "rate_limit",
206
+ "message": "Rate limit exceeded for thread-abc123"
207
+ }
208
+ }
209
+ }
210
+ ```
211
+
212
+ The caller decides retry vs fallback per session-runner contract — gdd's session-runner falls back to local Anthropic on `status: "error"` per D-07.
213
+
214
+ ### Codex ASP entry point
215
+
216
+ `codex app-server` (subcommand on the Codex CLI binary).
217
+
218
+ ---
219
+
220
+ ## Common framing rules (both protocols)
221
+
222
+ ### Line-delimited JSON-RPC
223
+
224
+ - Each message is a single JSON object on stdin/stdout, terminated by `\n`.
225
+ - Multiple messages may arrive in one chunk → client buffers until `\n`.
226
+ - One message may split across chunks → client buffers until `\n`.
227
+ - Lines longer than **16 MiB** are rejected with a structured error (the line buffer overflows, the client tears down and rejects all pending promises).
228
+
229
+ ### Request/response correlation
230
+
231
+ - Requests carry `id` (monotonic integer per session).
232
+ - Responses carry the same `id` in `result` or `error`.
233
+ - Notifications have no `id` and no `result` — they are routed to the active request's `onNotification` callback (each protocol allows only one "active" request at a time per session — half-duplex).
234
+
235
+ ### Process lifecycle
236
+
237
+ - The peer process is spawned via `scripts/lib/peer-cli/spawn-cmd.cjs` (handles Windows `.cmd` EINVAL workaround per D-04).
238
+ - The client connects directly OR through gdd's broker (`broker-lifecycle.cjs`) — both surfaces present the same `{initialize, prompt, close}` (ACP) or `{threadStart, threadResume, turn, close}` (ASP) API.
239
+ - On process death mid-request, the client rejects the in-flight promise with a structured `{error_class: "process_exited"}` event for telemetry.
240
+
241
+ ---
242
+
243
+ ## Adding a new protocol
244
+
245
+ gdd v1.27.0 ships only ACP and ASP. If a new peer speaks neither (e.g., a future REST-only or HTTP/2-streaming protocol), the path forward is:
246
+
247
+ 1. Document the gap in `.design/RESEARCH.md` for a future phase to scope a new protocol layer.
248
+ 2. Do **not** stretch ACP/ASP to fit — they're documented contracts, not generalist multiplexers.
249
+ 3. The `peer-cli-add` skill (Step 1's verification ladder) refuses to scaffold a peer that doesn't speak ACP or ASP — by design.
250
+
251
+ A future phase may add a new `scripts/lib/peer-cli/<protocol>-client.cjs` mirror following the same shape (line-buffer + JSON-RPC framing if applicable, or whatever the new protocol natively uses).
252
+
253
+ ---
254
+
255
+ ## Cross-references
256
+
257
+ - `scripts/lib/peer-cli/acp-client.cjs` — ACP client implementation.
258
+ - `scripts/lib/peer-cli/asp-client.cjs` — ASP client implementation.
259
+ - `scripts/lib/peer-cli/spawn-cmd.cjs` — Windows `.cmd` EINVAL workaround.
260
+ - `scripts/lib/peer-cli/broker-lifecycle.cjs` — long-lived broker.
261
+ - `scripts/lib/peer-cli/adapters/*.cjs` — per-peer thin wrappers.
262
+ - `scripts/lib/peer-cli/registry.cjs` — central dispatch.
263
+ - `tests/peer-cli-{acp,asp,spawn,registry,adapters}.test.cjs` — protocol-level tests.
264
+ - `docs/PEER-DELEGATION.md` — ops guide.
265
+ - `NOTICE` — Apache 2.0 attribution for cc-multi-cli.
266
+ - `.planning/phases/27-peer-cli-delegation/CONTEXT.md` — decision lineage (D-01, D-02, D-03, D-04).
@@ -45,6 +45,13 @@
45
45
  "phase": 19.6,
46
46
  "description": "3-invariant framework (body/attention/memory) with grep-able principle→code pairs and reducibility test; wired into design-discussant brief stage"
47
47
  },
48
+ {
49
+ "name": "peer-protocols",
50
+ "path": "reference/peer-protocols.md",
51
+ "type": "meta-rules",
52
+ "phase": 27,
53
+ "description": "Phase 27 ACP + ASP protocol cheat sheet for peer-CLI delegation — line-delimited JSON-RPC framing, initialize/prompt/threadStart/turn lifecycle, per-peer ACP entry points, error-path resolution semantics"
54
+ },
48
55
  {
49
56
  "name": "DEPRECATIONS",
50
57
  "path": "reference/DEPRECATIONS.md",
@@ -638,6 +645,13 @@
638
645
  "type": "heuristic",
639
646
  "description": "Rules for serial/parallel agent dispatch and Touches conflict detection"
640
647
  },
648
+ {
649
+ "name": "peer-cli-capabilities",
650
+ "path": "reference/peer-cli-capabilities.md",
651
+ "type": "meta-rules",
652
+ "phase": 27,
653
+ "description": "Phase 27 peer-CLI delegation capability matrix — which peer (codex/copilot/cursor/gemini/qwen) claims which agent role, protocol (ACP/ASP), tie-break order, and opt-in gating semantics"
654
+ },
641
655
  {
642
656
  "name": "performance",
643
657
  "path": "reference/performance.md",
@@ -8,7 +8,7 @@ This file is parsed by `scripts/lib/install/parse-runtime-models.cjs` and consum
8
8
  - `scripts/lib/install/installer.cjs` (26-03) — emits `models.json` per runtime config-dir at install time.
9
9
  - `hooks/budget-enforcer.ts` + `scripts/lib/budget-enforcer.cjs` (26-05) — concrete model name for cost lookup.
10
10
 
11
- **Strict schema** (D-03): each runtime block is a fenced ```json ... ``` block validated against `reference/schemas/runtime-models.schema.json`. Schema version is locked at `1` until a breaking change forces a version bump.
11
+ **Strict schema** (D-03): each runtime block is a fenced `json` code block validated against `reference/schemas/runtime-models.schema.json`. Schema version is locked at `1` until a breaking change forces a version bump.
12
12
 
13
13
  **Provenance discipline** (D-01): every row carries a `source_url` (runtime-author docs), `retrieved_at` (ISO timestamp), and `last_validated_cycle` (current GDD cycle ID). Placeholder URLs are tagged `<TODO: confirm at <runtime-author-docs-url>>` and validated by Phase 13.2 authority-watcher on later cycles.
14
14
 
@@ -118,7 +118,7 @@ Google's Gemini CLI runtime. Public tier docs at https://ai.google.dev/gemini-ap
118
118
 
119
119
  ## qwen — Qwen Code
120
120
 
121
- Alibaba's Qwen Code runtime. Public tier docs at https://qwenlm.github.io/qwen-code/. Seed picks per CONTEXT.md D-02.
121
+ Alibaba's Qwen Code runtime. Public tier docs at https://github.com/QwenLM/qwen-code. Seed picks per CONTEXT.md D-02.
122
122
 
123
123
  ```json
124
124
  {
@@ -135,7 +135,7 @@ Alibaba's Qwen Code runtime. Public tier docs at https://qwenlm.github.io/qwen-c
135
135
  },
136
136
  "provenance": [
137
137
  {
138
- "source_url": "https://qwenlm.github.io/qwen-code/",
138
+ "source_url": "https://github.com/QwenLM/qwen-code",
139
139
  "retrieved_at": "2026-04-29T00:00:00.000Z",
140
140
  "last_validated_cycle": "2026-04-29-v1.26",
141
141
  "note": "Qwen Code public model catalog."
@@ -18,8 +18,9 @@
18
18
 
19
19
  const path = require('node:path');
20
20
 
21
- const { listRuntimes, listRuntimeIds } = require('./lib/install/runtimes.cjs');
21
+ const { listRuntimes, listRuntimeIds, detectInstalledPeers, listPeerCapableRuntimes } = require('./lib/install/runtimes.cjs');
22
22
  const { installRuntime, uninstallRuntime } = require('./lib/install/installer.cjs');
23
+ const fs = require('node:fs');
23
24
 
24
25
  function parseArgs(argv) {
25
26
  const args = argv.slice(2);
@@ -60,6 +61,7 @@ function helpText() {
60
61
  ' --uninstall Remove the plugin from selected runtimes',
61
62
  ' --dry-run Print the diff without writing',
62
63
  ' --config-dir D Override the config directory',
64
+ ' --no-peer-prompt Suppress the post-install peer-CLI detection nudge',
63
65
  ' --help, -h Show this message',
64
66
  '',
65
67
  'Environment overrides (per-runtime):',
@@ -196,6 +198,103 @@ async function main() {
196
198
  '',
197
199
  ].join('\n'),
198
200
  );
201
+
202
+ // v1.27.1 — Plan 27-11 wiring: post-install peer-CLI detection nudge.
203
+ // Fires only on real install (not uninstall, not dry-run) when not
204
+ // suppressed by --no-peer-prompt. Silently skips when no peers detected.
205
+ // Always opt-in: writes .design/config.json#peer_cli.enabled_peers
206
+ // ONLY on explicit y/Y; default is no.
207
+ if (!uninstall && !dryRun && !flags.has('--no-peer-prompt')) {
208
+ try {
209
+ await maybeNudgePeerCli({ flags });
210
+ } catch (e) {
211
+ // Nudge is non-critical. Surface a one-line warning but don't fail
212
+ // the install — the plugin is fully functional without peer-CLI.
213
+ process.stderr.write(
214
+ `\n[peer-cli] post-install nudge skipped: ${e && e.message ? e.message : e}\n`,
215
+ );
216
+ }
217
+ }
218
+ }
219
+
220
+ // v1.27.1 — Plan 27-11: post-install nudge. Detects installed peer CLIs,
221
+ // asks the user (interactive y/N) whether to wire them as peers, writes
222
+ // .design/config.json#peer_cli.enabled_peers on yes. Default = NO (opt-in).
223
+ async function maybeNudgePeerCli({ flags }) {
224
+ const detected = detectInstalledPeers();
225
+ if (!detected || detected.length === 0) {
226
+ // Nothing detected — silent skip. (No bad UX of "we found 0 peers".)
227
+ return;
228
+ }
229
+
230
+ // Build the human-readable peer line for the prompt.
231
+ const allPeerCapable = listPeerCapableRuntimes();
232
+ const detectedDisplay = detected
233
+ .map((id) => {
234
+ const r = allPeerCapable.find((x) => x.id === id);
235
+ return r && r.displayName ? r.displayName : id;
236
+ })
237
+ .join(', ');
238
+
239
+ process.stdout.write(
240
+ [
241
+ '',
242
+ '✓ Detected peer CLIs: ' + detectedDisplay,
243
+ '',
244
+ 'gdd v1.27.0 introduced optional peer-CLI delegation. With your',
245
+ 'agents\\u2019 frontmatter `delegate_to:` set, gdd can route specific',
246
+ 'roles through these peer CLIs (cost or quality wins per Phase 23.5',
247
+ 'bandit). You can change this anytime via .design/config.json.',
248
+ '',
249
+ ].join('\n'),
250
+ );
251
+
252
+ // Decide interactive vs scripted. shouldUseInteractive lives in this
253
+ // file; reuse it. If non-TTY, default to no (silent opt-out) so CI
254
+ // installers don't hang waiting for input.
255
+ let confirmed = false;
256
+ if (shouldUseInteractive(flags)) {
257
+ try {
258
+ const clack = require('@clack/prompts');
259
+ const ans = await clack.confirm({
260
+ message: 'Enable peer-CLI delegation for these peers?',
261
+ initialValue: false,
262
+ });
263
+ confirmed = (ans === true);
264
+ } catch {
265
+ // @clack/prompts unavailable — silently default to no.
266
+ confirmed = false;
267
+ }
268
+ }
269
+
270
+ if (!confirmed) {
271
+ process.stdout.write(
272
+ 'Skipped — peer-CLI delegation remains disabled.\n' +
273
+ 'Enable later by adding to .design/config.json:\n' +
274
+ ' { "peer_cli": { "enabled_peers": ' + JSON.stringify(detected) + ' } }\n\n',
275
+ );
276
+ return;
277
+ }
278
+
279
+ // Write the allowlist. Merge with any existing .design/config.json.
280
+ const cfgPath = path.join(process.cwd(), '.design', 'config.json');
281
+ let cfg = {};
282
+ try {
283
+ if (fs.existsSync(cfgPath)) {
284
+ cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
285
+ }
286
+ } catch {
287
+ cfg = {};
288
+ }
289
+ if (!cfg.peer_cli || typeof cfg.peer_cli !== 'object') cfg.peer_cli = {};
290
+ cfg.peer_cli.enabled_peers = detected;
291
+ fs.mkdirSync(path.dirname(cfgPath), { recursive: true });
292
+ fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + '\n');
293
+ process.stdout.write(
294
+ `✓ Wrote .design/config.json — peer-CLI enabled for: ${detected.join(', ')}\n` +
295
+ ' Set delegate_to: <peer>-<role> on agent frontmatter to opt agents in.\n' +
296
+ ' See docs/PEER-DELEGATION.md for the full ops guide.\n\n',
297
+ );
199
298
  }
200
299
 
201
300
  main().catch((err) => {