@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +74 -0
- package/README.md +10 -8
- package/SKILL.md +3 -0
- package/agents/README.md +29 -0
- package/package.json +2 -2
- package/reference/peer-cli-capabilities.md +151 -0
- package/reference/peer-protocols.md +266 -0
- package/reference/registry.json +14 -0
- package/reference/runtime-models.md +3 -3
- package/scripts/install.cjs +100 -1
- package/scripts/lib/bandit-router.cjs +214 -7
- package/scripts/lib/budget-enforcer.cjs +69 -1
- package/scripts/lib/event-stream/index.ts +14 -1
- package/scripts/lib/event-stream/types.ts +125 -1
- package/scripts/lib/install/runtimes.cjs +58 -0
- package/scripts/lib/peer-cli/acp-client.cjs +375 -0
- package/scripts/lib/peer-cli/adapters/codex.cjs +101 -0
- package/scripts/lib/peer-cli/adapters/copilot.cjs +79 -0
- package/scripts/lib/peer-cli/adapters/cursor.cjs +78 -0
- package/scripts/lib/peer-cli/adapters/gemini.cjs +81 -0
- package/scripts/lib/peer-cli/adapters/qwen.cjs +72 -0
- package/scripts/lib/peer-cli/asp-client.cjs +587 -0
- package/scripts/lib/peer-cli/broker-lifecycle.cjs +406 -0
- package/scripts/lib/peer-cli/registry.cjs +434 -0
- package/scripts/lib/peer-cli/spawn-cmd.cjs +149 -0
- package/scripts/lib/runtime-detect.cjs +1 -1
- package/scripts/lib/session-runner/index.ts +362 -0
- package/scripts/lib/session-runner/types.ts +60 -0
- package/scripts/validate-frontmatter.ts +159 -1
- package/skills/peer-cli-add/SKILL.md +170 -0
- package/skills/peer-cli-customize/SKILL.md +110 -0
- 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).
|
package/reference/registry.json
CHANGED
|
@@ -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
|
|
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://
|
|
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://
|
|
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."
|
package/scripts/install.cjs
CHANGED
|
@@ -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) => {
|