@ask-llm/plugin 0.14.0 → 0.16.2

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 (49) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.cursor-plugin/plugin.json +25 -0
  3. package/CHANGELOG.md +966 -0
  4. package/README.md +49 -9
  5. package/agents/brainstorm-coordinator.md +70 -25
  6. package/agents/gemini-reviewer.md +1 -1
  7. package/dist/antigravity-run.js +0 -0
  8. package/dist/brainstorm-panel.d.ts +46 -0
  9. package/dist/brainstorm-panel.d.ts.map +1 -0
  10. package/dist/brainstorm-panel.js +247 -0
  11. package/dist/brainstorm-panel.js.map +1 -0
  12. package/dist/brainstorm-run.d.ts +3 -0
  13. package/dist/brainstorm-run.d.ts.map +1 -0
  14. package/dist/brainstorm-run.js +51 -0
  15. package/dist/brainstorm-run.js.map +1 -0
  16. package/dist/codex-run.js +0 -0
  17. package/dist/grok-run.js +0 -0
  18. package/dist/ollama-run.js +0 -0
  19. package/dist/run.js +0 -0
  20. package/mcp.json +11 -0
  21. package/package.json +18 -15
  22. package/pi/extensions/provider-tools.ts +8 -1
  23. package/scripts/benchmark/README.md +114 -0
  24. package/scripts/benchmark/fixtures/README.md +29 -0
  25. package/scripts/codex-pair-debounce-worker.mjs +0 -0
  26. package/scripts/codex-pair-log.mjs +4 -13
  27. package/scripts/codex-pair-prompt-drain.mjs +1 -1
  28. package/scripts/codex-pair-session.mjs +2 -2
  29. package/scripts/codex-pair-stop-gate.mjs +8 -8
  30. package/scripts/codex-pair-watch.mjs +20 -39
  31. package/skills/brainstorm/SKILL.md +62 -39
  32. package/skills/codex-pair/SKILL.md +44 -2
  33. package/skills/gemini-review/SKILL.md +1 -1
  34. package/skills/grok-pair/SKILL.md +115 -0
  35. package/skills/pairing-contract.md +40 -0
  36. package/scripts/lib/broker-lifecycle.mjs +0 -575
  37. package/scripts/lib/broker-rpc.mjs +0 -203
  38. package/scripts/lib/broker-transport.mjs +0 -407
  39. package/scripts/lib/broker.mjs +0 -537
  40. package/scripts/lib/debounce-state.mjs +0 -208
  41. package/scripts/lib/parser.d.mts +0 -12
  42. package/scripts/lib/parser.mjs +0 -229
  43. package/scripts/lib/process.mjs +0 -56
  44. package/scripts/lib/prompt.d.mts +0 -8
  45. package/scripts/lib/prompt.mjs +0 -41
  46. package/scripts/lib/session-registry.mjs +0 -162
  47. package/scripts/lib/state.d.mts +0 -58
  48. package/scripts/lib/state.mjs +0 -733
  49. package/scripts/lib/stop-gate.mjs +0 -134
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  <div align="center">
4
4
 
5
- **Canonical Claude Code + Pi host package for AI-to-AI collaboration**
5
+ **Canonical Claude Code, Cursor Agent, and Pi host package for AI-to-AI collaboration**
6
6
 
7
7
  </div>
8
8
 
9
- One publishable package that adds multi-provider code review, comparison, brainstorming, verification, image, and pairing workflows to [Claude Code](https://code.claude.com/docs/en/plugins) and [Pi](https://pi.dev). Both hosts consume one skill corpus and package version; host-specific behavior is kept in explicit adapters.
9
+ One publishable package that adds multi-provider code review, comparison, brainstorming, verification, image, and pairing workflows to [Claude Code](https://code.claude.com/docs/en/plugins), [Cursor Agent](https://cursor.com/docs/skills), and [Pi](https://pi.dev). The hosts consume one skill corpus and package version; host-specific behavior is kept in explicit adapters.
10
10
 
11
11
  Part of the [Ask LLM](https://github.com/Lykhoyda/ask-llm) monorepo.
12
12
 
@@ -23,9 +23,16 @@ Part of the [Ask LLM](https://github.com/Lykhoyda/ask-llm) monorepo.
23
23
 
24
24
  ### MCP Servers
25
25
 
26
- The plugin bundles the supported Codex MCP registration under Claude Code's plugin namespace. After installation or upgrade, fully restart Claude Code and run `/mcp`; `plugin:ask-llm:codex` should be connected and `/sol-review` will select its `ask-codex` tool automatically.
26
+ The plugin bundles only the Codex MCP registration under Claude Code's plugin namespace. After installation or upgrade, fully restart Claude Code and run `/mcp`; `plugin:ask-llm:codex` should be connected. `/sol-review` selects `ask-codex`.
27
27
 
28
- Existing user-scoped Codex registrations remain compatible and keep the shorter `codex:ask-codex` name. The other provider servers are still registered explicitly at user scope:
28
+ `/grok-pair` does not add servers to the plugin. Register the unified Ask LLM server at user scope (the recommended install: it exposes `ask-cursor-agent` for the Cursor Agent route plus the unified `ask-llm` tool, which pair skills call only fully pinned) and, optionally, the split Grok server for the `ask-grok` leaf:
29
+
30
+ ```bash
31
+ claude mcp add --scope user ask-llm -- npx -y @ask-llm/mcp
32
+ claude mcp add --scope user grok -- npx -y @ask-llm/grok-mcp
33
+ ```
34
+
35
+ Existing user-scoped Codex registrations remain compatible and keep their shorter names. Other providers are registered explicitly at user scope:
29
36
 
30
37
  ```bash
31
38
  claude mcp add --scope user gemini -- npx -y @ask-llm/gemini-mcp
@@ -33,6 +40,16 @@ claude mcp add --scope user ollama -- npx -y @ask-llm/ollama-mcp
33
40
  claude mcp add --scope user antigravity -- npx -y @ask-llm/antigravity-mcp
34
41
  ```
35
42
 
43
+ ### Cursor Agent
44
+
45
+ Cursor's supported Agent Skills surface exposes exactly `/codex-pair` and `/grok-pair` (the manifest sets `agents: []`, `commands: []`, and `hooks: {}` so Claude agents and the Claude-format hooks file are never auto-discovered, and the other skills stay Claude/Pi-only until they get Cursor adapters); its MCP surface is `mcp.json`, which bundles only the unified `ask-llm` server. For a source checkout:
46
+
47
+ ```bash
48
+ agent --plugin-dir ./packages/claude-plugin
49
+ ```
50
+
51
+ `/codex-pair` requires explicit `model=` and `effort=` values before consent, then uses a separately user-installed `ask-codex` leaf when exposed, otherwise the bundled unified `ask-llm` fully pinned (`provider: "codex"`, model, effort, include directories, session), with resumable Thread ID, cancellation, and result relay. It never guesses MCP-process environment defaults and does not pretend Claude-only hooks are active. `/grok-pair` gives Cursor-native `.cursor/mcp.json` and Tools & MCP reload guidance; it never sends Cursor users to `claude mcp add`. If installing only MCP configuration, the recommended minimal entry is `ask-llm` → `npx -y @ask-llm/mcp` in project `.cursor/mcp.json` or user `~/.cursor/mcp.json` (keep one registration per server — do not duplicate it when the plugin is loaded); add `codex` → `@ask-llm/codex-mcp` or `grok` → `@ask-llm/grok-mcp` only when you specifically want their `ask-codex`/`ask-grok` leaves, then reload MCP/restart Cursor Agent. When Cursor hosts `/grok-pair`, it never recursively invokes Cursor Agent.
52
+
36
53
  If Codex is missing entirely, register it explicitly with `claude mcp add --scope user codex -- npx -y @ask-llm/codex-mcp`. If `/mcp` shows the bundled registration but it is disconnected, run `npx -y @ask-llm/mcp doctor` and restart Claude Code. `/sol-review` preserves source-plugin and session-local MCP/settings context when reading the active `claude mcp list` inventory, reports missing and unavailable states separately, and discloses the explicit `codex exec` fallback after failed health or MCP transport failure.
37
54
 
38
55
  ### Pi
@@ -42,7 +59,9 @@ pi install npm:@ask-llm/plugin
42
59
  pi list
43
60
  ```
44
61
 
45
- Pi discovers the portable skills as `/skill:<name>` commands and registers native `ask-codex`, `ask-gemini`, `ask-grok`, `ask-ollama`, `ask-antigravity`, model-neutral `ask-cursor-agent`, and bounded concurrent `ask-multi` tools. Pi intentionally has no built-in MCP client; do not configure these as MCP servers in Pi. `fable-review` remains Claude Code-only and is excluded from Pi discovery.
62
+ Pi discovers the portable skills as `/skill:<name>` commands and registers native `ask-codex`, `ask-gemini`, `ask-grok`, `ask-ollama`, `ask-antigravity`, model-neutral `ask-cursor-agent`, and bounded concurrent `ask-multi` tools. Pi intentionally has no built-in MCP client; do not configure these as MCP servers in Pi. `fable-review` and `grok-pair` are excluded from Pi discovery; Grok pairing currently has Claude/Cursor adapters, while Pi retains its dedicated Codex pairing lifecycle.
63
+
64
+ The plugin's `ask-gemini-run`, Gemini reviewer agent/skill, and Pi `ask-gemini` tool all delegate to the canonical Gemini executor: `gemini-3.1-pro-preview` remains primary and quota errors fall back to `gemini-3.8-flash` unless `ASK_GEMINI_FALLBACK_MODEL` overrides it.
46
65
 
47
66
  For codex-pair, create `.codex-pair/context.md`, ensure Pi trusts the project, then run interactive `/codex-pair` to grant user-owned canonical-project consent. The marker alone never authorizes data transfer/cost. Revoke with `/codex-pair revoke`. Pi findings are non-blocking; blocking Stop-gate and one-shot print parity are not available.
48
67
 
@@ -63,11 +82,31 @@ See the [Pi host guide](https://lykhoyda.github.io/ask-llm/plugin/pi) for securi
63
82
  | `/fable-review` | Isolated, read-only review requesting native Fable, with runtime verification limits disclosed |
64
83
  | `/sol-review` | Model-pinned GPT-5.6 Sol review through the bundled `ask-codex` MCP tool; missing registration and service unavailability are diagnosed separately before the explicit CLI fallback |
65
84
  | `/ollama-review` | Local review — no data leaves your machine |
66
- | `/brainstorm` | Multi-LLM brainstorm with Claude Opus as a first-class research participant (default external: gemini,codex) |
85
+ | `/brainstorm` | Explicit multi-model brainstorm (default external: Antigravity + Codex); supports an exact no-Gemini Grok + GPT-5.6 Sol panel through Cursor Agent |
67
86
  | `/grok-review` | Grok review through explicit xAI API or Grok CLI harness; no fallback |
87
+ | `/grok-pair` | Consent-gated iterative Grok reviewer through exact Cursor Agent, xAI API, or Grok CLI route; no fallback |
88
+ | `/codex-pair` | Claude/Pi per-edit pairing dashboard; Cursor on-demand session adapter with explicit Thread ID continuity |
68
89
  | `/brainstorm-all` | Brainstorm with all five external providers (Gemini, Codex, Grok, Ollama, Antigravity) + Claude Opus research |
69
90
  | `/compare` | Side-by-side raw responses from multiple providers (no synthesis, no consensus extraction) |
70
91
 
92
+ ### Exact Grok + GPT-5.6 Sol brainstorm
93
+
94
+ The preferred architect panel routes both models through the model-neutral Cursor Agent harness with provider and exact account-catalog ID kept separate:
95
+
96
+ ```text
97
+ /brainstorm grok@cursor-agent:cursor-grok-4.6-high,codex@cursor-agent:gpt-5.6-sol-high "review this architecture"
98
+ ```
99
+
100
+ This panel calls exactly Grok and GPT-5.6 Sol—never Gemini. Cursor `Auto`, model rewriting, and harness/provider fallback are forbidden. If one participant fails, the result is partial and cannot be presented as two-model consensus. Catalogs are account-specific; confirm these exact IDs with `agent --list-models` and replace an unavailable ID explicitly.
101
+
102
+ Official Grok Build remains an explicit alternative when its installed headless contract is supported:
103
+
104
+ ```text
105
+ /brainstorm grok@grok-cli:grok-build,codex@cursor-agent:gpt-5.6-sol-high "review this architecture"
106
+ ```
107
+
108
+ A Grok CLI failure remains a Grok CLI failure; the workflow does not pivot to Cursor or xAI.
109
+
71
110
  ## Agents
72
111
 
73
112
  | Agent | Color | Description |
@@ -77,7 +116,7 @@ See the [Pi host guide](https://lykhoyda.github.io/ask-llm/plugin/pi) for securi
77
116
  | fable-reviewer | purple | Fable-requested review with source-verified findings |
78
117
  | sol-reviewer | blue | GPT-5.6 Sol review through Codex with source validation |
79
118
  | ollama-reviewer | yellow | 4-phase: context, prompt, synthesis, validation (local) |
80
- | brainstorm-coordinator | magenta | Claude Opus research + parallel multi-LLM consultation with synthesis; verified findings weighted higher than inferred |
119
+ | brainstorm-coordinator | magenta | Source-grounded research + parallel multi-model consultation; exact two-model mode keeps the host non-voting and partial failures out of consensus |
81
120
 
82
121
  ## Hooks
83
122
 
@@ -127,10 +166,11 @@ To disable:
127
166
 
128
167
  ## Requirements
129
168
 
130
- - **Claude Code or Pi 0.83.0+** installed
169
+ - **Claude Code, Cursor Agent, or Pi 0.83.0+** installed
131
170
  - **Claude Code** installed for marketplace agents, hooks, independent Fable review, and the blocking Stop gate
132
171
  - **Gemini CLI** authenticated — required for hooks and Gemini features
133
- - **Codex CLI** — required for `/codex-review` and brainstorm with Codex
172
+ - **Codex CLI** — required for `/codex-review` and direct-Codex brainstorm routes
173
+ - **Cursor Agent CLI** authenticated with exact catalog IDs — required only for `@cursor-agent` brainstorm routes
134
174
  - **Ollama** running locally — required for `/ollama-review`
135
175
 
136
176
  ## Documentation
@@ -32,18 +32,20 @@ The frontmatter and detailed implementation below define Claude Code subagent ex
32
32
 
33
33
  You are a brainstorming coordinator powered by Claude Opus. You have two jobs:
34
34
 
35
- 1. **You are a first-class research participant.** Perform your own deep, independent analysis of the topic — read the actual files, trace the real code paths, factor in framework-specific semantics. Your findings go into the synthesis as peer input, not as commentary on what the external providers said.
36
- 2. **You orchestrate external consultations.** Dispatch the topic to the selected external providers (Antigravity, Codex, Grok, Ollama, Gemini — default: antigravity,codex) via a **single blocking foreground Bash call**, collect their responses, and combine them with your own research in a structured synthesis.
35
+ 1. **Research independently before dispatch.** Perform deep analysis of the topic — read the actual files, trace real code paths, and factor in framework-specific semantics. In standard mode this is a peer participant. In the exact Grok + GPT-5.6 Sol mode it is a non-voting evidence memo: the requested panel must remain exactly two models.
36
+ 2. **Orchestrate explicit consultations.** Dispatch only the selected external participants (Antigravity, Codex, Grok, Ollama, Gemini — default: antigravity,codex) via a **single blocking foreground Bash call**, collect responses, and synthesize with provider, harness, requested model, independently observed served model (direct xAI API / Grok CLI only), and Cursor display label kept separate; a harness-echoed requested ID is selected-only and is never presented as the actual model.
37
37
 
38
- You run on Opus and you have filesystem access. Skipping your own research phase wastes the one participant with the strongest grounding — don't do it.
38
+ You run on Opus and have filesystem access. Never skip the independent research phase, but never count it as a third panel vote in exact two-model mode.
39
39
 
40
40
  ## Core Principles
41
41
 
42
- 1. **Sequential phases, internal parallelism** — Phase 3B (Claude research) runs first, then Phase 3A (external dispatch) runs via a single blocking Bash call that parallelizes providers *internally* via `&` + `wait`. This is not a stylistic choice — sub-agents cannot own background processes that outlive their turn (see the "Critical: Sub-Agent Background Job Lifecycle" section below).
42
+ 1. **Sequential phases, internal parallelism** — Phase 3B (Claude research) runs first, then Phase 3A (external dispatch) runs via one blocking Bash call. Standard mode parallelizes direct providers internally via `&` + `wait`; the exact Grok + Sol panel uses one foreground `brainstorm-run.js` process that owns both concurrent Cursor/direct children. This is not stylistic — sub-agents cannot own processes that outlive their turn (see the lifecycle section below).
43
43
  2. **Blindness to external responses is load-bearing** — Phase 3B must complete *before* Phase 3A dispatches external providers, otherwise Claude will anchor on external findings and stop being an independent participant. The sequential ordering enforces this structurally.
44
44
  3. **Verified findings outrank inferred ones** — when Claude has Read the actual files and traced real code, those findings carry more weight than an external LLM pattern-matching from a topic description alone.
45
- 4. **Preserve unique perspectives** — don't flatten differences; highlight where participants disagree.
46
- 5. **Actionable synthesis** — the output should help the user make decisions, not just list opinions.
45
+ 4. **Preserve identity and unique perspectives** — never flatten provider, harness, requested model ID, observed served model ID, or Cursor's optional reported display label; highlight disagreements. Report `modelVerification` per participant: `observed-exact`/`observed-alias` (direct route payload carried a served ID; an alias is a disclosed same-product dated snapshot, including the documented `-latest` form), `selected-unverified` (Cursor Agent or Codex CLI echoed the request, or a direct route reported no served ID; eligible but unverifiable), and `mismatch`/`fallback` (ineligible).
46
+ 5. **Mechanical two-model honesty** — in exact Grok + Sol mode, consensus is eligible only if both requested participants succeeded. One success is partial, never two-model consensus; the host memo cannot supply the missing vote.
47
+ 6. **No route invention** — never use Cursor Auto, infer a requested model from a display label, rewrite a model, or retry through another harness/provider.
48
+ 7. **Actionable synthesis** — the output should help the user make decisions, not just list opinions.
47
49
 
48
50
  ## How to Operate
49
51
 
@@ -62,7 +64,8 @@ Understand what needs brainstorming:
62
64
  Intent:
63
65
  - User request:
64
66
  - Brainstorm mode:
65
- - Providers:
67
+ - Participants: <provider via harness, exact requested model for each>
68
+ - Explicitly excluded:
66
69
 
67
70
  Scope:
68
71
  - Changed/referenced files:
@@ -102,8 +105,8 @@ Your own deep research phase. Do NOT skip this. Do NOT delegate it to a sub-agen
102
105
  1. **Read the actual artifacts.** If the topic references specific files, skills, or code, Read them. Don't reason about what you assume they contain — verify. Use Glob and Grep to find supporting context.
103
106
  2. **Trace through the real behavior.** If the topic involves a pipeline, effect, state machine, or control flow, mentally execute the code with the repo's actual conventions in mind. Factor in framework-specific semantics (React Compiler, XState, RTK Query, etc.) that a generic reviewer might miss.
104
107
  3. **Use WebFetch/WebSearch when the topic references external docs.** If the topic mentions a library, framework, RFC, or public URL, fetch the current docs — don't rely on training data.
105
- 4. **Form independent findings** structured identically to the external providers' output: numbered points, pros/cons, priorities.
106
- 5. **Update the Context Brief.** Record which files/docs you verified, which referenced artifacts were intentionally excluded, and which assumptions remain unverified before dispatch.
108
+ 4. **Form independent findings** structured identically to external output: numbered points, pros/cons, priorities. In exact Grok + Sol mode label this a **non-voting verification memo**, not a participant answer.
109
+ 5. **Update the Context Brief.** Record verified files/docs, intentionally excluded artifacts, unverified assumptions, and every exact participant identity before dispatch. For exact mode, explicitly record Gemini and all unselected routes as excluded.
107
110
  6. **Record confidence per finding.** Mark each finding as:
108
111
  - **Verified** — backed by an actual file Read, code trace, or fetched document (highest confidence)
109
112
  - **Inferred** — reasoned from the topic description without direct verification (lower confidence)
@@ -118,9 +121,43 @@ The user specifies which external providers to use. Default is `antigravity,code
118
121
  - `antigravity` — Google Antigravity, subscription-backed via your Google AI Pro/Ultra plan, via the `agy` CLI (experimental; requires `agy` >=1.1.5 installed + logged in)
119
122
  - `gemini` — Google Gemini (large context, strong at analysis) via the `gemini` CLI
120
123
  - `codex` — OpenAI Codex (strong at code reasoning) via `codex exec --sandbox read-only`
121
- - `grok` — Grok through the canonical runner and explicit `ASK_GROK_HARNESS` (`xai-api` default or `grok-cli`); may incur xAI API/plan usage and never falls back
124
+ - `grok` — bare Grok remains the compatible canonical-runner path with explicit `ASK_GROK_HARNESS` (`xai-api` default or `grok-cli`); routed Grok uses the exact selected harness/model and never falls back
122
125
  - `ollama` — Local Ollama (private, no data leaves machine) via the `ollama` CLI
123
126
 
127
+ Participant specs use `provider@harness:exact-model-id`. The preferred Grok route is Cursor Agent. The supported exact architect panel is:
128
+
129
+ - `grok@cursor-agent:cursor-grok-4.6-high`
130
+ - `codex@cursor-agent:gpt-5.6-sol-high`
131
+
132
+ Account catalogs can change; an unavailable exact ID is a clear failure, not permission to choose Auto or another ID. Grok Build remains explicit as `grok@grok-cli:grok-build` when the installed CLI supports the canonical contract. The exact panel contains no Gemini and must never launch a Gemini process/tool.
133
+
134
+ A list that mixes routed specs with bare provider names (for example `grok@cursor-agent:cursor-grok-4.6-high,antigravity`) is unsupported: stop before Phase 3A, report `Mixed brainstorm participant lists are not supported: routed "<spec>" cannot be combined with bare "<provider>". Use either an all-bare provider list or the exact routed Grok + GPT-5.6 Sol panel. No participant was substituted, rerouted, or dispatched.`, and dispatch nothing. Never downgrade a routed spec to `grok-run.js`/`codex-run.js` or promote a bare name into a routed spec; `brainstorm-run.js` refuses such lists with the same error. Generalized mixed panels are deferred to a future ADR.
135
+
136
+ **Exact Grok + GPT-5.6 Sol branch (preferred architect workflow):**
137
+
138
+ Use this branch instead of the generic template whenever the selected providers are exactly Grok and Codex with explicit route specs. Validate both specs first, then make one foreground call:
139
+
140
+ ```bash
141
+ set +e
142
+ workdir=$(mktemp -d /tmp/brainstorm-XXXXXX)
143
+ trap 'rm -rf "$workdir"' EXIT
144
+ cat > "$workdir/prompt.md" <<'PROMPT_EOF'
145
+ <INSERT THE PHASE 2 PROMPT HERE>
146
+ PROMPT_EOF
147
+
148
+ node "${CLAUDE_PLUGIN_ROOT}/dist/brainstorm-run.js" \
149
+ --participant 'grok@cursor-agent:cursor-grok-4.6-high' \
150
+ --participant 'codex@cursor-agent:gpt-5.6-sol-high' \
151
+ < "$workdir/prompt.md" > "$workdir/panel.json" 2> "$workdir/panel.err"
152
+ rc_panel=$?
153
+ echo "===== GROK + GPT-5.6 SOL PANEL (rc=$rc_panel) ====="
154
+ cat "$workdir/panel.json"
155
+ echo "===== PANEL STDERR ====="
156
+ cat "$workdir/panel.err"
157
+ ```
158
+
159
+ Substitute only user-supplied, grammar-validated exact specs. For the explicit Grok Build alternative, substitute only the Grok spec with `grok@grok-cli:grok-build`; do not change the Sol route. `brainstorm-run.js` starts both participants concurrently, preserves input order and identity, returns `complete | partial | failed`, and exits 2 for partial/failed participant execution. Parse its JSON even when rc=2. It does not know or support Gemini, and it does not pivot routes.
160
+
124
161
  **Required Bash tool call parameters:**
125
162
  - `timeout: 600000` — 10 minutes, the Bash tool maximum. The default 2 minutes will kill Codex at high reasoning effort mid-response, recreating the same silent-failure class this phase is designed to avoid.
126
163
  - Do NOT set `run_in_background: true`. This call MUST be foreground-blocking.
@@ -189,12 +226,12 @@ pid_codex=$!
189
226
 
190
227
  # Only include this block if grok was requested. The canonical runner preserves
191
228
  # explicit API-vs-CLI harness selection, key redaction, timeout/cancellation,
192
- # actual model attribution, and the no-fallback contract.
229
+ # served-model attribution, and the no-fallback contract.
193
230
  node "${CLAUDE_PLUGIN_ROOT}/dist/grok-run.js" "$(cat "$workdir/prompt.md")" > "$workdir/grok.out" 2> "$workdir/grok.err" &
194
231
  pid_grok=$!
195
232
 
196
233
  # Only include this line if ollama was requested:
197
- ollama run "${ASK_OLLAMA_MODEL:-qwen3.6:27b}" < "$workdir/prompt.md" > "$workdir/ollama.out" 2> "$workdir/ollama.err" &
234
+ ollama run "${ASK_OLLAMA_MODEL:-qwen3.8:27b}" < "$workdir/prompt.md" > "$workdir/ollama.out" 2> "$workdir/ollama.err" &
198
235
  pid_ollama=$!
199
236
 
200
237
  # Wait for each by PID so we capture per-provider exit codes independently.
@@ -236,7 +273,14 @@ cat "$workdir/ollama.err" 2>/dev/null
236
273
 
237
274
  ### Phase 4: Synthesis
238
275
 
239
- Now, and only now, parse the Phase 3A Bash output and combine it with your Phase 3B findings. Produce a structured synthesis.
276
+ Now, and only now, parse the Phase 3A output and combine it with Phase 3B evidence. In exact Grok + Sol mode, first apply the runner's deterministic gate:
277
+
278
+ - `complete` + `consensusEligible:true`: both exact participants answered; a point may be called two-model consensus only if both independently stated it. Carry each participant's `requestedModel`, `observedModel` (direct routes only), `reportedModel` (Cursor label), `modelVerification`, and `attributionNote` into the participant list verbatim.
279
+ - `partial`: name the failed participant with provider/harness/requested model/error, attribute surviving insights only to the successful participant, and do not create a Consensus section claiming panel agreement.
280
+ - `failed`: report both failures and provide no panel-derived synthesis.
281
+ - The non-voting Claude evidence memo may verify, reject, or contextualize a claim, but cannot turn one external answer into two-model consensus.
282
+
283
+ Then produce the structured synthesis.
240
284
 
241
285
  **Cross-check high-confidence external claims first.** Before promoting any external-provider finding to "Consensus," spot-check it against the source if it cites a specific file/line/symbol. External providers can return high-confidence claims that are factually wrong — for example, on 2026-04-17 Gemini returned two findings at 95/100 confidence that were contradicted by the actual `.d.ts` and an existing fallback path. A 30-second `Read` or `Grep` is the difference between recommending a real fix and recommending a non-fix. Mark each cross-checked finding as **Verified** (matches source), **Rejected** (false positive — exclude from synthesis), or **Unverifiable** (no source citation or external-only knowledge — present as-is with a note).
242
286
 
@@ -267,22 +311,21 @@ Surface this grade as the first line of the synthesis output (see Output Format
267
311
  **Synthesis confidence:** [PERFECT | VERIFIED | PARTIAL | FAILED] — [one-line reason citing what was/wasn't verified]
268
312
 
269
313
  ### Participants Consulted
270
- - ✅ Claude Opus: researched (verified against real files: path/to/a, path/to/b)
271
- - ✅ Gemini: responded
272
- - ✅ Codex: responded
273
- - ⏭️ Ollama: not available
314
+ - ℹ️ Claude Opus: non-voting evidence verifier (exact two-model mode; verified against real files: path/to/a, path/to/b)
315
+ - ✅ Grok via Cursor Agent — requested `cursor-grok-4.6-high` (selected-unverified: Cursor echoes the requested ID); reported display label `Cursor Grok 4.6` (label, not a catalog ID)
316
+ - ✅ Codex via Cursor Agent — requested `gpt-5.6-sol-high` (selected-unverified); reported display label `GPT-5.6 Sol 1M High`
317
+ - (direct route example) ✅ Grok via xAI API — requested `grok-4.6`; observed served `grok-4.6-<snapshot>` (observed-alias, disclosed same-product resolution)
318
+ - 🚫 Gemini: explicitly excluded (not called)
274
319
 
275
- ### Consensus (high confidence)
276
- 1. [Point] — agreed by Claude (verified), Gemini, Codex
277
- 2. [Point] — agreed by Gemini and Codex
320
+ ### Consensus (high confidence; omit for a partial exact panel)
321
+ 1. [Point] — independently agreed by <name both successful panel participants with provider/harness/model>
278
322
 
279
323
  ### Unique Insights
280
- - **Claude Opus** (verified): [Insight backed by actual file reads and why it matters]
281
- - **Gemini**: [Insight and why it matters]
282
- - **Codex**: [Insight and why it matters]
324
+ - **<Provider via harness — exact model>**: [Insight and why it matters]
325
+ - **Claude Opus evidence memo** (non-voting in exact mode): [Source-backed verification or rejection]
283
326
 
284
327
  ### Contradictions
285
- - [Topic]: Claude (verified against src/foo.ts) says X, Gemini (inferred) says Y. Assessment: Claude's view is more likely correct because [evidence].
328
+ - [Topic]: <participant A identity> says X; <participant B identity> says Y. Evidence assessment: [verified source and conclusion].
286
329
 
287
330
  ### Recommendations
288
331
  1. [Highest priority action]
@@ -310,7 +353,9 @@ The only place background jobs persist across turns is the **main conversation c
310
353
  - **Never skip Phase 3B.** It's what makes you a participant instead of a relay. If you skip it, the user gets exactly the same result they'd get from calling the providers directly — the Opus budget is wasted.
311
354
  - **Phase 3B runs BEFORE Phase 3A.** The ordering is how blindness is enforced *and* how the sub-agent background-job lifecycle bug is avoided. Do not reorder.
312
355
  - **Phase 3A is a single foreground blocking Bash call** with `timeout: 600000` — see the "Critical: Sub-Agent Background Job Lifecycle" section. Violating this reintroduces issue #23 silently.
313
- - **Never fabricate a provider's response.** If a provider exits non-zero or produces empty output, report it honestly in the Participants Consulted section.
356
+ - **Never fabricate a provider's response.** If a participant exits non-zero or produces empty output, report provider, harness, requested model, and error honestly.
357
+ - **Never misstate partial consensus.** One successful member of a two-model panel is one perspective, even when Claude's evidence agrees.
358
+ - **Never route implicitly.** Cursor Auto, display-label inference, model rewriting, and cross-harness/provider retries are forbidden.
314
359
  - **Don't bias the prompt toward any particular answer** — let participants form independent opinions.
315
360
  - **Verified findings outrank inferred ones in consensus scoring** — but external providers can still win when they catch domain patterns from their training data that aren't in the local repo.
316
361
  - **Keep the synthesis concise and actionable.** The user wants decisions, not essays.
@@ -14,7 +14,7 @@ tools:
14
14
  <!-- PORTABLE-CONTRACT:START -->
15
15
  ## Portable contract
16
16
 
17
- Review only the supplied changes and context. Ask Gemini for concrete correctness, security, and regression concerns; validate every candidate against source; require file/line evidence and reproduction for behavior claims; omit style-only or speculative findings; report provider failures explicitly.
17
+ Review only the supplied changes and context. Ask Gemini for concrete correctness, security, and regression concerns; validate every candidate against source; require file/line evidence and reproduction for behavior claims; omit style-only or speculative findings; report provider failures explicitly. Preserve the canonical `gemini-3.1-pro-preview` → `gemini-3.8-flash` quota fallback and disclose when fallback occurs.
18
18
  <!-- PORTABLE-CONTRACT:END -->
19
19
 
20
20
  <!-- HOST-ADAPTER:CLAUDE-CODE:START -->
File without changes
@@ -0,0 +1,46 @@
1
+ export declare const BRAINSTORM_PANEL_PROVIDERS: readonly ["grok", "codex"];
2
+ export type BrainstormPanelProvider = (typeof BRAINSTORM_PANEL_PROVIDERS)[number];
3
+ export type BrainstormPanelHarness = "cursor-agent" | "grok-cli" | "xai-api" | "codex-cli";
4
+ export declare const BARE_BRAINSTORM_PROVIDERS: readonly ["gemini", "codex", "grok", "ollama", "antigravity"];
5
+ export type BareBrainstormProvider = (typeof BARE_BRAINSTORM_PROVIDERS)[number];
6
+ export type BrainstormParticipantList = {
7
+ mode: "bare";
8
+ providers: BareBrainstormProvider[];
9
+ } | {
10
+ mode: "exact";
11
+ participants: BrainstormParticipant[];
12
+ };
13
+ export type BrainstormModelVerification = "observed-exact" | "observed-alias" | "selected-unverified" | "mismatch" | "fallback";
14
+ export interface BrainstormParticipant {
15
+ provider: BrainstormPanelProvider;
16
+ harness: BrainstormPanelHarness;
17
+ model: string;
18
+ }
19
+ export interface BrainstormParticipantResult extends BrainstormParticipant {
20
+ status: "fulfilled" | "rejected";
21
+ requestedModel: string;
22
+ observedModel?: string;
23
+ reportedModel?: string;
24
+ modelVerification?: BrainstormModelVerification;
25
+ attributionNote?: string;
26
+ response?: string;
27
+ error?: string;
28
+ }
29
+ export interface BrainstormPanelReport {
30
+ panel: "grok+gpt-5.6-sol";
31
+ status: "complete" | "partial" | "failed";
32
+ consensusEligible: boolean;
33
+ synthesisRule: string;
34
+ participants: BrainstormParticipantResult[];
35
+ }
36
+ export declare function parseBrainstormParticipant(spec: string): BrainstormParticipant;
37
+ export declare function parseBrainstormParticipantList(specs: string[]): BrainstormParticipantList;
38
+ export declare function validateBrainstormPanel(participants: BrainstormParticipant[]): void;
39
+ export declare function isSameProductResolution(requested: string, observed: string): boolean;
40
+ export declare function runBrainstormPanel(options: {
41
+ prompt: string;
42
+ participants: BrainstormParticipant[];
43
+ signal?: AbortSignal;
44
+ onProgress?: (message: string) => void;
45
+ }): Promise<BrainstormPanelReport>;
46
+ //# sourceMappingURL=brainstorm-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brainstorm-panel.d.ts","sourceRoot":"","sources":["../src/brainstorm-panel.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,0BAA0B,YAAI,MAAM,EAAE,OAAO,CAAU,CAAC;AACrE,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAClF,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAC3F,eAAO,MAAM,yBAAyB,YAAI,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAU,CAAC;AACvG,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhF,MAAM,MAAM,yBAAyB,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,sBAAsB,EAAE,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAAC;AAE7D,MAAM,MAAM,2BAA2B,GACnC,gBAAgB,GAChB,gBAAgB,GAChB,qBAAqB,GACrB,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,sBAAsB,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA4B,SAAQ,qBAAqB;IACxE,MAAM,EAAE,WAAW,GAAG,UAAU,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,2BAA2B,CAAC;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1C,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,2BAA2B,EAAE,CAAC;CAC7C;AAYD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,CAqB9E;AAMD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,yBAAyB,CAoBzF;AAED,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,qBAAqB,EAAE,GAAG,IAAI,CA4BnF;AAID,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CASpF;AAuLD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAiBjC"}
@@ -0,0 +1,247 @@
1
+ import { executeCodexCLI } from "@ask-llm/codex-mcp/executor";
2
+ import { executeGrok } from "@ask-llm/grok-mcp/executor";
3
+ import { executeCursorAgent } from "@ask-llm/mcp/cursor";
4
+ export const BRAINSTORM_PANEL_PROVIDERS = ["grok", "codex"];
5
+ export const BARE_BRAINSTORM_PROVIDERS = ["gemini", "codex", "grok", "ollama", "antigravity"];
6
+ const SYNTHESIS_RULE = "Call a point two-model consensus only when both requested participants fulfilled successfully and independently stated it. On any participant failure, label the run partial and attribute surviving insights to that participant only.";
7
+ function routeAllowed(participant) {
8
+ if (participant.provider === "grok") {
9
+ return ["cursor-agent", "grok-cli", "xai-api"].includes(participant.harness);
10
+ }
11
+ return ["cursor-agent", "codex-cli"].includes(participant.harness);
12
+ }
13
+ export function parseBrainstormParticipant(spec) {
14
+ const match = spec.match(/^(grok|codex)@(cursor-agent|grok-cli|xai-api|codex-cli):(.+)$/);
15
+ if (!match) {
16
+ throw new Error(`Invalid brainstorm participant "${spec}". Use provider@harness:exact-model-id (for example grok@cursor-agent:cursor-grok-4.6-high).`);
17
+ }
18
+ const participant = {
19
+ provider: match[1],
20
+ harness: match[2],
21
+ model: match[3].trim(),
22
+ };
23
+ if (!participant.model || participant.model.toLowerCase() === "auto") {
24
+ throw new Error(`Participant "${spec}" requires an exact non-Auto model ID from the selected harness catalog.`);
25
+ }
26
+ if (!routeAllowed(participant)) {
27
+ throw new Error(`Unsupported brainstorm route ${participant.provider}@${participant.harness}. Harness, provider, and model are not interchangeable; no substitute route was selected.`);
28
+ }
29
+ return participant;
30
+ }
31
+ function isBareProvider(spec) {
32
+ return BARE_BRAINSTORM_PROVIDERS.includes(spec);
33
+ }
34
+ export function parseBrainstormParticipantList(specs) {
35
+ const trimmed = specs.map((spec) => spec.trim()).filter(Boolean);
36
+ if (trimmed.length === 0)
37
+ throw new Error("The brainstorm participant list is empty.");
38
+ const bare = trimmed.filter((spec) => !spec.includes("@"));
39
+ const routed = trimmed.filter((spec) => spec.includes("@"));
40
+ if (bare.length > 0 && routed.length > 0) {
41
+ throw new Error(`Mixed brainstorm participant lists are not supported: routed ${routed.map((spec) => `"${spec}"`).join(", ")} cannot be combined with bare ${bare.map((spec) => `"${spec}"`).join(", ")}. Use either an all-bare provider list or the exact routed Grok + GPT-5.6 Sol panel. No participant was substituted, rerouted, or dispatched.`);
42
+ }
43
+ if (routed.length > 0) {
44
+ return { mode: "exact", participants: routed.map(parseBrainstormParticipant) };
45
+ }
46
+ const unknown = bare.find((spec) => !isBareProvider(spec));
47
+ if (unknown) {
48
+ throw new Error(`Unknown brainstorm provider "${unknown}". Supported bare providers: ${BARE_BRAINSTORM_PROVIDERS.join(", ")}; routed participants use provider@harness:exact-model-id. No substitute was selected.`);
49
+ }
50
+ return { mode: "bare", providers: bare.filter(isBareProvider) };
51
+ }
52
+ export function validateBrainstormPanel(participants) {
53
+ if (participants.length !== 2) {
54
+ throw new Error("The Grok + GPT-5.6 Sol panel requires exactly two participants.");
55
+ }
56
+ const providers = participants.map(({ provider }) => provider);
57
+ if (new Set(providers).size !== providers.length) {
58
+ throw new Error("The Grok + GPT-5.6 Sol panel requires one Grok participant and one Codex participant.");
59
+ }
60
+ for (const required of BRAINSTORM_PANEL_PROVIDERS) {
61
+ if (!providers.includes(required)) {
62
+ throw new Error(`The Grok + GPT-5.6 Sol panel is missing provider "${required}".`);
63
+ }
64
+ }
65
+ for (const participant of participants) {
66
+ if (!participant.model.trim() || participant.model.toLowerCase() === "auto") {
67
+ throw new Error(`${participant.provider}@${participant.harness} requires an exact non-Auto model ID.`);
68
+ }
69
+ if (!routeAllowed(participant)) {
70
+ throw new Error(`Unsupported brainstorm route ${participant.provider}@${participant.harness}. No provider or harness fallback was attempted.`);
71
+ }
72
+ if (participant.provider === "codex" && !participant.model.toLowerCase().includes("gpt-5.6-sol")) {
73
+ throw new Error(`The Codex participant must request an exact GPT-5.6 Sol model ID; received "${participant.model}". No model substitution was attempted.`);
74
+ }
75
+ }
76
+ }
77
+ const LATEST_ALIAS_SUFFIX = "-latest";
78
+ export function isSameProductResolution(requested, observed) {
79
+ const requestedId = requested.trim().toLowerCase();
80
+ const observedId = observed.trim().toLowerCase();
81
+ if (requestedId === observedId)
82
+ return true;
83
+ const productId = requestedId.endsWith(LATEST_ALIAS_SUFFIX)
84
+ ? requestedId.slice(0, -LATEST_ALIAS_SUFFIX.length)
85
+ : requestedId;
86
+ if (!productId || !observedId.startsWith(`${productId}-`))
87
+ return false;
88
+ return /^[0-9][0-9.-]*$/.test(observedId.slice(productId.length + 1));
89
+ }
90
+ function classifyObservedModel(participant, observedModel) {
91
+ const identity = `${participant.provider} via ${participant.harness}`;
92
+ if (observedModel.trim().toLowerCase() === participant.model.trim().toLowerCase()) {
93
+ return {
94
+ modelVerification: "observed-exact",
95
+ attributionNote: `${identity} reported served model "${observedModel}", matching the requested ID.`,
96
+ };
97
+ }
98
+ if (isSameProductResolution(participant.model, observedModel)) {
99
+ return {
100
+ modelVerification: "observed-alias",
101
+ attributionNote: `${identity} served "${observedModel}" for requested "${participant.model}" (disclosed provider-side alias/snapshot resolution of the same model; the requested ID was sent unchanged and was not rewritten).`,
102
+ };
103
+ }
104
+ throw new Error(`${identity} requested exact model "${participant.model}" but reported "${observedModel}". The response is excluded from two-model consensus; no additional route was attempted.`);
105
+ }
106
+ function selectedOnlyNote(participant, detail) {
107
+ return `${participant.provider} via ${participant.harness} ran the requested ID "${participant.model}" (${detail}); the harness does not independently confirm the served catalog model, so this attribution is selected-only and unverifiable, not an observed actual model.`;
108
+ }
109
+ async function invokeParticipant(participant, prompt, signal, onProgress) {
110
+ const identity = `${participant.provider} via ${participant.harness} (${participant.model})`;
111
+ const progress = onProgress ? (message) => onProgress(`[${identity}] ${message}`) : undefined;
112
+ const base = { ...participant, requestedModel: participant.model };
113
+ let observedModel;
114
+ let reportedModel;
115
+ let modelVerification;
116
+ try {
117
+ if (participant.harness === "cursor-agent") {
118
+ const result = await executeCursorAgent({
119
+ provider: participant.provider,
120
+ model: participant.model,
121
+ prompt,
122
+ signal,
123
+ onProgress: progress,
124
+ });
125
+ reportedModel = result.reportedModel;
126
+ if (result.usage.fellBack) {
127
+ modelVerification = "fallback";
128
+ throw new Error(`Cursor Agent reported a model fallback for requested "${participant.model}". The response is excluded from two-model consensus.`);
129
+ }
130
+ if (result.model !== participant.model) {
131
+ modelVerification = "mismatch";
132
+ throw new Error(`Cursor Agent ran "${result.model}" instead of requested "${participant.model}". The response is excluded from two-model consensus; no additional route was attempted.`);
133
+ }
134
+ modelVerification = "selected-unverified";
135
+ return {
136
+ ...base,
137
+ reportedModel,
138
+ modelVerification,
139
+ attributionNote: selectedOnlyNote(participant, reportedModel
140
+ ? `Cursor echoed the requested ID and reported display label "${reportedModel}", which is a label and not a catalog ID`
141
+ : "Cursor echoed the requested ID and reported no display label"),
142
+ response: result.response,
143
+ status: "fulfilled",
144
+ };
145
+ }
146
+ if (participant.provider === "grok") {
147
+ if (participant.harness !== "grok-cli" && participant.harness !== "xai-api") {
148
+ throw new Error(`Unsupported brainstorm route ${participant.provider}@${participant.harness}. No fallback was attempted.`);
149
+ }
150
+ const result = await executeGrok({
151
+ prompt,
152
+ model: participant.model,
153
+ harness: participant.harness,
154
+ reasoningEffort: "high",
155
+ signal,
156
+ onProgress: progress,
157
+ });
158
+ if (result.usage?.fellBack) {
159
+ modelVerification = "fallback";
160
+ throw new Error(`${participant.harness} reported a model fallback for requested "${participant.model}". The response is excluded from two-model consensus.`);
161
+ }
162
+ if (!result.reportedModel) {
163
+ if (result.model !== participant.model) {
164
+ modelVerification = "mismatch";
165
+ throw new Error(`${participant.provider} via ${participant.harness} ran "${result.model}" instead of requested "${participant.model}". The response is excluded from two-model consensus; no additional route was attempted.`);
166
+ }
167
+ modelVerification = "selected-unverified";
168
+ return {
169
+ ...base,
170
+ modelVerification,
171
+ attributionNote: selectedOnlyNote(participant, `${participant.harness} reported no served model ID, so only the requested ID is known`),
172
+ response: result.response,
173
+ status: "fulfilled",
174
+ };
175
+ }
176
+ observedModel = result.reportedModel;
177
+ let observed;
178
+ try {
179
+ observed = classifyObservedModel(participant, observedModel);
180
+ }
181
+ catch (error) {
182
+ modelVerification = "mismatch";
183
+ throw error;
184
+ }
185
+ modelVerification = observed.modelVerification;
186
+ return {
187
+ ...base,
188
+ observedModel,
189
+ modelVerification,
190
+ attributionNote: observed.attributionNote,
191
+ response: result.response,
192
+ status: "fulfilled",
193
+ };
194
+ }
195
+ const result = await executeCodexCLI({
196
+ prompt,
197
+ model: participant.model,
198
+ reasoningEffort: "high",
199
+ sandbox: "read-only",
200
+ signal,
201
+ onProgress: progress,
202
+ });
203
+ if (result.usage?.fellBack) {
204
+ modelVerification = "fallback";
205
+ throw new Error(`Codex CLI reported a model fallback to "${result.usage.model}" for requested "${participant.model}". The response is excluded from two-model consensus.`);
206
+ }
207
+ if (result.usage && result.usage.model !== participant.model) {
208
+ modelVerification = "mismatch";
209
+ throw new Error(`Codex CLI ran "${result.usage.model}" instead of requested "${participant.model}". The response is excluded from two-model consensus; no additional route was attempted.`);
210
+ }
211
+ modelVerification = "selected-unverified";
212
+ return {
213
+ ...base,
214
+ modelVerification,
215
+ attributionNote: selectedOnlyNote(participant, result.usage
216
+ ? "Codex CLI echoed the requested ID with no fallback"
217
+ : "served from the Codex response cache keyed by the requested ID, which stores only no-fallback responses"),
218
+ response: result.response,
219
+ status: "fulfilled",
220
+ };
221
+ }
222
+ catch (error) {
223
+ return {
224
+ ...base,
225
+ observedModel,
226
+ reportedModel,
227
+ modelVerification,
228
+ status: "rejected",
229
+ error: error instanceof Error ? error.message : String(error),
230
+ };
231
+ }
232
+ }
233
+ export async function runBrainstormPanel(options) {
234
+ if (!options.prompt.trim())
235
+ throw new Error("The brainstorm panel requires a non-empty prompt.");
236
+ validateBrainstormPanel(options.participants);
237
+ const participants = await Promise.all(options.participants.map((participant) => invokeParticipant(participant, options.prompt, options.signal, options.onProgress)));
238
+ const successCount = participants.filter(({ status }) => status === "fulfilled").length;
239
+ return {
240
+ panel: "grok+gpt-5.6-sol",
241
+ status: successCount === 2 ? "complete" : successCount === 1 ? "partial" : "failed",
242
+ consensusEligible: successCount === 2,
243
+ synthesisRule: SYNTHESIS_RULE,
244
+ participants,
245
+ };
246
+ }
247
+ //# sourceMappingURL=brainstorm-panel.js.map