diff --git a/.changeset/agile-ibex-chatter.md b/.changeset/agile-ibex-chatter.md new file mode 100644 index 000000000..d2165fd7a --- /dev/null +++ b/.changeset/agile-ibex-chatter.md @@ -0,0 +1,5 @@ +--- +type: Removed +pr: 4716 +--- +**Retired the Gemini CLI reviewer lane** — Google stopped serving Gemini CLI for free/Pro/Ultra on 2026-06-18, so `/gsd-review --gemini` spawned a binary that no longer answers for most users. The `--gemini` flag, its three `review.*.gemini` config keys, and its documentation in all five locales are gone; Antigravity's `--agy` lane already covers the Google slot. `gsd config-set review.models.gemini` now reports an unknown key — an existing key in `.planning/config.json` still parses and is simply never read. (#4709) diff --git a/capabilities/gemini/capability.json b/capabilities/gemini/capability.json deleted file mode 100644 index 08af70c05..000000000 --- a/capabilities/gemini/capability.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "id": "gemini", - "role": "reviewer", - "version": "1.14.0", - "title": "Gemini CLI", - "description": "Google Gemini CLI — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). Spawned as `gemini -p - -m ` with the plan piped on stdin.", - "tier": "full", - "requires": [], - "engines": { - "gsd": ">=1.8.0" - }, - "reviewer": { - "slug": "gemini", - "flags": [ - "--gemini" - ], - "transport": "spawn", - "probe": { - "kind": "command-exists", - "binary": "gemini" - }, - "invoke": { - "binary": "gemini", - "args": [ - "{{model}}", - "-p", - "-" - ], - "promptChannel": "stdin", - "outputChannel": "stdout", - "modelArg": "-m", - "effortChannel": "none" - }, - "timeoutFloorMs": 900000, - "timeoutConfigKey": "review.timeouts.gemini", - "emptyOutput": "stub-with-stderr", - "reviewsSection": "Gemini", - "evidenceClass": "source-grounded", - "requiresBinaries": [], - "promptBudgetKey": "review.max_prompt_tokens_per_reviewer.gemini", - "modelConfigKey": "review.models.gemini", - "effortConfigKey": null, - "defaultEffort": null, - "handler": null - }, - "config": { - "review.models.gemini": { - "type": "string", - "default": "", - "description": "Model passed to the Gemini reviewer lane." - }, - "review.max_prompt_tokens_per_reviewer.gemini": { - "type": "number", - "default": -1, - "description": "Prompt-token budget for the Gemini reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"." - }, - "review.timeouts.gemini": { - "type": "number", - "default": -1, - "description": "Outer wall-clock timeout override (seconds) for the Gemini reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset." - } - } -} diff --git a/commands/gsd/autonomous.md b/commands/gsd/autonomous.md index 1d830dd6b..beffbdc03 100644 --- a/commands/gsd/autonomous.md +++ b/commands/gsd/autonomous.md @@ -40,7 +40,7 @@ Optional flags: - `--converge` — run each phase's planning step through `gsd-plan-review-convergence` instead of plain `gsd-plan-phase`. Requires `workflow.plan_review_convergence=true`. - `--cross-ai` — compatibility alias for `--converge`. -When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `gsd-plan-review-convergence` may be passed through: `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. +When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `gsd-plan-review-convergence` may be passed through: `--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. Project context, phase list, and state are resolved inside the workflow using init commands (`gsd-tools query init.milestone-op`, `gsd-tools query roadmap.analyze`). No upfront context loading needed. diff --git a/commands/gsd/plan-review-convergence.md b/commands/gsd/plan-review-convergence.md index 736e60362..df390f313 100644 --- a/commands/gsd/plan-review-convergence.md +++ b/commands/gsd/plan-review-convergence.md @@ -1,7 +1,7 @@ --- name: gsd:plan-review-convergence description: "Cross-AI plan convergence - replan until review concerns are resolved." -argument-hint: " [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--antigravity] [--agy] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--text] [--ws ] [--all] [--max-cycles N]" +argument-hint: " [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--antigravity] [--agy] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--text] [--ws ] [--all] [--max-cycles N]" allowed-tools: - Read - Write @@ -20,7 +20,7 @@ Repeatedly: review plans with external AI CLIs → if HIGH or actionable non-HIG **Flow:** Skill("gsd-plan-phase") → Agent→Skill("gsd-review") → check unresolved HIGH + actionable non-HIGH → Skill("gsd-plan-phase --reviews") → Agent→Skill("gsd-review") → ... → Converge or escalate -Replaces gsd-plan-phase's internal gsd-plan-checker with external AI reviewers (codex, gemini, etc.). Plan-phase runs **inline** (bare Skill at depth 0) so it can spawn gsd-planner/gsd-plan-checker at depth 1. Review runs inside an isolated Agent (gsd-review is a Bash leaf — no sub-agents needed). Orchestrator only does loop control. +Replaces gsd-plan-phase's internal gsd-plan-checker with external AI reviewers (codex, claude, etc.). Plan-phase runs **inline** (bare Skill at depth 0) so it can spawn gsd-planner/gsd-plan-checker at depth 1. Review runs inside an isolated Agent (gsd-review is a Bash leaf — no sub-agents needed). Orchestrator only does loop control. **Orchestrator role:** Parse arguments, validate phase, run plan-phase inline (Skill at depth 0), spawn an Agent for gsd-review, check unresolved HIGH and actionable non-HIGH counts, stall detection, escalation gate. @@ -41,8 +41,7 @@ Phase number: extracted from $ARGUMENTS (required) **Flags:** - `--codex` — Use Codex CLI as reviewer (default if no reviewer flag given AND `review.default_reviewers` is unset; otherwise `review.default_reviewers` wins per ADR-0011 — #2315) -- `--gemini` — Use Gemini CLI as reviewer -- `--agy` / `--antigravity` — Use Antigravity CLI as reviewer (successor to the discontinued Gemini CLI) +- `--agy` / `--antigravity` — Use Antigravity CLI as reviewer - `--claude` — Use Claude CLI as reviewer (separate session) - `--coderabbit` — Use CodeRabbit as reviewer (reviews the working-tree diff, not the source tree) - `--opencode` — Use OpenCode as reviewer diff --git a/commands/gsd/progress.md b/commands/gsd/progress.md index 9a069b1ff..32728953f 100644 --- a/commands/gsd/progress.md +++ b/commands/gsd/progress.md @@ -25,7 +25,7 @@ Three modes: - **--next**: Detect current project state and automatically invoke the next logical GSD workflow step. Scans all prior phases for incomplete work before routing. `--next --force` bypasses safety gates. - **--next --auto**: Like `--next`, but after the determined step completes, automatically re-invokes `/gsd:progress --next --auto` to continue chaining steps until completion or a blocking decision. Enables hands-free plan→execute→verify→complete progression. -- **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop. +- **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop. - **--do "..."**: Smart dispatcher — match freeform intent to the best GSD command using routing rules, confirm the match, then hand off. - **--forensic**: Run 6-check integrity audit after the standard progress report. - **(no flag)**: Standard progress check + intelligent routing (Routes A through F). diff --git a/commands/gsd/review.md b/commands/gsd/review.md index 52096c30c..edb095923 100644 --- a/commands/gsd/review.md +++ b/commands/gsd/review.md @@ -1,7 +1,7 @@ --- name: gsd:review description: Request cross-AI peer review of phase plans from external AI CLIs -argument-hint: "--phase N [--gemini] [--claude] [--codex] [--opencode] [--qwen] [--cursor] [--agy] [--all]" +argument-hint: "--phase N [--claude] [--codex] [--opencode] [--qwen] [--cursor] [--agy] [--all]" allowed-tools: - Read - Write @@ -12,7 +12,7 @@ requires: [config, phase, plan-phase] --- -Invoke external AI CLIs (Gemini, Claude, Codex, OpenCode, Qwen Code, Cursor) to independently review phase plans. +Invoke external AI CLIs (Claude, Codex, OpenCode, Qwen Code, Cursor, Antigravity) to independently review phase plans. Produces a structured REVIEWS.md with per-reviewer feedback that can be fed back into planning via /gsd:plan-phase --reviews. @@ -27,7 +27,6 @@ planning via /gsd:plan-phase --reviews. Phase number: extracted from $ARGUMENTS (required) **Flags:** -- `--gemini` — Include Gemini CLI review - `--claude` — Include Claude CLI review (uses separate session) - `--codex` — Include Codex CLI review - `--opencode` — Include OpenCode review (uses model from user's OpenCode config) diff --git a/docs/CLI-TOOLS.md b/docs/CLI-TOOLS.md index acc6a2ca1..4fbb7b622 100644 --- a/docs/CLI-TOOLS.md +++ b/docs/CLI-TOOLS.md @@ -1423,7 +1423,7 @@ User-facing entry point: `/gsd-graphify` (see [Command Reference](COMMANDS.md#gs ```bash node gsd-tools.cjs config-set review.models.codex "gpt-5" -node gsd-tools.cjs config-set review.models.gemini "gemini-2.5-pro" +node gsd-tools.cjs config-set review.models.agy "gemini-3.1-pro-preview" node gsd-tools.cjs config-set review.models.opencode "claude-sonnet-4" node gsd-tools.cjs config-set review.models.claude "" # clear — fall back to session model ``` diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 3c51381a7..550cafd42 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -266,7 +266,7 @@ Cross-AI plan convergence loop — replan with review feedback until no HIGH con | Argument / Flag | Required | Description | |-----------------|----------|-------------| | `N` | **Yes** | Phase number to plan and review | -| Reviewer flags | No | Pass through every reviewer lane flag: `--gemini`, `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code` | +| Reviewer flags | No | Pass through every reviewer lane flag: `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code` | | `--all` | No | Run every configured reviewer. Lanes are dispatched **sequentially by default**; set `review.parallel_lanes` to `true` to dispatch them concurrently within a single review pass | | `--max-cycles N` | No | Override cycle cap (default 3) | @@ -754,7 +754,7 @@ Show status, next steps, and automatically advance to the next logical workflow | `--next --auto` | Like `--next`, but chains steps automatically until milestone completion or a blocking decision | | `--next --converge` | When the next action is planning, route it through `/gsd-plan-review-convergence`; requires `workflow.plan_review_convergence=true` | | `--cross-ai` | Alias for `--converge` | -| Reviewer flags | With `--converge`, pass through every reviewer lane flag: `--gemini`, `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code`, `--all`, and `--max-cycles N` | +| Reviewer flags | With `--converge`, pass through every reviewer lane flag: `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code`, `--all`, and `--max-cycles N` | | `--do "task description"` | Analyze freeform intent and dispatch to the most appropriate GSD command | | `--forensic` | Append a 6-check integrity audit after the standard report (STATE consistency, orphaned handoffs, deferred scope drift, memory-flagged pending work, blocking todos, uncommitted code) | @@ -1035,7 +1035,7 @@ Run all remaining phases autonomously. | `--interactive` | Lean context with user input | | `--converge` | Route each planning step through `/gsd-plan-review-convergence`; requires `workflow.plan_review_convergence=true` | | `--cross-ai` | Alias for `--converge` | -| Reviewer flags | With `--converge`, pass through every reviewer lane flag: `--gemini`, `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code`, `--all`, and `--max-cycles N` | +| Reviewer flags | With `--converge`, pass through every reviewer lane flag: `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code`, `--all`, and `--max-cycles N` | | `--text` | Replace `AskUserQuestion` prompts with plain numbered lists | ```bash @@ -1807,7 +1807,6 @@ Reviewers are prompted to verify the plan's claims against the actual repository | Flag | Description | |------|-------------| -| `--gemini` | Include Gemini CLI review | | `--claude` | Include Claude CLI review (separate session) | | `--codex` | Include Codex CLI review | | `--coderabbit` | Include CodeRabbit review | @@ -1823,7 +1822,7 @@ Reviewers are prompted to verify the plan's claims against the actual repository **No `jq`, `curl`, or `timeout` prerequisite.** Reviewer lanes used to shell out to these for JSON parsing, HTTP calls, and wall-clock bounding, which made five lanes unavailable on a stock Windows/Git-Bash host (no `jq`) and left one lane unbounded on stock macOS (no `timeout` or `gtimeout`). GSD now does all three itself, so every lane runs with nothing on your `PATH` but the reviewer's own CLI. A lane that declares an external tool it genuinely needs still reports itself unavailable with an install hint rather than running into an empty review. -**Unavailable reviewers:** an explicit reviewer flag is an assertion. If you name a reviewer that cannot run on this host — its CLI is not installed, a required external tool is missing, its local server is unreachable, or its egress destination changed (see below) — `/gsd-review` reports an **error** for that reviewer and does not proceed with a reduced set. This holds even when other named reviewers are available: `--gemini --qwen` on a host without `qwen` fails rather than silently becoming a Gemini-only review. +**Unavailable reviewers:** an explicit reviewer flag is an assertion. If you name a reviewer that cannot run on this host — its CLI is not installed, a required external tool is missing, its local server is unreachable, or its egress destination changed (see below) — `/gsd-review` reports an **error** for that reviewer and does not proceed with a reduced set. This holds even when other named reviewers are available: `--codex --qwen` on a host without `qwen` fails rather than silently becoming a Codex-only review. Reviewers reached through `--all` or `review.default_reviewers` behave differently: an undetected reviewer there is reported as an info note and skipped. Use `--all` for "whatever is available on this host", and `review.default_reviewers` for a preferred subset that may vary by host. @@ -1831,7 +1830,7 @@ Reviewers reached through `--all` or `review.default_reviewers` behave different **Default reviewer behavior (no flags):** - If `review.default_reviewers` is **unset**, `/gsd-review` runs all detected reviewers (current default behavior). -- If `review.default_reviewers` is **set**, `/gsd-review` runs only that subset (for example `["gemini","codex"]`). +- If `review.default_reviewers` is **set**, `/gsd-review` runs only that subset (for example `["codex","claude"]`). - `review.default_reviewers` may include names from `review.reviewer_instances`; each instance runs as its own reviewer identity using its configured adapter/model. Instance names are not CLI flags. - `--all` always overrides config and runs the full detected set. - Explicit flags (for example `--cursor`) override both `--all` and config defaults for that run. @@ -1844,11 +1843,11 @@ Its frontmatter records the model each reviewer resolved to, as `models:` (the m ```bash # set project default reviewers for no-flag /gsd-review runs -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' -/gsd-review --phase 2 # runs gemini+codex from config +/gsd-review --phase 2 # runs codex+claude from config /gsd-review --phase 3 --all -/gsd-review --phase 2 --gemini +/gsd-review --phase 2 --codex /gsd-review --phase 2 --cursor # one-off override ``` diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index af558877b..e0eb80189 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -294,7 +294,6 @@ The key suffix is **not** always the lane slug. Each lane declares the config ke |---------|------|---------|-------------| | `review.models.claude` | string | (session model) | Model id for Claude-flavored review. Defaults to the session model when unset | | `review.models.codex` | string | `null` | Model id for Codex review (injected into --model), e.g. `"gpt-5"` | -| `review.models.gemini` | string | `null` | Model id for Gemini review (injected into -m), e.g. `"gemini-2.5-pro"` | | `review.models.opencode` | string | `null` | Model id for OpenCode review (injected into --model), e.g. `"claude-sonnet-4"` | | `review.models.cursor` | string | `null` | Model id for Cursor review (injected into --model), e.g. `"cursor-grok-4.5-high"` | | `review.models.kimi-code` | string | `null` | Model id for Kimi Code review (injected into -m) | @@ -326,7 +325,7 @@ which schema validates them moved. One consequence follows: `` must now name a **declared reviewer lane**. Previously any slug matching `[a-zA-Z0-9_-]+` was accepted, so a typo or a key left over from a removed reviewer validated silently and was never read. Such a key is now rejected by `config-set`. The declared -lanes are `gemini`, `claude`, `codex`, `opencode`, `cursor`, `agy` (the Antigravity lane — its key suffix is +lanes are `claude`, `codex`, `opencode`, `cursor`, `agy` (the Antigravity lane — its key suffix is the CLI's own name, not the lane slug), `ollama`, `lm_studio` and `llama_cpp`. The same applies to `review.max_prompt_tokens_per_reviewer.`. `review.max_prompt_tokens` @@ -335,9 +334,9 @@ across lanes rather than one lane's behavior, so they remain central and are una ### Reviewer lane timeouts (`review.timeouts.*`, #3274) -Nine of the twelve declared reviewer lanes accept an outer wall-clock timeout override, federated +Eight of the eleven declared reviewer lanes accept an outer wall-clock timeout override, federated per-lane exactly like `review.max_prompt_tokens_per_reviewer.` above — the key is owned by -that lane's own capability manifest, not a central schema. Keys are seconds: `review.timeouts.gemini`, +that lane's own capability manifest, not a central schema. Keys are seconds: `review.timeouts.claude`, `review.timeouts.codex`, `review.timeouts.opencode`, `review.timeouts.antigravity`, `review.timeouts.kimi-code`, `review.timeouts.ollama`, `review.timeouts.lm_studio`, `review.timeouts.llama_cpp`. Unset (or `0`/negative/non-numeric) @@ -381,7 +380,7 @@ Before #4255 there was no review-specific source at all: every lane's level came prompt-fed, source-grounded review ran at the level chosen for a fast structural verifier, and a large plan set could come back as an empty lane. Effort is now a property of the review. -The lanes with no effort channel (`gemini`, `cursor`, `antigravity`, `qwen`, `coderabbit`, +The lanes with no effort channel (`cursor`, `antigravity`, `qwen`, `coderabbit`, `kimi-code`, `ollama`, `lm_studio`, `llama_cpp`) federate no key and emit no argument, matching the same narrow key-ownership invariant their model and timeout keys already follow. @@ -391,14 +390,14 @@ Use `review.default_reviewers` to scope the no-flag `/gsd-review` run to a subse | Setting | Type | Default | Description | |---------|------|---------|-------------| -| `review.default_reviewers` | string[] \| null | `null` (all detected reviewers) | Optional default subset for no-flag `/gsd-review`, e.g. `["gemini","codex"]`. Entries may be built-in reviewer slugs or configured `review.reviewer_instances` names. Precedence is: explicit reviewer flags > `--all` > `review.default_reviewers` > all detected. Unknown slugs are ignored with a warning when no instances are configured; with `review.reviewer_instances` present, unknown entries are hard errors to catch typoed instance names. Known-but-undetected slugs are ignored with an info note; empty arrays are rejected by `config-set`. This leniency is specific to the configured default: a reviewer named by an explicit CLI flag that cannot run is an error, not an info note. | +| `review.default_reviewers` | string[] \| null | `null` (all detected reviewers) | Optional default subset for no-flag `/gsd-review`, e.g. `["codex","claude"]`. Entries may be built-in reviewer slugs or configured `review.reviewer_instances` names. Precedence is: explicit reviewer flags > `--all` > `review.default_reviewers` > all detected. Unknown slugs are ignored with a warning when no instances are configured; with `review.reviewer_instances` present, unknown entries are hard errors to catch typoed instance names. Known-but-undetected slugs are ignored with an info note; empty arrays are rejected by `config-set`. This leniency is specific to the configured default: a reviewer named by an explicit CLI flag that cannot run is an error, not an info note. | Example: ```json { "review": { - "default_reviewers": ["gemini", "codex"] + "default_reviewers": ["codex", "claude"] } } ``` @@ -527,7 +526,7 @@ All workflow toggles follow the **absent = enabled** pattern. If a key is missin | `workflow.plan_bounce_script` | string | (none) | Path to the external script invoked for plan bounce validation. Receives the PLAN.md path as its first argument. Required when `plan_bounce` is `true`. Added in v1.36 | | `workflow.plan_bounce_passes` | number | `2` | Number of sequential bounce passes to run. Each pass feeds the previous pass's output back into the validator. Higher values increase rigor at the cost of latency. Added in v1.36 | | `workflow.post_planning_gaps` | boolean | `true` | Unified post-planning gap report (#2493). After all plans are generated and committed, scans REQUIREMENTS.md and CONTEXT.md `` against every PLAN.md in the phase directory, then prints one `Source \| Item \| Status` table. Word-boundary matching (REQ-1 vs REQ-10) and natural sort (REQ-02 before REQ-10). Non-blocking — informational report only. Set to `false` to skip Step 13e of plan-phase. | -| `workflow.plan_review_convergence` | boolean | `false` | Enable the `/gsd-plan-review-convergence` command. Disabled by default — the command exits with an enable instruction when this key is `false`. The command automates the manual plan→review→replan loop: it spawns configured reviewers (Codex, Gemini, Claude, OpenCode, Ollama, LM Studio, llama.cpp), counts unresolved HIGH concerns and actionable MEDIUM/LOW findings via the CYCLE_SUMMARY contract, replans with `--reviews` feedback, and repeats until converged or max cycles reached. Enable with `gsd config-set workflow.plan_review_convergence true`. Added in v1.39 | +| `workflow.plan_review_convergence` | boolean | `false` | Enable the `/gsd-plan-review-convergence` command. Disabled by default — the command exits with an enable instruction when this key is `false`. The command automates the manual plan→review→replan loop: it spawns configured reviewers (Codex, Claude, Antigravity, OpenCode, Ollama, LM Studio, llama.cpp), counts unresolved HIGH concerns and actionable MEDIUM/LOW findings via the CYCLE_SUMMARY contract, replans with `--reviews` feedback, and repeats until converged or max cycles reached. Enable with `gsd config-set workflow.plan_review_convergence true`. Added in v1.39 | | `workflow.plan_chunked` | boolean | `false` | Enable chunked planning mode. When `true` (or when `--chunked` flag is passed to `/gsd-plan-phase`), the orchestrator splits the single long-lived planner Task into a short outline Task followed by N short per-plan Tasks (~3-5 min each). Each plan is committed individually for crash resilience. If a Task hangs and the terminal is force-killed, rerunning with `--chunked` resumes from the last completed plan. Particularly useful on Windows where long-lived Tasks may hang on stdio. See [`planning.chunked_parallel`](#planning-settings) to dispatch the per-plan Tasks concurrently instead of one at a time. Added in v1.38 | | `workflow.code_review_command` | string | (none) | Shell command for external code review integration in `/gsd-ship`. Receives changed file paths via stdin. Non-zero exit blocks the ship workflow. Added in v1.36 | | `workflow.tdd_mode` | boolean | `false` | Enable TDD pipeline as a first-class execution mode. When `true`, the planner aggressively applies `type: tdd` to eligible tasks (business logic, APIs, validations, algorithms) and the executor enforces RED/GREEN/REFACTOR gate sequence. An end-of-phase collaborative review checkpoint verifies gate compliance. Added in v1.36 | @@ -1461,7 +1460,6 @@ Configure per-CLI model selection for `/gsd-review`. When set, overrides the CLI | Setting | Type | Default | Description | |---------|------|---------|-------------| -| `review.models.gemini` | string | (CLI default) | Model used when `--gemini` reviewer is invoked | | `review.models.claude` | string | (CLI default) | Model used when `--claude` reviewer is invoked | | `review.models.codex` | string | (CLI default) | Model used when `--codex` reviewer is invoked | | `review.models.opencode` | string | (CLI default) | Model used when `--opencode` reviewer is invoked | @@ -1471,9 +1469,9 @@ Configure per-CLI model selection for `/gsd-review`. When set, overrides the CLI | `review.models.ollama` | string | (server default) | Model name passed to Ollama when `--ollama` reviewer is invoked. If unset, the first available model reported by the server is used (e.g. `llama3`). Set to a specific tag: `gsd config-set review.models.ollama codellama` | | `review.models.lm_studio` | string | (server default) | Model name passed to LM Studio when `--lm-studio` reviewer is invoked. If unset, the first available model reported by the server is used. | | `review.models.llama_cpp` | string | (server default) | Model name passed to llama.cpp when `--llama-cpp` reviewer is invoked. If unset, the first model reported by `/v1/models` is used. | -| `review.default_reviewers` | string[] \| null | (all detected reviewers) | Default reviewer subset for no-flag `/gsd-review`. Example: `["gemini","codex"]`. May include configured `review.reviewer_instances` names. Explicit flags and `--all` override this setting. | +| `review.default_reviewers` | string[] \| null | (all detected reviewers) | Default reviewer subset for no-flag `/gsd-review`. Example: `["codex","claude"]`. May include configured `review.reviewer_instances` names. Explicit flags and `--all` override this setting. | | `review.max_prompt_tokens` | number\|null | null | Default maximum estimated tokens for the assembled review prompt. When set, the prompt is deterministically trimmed before being sent to each reviewer. Per-reviewer overrides via `review.max_prompt_tokens_per_reviewer` take precedence. null = no trim (current behavior). | -| `review.max_prompt_tokens_per_reviewer` | object | {} | Per-reviewer token budget overrides. Keys are reviewer slugs. Every declared reviewer lane accepts one (`gemini`, `claude`, `codex`, `coderabbit`, `opencode`, `qwen`, `cursor`, `antigravity`, `kimi-code`, `ollama`, `lm_studio`, `llama_cpp`). A lane's value of `-1` (the default) is unset and inherits `review.max_prompt_tokens`; `0` disables trimming for that lane specifically; any other number is that lane's own budget. | +| `review.max_prompt_tokens_per_reviewer` | object | {} | Per-reviewer token budget overrides. Keys are reviewer slugs. Every declared reviewer lane accepts one (`claude`, `codex`, `coderabbit`, `opencode`, `qwen`, `cursor`, `antigravity`, `kimi-code`, `ollama`, `lm_studio`, `llama_cpp`). A lane's value of `-1` (the default) is unset and inherits `review.max_prompt_tokens`; `0` disables trimming for that lane specifically; any other number is that lane's own budget. | | `review.parallel_lanes` | boolean | `false` | Dispatch independent reviewer lanes concurrently within a single `/gsd-review` pass. Default `false` keeps the sequential dispatch that protects against provider rate limits. Opt in only when your providers can accept concurrent requests. Convergence cycles stay sequential either way. | | `review.ollama_host` | string | `http://localhost:11434` | Base URL of the Ollama server. Override when running Ollama on a non-default port or remote host: `gsd config-set review.ollama_host http://192.168.1.10:11434` | | `review.lm_studio_host` | string | `http://localhost:1234` | Base URL of the LM Studio local server. Override when using a non-default port. | diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 0f4f3bb85..3153757c6 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -1414,9 +1414,9 @@ When verification returns `human_needed`, items are persisted as a trackable HUM ### 42. Cross-AI Peer Review -**Command:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` +**Command:** `/gsd-review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` -**Purpose:** Invoke external AI CLIs (Gemini, Claude, Codex, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity, Kimi Code) and local OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) to independently review phase plans. Produces structured REVIEWS.md with per-reviewer feedback. +**Purpose:** Invoke external AI CLIs (Claude, Codex, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity, Kimi Code) and local OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) to independently review phase plans. Produces structured REVIEWS.md with per-reviewer feedback. Each reviewer is a **declared lane**: its binary, prompt and output channels, timeout, availability probe, and empty-output policy come from a capability manifest rather than hand-written per-CLI logic, so a reviewer can be shipped as an installable capability instead of a core change. @@ -3735,7 +3735,7 @@ See [Resolve verify-command path findings](how-to/resolve-verify-command-path-fi **Config key:** `review.parallel_lanes` (default `false`) -**Purpose:** Reviewer lanes within one review pass have no data dependency on each other — they all inspect the same immutable plan snapshot — but were dispatched strictly one at a time, so a pass with Codex, Gemini and Claude cost roughly the sum of three long reviewer calls. The serialization was a deliberate, unconditional protection against provider rate limits, which made it a global policy imposed on users whose providers could comfortably take concurrent requests, or who run local model servers with no limits at all (#3034). +**Purpose:** Reviewer lanes within one review pass have no data dependency on each other — they all inspect the same immutable plan snapshot — but were dispatched strictly one at a time, so a pass with Codex, Antigravity and Claude cost roughly the sum of three long reviewer calls. The serialization was a deliberate, unconditional protection against provider rate limits, which made it a global policy imposed on users whose providers could comfortably take concurrent requests, or who run local model servers with no limits at all (#3034). **Behavior:** With the key enabled, the `invoke_reviewers` step dispatches each selected lane as a background job and joins all of them before `REVIEWS.md` and consensus are rendered. Wall-clock cost falls toward the slowest lane rather than the sum. Default remains `false`, preserving the existing sequential dispatch and its rate-limit protection. diff --git a/docs/features/cross-ai-peer-review.md b/docs/features/cross-ai-peer-review.md index 03bae1766..07ec5c865 100644 --- a/docs/features/cross-ai-peer-review.md +++ b/docs/features/cross-ai-peer-review.md @@ -4,9 +4,9 @@ title: Cross-AI Peer Review group: v1.27 Features --- -**Command:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` +**Command:** `/gsd-review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` -**Purpose:** Invoke external AI CLIs (Gemini, Claude, Codex, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity, Kimi Code) and local OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) to independently review phase plans. Produces structured REVIEWS.md with per-reviewer feedback. +**Purpose:** Invoke external AI CLIs (Claude, Codex, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity, Kimi Code) and local OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) to independently review phase plans. Produces structured REVIEWS.md with per-reviewer feedback. Each reviewer is a **declared lane**: its binary, prompt and output channels, timeout, availability probe, and empty-output policy come from a capability manifest rather than hand-written per-CLI logic, so a reviewer can be shipped as an installable capability instead of a core change. diff --git a/docs/features/opt-in-parallel-reviewer-lanes.md b/docs/features/opt-in-parallel-reviewer-lanes.md index 97f925693..f5fc38f3d 100644 --- a/docs/features/opt-in-parallel-reviewer-lanes.md +++ b/docs/features/opt-in-parallel-reviewer-lanes.md @@ -8,7 +8,7 @@ group: v1.7.0 Features **Config key:** `review.parallel_lanes` (default `false`) -**Purpose:** Reviewer lanes within one review pass have no data dependency on each other — they all inspect the same immutable plan snapshot — but were dispatched strictly one at a time, so a pass with Codex, Gemini and Claude cost roughly the sum of three long reviewer calls. The serialization was a deliberate, unconditional protection against provider rate limits, which made it a global policy imposed on users whose providers could comfortably take concurrent requests, or who run local model servers with no limits at all (#3034). +**Purpose:** Reviewer lanes within one review pass have no data dependency on each other — they all inspect the same immutable plan snapshot — but were dispatched strictly one at a time, so a pass with Codex, Antigravity and Claude cost roughly the sum of three long reviewer calls. The serialization was a deliberate, unconditional protection against provider rate limits, which made it a global policy imposed on users whose providers could comfortably take concurrent requests, or who run local model servers with no limits at all (#3034). **Behavior:** With the key enabled, the `invoke_reviewers` step dispatches each selected lane as a background job and joins all of them before `REVIEWS.md` and consensus are rendered. Wall-clock cost falls toward the slowest lane rather than the sum. Default remains `false`, preserving the existing sequential dispatch and its rate-limit protection. diff --git a/docs/how-to/run-phases-autonomously.md b/docs/how-to/run-phases-autonomously.md index 2a7967383..eb0de8c57 100644 --- a/docs/how-to/run-phases-autonomously.md +++ b/docs/how-to/run-phases-autonomously.md @@ -70,7 +70,7 @@ gsd config-set workflow.plan_review_convergence true /gsd-progress --next --auto --converge --codex --max-cycles 4 ``` -`--cross-ai` is accepted as an alias for `--converge`. Reviewer flags supported by `/gsd-plan-review-convergence` pass through unchanged, including `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. +`--cross-ai` is accepted as an alias for `--converge`. Reviewer flags supported by `/gsd-plan-review-convergence` pass through unchanged, including `--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. If `workflow.plan_review_convergence` is not enabled, the command stops before planning and prints the enable command instead of silently falling back to regular planning. diff --git a/docs/how-to/set-up-cross-ai-review.md b/docs/how-to/set-up-cross-ai-review.md index 966347562..245ea5ba0 100644 --- a/docs/how-to/set-up-cross-ai-review.md +++ b/docs/how-to/set-up-cross-ai-review.md @@ -8,7 +8,7 @@ ## Decide which reviewers to use -GSD Core can route review requests to any combination of: Gemini CLI, Claude (separate session), Codex CLI, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity CLI, Ollama, LM Studio, llama.cpp, and Kimi Code. +GSD Core can route review requests to any combination of: Claude (separate session), Codex CLI, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity CLI, Ollama, LM Studio, llama.cpp, and Kimi Code. That list is not fixed. Each of those is a declared reviewer lane, and a capability can ship its own — see [Ship a reviewer lane in your capability](ship-a-reviewer-lane.md). To see exactly which lanes your installation has, run `gsd-tools review-lane sections`. @@ -17,9 +17,6 @@ Each reviewer runs the same structured prompt against your `PLAN.md` files indep **If you have no external CLIs installed yet**, install at least one: ```bash -# Gemini CLI (free with Google credentials) -npm install -g @google/gemini-cli - # Antigravity CLI (free with Google credentials) curl -fsSL https://antigravity.google/cli/install.sh | bash @@ -37,12 +34,12 @@ By default, `/gsd-review` runs all detected CLIs. To pin a subset as project def /gsd-config --integrations ``` -The integrations wizard covers API keys, code-review CLI routing, and the `review.default_reviewers` list. Set the list to the reviewers you want as the no-flag default — for example `["gemini","codex"]`. +The integrations wizard covers API keys, code-review CLI routing, and the `review.default_reviewers` list. Set the list to the reviewers you want as the no-flag default — for example `["codex","claude"]`. Alternatively, set it directly with `gsd-tools`: ```bash -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' ``` For the full integration settings schema (API keys, model overrides per reviewer, local server host addresses), see [Configuration](../CONFIGURATION.md). @@ -64,7 +61,7 @@ GSD invokes each reviewer in sequence, collects structured feedback (Summary, St ### Select a single reviewer for a one-off run ```bash -/gsd-review --phase 3 --gemini +/gsd-review --phase 3 --agy /gsd-review --phase 3 --codex /gsd-review --phase 3 --cursor ``` @@ -139,7 +136,7 @@ This runs `plan-phase → review → replan → re-review` up to three cycles (d ```bash /gsd-plan-review-convergence 3 --codex -/gsd-plan-review-convergence 3 --gemini +/gsd-plan-review-convergence 3 --agy ``` ### Convergence with all reviewers and a higher cycle cap @@ -156,13 +153,13 @@ This runs `plan-phase → review → replan → re-review` up to three cycles (d | Situation | Recommended approach | |-----------|---------------------| -| You have Gemini CLI already installed | `--gemini` is always a good starting reviewer | -| You want free multi-reviewer coverage | `--gemini` + `--agy` (both use Google credentials) | +| You have Antigravity already installed | `--agy` is always a good starting reviewer | +| You want free multi-reviewer coverage | `--agy` (Google credentials) + `--claude` | | Your project is OpenAI-heavy | add `--codex` for an OpenAI-model perspective | | You want GitHub Copilot's model | add `--opencode` | | You want to avoid API costs entirely | configure Ollama with a local model and use `--ollama` | | You need maximum coverage before a release | `/gsd-plan-review-convergence N --all` | -| You're iterating quickly and want fast feedback | pick one CLI: `/gsd-review --phase N --gemini` | +| You're iterating quickly and want fast feedback | pick one CLI: `/gsd-review --phase N --agy` | --- diff --git a/docs/ja-JP/CLI-TOOLS.md b/docs/ja-JP/CLI-TOOLS.md index a600b623c..ee3de9d2f 100644 --- a/docs/ja-JP/CLI-TOOLS.md +++ b/docs/ja-JP/CLI-TOOLS.md @@ -479,7 +479,7 @@ node gsd-tools.cjs graphify snapshot [name] ```bash node gsd-tools.cjs config-set review.models.codex "codex exec --model gpt-5" -node gsd-tools.cjs config-set review.models.gemini "gemini -m gemini-2.5-pro" +node gsd-tools.cjs config-set review.models.agy "gemini-3.1-pro-preview" node gsd-tools.cjs config-set review.models.opencode "opencode run --model claude-sonnet-4" node gsd-tools.cjs config-set review.models.claude "" # クリア — セッションモデルにフォールバック ``` diff --git a/docs/ja-JP/COMMANDS.md b/docs/ja-JP/COMMANDS.md index 138664876..902b2b58d 100644 --- a/docs/ja-JP/COMMANDS.md +++ b/docs/ja-JP/COMMANDS.md @@ -218,7 +218,7 @@ WebSearch から取得したパッケージは `[ASSUMED]`(`[VERIFIED]` では | 引数 / フラグ | 必須 | 説明 | |-----------------|----------|-------------| | `N` | **Yes** | 計画およびレビューするフェーズ番号 | -| レビュアーフラグ | No | すべてのレビュアーレーンフラグをそのまま渡す: `--gemini`、`--claude`、`--codex`、`--coderabbit`、`--opencode`、`--qwen`、`--cursor`、`--agy` / `--antigravity`、`--ollama`、`--lm-studio`、`--llama-cpp`、`--kimi-code` | +| レビュアーフラグ | No | すべてのレビュアーレーンフラグをそのまま渡す: `--claude`、`--codex`、`--coderabbit`、`--opencode`、`--qwen`、`--cursor`、`--agy` / `--antigravity`、`--ollama`、`--lm-studio`、`--llama-cpp`、`--kimi-code` | | `--all` | No | 設定済みのすべてのレビュアーを実行。レーンはデフォルトでは**順次**ディスパッチされます。`review.parallel_lanes` を `true` にすると、1 回のレビューパス内で並行してディスパッチされます | | `--max-cycles N` | No | サイクル上限を上書き(デフォルト3) | @@ -1238,7 +1238,6 @@ AI システムの構築を含むフェーズの AI-SPEC.md デザインコン | フラグ | 説明 | |------|-------------| -| `--gemini` | Gemini CLI レビューを含める | | `--claude` | Claude CLI レビューを含める(別のセッション) | | `--codex` | Codex CLI レビューを含める | | `--coderabbit` | CodeRabbit レビューを含める | @@ -1254,7 +1253,7 @@ AI システムの構築を含むフェーズの AI-SPEC.md デザインコン **デフォルトレビュアーの動作(フラグなし):** - `review.default_reviewers` が**未設定**の場合、`/gsd-review` は検出されたすべてのレビュアーを実行します(現在のデフォルト動作)。 -- `review.default_reviewers` が**設定済み**の場合、`/gsd-review` はそのサブセットのみを実行します(例: `["gemini","codex"]`)。 +- `review.default_reviewers` が**設定済み**の場合、`/gsd-review` はそのサブセットのみを実行します(例: `["codex","claude"]`)。 - `--all` は常に設定を上書きし、完全な検出セットを実行します。 - 明示的なフラグ(例: `--cursor`)は、そのランの `--all` と設定デフォルトの両方を上書きします。 @@ -1262,11 +1261,11 @@ AI システムの構築を含むフェーズの AI-SPEC.md デザインコン ```bash # フラグなしの /gsd-review 実行用のプロジェクトデフォルトレビュアーを設定 -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' -/gsd-review --phase 2 # 設定から gemini+codex を実行 +/gsd-review --phase 2 # 設定から codex+claude を実行 /gsd-review --phase 3 --all -/gsd-review --phase 2 --gemini +/gsd-review --phase 2 --codex /gsd-review --phase 2 --cursor # ワンオフの上書き ``` diff --git a/docs/ja-JP/FEATURES.md b/docs/ja-JP/FEATURES.md index 3bc156e97..0ce322339 100644 --- a/docs/ja-JP/FEATURES.md +++ b/docs/ja-JP/FEATURES.md @@ -1164,7 +1164,7 @@ fix(03-01): correct auth token expiry ### 42. クロス AI ピアレビュー -**コマンド:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` +**コマンド:** `/gsd-review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` **目的:** 外部の AI CLI(Gemini、Claude、Codex、CodeRabbit、OpenCode、Qwen Code、Cursor、Antigravity、Kimi Code)とローカルの OpenAI 互換サーバー(Ollama、LM Studio、llama.cpp)を呼び出して、フェーズプランを独立してレビューします。レビュアーごとのフィードバックを含む構造化された REVIEWS.md を生成します。 diff --git a/docs/ja-JP/how-to/set-up-cross-ai-review.md b/docs/ja-JP/how-to/set-up-cross-ai-review.md index fe2fd41ed..2a485b215 100644 --- a/docs/ja-JP/how-to/set-up-cross-ai-review.md +++ b/docs/ja-JP/how-to/set-up-cross-ai-review.md @@ -8,16 +8,13 @@ ## 使用するレビュアーを決める -GSD Core は Gemini CLI、Claude(別セッション)、Codex CLI、CodeRabbit、OpenCode、Qwen Code、Cursor、Antigravity CLI、Ollama、LM Studio、llama.cpp の任意の組み合わせにレビューリクエストをルーティングできます。 +GSD Core は Claude(別セッション)、Codex CLI、CodeRabbit、OpenCode、Qwen Code、Cursor、Antigravity CLI、Ollama、LM Studio、llama.cpp の任意の組み合わせにレビューリクエストをルーティングできます。 各レビュアーは `PLAN.md` ファイルに対して同じ構造化プロンプトを独立して実行します。モデルによって盲点が異なるため、複数レビュアーのコンセンサスは単一レビュアーよりも多くの問題を検出できます。 **外部 CLI がまだインストールされていない場合**は、少なくとも 1 つをインストールしてください: ```bash -# Gemini CLI(Google 認証情報で無料) -npm install -g @google/gemini-cli - # Antigravity CLI(Google 認証情報で無料) curl -fsSL https://antigravity.google/cli/install.sh | bash @@ -35,12 +32,12 @@ npm install -g @openai/codex /gsd-config --integrations ``` -インテグレーションウィザードは API キー、コードレビュー CLI のルーティング、`review.default_reviewers` リストをカバーします。フラグなしのデフォルトとして使用したいレビュアーのリストを設定します。例: `["gemini","codex"]`。 +インテグレーションウィザードは API キー、コードレビュー CLI のルーティング、`review.default_reviewers` リストをカバーします。フラグなしのデフォルトとして使用したいレビュアーのリストを設定します。例: `["codex","claude"]`。 または `gsd-tools` で直接設定することもできます: ```bash -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' ``` インテグレーション設定スキーマの全体(API キー、レビュアーごとのモデルオーバーライド、ローカルサーバーのホストアドレス)については [設定](../CONFIGURATION.md) を参照してください。 @@ -60,7 +57,7 @@ GSD は各レビュアーを順番に呼び出し、構造化されたフィー ### 1 回限りの実行で特定のレビュアーを選ぶ ```bash -/gsd-review --phase 3 --gemini +/gsd-review --phase 3 --agy /gsd-review --phase 3 --codex /gsd-review --phase 3 --cursor ``` @@ -124,7 +121,7 @@ HIGH 重大度の懸念事項がすべて解決されるまで反復したい場 ```bash /gsd-plan-review-convergence 3 --codex -/gsd-plan-review-convergence 3 --gemini +/gsd-plan-review-convergence 3 --agy ``` ### すべてのレビュアーと高いサイクル上限でのコンバージェンス @@ -141,13 +138,13 @@ HIGH 重大度の懸念事項がすべて解決されるまで反復したい場 | 状況 | 推奨アプローチ | |-----------|---------------------| -| Gemini CLI がすでにインストール済み | `--gemini` は常に良い出発点のレビュアー | -| 無料のマルチレビュアーカバレッジが欲しい | `--gemini` + `--agy`(両方とも Google 認証情報を使用) | +| Antigravity がすでにインストール済み | `--agy` は常に良い出発点のレビュアー | +| 無料のマルチレビュアーカバレッジが欲しい | `--agy`(Google 認証情報) + `--claude` | | プロジェクトが OpenAI 中心 | OpenAI モデルの観点のために `--codex` を追加 | | GitHub Copilot のモデルが欲しい | `--opencode` を追加 | | API コストを完全に避けたい | Ollama にローカルモデルを設定して `--ollama` を使用 | | リリース前に最大限のカバレッジが必要 | `/gsd-plan-review-convergence N --all` | -| 素早く反復して高速なフィードバックが欲しい | 1 つの CLI を選ぶ: `/gsd-review --phase N --gemini` | +| 素早く反復して高速なフィードバックが欲しい | 1 つの CLI を選ぶ: `/gsd-review --phase N --agy` | --- diff --git a/docs/ko-KR/CLI-TOOLS.md b/docs/ko-KR/CLI-TOOLS.md index 991c7b05f..5469e1ce5 100644 --- a/docs/ko-KR/CLI-TOOLS.md +++ b/docs/ko-KR/CLI-TOOLS.md @@ -479,7 +479,7 @@ node gsd-tools.cjs graphify snapshot [name] ```bash node gsd-tools.cjs config-set review.models.codex "codex exec --model gpt-5" -node gsd-tools.cjs config-set review.models.gemini "gemini -m gemini-2.5-pro" +node gsd-tools.cjs config-set review.models.agy "gemini-3.1-pro-preview" node gsd-tools.cjs config-set review.models.opencode "opencode run --model claude-sonnet-4" node gsd-tools.cjs config-set review.models.claude "" # clear — fall back to session model ``` diff --git a/docs/ko-KR/COMMANDS.md b/docs/ko-KR/COMMANDS.md index 3274156a5..5ab20472c 100644 --- a/docs/ko-KR/COMMANDS.md +++ b/docs/ko-KR/COMMANDS.md @@ -218,7 +218,7 @@ WebSearch에서 가져온 패키지는 `[ASSUMED]`(`[VERIFIED]`가 아님)로 | 인수 / 플래그 | 필수 | 설명 | |-----------------|----------|-------------| | `N` | **예** | 계획 및 리뷰할 단계 번호 | -| 리뷰어 플래그 | 아니요 | 모든 리뷰어 레인 플래그를 그대로 전달: `--gemini`, `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code` | +| 리뷰어 플래그 | 아니요 | 모든 리뷰어 레인 플래그를 그대로 전달: `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code` | | `--all` | 아니요 | 구성된 모든 리뷰어를 실행합니다. 레인은 기본적으로 **순차적으로** 디스패치되며, `review.parallel_lanes`를 `true`로 설정하면 단일 리뷰 패스 내에서 동시에 디스패치됩니다 | | `--max-cycles N` | 아니요 | 사이클 상한 재정의 (기본값 3) | @@ -1244,7 +1244,6 @@ AI 시스템 구축을 포함하는 단계에 대한 AI-SPEC.md 디자인 계약 | 플래그 | 설명 | |------|-------------| -| `--gemini` | Gemini CLI 검토 포함 | | `--claude` | Claude CLI 검토 포함 (별도 세션) | | `--codex` | Codex CLI 검토 포함 | | `--coderabbit` | CodeRabbit 검토 포함 | @@ -1260,7 +1259,7 @@ AI 시스템 구축을 포함하는 단계에 대한 AI-SPEC.md 디자인 계약 **기본 리뷰어 동작 (플래그 없음):** - `review.default_reviewers`가 **설정되지 않은** 경우, `/gsd-review`는 감지된 모든 리뷰어를 실행합니다 (현재 기본 동작). -- `review.default_reviewers`가 **설정된** 경우, `/gsd-review`는 해당 하위 집합만 실행합니다 (예: `["gemini","codex"]`). +- `review.default_reviewers`가 **설정된** 경우, `/gsd-review`는 해당 하위 집합만 실행합니다 (예: `["codex","claude"]`). - `--all`은 항상 설정을 재정의하고 전체 감지된 집합을 실행합니다. - 명시적 플래그 (예: `--cursor`)는 해당 실행에 대해 `--all`과 설정 기본값 모두를 재정의합니다. @@ -1268,11 +1267,11 @@ AI 시스템 구축을 포함하는 단계에 대한 AI-SPEC.md 디자인 계약 ```bash # 플래그 없는 /gsd-review 실행을 위한 프로젝트 기본 리뷰어 설정 -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' -/gsd-review --phase 2 # 설정에서 gemini+codex 실행 +/gsd-review --phase 2 # 설정에서 codex+claude 실행 /gsd-review --phase 3 --all -/gsd-review --phase 2 --gemini +/gsd-review --phase 2 --codex /gsd-review --phase 2 --cursor # 일회성 재정의 ``` diff --git a/docs/ko-KR/FEATURES.md b/docs/ko-KR/FEATURES.md index ee1ee6e17..f8870341b 100644 --- a/docs/ko-KR/FEATURES.md +++ b/docs/ko-KR/FEATURES.md @@ -1068,7 +1068,7 @@ fix(03-01): correct auth token expiry ### 42. Cross-AI Peer Review -**명령어:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` +**명령어:** `/gsd-review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` **목적:** 외부 AI CLI(Gemini, Claude, Codex, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity, Kimi Code)와 로컬 OpenAI 호환 서버(Ollama, LM Studio, llama.cpp)를 호출하여 페이즈 계획을 독립적으로 검토합니다. 검토자별 피드백이 담긴 구조화된 REVIEWS.md를 생성합니다. diff --git a/docs/ko-KR/how-to/set-up-cross-ai-review.md b/docs/ko-KR/how-to/set-up-cross-ai-review.md index 41cee2298..e503e4f31 100644 --- a/docs/ko-KR/how-to/set-up-cross-ai-review.md +++ b/docs/ko-KR/how-to/set-up-cross-ai-review.md @@ -8,16 +8,13 @@ ## 어떤 리뷰어를 사용할지 결정 -GSD Core는 Gemini CLI, Claude(별도 세션), Codex CLI, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity CLI, Ollama, LM Studio, llama.cpp의 조합으로 리뷰 요청을 라우팅할 수 있습니다. +GSD Core는 Claude(별도 세션), Codex CLI, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity CLI, Ollama, LM Studio, llama.cpp의 조합으로 리뷰 요청을 라우팅할 수 있습니다. 각 리뷰어는 `PLAN.md` 파일에 대해 동일한 구조화된 프롬프트를 독립적으로 실행합니다. 서로 다른 모델은 서로 다른 맹점을 가지고 있으므로 멀티 리뷰어 합의가 단일 리뷰어보다 더 많은 문제를 발견합니다. **외부 CLI가 아직 설치되지 않은 경우**, 최소 하나를 설치하세요: ```bash -# Gemini CLI (Google 자격 증명으로 무료) -npm install -g @google/gemini-cli - # Antigravity CLI (Google 자격 증명으로 무료) curl -fsSL https://antigravity.google/cli/install.sh | bash @@ -35,12 +32,12 @@ npm install -g @openai/codex /gsd-config --integrations ``` -통합 마법사는 API 키, 코드 리뷰 CLI 라우팅, `review.default_reviewers` 목록을 다룹니다. 목록을 플래그 없는 기본값으로 사용하려는 리뷰어로 설정하세요. 예: `["gemini","codex"]`. +통합 마법사는 API 키, 코드 리뷰 CLI 라우팅, `review.default_reviewers` 목록을 다룹니다. 목록을 플래그 없는 기본값으로 사용하려는 리뷰어로 설정하세요. 예: `["codex","claude"]`. 또는 `gsd-tools`로 직접 설정하세요: ```bash -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' ``` 전체 통합 설정 스키마(API 키, 리뷰어별 모델 재정의, 로컬 서버 호스트 주소)에 대해서는 [설정](../CONFIGURATION.md)을 참고하세요. @@ -60,7 +57,7 @@ GSD는 각 리뷰어를 순서대로 호출하고 구조화된 피드백(요약, ### 일회성 실행을 위한 단일 리뷰어 선택 ```bash -/gsd-review --phase 3 --gemini +/gsd-review --phase 3 --agy /gsd-review --phase 3 --codex /gsd-review --phase 3 --cursor ``` @@ -124,7 +121,7 @@ Ollama 또는 LM Studio를 로컬에서 실행하는 경우 서버에 접근할 ```bash /gsd-plan-review-convergence 3 --codex -/gsd-plan-review-convergence 3 --gemini +/gsd-plan-review-convergence 3 --agy ``` ### 모든 리뷰어로 더 높은 사이클 상한으로 수렴 @@ -141,13 +138,13 @@ Ollama 또는 LM Studio를 로컬에서 실행하는 경우 서버에 접근할 | 상황 | 권장 방법 | |-----------|---------------------| -| Gemini CLI가 이미 설치되어 있는 경우 | `--gemini`는 항상 좋은 시작 리뷰어 | -| 무료 멀티 리뷰어 커버리지를 원하는 경우 | `--gemini` + `--agy` (둘 다 Google 자격 증명 사용) | +| Antigravity가 이미 설치되어 있는 경우 | `--agy`는 항상 좋은 시작 리뷰어 | +| 무료 멀티 리뷰어 커버리지를 원하는 경우 | `--agy` (Google 자격 증명) + `--claude` | | OpenAI 중심 프로젝트인 경우 | OpenAI 모델 관점을 위해 `--codex` 추가 | | GitHub Copilot 모델을 원하는 경우 | `--opencode` 추가 | | API 비용을 완전히 피하려는 경우 | 로컬 모델로 Ollama를 설정하고 `--ollama` 사용 | | 릴리스 전 최대 커버리지가 필요한 경우 | `/gsd-plan-review-convergence N --all` | -| 빠르게 반복하며 빠른 피드백을 원하는 경우 | CLI 하나 선택: `/gsd-review --phase N --gemini` | +| 빠르게 반복하며 빠른 피드백을 원하는 경우 | CLI 하나 선택: `/gsd-review --phase N --agy` | --- diff --git a/docs/pt-BR/CLI-TOOLS.md b/docs/pt-BR/CLI-TOOLS.md index d0445eee3..ce26ef0c2 100644 --- a/docs/pt-BR/CLI-TOOLS.md +++ b/docs/pt-BR/CLI-TOOLS.md @@ -482,7 +482,7 @@ Ponto de entrada para o usuário: `/gsd-graphify` (consulte a [Referência de Co ```bash node gsd-tools.cjs config-set review.models.codex "codex exec --model gpt-5" -node gsd-tools.cjs config-set review.models.gemini "gemini -m gemini-2.5-pro" +node gsd-tools.cjs config-set review.models.agy "gemini-3.1-pro-preview" node gsd-tools.cjs config-set review.models.opencode "opencode run --model claude-sonnet-4" node gsd-tools.cjs config-set review.models.claude "" # limpa — retorna ao modelo da sessão ``` diff --git a/docs/pt-BR/COMMANDS.md b/docs/pt-BR/COMMANDS.md index 40a56a238..46a5734d6 100644 --- a/docs/pt-BR/COMMANDS.md +++ b/docs/pt-BR/COMMANDS.md @@ -218,7 +218,7 @@ Loop de convergência de planos cross-AI — replaneja com feedback de revisão | Argumento / Flag | Obrigatório | Descrição | |------------------|-------------|-----------| | `N` | **Sim** | Número da fase a planejar e revisar | -| Flags de revisor | Não | Repassa todas as flags de lane de revisor: `--gemini`, `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code` | +| Flags de revisor | Não | Repassa todas as flags de lane de revisor: `--claude`, `--codex`, `--coderabbit`, `--opencode`, `--qwen`, `--cursor`, `--agy` / `--antigravity`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--kimi-code` | | `--all` | Não | Executa todos os revisores configurados. As lanes são despachadas **sequencialmente** por padrão; defina `review.parallel_lanes` como `true` para despachá-las simultaneamente em uma única passagem de revisão | | `--max-cycles N` | Não | Substitui o limite de ciclos (padrão 3) | @@ -1241,7 +1241,6 @@ Revisão por pares cross-AI de planos de fase a partir de CLIs de IA externas. | Flag | Descrição | |------|-----------| -| `--gemini` | Inclui revisão pelo Gemini CLI | | `--claude` | Inclui revisão pelo Claude CLI (sessão separada) | | `--codex` | Inclui revisão pelo Codex CLI | | `--coderabbit` | Inclui revisão pelo CodeRabbit | @@ -1257,7 +1256,7 @@ Revisão por pares cross-AI de planos de fase a partir de CLIs de IA externas. **Comportamento do revisor padrão (sem flags):** - Se `review.default_reviewers` estiver **não definido**, `/gsd-review` executa todos os revisores detectados (comportamento padrão atual). -- Se `review.default_reviewers` estiver **definido**, `/gsd-review` executa somente esse subconjunto (por exemplo `["gemini","codex"]`). +- Se `review.default_reviewers` estiver **definido**, `/gsd-review` executa somente esse subconjunto (por exemplo `["codex","claude"]`). - `--all` sempre substitui a configuração e executa o conjunto detectado completo. - Flags explícitas (por exemplo `--cursor`) substituem tanto `--all` quanto os padrões de configuração para aquela execução. @@ -1265,11 +1264,11 @@ Revisão por pares cross-AI de planos de fase a partir de CLIs de IA externas. ```bash # define revisores padrão do projeto para execuções de /gsd-review sem flag -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' -/gsd-review --phase 2 # executa gemini+codex da configuração +/gsd-review --phase 2 # executa codex+claude da configuração /gsd-review --phase 3 --all -/gsd-review --phase 2 --gemini +/gsd-review --phase 2 --codex /gsd-review --phase 2 --cursor # substituição avulsa ``` diff --git a/docs/pt-BR/CONFIGURATION.md b/docs/pt-BR/CONFIGURATION.md index 8fa86b8ad..0f3bf0d05 100644 --- a/docs/pt-BR/CONFIGURATION.md +++ b/docs/pt-BR/CONFIGURATION.md @@ -195,7 +195,6 @@ Os campos de chave de API aceitam um valor string (a própria chave). Também po |---------|------|---------|-------------| | `review.models.claude` | string | (modelo da sessão) | Comando para revisão com sabor Claude. Usa o modelo da sessão quando não definido | | `review.models.codex` | string | `null` | Comando para revisão Codex, por exemplo `"codex exec --model gpt-5"` | -| `review.models.gemini` | string | `null` | Comando para revisão Gemini, por exemplo `"gemini -m gemini-2.5-pro"` | | `review.models.opencode` | string | `null` | Comando para revisão OpenCode, por exemplo `"opencode run --model claude-sonnet-4"` | O slug `` é validado contra `[a-zA-Z0-9_-]+`. Slugs vazios ou que contenham caminhos são rejeitados pelo `config-set`. @@ -206,14 +205,14 @@ Use `review.default_reviewers` para limitar a execução de `/gsd-review` sem fl | Configuração | Tipo | Padrão | Descrição | |---------|------|---------|-------------| -| `review.default_reviewers` | string[] \| null | `null` (todos os revisores detectados) | Subconjunto padrão opcional para `/gsd-review` sem flags, por exemplo `["gemini","codex"]`. Precedência: flags de revisor explícitas > `--all` > `review.default_reviewers` > todos detectados. Slugs desconhecidos são ignorados com aviso; slugs conhecidos mas não detectados são ignorados com uma nota informativa; arrays vazios são rejeitados pelo `config-set`. | +| `review.default_reviewers` | string[] \| null | `null` (todos os revisores detectados) | Subconjunto padrão opcional para `/gsd-review` sem flags, por exemplo `["codex","claude"]`. Precedência: flags de revisor explícitas > `--all` > `review.default_reviewers` > todos detectados. Slugs desconhecidos são ignorados com aviso; slugs conhecidos mas não detectados são ignorados com uma nota informativa; arrays vazios são rejeitados pelo `config-set`. | Exemplo: ```json { "review": { - "default_reviewers": ["gemini", "codex"] + "default_reviewers": ["codex", "claude"] } } ``` @@ -254,7 +253,7 @@ Todos os controles de fluxo de trabalho seguem o padrão **ausente = habilitado* | `workflow.plan_bounce_script` | string | (nenhum) | Caminho para o script externo invocado na validação de bounce de plano. Recebe o caminho do PLAN.md como primeiro argumento. Obrigatório quando `plan_bounce` é `true`. Adicionado na v1.36 | | `workflow.plan_bounce_passes` | number | `2` | Número de passagens sequenciais de bounce a executar. Cada passagem alimenta a saída da passagem anterior de volta no validador. Valores maiores aumentam o rigor ao custo de latência. Adicionado na v1.36 | | `workflow.post_planning_gaps` | boolean | `true` | Relatório unificado de lacunas pós-planejamento (#2493). Após todos os planos serem gerados e commitados, verifica REQUIREMENTS.md e as `` de CONTEXT.md em relação a cada PLAN.md no diretório da fase, então imprime uma tabela `Source \| Item \| Status`. Correspondência por limite de palavra (REQ-1 vs REQ-10) e ordenação natural (REQ-02 antes de REQ-10). Não bloqueante — apenas relatório informativo. Defina como `false` para pular o Passo 13e da fase de planejamento. | -| `workflow.plan_review_convergence` | boolean | `false` | Habilita o comando `/gsd-plan-review-convergence`. Desabilitado por padrão — o comando sai com instrução de habilitação quando esta chave é `false`. O comando automatiza o loop manual de plan→review→replan: gera revisores configurados (Codex, Gemini, Claude, OpenCode, Ollama, LM Studio, llama.cpp), conta preocupações HIGH não resolvidas via contrato CYCLE_SUMMARY, replaneja com feedback `--reviews` e repete até convergir ou atingir o número máximo de ciclos. Habilite com `gsd config-set workflow.plan_review_convergence true`. Adicionado na v1.39 | +| `workflow.plan_review_convergence` | boolean | `false` | Habilita o comando `/gsd-plan-review-convergence`. Desabilitado por padrão — o comando sai com instrução de habilitação quando esta chave é `false`. O comando automatiza o loop manual de plan→review→replan: gera revisores configurados (Codex, Claude, OpenCode, Ollama, LM Studio, llama.cpp), conta preocupações HIGH não resolvidas via contrato CYCLE_SUMMARY, replaneja com feedback `--reviews` e repete até convergir ou atingir o número máximo de ciclos. Habilite com `gsd config-set workflow.plan_review_convergence true`. Adicionado na v1.39 | | `workflow.plan_chunked` | boolean | `false` | Habilita o modo de planejamento em chunks. Quando `true` (ou quando a flag `--chunked` é passada para `/gsd-plan-phase`), o orquestrador divide a única Task de planejamento de longa duração em uma Task curta de esboço seguida de N Tasks curtas por plano (~3-5 min cada). Cada plano é commitado individualmente para resiliência a falhas. Se uma Task travar e o terminal for forçado a fechar, reexecutar com `--chunked` retoma a partir do último plano concluído. Particularmente útil no Windows onde Tasks de longa duração podem travar em stdio. Adicionado na v1.38 | | `workflow.code_review_command` | string | (nenhum) | Comando shell para integração de revisão de código externa em `/gsd-ship`. Recebe caminhos de arquivos alterados via stdin. Saída diferente de zero bloqueia o fluxo de trabalho de ship. Adicionado na v1.36 | | `workflow.tdd_mode` | boolean | `false` | Habilita o pipeline TDD como modo de execução de primeira classe. Quando `true`, o planejador aplica agressivamente `type: tdd` a tarefas elegíveis (lógica de negócios, APIs, validações, algoritmos) e o executor impõe a sequência de gate RED/GREEN/REFACTOR. Um ponto de revisão colaborativa ao final da fase verifica a conformidade com o gate. Adicionado na v1.36 | @@ -692,7 +691,6 @@ Configure a seleção de modelo por CLI para `/gsd-review`. Quando definido, sub | Configuração | Tipo | Padrão | Descrição | |---------|------|---------|-------------| -| `review.models.gemini` | string | (padrão da CLI) | Modelo usado quando o revisor `--gemini` é invocado | | `review.models.claude` | string | (padrão da CLI) | Modelo usado quando o revisor `--claude` é invocado | | `review.models.codex` | string | (padrão da CLI) | Modelo usado quando o revisor `--codex` é invocado | | `review.models.opencode` | string | (padrão da CLI) | Modelo usado quando o revisor `--opencode` é invocado | @@ -701,9 +699,9 @@ Configure a seleção de modelo por CLI para `/gsd-review`. Quando definido, sub | `review.models.ollama` | string | (padrão do servidor) | Nome do modelo passado ao Ollama quando o revisor `--ollama` é invocado. Se não definido, o primeiro modelo disponível reportado pelo servidor é usado (por exemplo `llama3`). Defina para uma tag específica: `gsd config-set review.models.ollama codellama` | | `review.models.lm_studio` | string | (padrão do servidor) | Nome do modelo passado ao LM Studio quando o revisor `--lm-studio` é invocado. Se não definido, o primeiro modelo disponível reportado pelo servidor é usado. | | `review.models.llama_cpp` | string | (padrão do servidor) | Nome do modelo passado ao llama.cpp quando o revisor `--llama-cpp` é invocado. Se não definido, o primeiro modelo reportado por `/v1/models` é usado. | -| `review.default_reviewers` | string[] \| null | (todos os revisores detectados) | Subconjunto de revisores padrão para `/gsd-review` sem flags. Exemplo: `["gemini","codex"]`. Flags explícitas e `--all` substituem esta configuração. | +| `review.default_reviewers` | string[] \| null | (todos os revisores detectados) | Subconjunto de revisores padrão para `/gsd-review` sem flags. Exemplo: `["codex","claude"]`. Flags explícitas e `--all` substituem esta configuração. | | `review.max_prompt_tokens` | number\|null | null | Máximo padrão de tokens estimados para o prompt de revisão montado. Quando definido, o prompt é cortado deterministicamente antes de ser enviado a cada revisor. Substituições por revisor via `review.max_prompt_tokens_per_reviewer` têm precedência. null = sem corte (comportamento atual). | -| `review.max_prompt_tokens_per_reviewer` | object | {} | Substituições de orçamento de tokens por revisor. As chaves são slugs de revisor (ollama, llama_cpp, lm_studio, gemini, claude, codex, opencode, qwen, cursor). Os valores substituem `review.max_prompt_tokens` para aquele revisor. Recomendado para servidores de modelos locais. | +| `review.max_prompt_tokens_per_reviewer` | object | {} | Substituições de orçamento de tokens por revisor. As chaves são slugs de revisor (ollama, llama_cpp, lm_studio, claude, codex, opencode, qwen, cursor). Os valores substituem `review.max_prompt_tokens` para aquele revisor. Recomendado para servidores de modelos locais. | | `review.ollama_host` | string | `http://localhost:11434` | URL base do servidor Ollama. Substitua quando executar o Ollama em uma porta não padrão ou host remoto: `gsd config-set review.ollama_host http://192.168.1.10:11434` | | `review.lm_studio_host` | string | `http://localhost:1234` | URL base do servidor local LM Studio. Substitua quando usar uma porta não padrão. | | `review.llama_cpp_host` | string | `http://localhost:8080` | URL base do servidor llama.cpp (`llama-server`). Substitua quando usar uma porta não padrão. | @@ -718,7 +716,7 @@ Servidores de modelos locais (Ollama, llama.cpp, LM Studio) geralmente aceitam m { "review": { "models": { - "gemini": "gemini-2.5-pro", + "agy": "gemini-3.1-pro-preview", "qwen": "qwen-max" } } diff --git a/docs/pt-BR/how-to/set-up-cross-ai-review.md b/docs/pt-BR/how-to/set-up-cross-ai-review.md index ab067075d..92bbbefa4 100644 --- a/docs/pt-BR/how-to/set-up-cross-ai-review.md +++ b/docs/pt-BR/how-to/set-up-cross-ai-review.md @@ -8,16 +8,13 @@ ## Decidir quais revisores usar -O GSD Core pode encaminhar solicitações de revisão para qualquer combinação de: Gemini CLI, Claude (sessão separada), Codex CLI, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity CLI, Ollama, LM Studio e llama.cpp. +O GSD Core pode encaminhar solicitações de revisão para qualquer combinação de: Claude (sessão separada), Codex CLI, CodeRabbit, OpenCode, Qwen Code, Cursor, Antigravity CLI, Ollama, LM Studio e llama.cpp. Cada revisor executa o mesmo prompt estruturado contra seus arquivos `PLAN.md` de forma independente. Como diferentes modelos têm diferentes pontos cegos, o consenso de múltiplos revisores detecta mais problemas do que qualquer revisor individual. **Se você ainda não tem CLIs externos instalados**, instale pelo menos um: ```bash -# Gemini CLI (gratuito com credenciais Google) -npm install -g @google/gemini-cli - # Antigravity CLI (gratuito com credenciais Google) curl -fsSL https://antigravity.google/cli/install.sh | bash @@ -35,12 +32,12 @@ Por padrão, `/gsd-review` executa todos os CLIs detectados. Para fixar um subco /gsd-config --integrations ``` -O assistente de integrações cobre chaves de API, roteamento de CLIs para revisão de código e a lista `review.default_reviewers`. Defina a lista com os revisores que você deseja como padrão sem flags — por exemplo `["gemini","codex"]`. +O assistente de integrações cobre chaves de API, roteamento de CLIs para revisão de código e a lista `review.default_reviewers`. Defina a lista com os revisores que você deseja como padrão sem flags — por exemplo `["codex","claude"]`. Como alternativa, defina diretamente com `gsd-tools`: ```bash -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' ``` Para o esquema completo de configurações de integração (chaves de API, substituições de modelo por revisor, endereços de servidor local), consulte [Configuração](../CONFIGURATION.md). @@ -60,7 +57,7 @@ O GSD invoca cada revisor em sequência, coleta feedback estruturado (Resumo, Po ### Selecionar um único revisor para uma execução pontual ```bash -/gsd-review --phase 3 --gemini +/gsd-review --phase 3 --agy /gsd-review --phase 3 --codex /gsd-review --phase 3 --cursor ``` @@ -124,7 +121,7 @@ Isso executa `plan-phase → review → replan → re-review` por até três cic ```bash /gsd-plan-review-convergence 3 --codex -/gsd-plan-review-convergence 3 --gemini +/gsd-plan-review-convergence 3 --agy ``` ### Convergência com todos os revisores e um limite maior de ciclos @@ -141,13 +138,13 @@ Isso executa `plan-phase → review → replan → re-review` por até três cic | Situação | Abordagem recomendada | |-----------|---------------------| -| Você já tem o Gemini CLI instalado | `--gemini` é sempre um bom revisor inicial | -| Você quer cobertura gratuita com múltiplos revisores | `--gemini` + `--agy` (ambos usam credenciais Google) | +| Você já tem o Antigravity instalado | `--agy` é sempre um bom revisor inicial | +| Você quer cobertura gratuita com múltiplos revisores | `--agy` (credenciais Google) + `--claude` | | Seu projeto é fortemente baseado em OpenAI | adicione `--codex` para uma perspectiva de modelo OpenAI | | Você quer o modelo do GitHub Copilot | adicione `--opencode` | | Você quer evitar custos de API completamente | configure o Ollama com um modelo local e use `--ollama` | | Você precisa de cobertura máxima antes de um lançamento | `/gsd-plan-review-convergence N --all` | -| Você está iterando rapidamente e quer feedback rápido | escolha um CLI: `/gsd-review --phase N --gemini` | +| Você está iterando rapidamente e quer feedback rápido | escolha um CLI: `/gsd-review --phase N --agy` | --- diff --git a/docs/reference/capability-matrix.md b/docs/reference/capability-matrix.md index 561f9c52d..6e2817bd2 100644 --- a/docs/reference/capability-matrix.md +++ b/docs/reference/capability-matrix.md @@ -104,7 +104,7 @@ emission), so their extension-point and hook-kind cells are `—`. | `windsurf` | runtime | core | `>=1.6.0` | — | — | first-party | | `zcode` | runtime | core | `>=1.6.0` | — | — | first-party | -### Reviewer capabilities (role: reviewer) — 5 +### Reviewer capabilities (role: reviewer) — 4 Reviewer capabilities declare a cross-AI **reviewer lane** — one external CLI or model endpoint `/gsd-review` hands a plan to (ADR-2782 D3). They are not install @@ -122,7 +122,6 @@ at install like any other — see | id | role | tier | engines.gsd | extension points | hook kinds | source | |---|---|---|---|---|---|---| | `coderabbit` | reviewer | full | `>=1.8.0` | — | — | first-party | -| `gemini` | reviewer | full | `>=1.8.0` | — | — | first-party | | `llama-cpp` | reviewer | full | `>=1.8.0` | — | — | first-party | | `lm-studio` | reviewer | full | `>=1.8.0` | — | — | first-party | | `ollama` | reviewer | full | `>=1.8.0` | — | — | first-party | diff --git a/docs/zh-CN/CLI-TOOLS.md b/docs/zh-CN/CLI-TOOLS.md index e77fb61e5..948e5706d 100644 --- a/docs/zh-CN/CLI-TOOLS.md +++ b/docs/zh-CN/CLI-TOOLS.md @@ -479,7 +479,7 @@ node gsd-tools.cjs graphify snapshot [name] ```bash node gsd-tools.cjs config-set review.models.codex "codex exec --model gpt-5" -node gsd-tools.cjs config-set review.models.gemini "gemini -m gemini-2.5-pro" +node gsd-tools.cjs config-set review.models.agy "gemini-3.1-pro-preview" node gsd-tools.cjs config-set review.models.opencode "opencode run --model claude-sonnet-4" node gsd-tools.cjs config-set review.models.claude "" # 清除——回退到会话模型 ``` diff --git a/docs/zh-CN/COMMANDS.md b/docs/zh-CN/COMMANDS.md index 94361d277..bdc904c6e 100644 --- a/docs/zh-CN/COMMANDS.md +++ b/docs/zh-CN/COMMANDS.md @@ -218,7 +218,7 @@ v1.40 中,六个命名空间路由器作为第一阶段入口点随附发布 | 参数 / 标志 | 必填 | 描述 | |-----------------|----------|-------------| | `N` | **是** | 要规划和审查的阶段编号 | -| 审查者标志 | 否 | 原样传递所有审查者通道标志:`--gemini`、`--claude`、`--codex`、`--coderabbit`、`--opencode`、`--qwen`、`--cursor`、`--agy` / `--antigravity`、`--ollama`、`--lm-studio`、`--llama-cpp`、`--kimi-code` | +| 审查者标志 | 否 | 原样传递所有审查者通道标志:`--claude`、`--codex`、`--coderabbit`、`--opencode`、`--qwen`、`--cursor`、`--agy` / `--antigravity`、`--ollama`、`--lm-studio`、`--llama-cpp`、`--kimi-code` | | `--all` | 否 | 运行所有已配置的审查者。审查通道默认**顺序**分发;将 `review.parallel_lanes` 设为 `true` 可在单次审查中并发分发 | | `--max-cycles N` | 否 | 覆盖循环上限(默认 3) | @@ -1238,7 +1238,6 @@ node gsd-tools.cjs intel api-surface # 渲染 api-map.json → API- | 标志 | 描述 | |------|-------------| -| `--gemini` | 包含 Gemini CLI 审查 | | `--claude` | 包含 Claude CLI 审查(独立会话) | | `--codex` | 包含 Codex CLI 审查 | | `--coderabbit` | 包含 CodeRabbit 审查 | @@ -1254,7 +1253,7 @@ node gsd-tools.cjs intel api-surface # 渲染 api-map.json → API- **默认审查者行为(无标志):** - 如果 `review.default_reviewers` **未设置**,`/gsd-review` 运行所有检测到的审查者(当前默认行为)。 -- 如果 `review.default_reviewers` **已设置**,`/gsd-review` 仅运行该子集(例如 `["gemini","codex"]`)。 +- 如果 `review.default_reviewers` **已设置**,`/gsd-review` 仅运行该子集(例如 `["codex","claude"]`)。 - `--all` 始终覆盖配置并运行完整的检测集。 - 显式标志(例如 `--cursor`)在该次运行中覆盖 `--all` 和配置默认值。 @@ -1262,11 +1261,11 @@ node gsd-tools.cjs intel api-surface # 渲染 api-map.json → API- ```bash # 设置项目默认审查者,用于无标志的 /gsd-review 运行 -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' -/gsd-review --phase 2 # 使用配置中的 gemini+codex 运行 +/gsd-review --phase 2 # 使用配置中的 codex+claude 运行 /gsd-review --phase 3 --all -/gsd-review --phase 2 --gemini +/gsd-review --phase 2 --codex /gsd-review --phase 2 --cursor # 一次性覆盖 ``` diff --git a/docs/zh-CN/CONFIGURATION.md b/docs/zh-CN/CONFIGURATION.md index 6f3cfb918..54468329d 100644 --- a/docs/zh-CN/CONFIGURATION.md +++ b/docs/zh-CN/CONFIGURATION.md @@ -195,7 +195,6 @@ API 密钥字段接受字符串值(密钥本身)。也可以设置为哨兵 |---------|------|---------|-------------| | `review.models.claude` | string | (会话模型) | Claude 风格审查的命令。未设置时默认使用会话模型 | | `review.models.codex` | string | `null` | Codex 审查命令,如 `"codex exec --model gpt-5"` | -| `review.models.gemini` | string | `null` | Gemini 审查命令,如 `"gemini -m gemini-2.5-pro"` | | `review.models.opencode` | string | `null` | OpenCode 审查命令,如 `"opencode run --model claude-sonnet-4"` | `` slug 需通过 `[a-zA-Z0-9_-]+` 验证。空值或包含路径的 slug 会被 `config-set` 拒绝。 @@ -206,14 +205,14 @@ API 密钥字段接受字符串值(密钥本身)。也可以设置为哨兵 | 设置 | 类型 | 默认值 | 描述 | |---------|------|---------|-------------| -| `review.default_reviewers` | string[] \| null | `null`(所有已检测审查器) | 无标志 `/gsd-review` 的可选默认子集,如 `["gemini","codex"]`。优先级顺序:显式审查器标志 > `--all` > `review.default_reviewers` > 所有已检测。未知 slug 以警告忽略;已知但未检测到的 slug 以信息提示忽略;空数组会被 `config-set` 拒绝。 | +| `review.default_reviewers` | string[] \| null | `null`(所有已检测审查器) | 无标志 `/gsd-review` 的可选默认子集,如 `["codex","claude"]`。优先级顺序:显式审查器标志 > `--all` > `review.default_reviewers` > 所有已检测。未知 slug 以警告忽略;已知但未检测到的 slug 以信息提示忽略;空数组会被 `config-set` 拒绝。 | 示例: ```json { "review": { - "default_reviewers": ["gemini", "codex"] + "default_reviewers": ["codex", "claude"] } } ``` @@ -254,7 +253,7 @@ API 密钥字段接受字符串值(密钥本身)。也可以设置为哨兵 | `workflow.plan_bounce_script` | string | (无) | 用于计划反弹验证的外部脚本路径。接收 PLAN.md 路径作为第一个参数。当 `plan_bounce` 为 `true` 时必需。v1.36 新增 | | `workflow.plan_bounce_passes` | number | `2` | 顺序执行的反弹轮数。每轮将上一轮的输出反馈给验证器。较高的值提升严格性,但会增加延迟。v1.36 新增 | | `workflow.post_planning_gaps` | boolean | `true` | 统一的规划后差距报告(#2493)。所有计划生成并提交后,扫描 REQUIREMENTS.md 和 CONTEXT.md 的 `` 与阶段目录中的每个 PLAN.md,然后打印一个 `Source \| Item \| Status` 表格。单词边界匹配(REQ-1 vs REQ-10)和自然排序(REQ-02 在 REQ-10 之前)。非阻塞——仅为信息性报告。设为 `false` 跳过计划阶段的步骤 13e。 | -| `workflow.plan_review_convergence` | boolean | `false` | 启用 `/gsd-plan-review-convergence` 命令。默认禁用——此键为 `false` 时命令以启用说明退出。该命令自动化手动计划→审查→重新规划循环:派生已配置的审查器(Codex、Gemini、Claude、OpenCode、Ollama、LM Studio、llama.cpp),通过 CYCLE_SUMMARY 契约计算未解决的 HIGH 问题,用 `--reviews` 反馈重新规划,并重复直至收敛或达到最大循环次数。通过 `gsd config-set workflow.plan_review_convergence true` 启用。v1.39 新增 | +| `workflow.plan_review_convergence` | boolean | `false` | 启用 `/gsd-plan-review-convergence` 命令。默认禁用——此键为 `false` 时命令以启用说明退出。该命令自动化手动计划→审查→重新规划循环:派生已配置的审查器(Codex、Claude、OpenCode、Ollama、LM Studio、llama.cpp),通过 CYCLE_SUMMARY 契约计算未解决的 HIGH 问题,用 `--reviews` 反馈重新规划,并重复直至收敛或达到最大循环次数。通过 `gsd config-set workflow.plan_review_convergence true` 启用。v1.39 新增 | | `workflow.plan_chunked` | boolean | `false` | 启用分块规划模式。为 `true`(或向 `/gsd-plan-phase` 传递 `--chunked` 标志)时,编排器将单个长期规划器任务拆分为一个简短的轮廓任务,后跟 N 个简短的按计划任务(每个约 3-5 分钟)。每个计划单独提交以具备崩溃韧性。如果任务挂起且终端被强制终止,使用 `--chunked` 重新运行将从最后完成的计划处恢复。在长期任务可能在 stdio 上挂起的 Windows 上特别有用。v1.38 新增 | | `workflow.code_review_command` | string | (无) | `/gsd-ship` 中外部代码审查集成的 shell 命令。通过 stdin 接收更改的文件路径。非零退出阻塞发布工作流。v1.36 新增 | | `workflow.tdd_mode` | boolean | `false` | 将 TDD 流水线作为一等执行模式启用。为 `true` 时,规划器积极地将 `type: tdd` 应用于符合条件的任务(业务逻辑、API、验证、算法),执行器强制执行 RED/GREEN/REFACTOR 门禁序列。阶段结束时的协作审查检查点验证门禁合规性。v1.36 新增 | @@ -670,7 +669,6 @@ gsd-tools query config-set features.thinking_partner false | 设置 | 类型 | 默认值 | 描述 | |---------|------|---------|-------------| -| `review.models.gemini` | string | (CLI 默认) | 调用 `--gemini` 审查器时使用的模型 | | `review.models.claude` | string | (CLI 默认) | 调用 `--claude` 审查器时使用的模型 | | `review.models.codex` | string | (CLI 默认) | 调用 `--codex` 审查器时使用的模型 | | `review.models.opencode` | string | (CLI 默认) | 调用 `--opencode` 审查器时使用的模型 | @@ -679,9 +677,9 @@ gsd-tools query config-set features.thinking_partner false | `review.models.ollama` | string | (服务器默认) | 调用 `--ollama` 审查器时传递给 Ollama 的模型名称。未设置时使用服务器报告的第一个可用模型(如 `llama3`)。设置为特定标签:`gsd config-set review.models.ollama codellama` | | `review.models.lm_studio` | string | (服务器默认) | 调用 `--lm-studio` 审查器时传递给 LM Studio 的模型名称。未设置时使用服务器报告的第一个可用模型。 | | `review.models.llama_cpp` | string | (服务器默认) | 调用 `--llama-cpp` 审查器时传递给 llama.cpp 的模型名称。未设置时使用 `/v1/models` 报告的第一个模型。 | -| `review.default_reviewers` | string[] \| null | (所有已检测审查器) | 无标志 `/gsd-review` 的默认审查器子集。示例:`["gemini","codex"]`。显式标志和 `--all` 覆盖此设置。 | +| `review.default_reviewers` | string[] \| null | (所有已检测审查器) | 无标志 `/gsd-review` 的默认审查器子集。示例:`["codex","claude"]`。显式标志和 `--all` 覆盖此设置。 | | `review.max_prompt_tokens` | number\|null | null | 组装审查提示词的默认最大预估 token 数。设置后,在发送给每个审查器之前对提示词进行确定性裁剪。按审查器覆盖通过 `review.max_prompt_tokens_per_reviewer` 优先。null = 不裁剪(当前行为)。 | -| `review.max_prompt_tokens_per_reviewer` | object | {} | 按审查器的 token 预算覆盖。键为审查器 slug(ollama、llama_cpp、lm_studio、gemini、claude、codex、opencode、qwen、cursor)。值覆盖该审查器的 `review.max_prompt_tokens`。推荐用于本地模型服务器。 | +| `review.max_prompt_tokens_per_reviewer` | object | {} | 按审查器的 token 预算覆盖。键为审查器 slug(ollama、llama_cpp、lm_studio、claude、codex、opencode、qwen、cursor)。值覆盖该审查器的 `review.max_prompt_tokens`。推荐用于本地模型服务器。 | | `review.ollama_host` | string | `http://localhost:11434` | Ollama 服务器的基础 URL。在非默认端口或远程主机上运行 Ollama 时覆盖:`gsd config-set review.ollama_host http://192.168.1.10:11434` | | `review.lm_studio_host` | string | `http://localhost:1234` | LM Studio 本地服务器的基础 URL。使用非默认端口时覆盖。 | | `review.llama_cpp_host` | string | `http://localhost:8080` | llama.cpp 服务器(`llama-server`)的基础 URL。使用非默认端口时覆盖。 | @@ -696,7 +694,7 @@ gsd-tools query config-set features.thinking_partner false { "review": { "models": { - "gemini": "gemini-2.5-pro", + "agy": "gemini-3.1-pro-preview", "qwen": "qwen-max" } } diff --git a/docs/zh-CN/FEATURES.md b/docs/zh-CN/FEATURES.md index 3ab9c5666..fcae0173e 100644 --- a/docs/zh-CN/FEATURES.md +++ b/docs/zh-CN/FEATURES.md @@ -1174,7 +1174,7 @@ GSD update available: 1.39.0 → 1.40.0. Run /gsd-update. ### 42. 跨 AI 同行评审 -**命令:** `/gsd-review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` +**命令:** `/gsd-review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all]` **目的:** 调用外部 AI CLI(Gemini、Claude、Codex、CodeRabbit、OpenCode、Qwen Code、Cursor、Antigravity、Kimi Code)和本地 OpenAI 兼容服务器(Ollama、LM Studio、llama.cpp)独立审查阶段计划。生成包含每位审查者反馈的结构化 REVIEWS.md。 diff --git a/docs/zh-CN/how-to/set-up-cross-ai-review.md b/docs/zh-CN/how-to/set-up-cross-ai-review.md index 5cd718321..05de12318 100644 --- a/docs/zh-CN/how-to/set-up-cross-ai-review.md +++ b/docs/zh-CN/how-to/set-up-cross-ai-review.md @@ -8,16 +8,13 @@ ## 决定使用哪些评审者 -GSD Core 可将评审请求路由至以下任意组合:Gemini CLI、Claude(独立会话)、Codex CLI、CodeRabbit、OpenCode、Qwen Code、Cursor、Antigravity CLI、Ollama、LM Studio 以及 llama.cpp。 +GSD Core 可将评审请求路由至以下任意组合:Claude(独立会话)、Codex CLI、CodeRabbit、OpenCode、Qwen Code、Cursor、Antigravity CLI、Ollama、LM Studio 以及 llama.cpp。 每位评审者会独立地对您的 `PLAN.md` 文件执行相同的结构化提示。由于不同模型存在不同的盲区,多评审者共识能比任何单一评审者发现更多问题。 **如果您尚未安装任何外部 CLI**,请至少安装一个: ```bash -# Gemini CLI(使用 Google 凭据免费使用) -npm install -g @google/gemini-cli - # Antigravity CLI(使用 Google 凭据免费使用) curl -fsSL https://antigravity.google/cli/install.sh | bash @@ -35,12 +32,12 @@ npm install -g @openai/codex /gsd-config --integrations ``` -集成向导涵盖 API 密钥、代码评审 CLI 路由以及 `review.default_reviewers` 列表。将该列表设置为您希望作为无标志默认值的评审者——例如 `["gemini","codex"]`。 +集成向导涵盖 API 密钥、代码评审 CLI 路由以及 `review.default_reviewers` 列表。将该列表设置为您希望作为无标志默认值的评审者——例如 `["codex","claude"]`。 或者,也可通过 `gsd-tools` 直接设置: ```bash -gsd config-set review.default_reviewers '["gemini","codex"]' +gsd config-set review.default_reviewers '["codex","claude"]' ``` 完整的集成设置架构(API 密钥、每个评审者的模型覆盖、本地服务器主机地址)请参阅[配置](../CONFIGURATION.md)。 @@ -60,7 +57,7 @@ GSD 会依次调用每位评审者,收集结构化反馈(摘要、优点、H ### 为一次性运行选择单个评审者 ```bash -/gsd-review --phase 3 --gemini +/gsd-review --phase 3 --agy /gsd-review --phase 3 --codex /gsd-review --phase 3 --cursor ``` @@ -124,7 +121,7 @@ GSD 会依次调用每位评审者,收集结构化反馈(摘要、优点、H ```bash /gsd-plan-review-convergence 3 --codex -/gsd-plan-review-convergence 3 --gemini +/gsd-plan-review-convergence 3 --agy ``` ### 使用所有评审者并提高循环上限进行收敛 @@ -141,13 +138,13 @@ GSD 会依次调用每位评审者,收集结构化反馈(摘要、优点、H | 场景 | 推荐方式 | |-----------|---------------------| -| 已安装 Gemini CLI | `--gemini` 始终是良好的起始评审者 | -| 希望免费多评审者覆盖 | `--gemini` + `--agy`(两者均使用 Google 凭据) | +| 已安装 Antigravity | `--agy` 始终是良好的起始评审者 | +| 希望免费多评审者覆盖 | `--agy`(Google 凭据)+ `--claude` | | 项目以 OpenAI 为主 | 添加 `--codex` 以获取 OpenAI 模型视角 | | 希望使用 GitHub Copilot 的模型 | 添加 `--opencode` | | 希望完全避免 API 费用 | 使用本地模型配置 Ollama 并使用 `--ollama` | | 发布前需要最大覆盖率 | `/gsd-plan-review-convergence N --all` | -| 快速迭代并希望获得快速反馈 | 选择一个 CLI:`/gsd-review --phase N --gemini` | +| 快速迭代并希望获得快速反馈 | 选择一个 CLI:`/gsd-review --phase N --agy` | --- diff --git a/gsd-core/bin/lib/capability-registry.cjs b/gsd-core/bin/lib/capability-registry.cjs index 562120cfc..d7e56882d 100644 --- a/gsd-core/bin/lib/capability-registry.cjs +++ b/gsd-core/bin/lib/capability-registry.cjs @@ -1790,69 +1790,6 @@ const capabilities = { } ] }, - "gemini": { - "id": "gemini", - "role": "reviewer", - "version": "1.14.0", - "title": "Gemini CLI", - "description": "Google Gemini CLI — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). Spawned as `gemini -p - -m ` with the plan piped on stdin.", - "tier": "full", - "requires": [], - "engines": { - "gsd": ">=1.8.0" - }, - "reviewer": { - "slug": "gemini", - "flags": [ - "--gemini" - ], - "transport": "spawn", - "probe": { - "kind": "command-exists", - "binary": "gemini" - }, - "invoke": { - "binary": "gemini", - "args": [ - "{{model}}", - "-p", - "-" - ], - "promptChannel": "stdin", - "outputChannel": "stdout", - "modelArg": "-m", - "effortChannel": "none" - }, - "timeoutFloorMs": 900000, - "timeoutConfigKey": "review.timeouts.gemini", - "emptyOutput": "stub-with-stderr", - "reviewsSection": "Gemini", - "evidenceClass": "source-grounded", - "requiresBinaries": [], - "promptBudgetKey": "review.max_prompt_tokens_per_reviewer.gemini", - "modelConfigKey": "review.models.gemini", - "effortConfigKey": null, - "defaultEffort": null, - "handler": null - }, - "config": { - "review.models.gemini": { - "type": "string", - "default": "", - "description": "Model passed to the Gemini reviewer lane." - }, - "review.max_prompt_tokens_per_reviewer.gemini": { - "type": "number", - "default": -1, - "description": "Prompt-token budget for the Gemini reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"." - }, - "review.timeouts.gemini": { - "type": "number", - "default": -1, - "description": "Outer wall-clock timeout override (seconds) for the Gemini reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset." - } - } - }, "graphify": { "id": "graphify", "role": "feature", @@ -4942,9 +4879,6 @@ const configKeys = { "external_job.submit_timeout_ms": "external-job", "external_job.poll_timeout_ms": "external-job", "workflow.post_planning_gaps": "gap-analysis", - "review.models.gemini": "gemini", - "review.max_prompt_tokens_per_reviewer.gemini": "gemini", - "review.timeouts.gemini": "gemini", "graphify.enabled": "graphify", "intel.enabled": "intel", "review.models.kimi-code": "kimi-code", @@ -5238,24 +5172,6 @@ const configSchema = { "default": true, "description": "Run the post-planning gap analysis report after plans are generated." }, - "review.models.gemini": { - "owner": "gemini", - "type": "string", - "default": "", - "description": "Model passed to the Gemini reviewer lane." - }, - "review.max_prompt_tokens_per_reviewer.gemini": { - "owner": "gemini", - "type": "number", - "default": -1, - "description": "Prompt-token budget for the Gemini reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"." - }, - "review.timeouts.gemini": { - "owner": "gemini", - "type": "number", - "default": -1, - "description": "Outer wall-clock timeout override (seconds) for the Gemini reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset." - }, "graphify.enabled": { "owner": "graphify", "type": "boolean", @@ -8145,7 +8061,6 @@ const _requiresGraph = { "drift": [], "external-job": [], "gap-analysis": [], - "gemini": [], "graphify": [], "hermes": [], "intel": [], diff --git a/gsd-core/references/planning-config.md b/gsd-core/references/planning-config.md index c19224b64..4ed69afe7 100644 --- a/gsd-core/references/planning-config.md +++ b/gsd-core/references/planning-config.md @@ -266,7 +266,7 @@ Generated from `CONFIG_DEFAULTS` (configuration.cjs) and `VALID_CONFIG_KEYS` (co | `context_window` | number | `200000` | `200000`, `1000000` | Context window size; set `1000000` for 1M-context models | | `resolve_model_ids` | boolean\|string | `false` | `false`, `true`, `"omit"` | Map model aliases to full Claude IDs; `"omit"` returns empty string | | `context` | string\|null | `null` | `"dev"`, `"research"`, `"review"` | Execution context profile that adjusts agent behavior: `"dev"` for development tasks, `"research"` for investigation/exploration, `"review"` for code review workflows | -| `review.models.` | string\|null | `null` | Any model ID string | Per-CLI model override for /gsd:review (e.g., `review.models.gemini`). Falls back to CLI default when null. | +| `review.models.` | string\|null | `null` | Any model ID string | Per-CLI model override for /gsd:review (e.g., `review.models.codex`). Falls back to CLI default when null. | | `review.max_prompt_tokens` | number\|null | `null` | Any positive integer, or `null` | Central, cross-lane default cap (in estimated tokens) on the assembled review prompt; `null` means no trim. A per-lane `review.max_prompt_tokens_per_reviewer.` value overrides it for that lane: `-1` means unset (inherits this global default), `0` means "do not trim that lane" (not unset — it is an explicit, standing opt-out). _Alias:_ `max_prompt_tokens` is the flat-key form used in `CONFIG_DEFAULTS`; `review.max_prompt_tokens` is the canonical namespaced form. | ### Workflow Fields diff --git a/gsd-core/workflows/help/modes/full.compact.md b/gsd-core/workflows/help/modes/full.compact.md index 8806a72e9..18330c45f 100644 --- a/gsd-core/workflows/help/modes/full.compact.md +++ b/gsd-core/workflows/help/modes/full.compact.md @@ -202,7 +202,7 @@ Usage: `/gsd:ship 4` or `/gsd:ship 4 --draft` --- -**`/gsd:review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--all]`** — Detects available external AI CLIs, each independently reviews the phase's plans with the same structured prompt (CodeRabbit reviews the live diff, up to ~5 min), produces REVIEWS.md with consensus. Feed back via `/gsd:plan-phase N --reviews`. +**`/gsd:review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--all]`** — Detects available external AI CLIs, each independently reviews the phase's plans with the same structured prompt (CodeRabbit reviews the live diff, up to ~5 min), produces REVIEWS.md with consensus. Feed back via `/gsd:plan-phase N --reviews`. Usage: `/gsd:review --phase 3 --all` @@ -280,7 +280,7 @@ Every command below is also a live `/gsd-*` slash command, grouped by purpose. - **`/gsd:mvp-phase `** — Plans a phase as a vertical MVP slice (user story + SPIDR splitting) before handoff to plan-phase; same end-state as `/gsd:plan-phase --mvp` with a guided intro. - **`/gsd:ultraplan-phase [phase]`** — [BETA] Offload plan phase to Claude Code's ultraplan cloud; review in browser, import back. -- **`/gsd:plan-review-convergence [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy/--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all] [--text] [--ws ] [--max-cycles N]`** — Cross-AI convergence loop: replan with review feedback until no HIGH concerns remain (cloud and local-model reviewers). +- **`/gsd:plan-review-convergence [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy/--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all] [--text] [--ws ] [--max-cycles N]`** — Cross-AI convergence loop: replan with review feedback until no HIGH concerns remain (cloud and local-model reviewers). - **`/gsd:autonomous [--from N] [--to N] [--only N] [--interactive] [--converge]`** — Runs all remaining phases unattended: discuss → plan → execute per phase; `--converge`/`--cross-ai` routes planning through convergence. ### Quality, Review & Verification diff --git a/gsd-core/workflows/help/modes/full.md b/gsd-core/workflows/help/modes/full.md index 1df7fb437..a9976e4e3 100644 --- a/gsd-core/workflows/help/modes/full.md +++ b/gsd-core/workflows/help/modes/full.md @@ -302,7 +302,7 @@ Modes: - **default** — progress report + intelligent routing - **`--next`** — auto-advance to the next logical step (use `--next --force` to bypass safety gates) - **`--next --auto`** — like `--next`, but chains steps automatically until milestone completion or a blocking decision -- **`--next --converge`** — when the next action is planning, route it through `/gsd:plan-review-convergence` instead of `/gsd:plan-phase`; requires `workflow.plan_review_convergence=true`. `--cross-ai` is an alias. Reviewer flags (`--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` forward to the convergence loop. +- **`--next --converge`** — when the next action is planning, route it through `/gsd:plan-review-convergence` instead of `/gsd:plan-phase`; requires `workflow.plan_review_convergence=true`. `--cross-ai` is an alias. Reviewer flags (`--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` forward to the convergence loop. - **`--forensic`** — append a 6-check integrity audit after the progress report - **`--do ""`** — smart router: dispatch freeform intent to the matching `/gsd-*` command (see *Smart Router* above) @@ -477,10 +477,10 @@ Usage: `/gsd:ship 4` or `/gsd:ship 4 --draft` --- -**`/gsd:review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--all]`** +**`/gsd:review --phase N [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--all]`** Cross-AI peer review — invoke external AI CLIs to independently review phase plans. -- Detects available CLIs (gemini, claude, codex, coderabbit, agy) +- Detects available CLIs (claude, codex, coderabbit, agy) - Each CLI reviews plans independently with the same structured prompt - CodeRabbit reviews the current git diff (not a prompt) — may take up to 5 minutes - Produces REVIEWS.md with per-reviewer feedback and consensus summary @@ -641,7 +641,7 @@ The commands above cover the most common day-to-day flows. Every command listed - **`/gsd:mvp-phase `** — Plan a phase as a vertical MVP slice (user story + SPIDR splitting) before handing off to plan-phase. Same end-state as `/gsd:plan-phase --mvp`, with a guided MVP-shaping intro. - **`/gsd:ultraplan-phase [phase]`** — [BETA] Offload plan phase to Claude Code's ultraplan cloud; review in browser and import back. -- **`/gsd:plan-review-convergence [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy/--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all] [--text] [--ws ] [--max-cycles N]`** — Cross-AI plan convergence loop — replan with review feedback until no HIGH concerns remain. Supports both cloud reviewers (Gemini/Claude/Codex/CodeRabbit/OpenCode/Qwen/Cursor/Antigravity/Kimi Code) and local model runtimes (Ollama, LM Studio, llama.cpp). +- **`/gsd:plan-review-convergence [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy/--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all] [--text] [--ws ] [--max-cycles N]`** — Cross-AI plan convergence loop — replan with review feedback until no HIGH concerns remain. Supports both cloud reviewers (Claude/Codex/CodeRabbit/OpenCode/Qwen/Cursor/Antigravity/Kimi Code) and local model runtimes (Ollama, LM Studio, llama.cpp). - **`/gsd:autonomous [--from N] [--to N] [--only N] [--interactive] [--converge]`** — Run all remaining phases autonomously: discuss → plan → execute per phase. `--converge` routes planning through plan-review convergence; `--cross-ai` is an alias. ### Quality, Review & Verification diff --git a/gsd-core/workflows/plan-review-convergence.md b/gsd-core/workflows/plan-review-convergence.md index fccca10e9..dc66afdbf 100644 --- a/gsd-core/workflows/plan-review-convergence.md +++ b/gsd-core/workflows/plan-review-convergence.md @@ -105,7 +105,7 @@ if [ -z "$REVIEWER_FLAGS" ]; then fi else # Strip the leading space accumulated by the parse block so the banner renders - # "Reviewers: --gemini" not "Reviewers: --gemini" (#2315 review nit). + # "Reviewers: --codex" not "Reviewers: --codex" (#2315 review nit). REVIEWER_DISPLAY="${REVIEWER_FLAGS# }" fi ``` diff --git a/gsd-core/workflows/review.md b/gsd-core/workflows/review.md index 3b5ab8160..2eefd8634 100644 --- a/gsd-core/workflows/review.md +++ b/gsd-core/workflows/review.md @@ -18,7 +18,6 @@ Check which AI CLIs are available on the system: ```bash _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi # Check each CLI -command -v gemini >/dev/null 2>&1 && echo "gemini:available" || echo "gemini:missing" command -v claude >/dev/null 2>&1 && echo "claude:available" || echo "claude:missing" command -v codex >/dev/null 2>&1 && echo "codex:available" || echo "codex:missing" command -v coderabbit >/dev/null 2>&1 && echo "coderabbit:available" || echo "coderabbit:missing" @@ -62,15 +61,14 @@ that lane. Tell the user to install jq: ``` NOTE: jq is not on PATH — the ollama, lm_studio, llama_cpp, opencode, and antigravity reviewer lanes are unavailable. Install jq (https://jqlang.org/download/) -or select a lane that does not require it (--gemini, --claude, --codex, +or select a lane that does not require it (--claude, --codex, --coderabbit, --qwen, --cursor). ``` -The remaining lanes (`gemini`, `claude`, `codex`, `coderabbit`, `qwen`, `cursor`) +The remaining lanes (`claude`, `codex`, `coderabbit`, `qwen`, `cursor`) do not require jq and must stay selectable on a jq-less host. Parse flags from `$ARGUMENTS`: -- `--gemini` → include Gemini - `--claude` → include Claude - `--codex` → include Codex - `--coderabbit` → include CodeRabbit @@ -86,7 +84,7 @@ Parse flags from `$ARGUMENTS`: - No flags → if `review.default_reviewers` is set, include only configured reviewers that are detected; otherwise include all available Reviewer-selection precedence: -1. Individual reviewer flags (`--gemini`, `--codex`, etc.) +1. Individual reviewer flags (`--claude`, `--codex`, etc.) 2. `--all` 3. `review.default_reviewers` 4. No key + no flags → all detected reviewers @@ -94,7 +92,7 @@ Reviewer-selection precedence: **Explicit reviewer flags are an assertion, not a preference (ADR-2782 D4).** A lane the user named on the command line and that cannot run is an **error**, surfaced and non-silent — even when other named lanes did run. Do not proceed with a thinner reviewer set and report success: -`--gemini --qwen` on a host without `qwen` fails, it does not quietly become a Gemini-only +`--codex --qwen` on a host without `qwen` fails, it does not quietly become a Codex-only review. This applies however the lane became unavailable — binary missing, prerequisite `jq` absent, or a local server not reachable. @@ -103,7 +101,7 @@ lane somebody asked for is an error.* A user who wants "whatever is available" h user who wants a preferred set has `review.default_reviewers`. Both stay lenient below. `review.default_reviewers` behavior: -- Value must be a non-empty array of slug strings (configured via `gsd config-set review.default_reviewers '["gemini","codex"]'`) +- Value must be a non-empty array of slug strings (configured via `gsd config-set review.default_reviewers '["codex","claude"]'`) - Unknown slugs warn and are ignored - Known-but-undetected slugs emit an info note and are ignored — a configured default is a preference evaluated across many hosts, so a subset being present is expected, not an error @@ -116,7 +114,6 @@ If `section_manifest` is `null` or `"reviewer-instances-note-1"` is in its `incl If no CLIs are available: ``` No external AI CLIs found. Install at least one: -- gemini: https://github.com/google-gemini/gemini-cli - codex: https://github.com/openai/codex - claude: https://github.com/anthropics/claude-code - opencode: https://opencode.ai (leverages GitHub Copilot subscription models) @@ -142,7 +139,7 @@ elif [ -n "$CLAUDE_CODE_ENTRYPOINT" ]; then # Running inside Claude Code CLI — skip claude for independence SELF_CLI="claude" else - # Other environments (Gemini CLI, Codex CLI, etc.) + # Other environments (Codex CLI, Antigravity CLI, etc.) # Fall back to AI self-identification to decide which CLI to skip SELF_CLI="auto" fi @@ -150,7 +147,7 @@ fi Rules: - If `SELF_CLI="none"` → invoke ALL available CLIs (no skip) -- If `SELF_CLI="claude"` → skip claude, use gemini/codex +- If `SELF_CLI="claude"` → skip claude, use codex/antigravity - If `SELF_CLI="auto"` → the executing AI identifies itself and skips its own CLI - At least one DIFFERENT CLI must be available for the review to proceed. @@ -731,7 +728,7 @@ a lane, its `value` already carries a `(reasoning=)` suffix (e.g. ```markdown --- phase: {N} -reviewers: [gemini, claude, codex, coderabbit, opencode, qwen, cursor, antigravity, ollama, lm_studio, llama_cpp] # populate at runtime with only the reviewers actually invoked +reviewers: [claude, codex, coderabbit, opencode, qwen, cursor, antigravity, ollama, lm_studio, llama_cpp] # populate at runtime with only the reviewers actually invoked reviewed_at: {ISO timestamp} plans_reviewed: [{list of PLAN.md files}] models: # resolved model per reviewer; `unknown` when not recoverable diff --git a/gsd-core/workflows/settings-integrations.md b/gsd-core/workflows/settings-integrations.md index e6840d714..f58f92b73 100644 --- a/gsd-core/workflows/settings-integrations.md +++ b/gsd-core/workflows/settings-integrations.md @@ -163,7 +163,7 @@ namespace — any other slug fails with `Unknown config key`. Settable keys (the shipped registry's model-bearing lanes): `review.models.agy` (Antigravity), `review.models.claude`, `review.models.codex`, -`review.models.cursor`, `review.models.gemini`, `review.models.kimi-code`, +`review.models.cursor`, `review.models.kimi-code`, `review.models.llama_cpp`, `review.models.lm_studio`, `review.models.ollama`, `review.models.opencode`. @@ -197,7 +197,6 @@ AskUserQuestion([ options: [ { label: "Claude", description: "review.models.claude — defaults to session model when unset" }, { label: "Codex", description: "review.models.codex — bare model id injected into --model, e.g. 'gpt-5'" }, - { label: "Gemini", description: "review.models.gemini — bare model id injected into -m, e.g. 'gemini-2.5-pro'" }, { label: "OpenCode", description: "review.models.opencode — bare model id injected into --model, e.g. 'claude-sonnet-4'" } ] } diff --git a/gsd-core/workflows/sync-skills.md b/gsd-core/workflows/sync-skills.md index dcaa4a736..08f877d55 100644 --- a/gsd-core/workflows/sync-skills.md +++ b/gsd-core/workflows/sync-skills.md @@ -79,8 +79,8 @@ done **#3025 — Cross-runtime refuse guard (run BEFORE Step 2 resolution / Step 5 copy):** Skill content and directory layout are runtime-specific. The installer applies per-runtime -converters, adapter headers, brand swaps, and layout rules at install time, and two runtimes -(`grok`, `gemini`) resolve to ANOTHER runtime's skills root. A verbatim copy from one runtime's +converters, adapter headers, brand swaps, and layout rules at install time, and one runtime +(`grok`) resolves to ANOTHER runtime's skills root. A verbatim copy from one runtime's skills root therefore produces content the installer would never have written for the destination, and can damage a runtime the user never named. Every cross-runtime pair is unsafe (content and/or layout and/or aliasing); only identity (`--from` == `--to`) is safe. Refuse cross-runtime and point diff --git a/skills/gsd-autonomous/SKILL.md b/skills/gsd-autonomous/SKILL.md index 6cc9de4d8..30cad73a3 100644 --- a/skills/gsd-autonomous/SKILL.md +++ b/skills/gsd-autonomous/SKILL.md @@ -39,7 +39,7 @@ Optional flags: - `--converge` — run each phase's planning step through `gsd-plan-review-convergence` instead of plain `gsd-plan-phase`. Requires `workflow.plan_review_convergence=true`. - `--cross-ai` — compatibility alias for `--converge`. -When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `gsd-plan-review-convergence` may be passed through: `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. +When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `gsd-plan-review-convergence` may be passed through: `--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. Project context, phase list, and state are resolved inside the workflow using init commands (`gsd-tools query init.milestone-op`, `gsd-tools query roadmap.analyze`). No upfront context loading needed. diff --git a/skills/gsd-plan-review-convergence/SKILL.md b/skills/gsd-plan-review-convergence/SKILL.md index 0026ceda2..9c90235f5 100644 --- a/skills/gsd-plan-review-convergence/SKILL.md +++ b/skills/gsd-plan-review-convergence/SKILL.md @@ -1,7 +1,7 @@ --- name: gsd-plan-review-convergence description: "Cross-AI plan convergence - replan until review concerns are resolved." -argument-hint: " [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--antigravity] [--agy] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--text] [--ws ] [--all] [--max-cycles N]" +argument-hint: " [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--antigravity] [--agy] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--text] [--ws ] [--all] [--max-cycles N]" allowed-tools: - Read - Write @@ -20,7 +20,7 @@ Repeatedly: review plans with external AI CLIs → if HIGH or actionable non-HIG **Flow:** Skill("gsd-plan-phase") → Agent→Skill("gsd-review") → check unresolved HIGH + actionable non-HIGH → Skill("gsd-plan-phase --reviews") → Agent→Skill("gsd-review") → ... → Converge or escalate -Replaces gsd-plan-phase's internal gsd-plan-checker with external AI reviewers (codex, gemini, etc.). Plan-phase runs **inline** (bare Skill at depth 0) so it can spawn gsd-planner/gsd-plan-checker at depth 1. Review runs inside an isolated Agent (gsd-review is a Bash leaf — no sub-agents needed). Orchestrator only does loop control. +Replaces gsd-plan-phase's internal gsd-plan-checker with external AI reviewers (codex, claude, etc.). Plan-phase runs **inline** (bare Skill at depth 0) so it can spawn gsd-planner/gsd-plan-checker at depth 1. Review runs inside an isolated Agent (gsd-review is a Bash leaf — no sub-agents needed). Orchestrator only does loop control. **Orchestrator role:** Parse arguments, validate phase, run plan-phase inline (Skill at depth 0), spawn an Agent for gsd-review, check unresolved HIGH and actionable non-HIGH counts, stall detection, escalation gate. @@ -41,8 +41,7 @@ Phase number: extracted from $ARGUMENTS (required) **Flags:** - `--codex` — Use Codex CLI as reviewer (default if no reviewer flag given AND `review.default_reviewers` is unset; otherwise `review.default_reviewers` wins per ADR-0011 — #2315) -- `--gemini` — Use Gemini CLI as reviewer -- `--agy` / `--antigravity` — Use Antigravity CLI as reviewer (successor to the discontinued Gemini CLI) +- `--agy` / `--antigravity` — Use Antigravity CLI as reviewer - `--claude` — Use Claude CLI as reviewer (separate session) - `--coderabbit` — Use CodeRabbit as reviewer (reviews the working-tree diff, not the source tree) - `--opencode` — Use OpenCode as reviewer diff --git a/skills/gsd-progress/SKILL.md b/skills/gsd-progress/SKILL.md index d24715a90..75a3cd196 100644 --- a/skills/gsd-progress/SKILL.md +++ b/skills/gsd-progress/SKILL.md @@ -24,7 +24,7 @@ Three modes: - **--next**: Detect current project state and automatically invoke the next logical GSD workflow step. Scans all prior phases for incomplete work before routing. `--next --force` bypasses safety gates. - **--next --auto**: Like `--next`, but after the determined step completes, automatically re-invokes `/gsd-progress --next --auto` to continue chaining steps until completion or a blocking decision. Enables hands-free plan→execute→verify→complete progression. -- **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop. +- **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop. - **--do "..."**: Smart dispatcher — match freeform intent to the best GSD command using routing rules, confirm the match, then hand off. - **--forensic**: Run 6-check integrity audit after the standard progress report. - **(no flag)**: Standard progress check + intelligent routing (Routes A through F). diff --git a/skills/gsd-review/SKILL.md b/skills/gsd-review/SKILL.md index 9773eecb1..403358cc3 100644 --- a/skills/gsd-review/SKILL.md +++ b/skills/gsd-review/SKILL.md @@ -1,7 +1,7 @@ --- name: gsd-review description: "Request cross-AI peer review of phase plans from external AI CLIs" -argument-hint: "--phase N [--gemini] [--claude] [--codex] [--opencode] [--qwen] [--cursor] [--agy] [--all]" +argument-hint: "--phase N [--claude] [--codex] [--opencode] [--qwen] [--cursor] [--agy] [--all]" allowed-tools: - Read - Write @@ -12,7 +12,7 @@ allowed-tools: -Invoke external AI CLIs (Gemini, Claude, Codex, OpenCode, Qwen Code, Cursor) to independently review phase plans. +Invoke external AI CLIs (Claude, Codex, OpenCode, Qwen Code, Cursor, Antigravity) to independently review phase plans. Produces a structured REVIEWS.md with per-reviewer feedback that can be fed back into planning via /gsd-plan-phase --reviews. @@ -27,7 +27,6 @@ planning via /gsd-plan-phase --reviews. Phase number: extracted from $ARGUMENTS (required) **Flags:** -- `--gemini` — Include Gemini CLI review - `--claude` — Include Claude CLI review (uses separate session) - `--codex` — Include Codex CLI review - `--opencode` — Include OpenCode review (uses model from user's OpenCode config) diff --git a/src/config.cts b/src/config.cts index 1b199538d..f9d1076b1 100644 --- a/src/config.cts +++ b/src/config.cts @@ -595,7 +595,7 @@ function _setNestedValue( /** * Deletes a value from the config object, allowing nested values via dot - * notation (e.g., "review.models.gemini"). Mirrors `_setNestedValue`'s + * notation (e.g., "review.models.codex"). Mirrors `_setNestedValue`'s * prototype-pollution guard on every path segment (including intermediates). * * Unlike `_setNestedValue`, this NEVER creates missing intermediate objects — diff --git a/src/review-lane-descriptor.cts b/src/review-lane-descriptor.cts index 753b37b8c..4eb9b8fad 100644 --- a/src/review-lane-descriptor.cts +++ b/src/review-lane-descriptor.cts @@ -105,7 +105,7 @@ export type LaneProbe = * `args` is an argv TEMPLATE, not a prefix. The injected pieces — model, effort, output file, * argv-borne prompt — do not all go in the same place, and no positional rule expresses that: * `codex` injects the model in the MIDDLE (after the `exec --ephemeral` subcommand) and the output - * file later still, while `gemini` injects the model first and five lanes end with a bare `-` that + * file later still, while `kimi-code` injects the model first and five lanes end with a bare `-` that * must stay last. Splicing by position silently produced * `codex --model M -o F exec --ephemeral …`, which is not a valid codex invocation. * @@ -278,36 +278,16 @@ const SPAWN_STDIN_STDOUT = { } as const; /** - * The twelve declared lanes, in `write_reviews` order. + * The eleven declared lanes, in `write_reviews` order. + * + * The `gemini` lane was retired by #4709: Google sunset Gemini CLI on 2026-06-18 (the same + * sunset that removed the gemini RUNTIME in #1928/1.8.0), so the lane spawned a binary that no + * longer serves the free/Pro/Ultra tiers that are GSD's audience. * * `kimi-code` joined in Phase 5b (#2799, closes #2718) — ADR-2782's phase table lands it here * rather than in 5a precisely so it arrives together with the iteration that can invoke it. */ export const REVIEWER_LANES: ReadonlyArray = Object.freeze([ - { - slug: 'gemini', - flags: ['--gemini'], - transport: 'spawn', - probe: { kind: 'command-exists', binary: 'gemini' }, - invoke: { - binary: 'gemini', - args: ['{{model}}', '-p', '-'], - ...SPAWN_STDIN_STDOUT, - modelArg: '-m', - effortChannel: 'none', - }, - timeoutFloorMs: 900_000, - timeoutConfigKey: 'review.timeouts.gemini', - emptyOutput: 'stub-with-stderr', - reviewsSection: 'Gemini', - evidenceClass: 'source-grounded', - requiresBinaries: [], - promptBudgetKey: 'review.max_prompt_tokens_per_reviewer.gemini', - modelConfigKey: 'review.models.gemini', - effortConfigKey: null, - defaultEffort: null, - handler: null, - }, { // 1_200_000 rather than the 900_000 floor: headless Claude measured ~525 s // on a large plan set (review.md:304). @@ -323,8 +303,8 @@ export const REVIEWER_LANES: ReadonlyArray = Object.freeze([ effortChannel: 'argv', // #2483: without these the claude leg is the only reviewer that additionally inherits the // invoking user's global CLAUDE.md, the project CLAUDE.md, and Claude Code auto-memory — - // a context asymmetry against the independent-review premise (gemini sees only the - // assembled prompt; codex runs --ephemeral). Both flags, not just the first: CLAUDE.md + // a context asymmetry against the independent-review premise (codex sees only the + // assembled prompt and runs --ephemeral). Both flags, not just the first: CLAUDE.md // loading and auto-memory are independently-toggled mechanisms, and an environment // exporting CLAUDE_CODE_DISABLE_AUTO_MEMORY=0 forces auto-memory back ON — the explicit // pair is robust against that. Applies when /gsd:review runs from a non-Claude-Code host; @@ -1060,7 +1040,7 @@ const NON_LANE_SIGNATURE_FLAGS: ReadonlySet = new Set(['--all']); /** * Is `flag` documented in `text` under one of the two structural shapes docs actually use? * - * Backticked is the `COMMANDS.md` table-cell shape; bracketed (`[--gemini]`) is the + * Backticked is the `COMMANDS.md` table-cell shape; bracketed (`[--codex]`) is the * `FEATURES.md` signature shape. Requiring one of those two delimiters — rather than a bare * substring — is what keeps prose and fenced examples from satisfying the gate, and it bounds the * token for free: a backticked `--claude` demands its closing backtick, so a backticked @@ -1155,7 +1135,7 @@ const BRACKETED_FLAG_RE = /\[(--[a-z0-9][a-z0-9-]*)\]/g; * cell 3. A file-scoped check is therefore satisfied by the forwarding row alone, so deleting a * lane's actual table row — the exact #2781 regression — passes. Keying on cell 1 separates the * two: `| `--agy` / `--antigravity` | … |` is one lane row declaring two flags, while - * `| Reviewer flags | No | … `--gemini`, `--claude` … |` is not a lane row at all. + * `| Reviewer flags | No | … `--codex`, `--claude` … |` is not a lane row at all. */ function flagsInFirstTableCell(lines: string[], declared: ReadonlySet): Set { const found = new Set(); diff --git a/src/review-reviewer-selection.cts b/src/review-reviewer-selection.cts index 8ddaa8788..5a878b0c7 100644 --- a/src/review-reviewer-selection.cts +++ b/src/review-reviewer-selection.cts @@ -19,7 +19,7 @@ * `reviewer` bodies in the capability registry, not a hand-maintained tail. * A capability of EITHER `role: "runtime"` (the six dual-purpose hosts — * antigravity/claude/codex/cursor/opencode/qwen) or the lane-only - * `role: "reviewer"` (gemini/coderabbit/ollama/lm_studio/llama_cpp) may carry + * `role: "reviewer"` (coderabbit/ollama/lm_studio/llama_cpp) may carry * a `reviewer` body, and it is the body's `reviewer.slug` — NOT the capability * id — that becomes the roster entry: the two differ for `lm-studio` (id) / * `lm_studio` (slug) and `llama-cpp` (id) / `llama_cpp` (slug), ADR-2782's @@ -306,7 +306,7 @@ export function resolveReviewerSelection( // ADR-2782 D4: absent-safe governs DISCOVERY, never explicit selection. // Not finding a lane nobody asked for is normal; failing to run a lane // somebody asked for is an error. Every miss used to be an `info`, so a - // PARTIAL miss (`--gemini --qwen` with qwen absent) ran the review with a + // PARTIAL miss (`--codex --qwen` with qwen absent) ran the review with a // thinner reviewer set while present_results reported success — "a cross-AI // review that silently drops a lane is blind in one eye" (review.md). // A total miss already errored, but only as a side effect of the selected diff --git a/tests/adr-15-progress-converge.test.cjs b/tests/adr-15-progress-converge.test.cjs index b5ce56b96..66a9e24c5 100644 --- a/tests/adr-15-progress-converge.test.cjs +++ b/tests/adr-15-progress-converge.test.cjs @@ -104,7 +104,7 @@ describe('ADR-15: /gsd:progress --next --auto --converge (#1190)', () => { // They must now be DERIVED at runtime via `gsd_run review-lane flags`, not listed. const formerlyHardcodedLaneFlags = [ '--codex', - '--gemini', + '--qwen', '--claude', '--opencode', '--ollama', diff --git a/tests/autonomous-converge.test.cjs b/tests/autonomous-converge.test.cjs index c06d66e4b..cc7df0224 100644 --- a/tests/autonomous-converge.test.cjs +++ b/tests/autonomous-converge.test.cjs @@ -119,7 +119,7 @@ describe('autonomous --converge flag (#711)', () => { // They must now be DERIVED at runtime via `gsd_run review-lane flags`, not listed. const formerlyHardcodedLaneFlags = [ '--codex', - '--gemini', + '--qwen', '--claude', '--opencode', '--ollama', diff --git a/tests/config.test.cjs b/tests/config.test.cjs index 6183148ba..04587ad30 100644 --- a/tests/config.test.cjs +++ b/tests/config.test.cjs @@ -840,17 +840,17 @@ describe('config-set null — unset/clear (#2046)', () => { afterEach(() => { cleanup(tmpDir); }); test('non-secret routing key: config-set null removes the key (not the string "null")', () => { - const setResult = runGsdTools('config-set review.models.gemini foo', tmpDir); + const setResult = runGsdTools('config-set review.models.codex foo', tmpDir); assert.ok(setResult.success, `Command failed: ${setResult.error}`); - assert.strictEqual(readConfig(tmpDir).review.models.gemini, 'foo'); + assert.strictEqual(readConfig(tmpDir).review.models.codex, 'foo'); - const unsetResult = runGsdTools('config-set review.models.gemini null', tmpDir); + const unsetResult = runGsdTools('config-set review.models.codex null', tmpDir); assert.ok(unsetResult.success, `Command failed: ${unsetResult.error}`); const config = readConfig(tmpDir); assert.ok( - !config.review || !config.review.models || !Object.prototype.hasOwnProperty.call(config.review.models, 'gemini'), - 'review.models.gemini must be absent on disk after unset, not the string "null"' + !config.review || !config.review.models || !Object.prototype.hasOwnProperty.call(config.review.models, 'codex'), + 'review.models.codex must be absent on disk after unset, not the string "null"' ); // #2797: review.models. is federated to its lane capability now, and a @@ -859,7 +859,7 @@ describe('config-set null — unset/clear (#2046)', () => { // instead of erroring. The property this test actually guards is unchanged // and asserted above: the key is REMOVED from disk, never persisted as the // literal string "null". - const getResult = runGsdTools('config-get review.models.gemini', tmpDir); + const getResult = runGsdTools('config-get review.models.codex', tmpDir); const shown = (getResult.output || '').trim(); assert.ok( shown === '' || shown === '""' || shown === 'undefined', @@ -913,8 +913,8 @@ describe('config-set null — unset/clear (#2046)', () => { }); test('literal-"null" guard: no config-set null ever persists the literal string "null" on disk', () => { - runGsdTools('config-set review.models.gemini foo', tmpDir); - runGsdTools('config-set review.models.gemini null', tmpDir); + runGsdTools('config-set review.models.codex foo', tmpDir); + runGsdTools('config-set review.models.codex null', tmpDir); runGsdTools('config-set brave_search sk-test-1234', tmpDir); runGsdTools('config-set brave_search null', tmpDir); runGsdTools('config-set context dev', tmpDir); @@ -1078,17 +1078,17 @@ describe('config-set --dry-run (#4444)', () => { }); test('config-set null --dry-run does not unset (dry-run covers the unset branch too)', () => { - const seed = runGsdTools('config-set review.models.gemini foo', tmpDir); + const seed = runGsdTools('config-set review.models.codex foo', tmpDir); assert.ok(seed.success, `seed failed: ${seed.error}`); - const dryRun = runGsdTools('config-set review.models.gemini null --dry-run', tmpDir); + const dryRun = runGsdTools('config-set review.models.codex null --dry-run', tmpDir); assert.ok(dryRun.success, `Command failed: ${dryRun.error}`); const output = JSON.parse(dryRun.output); assert.strictEqual(output.dry_run, true); assert.strictEqual(output.would_unset, true); // Still present on disk — the dry-run must not have unset it. - assert.strictEqual(readConfig(tmpDir).review.models.gemini, 'foo'); + assert.strictEqual(readConfig(tmpDir).review.models.codex, 'foo'); }); }); diff --git a/tests/feat-2483-review-claude-mds-guard.test.cjs b/tests/feat-2483-review-claude-mds-guard.test.cjs index aa26ffdfb..b5de6b076 100644 --- a/tests/feat-2483-review-claude-mds-guard.test.cjs +++ b/tests/feat-2483-review-claude-mds-guard.test.cjs @@ -7,7 +7,7 @@ * * That made it the only reviewer seeing anything beyond the prompt file: the prompt is assembled * once (PROJECT.md, the roadmap section, every PLAN file, CONTEXT.md, RESEARCH.md, REQUIREMENTS.md) - * before any lane runs, gemini receives only that prompt, and codex runs `--ephemeral`. Beyond the + * before any lane runs, qwen receives only that prompt, and codex runs `--ephemeral`. Beyond the * measured injection cost, the asymmetry cuts at the workflow's premise — "independent review" * meant something different for the claude lane than for the other two. * @@ -121,7 +121,7 @@ describe('#2483 the claude reviewer lane suppresses CLAUDE.md + auto-memory inje 'the claude lane must declare BOTH CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 and ' + 'CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 — CLAUDE.md loading and auto-memory are ' + 'independently-toggled mechanisms, and a lane missing either re-inherits that half of the ' + - 'context, reintroducing the asymmetry against the prompt-fed gemini and codex lanes' + 'context, reintroducing the asymmetry against the prompt-fed qwen and codex lanes' ); }); @@ -251,9 +251,9 @@ describe('#2483 the claude reviewer lane suppresses CLAUDE.md + auto-memory inje transport: 'spawn', flags: ['--evil-reviewer'], reviewsSection: 'Evil Review', - probe: { ...laneFor('gemini').probe }, + probe: { ...laneFor('qwen').probe }, timeoutFloorMs: 1000, - emptyOutput: laneFor('gemini').emptyOutput, + emptyOutput: laneFor('qwen').emptyOutput, requiresBinaries: [], handler: null, invoke: { @@ -513,9 +513,9 @@ describe('#2483 the claude reviewer lane suppresses CLAUDE.md + auto-memory inje // environment untouched rather than passing an empty object, which on some spawn wirings is // the difference between inheriting and being handed a stripped environment. const seen = []; - await runLane(planFor('gemini'), spyDeps(seen), { repoRoot: ROOT }); + await runLane(planFor('qwen'), spyDeps(seen), { repoRoot: ROOT }); const dispatch = seen.find((c) => !c.argv.includes('--help')); - assert.ok(dispatch, 'the runner never reached the gemini dispatch'); + assert.ok(dispatch, 'the runner never reached the qwen dispatch'); assert.ok(!('env' in dispatch.opts), 'an unguarded lane must not pass an env key to spawn'); }); }); diff --git a/tests/gemini-runtime-removed.test.cjs b/tests/gemini-runtime-removed.test.cjs index 927923f45..1b6b1b2e7 100644 --- a/tests/gemini-runtime-removed.test.cjs +++ b/tests/gemini-runtime-removed.test.cjs @@ -428,4 +428,104 @@ describe('#4709 no shipped surface mints a retired runtime id', () => { + 'support. Labels must match the runtime label table (src/runtime-name-policy.cts ' + `RUNTIME_LABELS), so a retired runtime cannot linger here. Offenders:\n ${offenders.join('\n ')}`); }); + +/** + * #4709 Phase 3 — the Gemini CLI reviewer lane is retired. + * + * #1928 removed the gemini RUNTIME in 1.8.0 after Google sunset Gemini CLI on 2026-06-18. The + * reviewer lane was re-created afterwards by the reviewer-lane-as-manifest-data work (6a9babda69, + * #2798/#2837) — per the maintainer that re-creation was an error in that buildout, not a + * decision, so retiring it corrects a mistake and needs no ADR-2782 amendment. + * + * The lane spawned `gemini {{model}} -p -`, a binary Google no longer serves for the + * free/Pro/Ultra tiers that ARE GSD's audience. + * + * Every assertion below is STRUCTURAL — a declared lane, an owned config key, a capability count. + * None asserts that the string "gemini" is absent, because that string is load-bearing across + * Antigravity's real on-disk contract (~/.gemini/antigravity, ~/.gemini/config, hookEvents + * "gemini", GEMINI.md) and across Google's own model IDs. The Antigravity block below is the + * negative space that keeps this removal from overreaching. + */ +describe('#4709 the Gemini CLI reviewer lane is retired', () => { + const reviewerIds = () => Object.keys(registry.capabilities) + .filter((id) => registry.capabilities[id] && registry.capabilities[id].reviewer); + + test('capabilities/gemini/ no longer exists', () => { + assert.strictEqual( + fs.existsSync(path.join(ROOT, 'capabilities', 'gemini')), + false, + 'the gemini capability directory must be deleted, not emptied', + ); + }); + + test('no capability declares a gemini reviewer lane', () => { + const offenders = reviewerIds().filter((id) => { + const rev = registry.capabilities[id].reviewer; + return id === 'gemini' || rev.slug === 'gemini' || (rev.flags || []).includes('--gemini'); + }); + assert.deepStrictEqual( + offenders, + [], + 'a reviewer lane still resolves for the retired Gemini CLI; --gemini would spawn a binary ' + + `Google stopped serving on 2026-06-18. Offenders: ${offenders.join(', ')}`, + ); + }); + + test('no config key is owned for the retired lane', () => { + const offenders = Object.keys(registry.configKeys).filter((k) => /\.gemini$/.test(k)); + assert.deepStrictEqual( + offenders, + [], + 'the retired lane still owns config keys, so `gsd config-set` would accept settings for a ' + + `lane that cannot run. Offenders:\n ${offenders.join('\n ')}`, + ); + }); + + test('exactly 11 reviewer lanes remain', () => { + // Counted from the registry, not hardcoded per-name, so adding a 12th lane later cannot + // silently re-admit gemini under cover of the count still "looking right". + const ids = reviewerIds().sort(); + assert.strictEqual( + ids.length, + 11, + `expected 11 reviewer lanes after retiring gemini, got ${ids.length}: ${ids.join(', ')}`, + ); + assert.ok(!ids.includes('gemini'), 'gemini must not be among them'); + }); + + test("Antigravity's reviewer lane is untouched (negative space)", () => { + const agy = registry.capabilities.antigravity; + assert.ok(agy && agy.reviewer, 'antigravity must still declare a reviewer lane'); + assert.strictEqual(agy.reviewer.slug, 'antigravity'); + for (const flag of ['--antigravity', '--agy']) { + assert.ok( + (agy.reviewer.flags || []).includes(flag), + `antigravity must keep its ${flag} flag`, + ); + } + // Its own keys survive, including the deliberately `agy`-suffixed model key. + for (const key of [ + 'review.models.agy', + 'review.timeouts.antigravity', + 'review.max_prompt_tokens_per_reviewer.antigravity', + ]) { + assert.ok( + Object.prototype.hasOwnProperty.call(registry.configKeys, key), + `antigravity must still own ${key}`, + ); + } + }); + + test('the other ten lanes are untouched (negative space)', () => { + const expected = [ + 'antigravity', 'claude', 'coderabbit', 'codex', 'cursor', + 'kimi-code', 'llama-cpp', 'lm-studio', 'ollama', 'opencode', 'qwen', + ]; + assert.deepStrictEqual( + reviewerIds().sort(), + expected, + 'retiring gemini must remove exactly one lane and disturb no other', + ); + }); +}); }); diff --git a/tests/plan-review-convergence.test.cjs b/tests/plan-review-convergence.test.cjs index cb6aeebec..5e026c6af 100644 --- a/tests/plan-review-convergence.test.cjs +++ b/tests/plan-review-convergence.test.cjs @@ -116,7 +116,7 @@ describe('plan-review-convergence command source (#2306)', () => { test('command declares all reviewer flags in context', () => { assert.ok(command.includes('--codex'), 'must document --codex flag'); - assert.ok(command.includes('--gemini'), 'must document --gemini flag'); + assert.ok(command.includes('--coderabbit'), 'must document --coderabbit flag'); assert.ok(command.includes('--claude'), 'must document --claude flag'); assert.ok(command.includes('--opencode'), 'must document --opencode flag'); assert.ok(command.includes('--all'), 'must document --all flag'); @@ -272,10 +272,10 @@ describe('plan-review-convergence: --agy/--antigravity reviewer whitelist (#2293 // invocation (no flag) MUST yield an empty REVIEWER_FLAGS here; the default // is resolved later in step 1.5 against review.default_reviewers. assert.strictEqual(run('5'), '', 'no reviewer flag → empty REVIEWER_FLAGS from parse (default applied in step 1.5 per #2315)'); - const mixed = run('5 --codex --gemini'); - assert.ok(mixed.includes('--codex') && mixed.includes('--gemini'), 'existing flags still recognized'); + const mixed = run('5 --codex --coderabbit'); + assert.ok(mixed.includes('--codex') && mixed.includes('--coderabbit'), 'existing flags still recognized'); // --agy must not be spuriously matched by an unrelated flag (independence). - assert.ok(!run('5 --gemini').includes('--agy'), '--gemini must not trip the --agy whitelist'); + assert.ok(!run('5 --coderabbit').includes('--agy'), '--coderabbit must not trip the --agy whitelist'); }); }); @@ -377,7 +377,7 @@ describe('plan-review-convergence: #2315 respects review.default_reviewers (no-f // - bare + default_reviewers configured → empty REVIEWER_FLAGS (gsd-review applies default) // - bare + default_reviewers unset → --codex fallback (pre-fix behavior preserved) // - bare + empty-array default → --codex fallback (defensive — schema would reject) - // - explicit --gemini + default set → --gemini wins (explicit flags unaffected, #2315 AC5) + // - explicit --codex + default set → --codex wins (explicit flags unaffected, #2315 AC5) test('[behavioral] no-flag invocation resolves to default_reviewers when configured, --codex otherwise', (t) => { if (process.platform === 'win32') { t.skip('POSIX shell extraction; not run on Windows'); return; } if (!jqAvailable) { t.skip('jq not on PATH — workflow resolution block pipes through jq (production dependency, review.md:244); structural tests above still validate the fix'); return; } @@ -444,9 +444,9 @@ describe('plan-review-convergence: #2315 respects review.default_reviewers (no-f r = run({ args: '5', defaultReviewers: '[]' }); assert.ok(/REVIEWER_FLAGS=\[--codex\]/.test(r), `empty-array default → --codex fallback, got: "${r}"`); - // AC5 (out of scope but must not regress): explicit --gemini overrides configured default. - r = run({ args: '5 --gemini', defaultReviewers: '["claude"]' }); - assert.ok(/REVIEWER_FLAGS=\[.*--gemini.*\]/.test(r), `explicit flag wins over configured default, got: "${r}"`); + // AC5 (out of scope but must not regress): explicit --codex overrides configured default. + r = run({ args: '5 --codex', defaultReviewers: '["claude"]' }); + assert.ok(/REVIEWER_FLAGS=\[.*--codex.*\]/.test(r), `explicit flag wins over configured default, got: "${r}"`); }); // Property test — CLAUDE.md mandates at least one fast-check (fc) property diff --git a/tests/review-default-reviewers-resolution.test.cjs b/tests/review-default-reviewers-resolution.test.cjs index bc22226ad..6baeabffc 100644 --- a/tests/review-default-reviewers-resolution.test.cjs +++ b/tests/review-default-reviewers-resolution.test.cjs @@ -10,35 +10,35 @@ const { describe('review default reviewers resolution (#3079)', () => { test('no flags + config defaults selects configured subset', () => { const result = resolveReviewerSelection({ - detected: ['gemini', 'codex', 'claude'], + detected: ['qwen', 'codex', 'claude'], explicitFlags: [], allFlag: false, - configuredDefaultReviewers: ['gemini', 'codex'], + configuredDefaultReviewers: ['qwen', 'codex'], }); assert.strictEqual(result.source, 'config_default'); - assert.deepStrictEqual(result.selected, ['codex', 'gemini']); + assert.deepStrictEqual(result.selected, ['codex', 'qwen']); assert.deepStrictEqual(result.errors, []); }); test('--all ignores configured defaults', () => { const result = resolveReviewerSelection({ - detected: ['gemini', 'codex', 'claude'], + detected: ['qwen', 'codex', 'claude'], explicitFlags: [], allFlag: true, - configuredDefaultReviewers: ['gemini'], + configuredDefaultReviewers: ['qwen'], }); assert.strictEqual(result.source, 'all_flag'); - assert.deepStrictEqual(result.selected, ['claude', 'codex', 'gemini']); + assert.deepStrictEqual(result.selected, ['claude', 'codex', 'qwen']); }); test('explicit flags win over config defaults', () => { const result = resolveReviewerSelection({ - detected: ['gemini', 'codex', 'claude', 'cursor'], + detected: ['qwen', 'codex', 'claude', 'cursor'], explicitFlags: ['cursor'], allFlag: false, - configuredDefaultReviewers: ['gemini', 'codex'], + configuredDefaultReviewers: ['qwen', 'codex'], }); assert.strictEqual(result.source, 'explicit_flags'); @@ -47,7 +47,7 @@ describe('review default reviewers resolution (#3079)', () => { test('unknown configured slugs warn and all-undetected known slugs error', () => { const result = resolveReviewerSelection({ - detected: ['gemini'], + detected: ['qwen'], explicitFlags: [], allFlag: false, configuredDefaultReviewers: ['unknown_slug', 'codex'], diff --git a/tests/review-lane-descriptor.test.cjs b/tests/review-lane-descriptor.test.cjs index 9bd6444f4..728cde6ce 100644 --- a/tests/review-lane-descriptor.test.cjs +++ b/tests/review-lane-descriptor.test.cjs @@ -306,19 +306,19 @@ describe('reviewer lane parity — descriptor-internal uniqueness (ADR-2782 D8)' }); test('duplicate lane flags are a violation', () => { - const clash = { ...fakeLane('acme'), flags: ['--gemini'] }; + const clash = { ...fakeLane('acme'), flags: ['--codex'] }; const r = check({ descriptor: [...REVIEWER_LANES, clash] }); assert.ok( - reasons(r).includes(`${PARITY_VIOLATION.DUPLICATE_FLAG}:--gemini`), + reasons(r).includes(`${PARITY_VIOLATION.DUPLICATE_FLAG}:--codex`), `expected a duplicate-flag violation, got: ${JSON.stringify(reasons(r))}`, ); }); test('duplicate reviewsSection is a violation', () => { - const clash = { ...fakeLane('acme'), reviewsSection: 'Gemini' }; + const clash = { ...fakeLane('acme'), reviewsSection: 'Codex' }; const r = check({ descriptor: [...REVIEWER_LANES, clash] }); assert.ok( - reasons(r).includes(`${PARITY_VIOLATION.DUPLICATE_SECTION}:Gemini`), + reasons(r).includes(`${PARITY_VIOLATION.DUPLICATE_SECTION}:Codex`), `expected a duplicate-section violation, got: ${JSON.stringify(reasons(r))}`, ); }); @@ -754,7 +754,7 @@ const { } = require('../gsd-core/bin/lib/review-lane-descriptor.cjs'); /** A first-party lane set small enough to read at a glance, but real-shaped. */ -const FP = REVIEWER_LANES.slice(0, 2); // gemini, claude +const FP = REVIEWER_LANES.slice(0, 2); // claude, codex const FP_SLUGS = FP.map((l) => l.slug); /** A valid overlay `reviewer` body, field-identical to a SpawnLane (ADR-2782 D1). */ @@ -812,7 +812,7 @@ describe('mergeReviewerLanes (#2927)', () => { const merged = mergeReviewerLanes(FP, registry(reviewerCap(overlayLane()))); const slugs = merged.map((l) => l.slug); assert.ok(slugs.includes('agy-revisor'), 'overlay slug admitted into merged set'); - assert.ok(slugs.includes('gemini'), 'first-party lanes preserved'); + assert.ok(slugs.includes('claude'), 'first-party lanes preserved'); // the overlay body itself is the merged entry (no translation layer) const overlay = merged.find((l) => l.slug === 'agy-revisor'); assert.ok(overlay, 'agy-revisor overlay lane should be present in merged set'); diff --git a/tests/review-lane-invocation.test.cjs b/tests/review-lane-invocation.test.cjs index 06258d545..79ca1803c 100644 --- a/tests/review-lane-invocation.test.cjs +++ b/tests/review-lane-invocation.test.cjs @@ -43,7 +43,6 @@ const FC = { seed: 42, numRuns: 200 }; /** Config with every model key set, so the model-bearing rows exercise the configured branch. */ const FULL_CONFIG = { - 'review.models.gemini': 'G', 'review.models.claude': 'C', 'review.models.codex': 'X', 'review.models.opencode': 'O', @@ -78,7 +77,6 @@ const FILE_REF = fileRefPrompt(`${RUN}/gsd-review-prompt.md`, ROOT); * each still gets its own named constant since each describes an * independently-configured external tool, not a shared internal class norm. */ -const GEMINI_NATIVE_TIMEOUT_MS = 900000; const CLAUDE_NATIVE_TIMEOUT_MS = 1200000; const CODEX_NATIVE_TIMEOUT_MS = 1200000; const CODERABBIT_NATIVE_TIMEOUT_MS = 360000; @@ -98,7 +96,6 @@ const KIMI_CODE_NATIVE_TIMEOUT_MS = 900000; * effort available. `stdin` is the prompt path for a stdin lane, `null` otherwise. */ const GOLDEN = [ - { slug: 'gemini', binary: 'gemini', argv: ['-m', 'G', '-p', '-'], stdin: true, out: 'stdout', timeout: GEMINI_NATIVE_TIMEOUT_MS }, { slug: 'claude', binary: 'claude', argv: ['--model', 'C', '--effort', 'high', '-p', '-'], stdin: true, out: 'stdout', timeout: CLAUDE_NATIVE_TIMEOUT_MS }, { slug: 'codex', @@ -179,7 +176,7 @@ describe('#3274 — timeoutConfigKey resolves the outer wall-clock cap', () => { const r = resolve('antigravity', { config: { [AGY_KEY]: 900 } }); // 900_000 here is the arithmetic result of this test's own input (900 // configured seconds * 1000), not a reuse of any lane's *_NATIVE_TIMEOUT_MS - // golden default -- it only coincidentally matches GEMINI/QWEN/CURSOR/ + // golden default -- it only coincidentally matches QWEN/CURSOR/ // KIMI_CODE_NATIVE_TIMEOUT_MS (all 900000). antigravity's own native // default is ANTIGRAVITY_NATIVE_TIMEOUT_MS (600000), unrelated here. assert.equal(r.plan.timeoutMs, 900_000); @@ -208,7 +205,7 @@ describe('#3274 — timeoutConfigKey resolves the outer wall-clock cap', () => { }); test('a lane with no timeoutConfigKey field falls back like an unset key (row 7)', () => { - const lane = { ...REVIEWER_LANES.find((l) => l.slug === 'gemini') }; + const lane = { ...REVIEWER_LANES.find((l) => l.slug === 'claude') }; delete lane.timeoutConfigKey; const r = resolveLanePlan({ lane, configGet: () => 900, runDir: RUN, repoRoot: ROOT }); assert.equal(r.ok, true); @@ -231,9 +228,9 @@ describe('#3274 — timeoutConfigKey resolves the outer wall-clock cap', () => { }); test("a non-antigravity lane's configured timeout does not touch argv (row 13)", () => { - const key = REVIEWER_LANES.find((l) => l.slug === 'gemini').timeoutConfigKey; - const unset = resolve('gemini', { config: {} }); - const configured = resolve('gemini', { config: { [key]: 300 } }); + const key = REVIEWER_LANES.find((l) => l.slug === 'claude').timeoutConfigKey; + const unset = resolve('claude', { config: {} }); + const configured = resolve('claude', { config: { [key]: 300 } }); assert.deepStrictEqual(configured.plan.argv, unset.plan.argv); assert.notEqual(configured.plan.timeoutMs, unset.plan.timeoutMs); }); @@ -344,7 +341,7 @@ describe('reviewer lane invocation — model resolution', () => { // `"null"` is the four literal characters `config-get --raw` prints for a missing key — every // bash leg tested for it. A config written by an older workflow can still contain it. for (const bad of [undefined, null, '', ' ', 'null', 'undefined']) { - const r = resolve('gemini', { config: { 'review.models.gemini': bad } }); + const r = resolve('claude', { config: { 'review.models.claude': bad }, effortArgs: [] }); assert.deepStrictEqual(r.plan.argv, ['-p', '-'], `${JSON.stringify(bad)} must not reach argv`); } }); @@ -353,15 +350,15 @@ describe('reviewer lane invocation — model resolution', () => { // String(0) would put "0" in as a model name. A wrong model silently reviewed is worse than no // override at all. for (const bad of [0, 1, true, false, [], {}, ['a']]) { - const r = resolve('gemini', { config: { 'review.models.gemini': bad } }); + const r = resolve('claude', { config: { 'review.models.claude': bad }, effortArgs: [] }); assert.deepStrictEqual(r.plan.argv, ['-p', '-'], `${JSON.stringify(bad)} must not reach argv`); } }); test('shell metacharacters in a model value stay a single inert argv element', () => { const hostile = '; rm -rf /; $(whoami) `id` && echo "x"'; - const r = resolve('gemini', { config: { 'review.models.gemini': hostile } }); - assert.deepStrictEqual(r.plan.argv, ['-m', hostile, '-p', '-']); + const r = resolve('claude', { config: { 'review.models.claude': hostile }, effortArgs: [] }); + assert.deepStrictEqual(r.plan.argv, ['--model', hostile, '-p', '-']); // Nothing here builds a shell string; the runner spawns with shell:false and an argv array. assert.equal(r.plan.argv.filter((a) => a === hostile).length, 1); }); diff --git a/tests/review-lane-runner.test.cjs b/tests/review-lane-runner.test.cjs index 82c2985cc..32bce7f09 100644 --- a/tests/review-lane-runner.test.cjs +++ b/tests/review-lane-runner.test.cjs @@ -138,7 +138,7 @@ describe('runner — egress host re-verification (ADR-2782 D5 rules 2-4)', () => describe('runner — probe (ADR-2782 D7)', () => { test('command-exists both ways', async () => { - const p = plan('gemini'); + const p = plan('cursor'); assert.equal((await probeLane(p, deps({ hasBinary: () => true }))).available, true); const miss = await probeLane(p, deps({ hasBinary: () => false })); assert.equal(miss.available, false); @@ -182,7 +182,7 @@ describe('runner — probe (ADR-2782 D7)', () => { }); test('a missing required binary is named rather than left to fail obscurely', async () => { - const p = { ...plan('gemini'), requiresBinaries: ['jq'] }; + const p = { ...plan('cursor'), requiresBinaries: ['jq'] }; const r = await probeLane(p, deps({ hasBinary: (n) => n !== 'jq' })); assert.equal(r.available, false); assert.equal(r.reason, LANE_UNAVAILABLE.MISSING_REQUIRED_BINARY); @@ -208,7 +208,7 @@ describe('runner — probe (ADR-2782 D7)', () => { describe('runner — empty-output policy (#2494 / #2605 / #2794)', () => { test('a real review is written verbatim', () => { - const p = plan('gemini'); + const p = plan('cursor'); const d = deps(); const r = writeReviewOrStub(p, '## Findings\nreal', d); assert.equal(r.stubbed, false); @@ -216,8 +216,8 @@ describe('runner — empty-output policy (#2494 / #2605 / #2794)', () => { }); test('empty output writes a stub carrying the captured stderr', () => { - const p = plan('gemini'); - const d = deps({ files: { [`${RUN}/gsd-review-gemini.err`]: 'auth failed' } }); + const p = plan('cursor'); + const d = deps({ files: { [`${RUN}/gsd-review-cursor.err`]: 'auth failed' } }); const r = writeReviewOrStub(p, '', d); assert.equal(r.stubbed, true); assert.ok(d.files[p.reviewPath].includes('failed or returned empty output')); @@ -226,7 +226,7 @@ describe('runner — empty-output policy (#2494 / #2605 / #2794)', () => { test('whitespace-only output is stubbed on every lane', () => { // Before this, `[ ! -s file ]` counted bytes so " " rendered as a clean review on five lanes. - for (const slug of ['gemini', 'claude', 'codex', 'qwen', 'cursor']) { + for (const slug of ['antigravity', 'claude', 'codex', 'qwen', 'cursor']) { const p = plan(slug); const d = deps(); assert.equal(writeReviewOrStub(p, ' \n', d).stubbed, true, `${slug} accepted whitespace`); @@ -316,9 +316,9 @@ describe('runner — empty-output policy (#2494 / #2605 / #2794)', () => { }); test('#4255 — a lane that sent no effort argument says so, rather than naming a level', () => { - // gemini declares no effort channel, so `plan.effort` is null. Printing a level there would + // cursor declares no effort channel, so `plan.effort` is null. Printing a level there would // be a lie about what reached the CLI; the stub says the CLI's own configuration applied. - const p = plan('gemini'); + const p = plan('cursor'); const d = deps(); writeReviewOrStub(p, '', d, undefined, { status: 0 }); const out = d.files[p.reviewPath]; @@ -337,7 +337,7 @@ describe('runner — empty-output policy (#2494 / #2605 / #2794)', () => { test('the stub is distinguishable from a real review', () => { // The ambiguity between "failed" and "ran cleanly with nothing to report" IS the defect. - const p = plan('gemini'); + const p = plan('cursor'); const d = deps(); writeReviewOrStub(p, '', d); assert.ok(/failed or returned empty output/.test(d.files[p.reviewPath])); @@ -355,7 +355,7 @@ describe('runner — empty-output policy (#2494 / #2605 / #2794)', () => { test('a filesystem write failure degrades rather than crashing the run', () => { // Injected by making the seam throw — never chmod 0o000, which root bypasses. - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ writeFile: () => { throw new Error('EROFS'); } }); assert.throws(() => writeReviewOrStub(p, 'x', d), /EROFS/); }); @@ -732,7 +732,7 @@ describe('runner — openai-compatible handler', () => { describe('runner — orchestration', () => { test('an unavailable lane requested EXPLICITLY is surfaced (D4 carve-out)', async () => { - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ hasBinary: () => false }); const r = await runLane(p, d, { repoRoot: ROOT, explicitlyRequested: true }); assert.equal(r.ok, false); @@ -740,7 +740,7 @@ describe('runner — orchestration', () => { }); test('an unavailable lane nobody asked for is quiet but still reported', async () => { - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ hasBinary: () => false }); const r = await runLane(p, d, { repoRoot: ROOT, explicitlyRequested: false }); assert.equal(r.ok, false); @@ -762,14 +762,14 @@ describe('runner — orchestration', () => { }); test('stderr is always captured to the sidecar, never discarded', async () => { - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ spawn: () => ({ status: 0, stdout: 'R', stderr: 'a warning' }) }); await runLane(p, d, { repoRoot: ROOT }); assert.equal(d.files[p.errPath], 'a warning'); }); test('the prompt reaches stdin for a stdin lane', async () => { - const p = plan('gemini'); + const p = plan('qwen'); const d = deps({ files: { [`${RUN}/gsd-review-prompt.md`]: 'THE PLAN' }, spawn: (b, a, o) => { d.spawns.push({ b, a, o }); return { status: 0, stdout: 'R', stderr: '' }; }, @@ -808,7 +808,7 @@ describe('runner — orchestration', () => { describe('runner — #3086: spawn errorCode surfaced in err file', () => { test('a spawn ENOENT writes the error code to the err file', async () => { - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ spawn: () => ({ status: null, stdout: '', stderr: '', errorCode: 'ENOENT' }), }); @@ -830,7 +830,7 @@ describe('runner — #3086: spawn errorCode surfaced in err file', () => { }); test('a successful spawn with stderr does NOT add a spawn error marker', async () => { - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ spawn: () => ({ status: 0, stdout: '## Review\nok', stderr: 'some warning', errorCode: undefined }), }); @@ -919,7 +919,7 @@ describe('#2494 — a failed lane writes a diagnosable stub, not a zero-byte fil } test('a successful review passes through untouched', async () => { - const p = planFor('gemini'); + const p = planFor('cursor'); const d = deps({ status: 0, stdout: 'Looks good.\n', stderr: '' }); const r = await runLane(p, d, { repoRoot: ROOT }); @@ -1148,7 +1148,7 @@ describe('#2794 qwen reviewer stderr capture', () => { }); // #3194 — a source-grounded lane's grounding is VERIFIED from its review output, never trusted -// from its declaration. The gemini lane declares evidenceClass 'source-grounded', but nothing at +// from its declaration. The cursor lane declares evidenceClass 'source-grounded', but nothing at // invocation obliged grounding and nothing verified it, so measured plan-only reviews (zero real // file:line citations, invented PLAN-line references) rode the declared class at full consensus // weight — the weakest review getting the strongest weight, silently. The fix stamps a @@ -1224,8 +1224,8 @@ describe('#3194 — evidence grounding is verified from review output, not decla }); describe('runLane — the stamp reaches {run_dir}/gsd-review-.md', () => { - test('gemini: zero citations → the review file carries the down-weight marker', async () => { - const p = plan('gemini'); + test('cursor: zero citations → the review file carries the down-weight marker', async () => { + const p = plan('cursor'); const d = deps({ spawn: () => ({ status: 0, stdout: PLAN_ONLY, stderr: '' }) }); await runLane(p, d, { repoRoot: ROOT }); assert.ok( @@ -1234,8 +1234,8 @@ describe('#3194 — evidence grounding is verified from review output, not decla ); }); - test('gemini: one citation → full weight, no marker', async () => { - const p = plan('gemini'); + test('cursor: one citation → full weight, no marker', async () => { + const p = plan('cursor'); const d = deps({ spawn: () => ({ status: 0, stdout: CITED, stderr: '' }) }); await runLane(p, d, { repoRoot: ROOT }); assert.ok(!d.files[p.reviewPath].includes(MARKER)); @@ -1281,7 +1281,7 @@ describe('#3194 — evidence grounding is verified from review output, not decla test('the resolved plan carries the declared evidenceClass (#3194 seam)', () => { // The runner gates the stamp on this field; before #3194 the plan did not carry it at all, // so the executor had no access to the declaration it was supposed to verify. - assert.equal(plan('gemini').evidenceClass, 'source-grounded'); + assert.equal(plan('cursor').evidenceClass, 'source-grounded'); assert.equal(plan('ollama').evidenceClass, 'source-grounded'); assert.equal(plan('coderabbit').evidenceClass, 'diff-only'); }); @@ -1521,29 +1521,29 @@ describe('#2295 — parseTranscriptModel', () => { describe('#2295 — resolveLanePlan records only a model that was APPLIED', () => { test('a configured model that reached argv is recorded on the plan', () => { - const p = plan('gemini', { 'review.models.gemini': 'gemini-3-pro' }); - assert.equal(p.model, 'gemini-3-pro'); - assert.ok(p.argv.includes('gemini-3-pro'), 'and it really is in argv'); + const p = plan('cursor', { 'review.models.cursor': 'cursor-3-pro' }); + assert.equal(p.model, 'cursor-3-pro'); + assert.ok(p.argv.includes('cursor-3-pro'), 'and it really is in argv'); }); test('an unset config yields no plan model', () => { - assert.equal(plan('gemini').model, null); + assert.equal(plan('cursor').model, null); }); test('a lane declaring no modelConfigKey records no model', () => { - assert.equal(plan('cursor').model, null); + assert.equal(plan('qwen').model, null); assert.equal(plan('coderabbit').model, null); }); test('the unset sentinels do not become a model', () => { for (const v of ['', ' ', 'null', 'undefined']) { - assert.equal(plan('gemini', { 'review.models.gemini': v }).model, null, `sentinel ${JSON.stringify(v)}`); + assert.equal(plan('cursor', { 'review.models.cursor': v }).model, null, `sentinel ${JSON.stringify(v)}`); } }); test('a non-string config value is not coerced into a model', () => { for (const v of [0, 42, true, { id: 'x' }, ['x']]) { - assert.equal(plan('gemini', { 'review.models.gemini': v }).model, null); + assert.equal(plan('cursor', { 'review.models.cursor': v }).model, null); } }); @@ -1552,12 +1552,12 @@ describe('#2295 — resolveLanePlan records only a model that was APPLIED', () = // argument that carries it. The CLI then reviews with its own default while the config says // otherwise. Recording the config value here would assert a model that never ran — the // inverse of the very failure #2295 exists to end. - const gemini = REVIEWER_LANES.find((l) => l.slug === 'gemini'); + const cursor = REVIEWER_LANES.find((l) => l.slug === 'cursor'); const lane = { - ...gemini, + ...cursor, slug: 'noarg', modelConfigKey: 'review.models.noarg', - invoke: { ...gemini.invoke, modelArg: null }, + invoke: { ...cursor.invoke, modelArg: null }, }; const r = resolveLanePlan({ lane, @@ -1578,10 +1578,10 @@ describe('#2295 — resolveLanePlan records only a model that was APPLIED', () = describe('#2295 — runLane reports the resolved model', () => { test('a pinned spawn model is reported as pinned', async () => { - const p = plan('gemini', { 'review.models.gemini': 'gemini-3-pro' }); + const p = plan('cursor', { 'review.models.cursor': 'cursor-3-pro' }); const d = deps({ spawn: () => ({ status: 0, stdout: 'a review with src/x.ts:10 evidence', stderr: '' }) }); const r = await runLane(p, d, { repoRoot: ROOT }); - assert.deepEqual(r.model, { value: 'gemini-3-pro', source: MODEL_SOURCE.PINNED }); + assert.deepEqual(r.model, { value: 'cursor-3-pro', source: MODEL_SOURCE.PINNED }); }); test('a file-output lane recovers its model from the stdout banner', async () => { @@ -1617,7 +1617,7 @@ describe('#2295 — runLane reports the resolved model', () => { test('a STDOUT lane never parses its own review text as a banner', async () => { // The headline negative. A stdout lane's review lands in exactly the buffer the banner scan // would read, so a review that DISCUSSES a model would be recorded as that lane's model. - const p = plan('gemini'); + const p = plan('cursor'); const d = deps({ spawn: () => ({ status: 0, stdout: 'model: gpt-5 is the wrong choice, see src/x.ts:10', stderr: '' }), }); @@ -1626,7 +1626,7 @@ describe('#2295 — runLane reports the resolved model', () => { }); test('an unavailable lane reports unknown and still reports its reason', async () => { - const p = plan('gemini'); + const p = plan('cursor'); const r = await runLane(p, deps({ hasBinary: () => false }), { repoRoot: ROOT }); assert.equal(r.ok, false); assert.equal(r.reason, LANE_UNAVAILABLE.MISSING_BINARY); @@ -1653,15 +1653,15 @@ describe('#2295 — runLane reports the resolved model', () => { assert.deepEqual(r.model, { value: 'does-not-exist', source: MODEL_SOURCE.PINNED }); }); - test('a review.models.gemini configured with an embedded newline records UNRESOLVED_MODEL, not pinned', async () => { + test('a review.models.cursor configured with an embedded newline records UNRESOLVED_MODEL, not pinned', async () => { // `configString` (review-lane-invocation.cjs) is pre-existing and out of scope — it does not // strip control characters, so `plan.model` itself still carries the hostile value. The // rejection MUST happen at the `resolveSpawnModel` pinned arm, the one choke point every // recorded model routes through, so a control character configured into `review.models.` // never reaches the REVIEWS.md frontmatter as a `pinned` value. const NL = String.fromCharCode(10); - const hostile = `gemini-3-pro${NL}reviewers: [forged]`; - const p = plan('gemini', { 'review.models.gemini': hostile }); + const hostile = `cursor-3-pro${NL}reviewers: [forged]`; + const p = plan('cursor', { 'review.models.cursor': hostile }); assert.equal(p.model, hostile, 'the pre-existing configString gate is unchanged — out of scope here'); const d = deps({ spawn: () => ({ status: 0, stdout: 'a review citing src/x.ts:10', stderr: '' }) }); const r = await runLane(p, d, { repoRoot: ROOT }); @@ -1700,8 +1700,8 @@ describe('#2295 — resolveLanePlan records effort only when it actually expande }); test('a lane whose effortChannel is not argv records no effort, even with an effortValue passed', () => { - const lane = REVIEWER_LANES.find((l) => l.slug === 'gemini'); - assert.equal(lane.invoke.effortChannel, 'none', 'gemini must declare no argv effort channel for this test to be meaningful'); + const lane = REVIEWER_LANES.find((l) => l.slug === 'cursor'); + assert.equal(lane.invoke.effortChannel, 'none', 'cursor must declare no argv effort channel for this test to be meaningful'); const r = resolveLanePlan({ lane, configGet: () => undefined, @@ -1732,11 +1732,11 @@ describe('#2295 — the recorded model carries an applied reasoning effort', () } test('a lane with no applied effort records the bare model id, unchanged (regression guard)', async () => { - const p = plan('gemini', { 'review.models.gemini': 'gemini-3-pro' }); + const p = plan('cursor', { 'review.models.cursor': 'cursor-3-pro' }); assert.equal(p.effort, null); const d = deps({ spawn: () => ({ status: 0, stdout: 'a review with src/x.ts:10 evidence', stderr: '' }) }); const r = await runLane(p, d, { repoRoot: ROOT }); - assert.deepEqual(r.model, { value: 'gemini-3-pro', source: MODEL_SOURCE.PINNED }); + assert.deepEqual(r.model, { value: 'cursor-3-pro', source: MODEL_SOURCE.PINNED }); }); test('a pinned codex model plus an applied effort records "o4-mini (reasoning=low)"', async () => { @@ -1993,7 +1993,7 @@ describe('#2295 — properties (pinned seed, bounded runs)', () => { test('every reported spawn model satisfies the value-source biconditional', () => { fc.assert( fc.property( - fc.constantFrom('gemini', 'codex', 'antigravity', 'cursor', 'coderabbit'), + fc.constantFrom('claude', 'codex', 'antigravity', 'cursor', 'coderabbit'), fc.option(fc.string(), { nil: undefined }), fc.string(), (slug, configured, stdout) => { diff --git a/tests/review-model-config.test.cjs b/tests/review-model-config.test.cjs index da4f81f2a..93f15c913 100644 --- a/tests/review-model-config.test.cjs +++ b/tests/review-model-config.test.cjs @@ -27,17 +27,6 @@ describe('review.models. config key', () => { cleanup(tmpDir); }); - test('isValidConfigKey accepts review.models.gemini', () => { - // Exercised via config-set, which calls isValidConfigKey internally and - // errors out if the key is not valid. - const result = runGsdTools( - ['config-set', 'review.models.gemini', 'gemini-3.1-pro-preview'], - tmpDir, - { HOME: tmpDir, USERPROFILE: tmpDir } - ); - assert.ok(result.success, `config-set should succeed for review.models.gemini: ${result.error}`); - }); - test('isValidConfigKey accepts review.models.codex', () => { const result = runGsdTools( ['config-set', 'review.models.codex', 'gpt-5-codex'], @@ -94,21 +83,21 @@ describe('review.models. config key', () => { test('round-trip: config-set then config-get for a model ID', () => { const setResult = runGsdTools( - ['config-set', 'review.models.gemini', 'gemini-3.1-pro-preview'], + ['config-set', 'review.models.codex', 'gpt-5.6-sol'], tmpDir, { HOME: tmpDir, USERPROFILE: tmpDir } ); assert.ok(setResult.success, `config-set failed: ${setResult.error}`); const getResult = runGsdTools( - ['config-get', 'review.models.gemini', '--raw'], + ['config-get', 'review.models.codex', '--raw'], tmpDir, { HOME: tmpDir, USERPROFILE: tmpDir } ); assert.ok(getResult.success, `config-get failed: ${getResult.error}`); assert.strictEqual( getResult.output, - 'gemini-3.1-pro-preview', + 'gpt-5.6-sol', 'config-get should return the value set via config-set' ); }); @@ -121,14 +110,14 @@ describe('review.models. config key', () => { // review.md:259) treats the resulting empty read as "no override → use the // reviewer's default", exactly as it treated the old "null" sentinel. const setResult = runGsdTools( - ['config-set', 'review.models.gemini', 'gemini-3.1-pro-preview'], + ['config-set', 'review.models.codex', 'gpt-5.6-sol'], tmpDir, { HOME: tmpDir, USERPROFILE: tmpDir } ); assert.ok(setResult.success, `config-set failed: ${setResult.error}`); const clearResult = runGsdTools( - ['config-set', 'review.models.gemini', 'null'], + ['config-set', 'review.models.codex', 'null'], tmpDir, { HOME: tmpDir, USERPROFILE: tmpDir } ); @@ -140,17 +129,17 @@ describe('review.models. config key', () => { const config = JSON.parse(rawText); assert.ok( !config.review || !config.review.models || - !Object.prototype.hasOwnProperty.call(config.review.models, 'gemini'), - `review.models.gemini must be absent after clear, got: ${rawText}` + !Object.prototype.hasOwnProperty.call(config.review.models, 'codex'), + `review.models.codex must be absent after clear, got: ${rawText}` ); - assert.doesNotMatch(rawText, /"gemini":\s*"null"/, - 'must never persist review.models.gemini as the literal string "null"'); + assert.doesNotMatch(rawText, /"codex":\s*"null"/, + 'must never persist review.models.codex as the literal string "null"'); // config-get on the removed key yields EMPTY (the review workflow reads it as // `... 2>/dev/null || echo ""` → empty → the `[ -n "$VAR" ]` guard falls back // to the reviewer default). // - // #2797: this key is now federated to the `gemini` lane capability, and a + // #2797: this key is now federated to the `codex` lane capability, and a // federated key always resolves to its declared default — so config-get exits // 0 with empty output rather than exiting non-zero with "Key not found". The // WORKFLOW outcome is unchanged: the guard above sees empty either way, which @@ -160,7 +149,7 @@ describe('review.models. config key', () => { // must never yield the literal string "null", which would be handed to the // CLI as a model name. const getResult = runGsdTools( - ['config-get', 'review.models.gemini', '--raw'], + ['config-get', 'review.models.codex', '--raw'], tmpDir, { HOME: tmpDir, USERPROFILE: tmpDir } ); diff --git a/tests/review-reviewer-selection.test.cjs b/tests/review-reviewer-selection.test.cjs index 11b33cd34..e23a647d0 100644 --- a/tests/review-reviewer-selection.test.cjs +++ b/tests/review-reviewer-selection.test.cjs @@ -285,12 +285,16 @@ describe('resolveReviewerSelection — discovery paths stay lenient (ADR-2782 D4 }); test('a configured default that is undetected stays an info, not an error', () => { + // `qwen` is a genuinely KNOWN lane (REVIEWER_LANES) that is simply absent from `detected` here — + // the shape this test needs. `gemini` no longer works as this fixture: it was retired from + // REVIEWER_LANES by #4709, so it now falls into the UNKNOWN-slug branch (a warning) instead of + // the known-but-undetected branch (an info) this test exists to prove. const r = resolveReviewerSelection({ - detected: ['gemini'], - configuredDefaultReviewers: ['gemini', 'codex'], + detected: ['qwen'], + configuredDefaultReviewers: ['qwen', 'codex'], }); assert.equal(r.source, 'config_default'); - assert.deepStrictEqual(r.selected, ['gemini']); + assert.deepStrictEqual(r.selected, ['qwen']); assert.deepStrictEqual(r.errors, [], 'a preference miss must not become an error'); assert.ok( r.infos.some((i) => i.includes('codex')), @@ -299,9 +303,13 @@ describe('resolveReviewerSelection — discovery paths stay lenient (ADR-2782 D4 }); test('an unknown configured slug stays a warning', () => { + // `qwen` here plays the genuinely KNOWN, detected lane so `selected`/`errors` behave as expected; + // `__nope__` remains the genuinely UNKNOWN slug under test — `gemini` would ALSO now be a valid + // fixture for the unknown branch (retired from REVIEWER_LANES by #4709), but `__nope__` already + // names that branch unambiguously without relying on retirement history. const r = resolveReviewerSelection({ - detected: ['gemini'], - configuredDefaultReviewers: ['gemini', '__nope__'], + detected: ['qwen'], + configuredDefaultReviewers: ['qwen', '__nope__'], }); assert.deepStrictEqual(r.errors, []); assert.ok(r.warnings.some((w) => w.includes('__nope__'))); diff --git a/tests/reviewer-config-federation.test.cjs b/tests/reviewer-config-federation.test.cjs index cb3b3ab90..4415b691a 100644 --- a/tests/reviewer-config-federation.test.cjs +++ b/tests/reviewer-config-federation.test.cjs @@ -33,7 +33,6 @@ const { REVIEWER_LANES } = require('../gsd-core/bin/lib/review-lane-descriptor.c /** Keys that moved to a lane capability, with the lane that must own each. */ const FEDERATED = { - 'review.models.gemini': 'gemini', 'review.models.claude': 'claude', 'review.models.codex': 'codex', 'review.models.opencode': 'opencode', diff --git a/tests/reviewer-docs-parity.test.cjs b/tests/reviewer-docs-parity.test.cjs index cced14904..204f1d830 100644 --- a/tests/reviewer-docs-parity.test.cjs +++ b/tests/reviewer-docs-parity.test.cjs @@ -25,7 +25,7 @@ const { const ROOT = path.join(__dirname, '..'); -/** Every declared flag, in descriptor order (13 across 12 lanes — antigravity carries two). */ +/** Every declared flag, in descriptor order (12 across 11 lanes — antigravity carries two). */ const ALL_FLAGS = REVIEWER_LANES.flatMap((l) => l.flags); /** Every declared reviewsSection title. */ const ALL_TITLES = REVIEWER_LANES.map((l) => l.reviewsSection); @@ -77,11 +77,11 @@ describe('reviewer docs parity — flag arm', () => { }); test('every missing flag is named, not just the first', () => { - const missing = ALL_FLAGS.filter((f) => f !== '--gemini' && f !== '--qwen'); + const missing = ALL_FLAGS.filter((f) => f !== '--codex' && f !== '--qwen'); const r = checkReviewerDocsParity({ descriptor: REVIEWER_LANES, docs: { d: commandsDoc(missing) } }); assert.strictEqual(r.violations.length, 2); const subjects = r.violations.map((v) => v.subject).sort(); - assert.deepStrictEqual(subjects, ['--gemini', '--qwen']); + assert.deepStrictEqual(subjects, ['--codex', '--qwen']); for (const v of r.violations) { assert.strictEqual(v.reason, DOCS_PARITY_VIOLATION.DOC_FLAG_MISSING); } @@ -115,11 +115,11 @@ describe('reviewer docs parity — flag arm', () => { }); test('bracketed flags satisfy the gate too', () => { - const rest = ALL_FLAGS.filter((f) => f !== '--gemini'); + const rest = ALL_FLAGS.filter((f) => f !== '--codex'); const doc = [ '### `/gsd-review`', '', - `Reviewer flags: [--gemini] ${backtickAll(rest)}`, + `Reviewer flags: [--codex] ${backtickAll(rest)}`, '', ].join('\n'); const r = checkReviewerDocsParity({ descriptor: REVIEWER_LANES, docs: { d: doc } }); @@ -132,12 +132,12 @@ describe('reviewer docs parity — signature arm', () => { const doc = [ backtickAll(ALL_FLAGS), '', - '**Command:** `/gsd-review --phase N [--gemini] [--all]`', + '**Command:** `/gsd-review --phase N [--codex] [--all]`', '', `**Purpose:** ${ALL_TITLES.join(', ')}.`, ].join('\n'); const r = checkReviewerDocsParity({ descriptor: REVIEWER_LANES, docs: { d: doc } }); - const omitted = ALL_FLAGS.filter((f) => f !== '--gemini'); + const omitted = ALL_FLAGS.filter((f) => f !== '--codex'); assert.strictEqual(r.violations.length, omitted.length); assert.ok(r.violations.every((v) => v.reason === DOCS_PARITY_VIOLATION.SIGNATURE_FLAG_MISSING)); assert.deepStrictEqual( @@ -582,7 +582,7 @@ describe('reviewer docs parity — independence and properties', () => { }); test('verdict is independent of doc key insertion order', () => { - const dirty = commandsDoc(ALL_FLAGS.filter((f) => f !== '--gemini')); + const dirty = commandsDoc(ALL_FLAGS.filter((f) => f !== '--codex')); const clean = commandsDoc(ALL_FLAGS); const forward = checkReviewerDocsParity({ descriptor: REVIEWER_LANES, docs: { a: dirty, b: clean } }); const reversed = checkReviewerDocsParity({ descriptor: REVIEWER_LANES, docs: { b: clean, a: dirty } }); @@ -678,7 +678,7 @@ describe('reviewer docs parity — the shipped repo', () => { test('the shipped descriptor is non-empty', () => { // Guards the vacuous-truth failure mode: an empty roster trivially satisfies every check below. - assert.ok(REVIEWER_LANES.length >= 12, 'expected at least the 12 shipped lanes'); + assert.ok(REVIEWER_LANES.length >= 11, 'expected at least the 11 shipped lanes'); }); test('the shipped docs satisfy reviewer lane parity', () => { diff --git a/tests/reviewer-lane-declarations.test.cjs b/tests/reviewer-lane-declarations.test.cjs index c6510ff89..1f4500c16 100644 --- a/tests/reviewer-lane-declarations.test.cjs +++ b/tests/reviewer-lane-declarations.test.cjs @@ -85,8 +85,13 @@ const capabilityRegistry = require('../gsd-core/bin/lib/capability-registry.cjs' const ROOT = path.join(__dirname, '..'); -/** The five net-new lane-only `role:"reviewer"` capabilities (ADR-2782 D3). */ -const NEW_LANE_ONLY_IDS = ['gemini', 'coderabbit', 'ollama', 'lm-studio', 'llama-cpp']; +/** + * The four net-new lane-only `role:"reviewer"` capabilities (ADR-2782 D3). + * + * Was five: `gemini` was retired by #4709 (Google sunset Gemini CLI 2026-06-18, the same sunset + * that removed the gemini RUNTIME in #1928/1.8.0), so `capabilities/gemini/` no longer exists. + */ +const NEW_LANE_ONLY_IDS = ['coderabbit', 'ollama', 'lm-studio', 'llama-cpp']; /** The six pre-existing dual-purpose `role:"runtime"` capabilities. */ const RUNTIME_REVIEWER_IDS = ['antigravity', 'claude', 'codex', 'cursor', 'opencode', 'qwen']; @@ -98,7 +103,7 @@ const RUNTIME_REVIEWER_IDS = ['antigravity', 'claude', 'codex', 'cursor', 'openc * refactor would otherwise sail through. */ const LITERAL_ROSTER = [ - 'antigravity', 'claude', 'coderabbit', 'codex', 'cursor', 'gemini', + 'antigravity', 'claude', 'coderabbit', 'codex', 'cursor', // `kimi-code` joined in Phase 5b (#2799, closes #2718) — see // kimiCodeIsDeclaredAndInvocableInThisPhase for why it landed here and not in 5a. 'kimi-code', @@ -212,8 +217,8 @@ describe('A. The five new lane-only capabilities', () => { `"${expectedSlug}" would fail KEBAB_RE as a folder/id — that is exactly the trap this row guards`, ); } - // The other three new capabilities are single-word and unaffected: id === slug. - for (const id of ['gemini', 'coderabbit', 'ollama']) { + // The other two new capabilities are single-word and unaffected: id === slug. + for (const id of ['coderabbit', 'ollama']) { const cap = SHIPPED.capMap.get(id); assert.ok(KEBAB_RE.test(id), `capability id "${id}" must satisfy KEBAB_RE`); assert.equal(cap.reviewer.slug, id, `single-word capability "${id}" must have a matching slug`); @@ -351,7 +356,7 @@ describe('C. Roster derivation — src/review-reviewer-selection.cts', () => { // KEYSTONE. This row is GREEN before and after #2801 — it is the invariant // the phase must not break, not a red row. The literal list is never // computed by the machinery under test. - assert.equal(KNOWN_REVIEWER_SLUGS.length, 12, 'roster must be exactly 12 — not 11, not 13'); + assert.equal(KNOWN_REVIEWER_SLUGS.length, 11, 'roster must be exactly 11 — not 10, not 12'); assert.deepEqual( [...KNOWN_REVIEWER_SLUGS].sort(), LITERAL_ROSTER, `roster must be exactly the declared lane set, got: ${JSON.stringify(KNOWN_REVIEWER_SLUGS)}`, @@ -590,13 +595,13 @@ describe('D. Cross-phase invariants that must not regress', () => { // derivation would also surface here — normalizeReviewerInstances / // resolveReviewerSelection gate config_default membership on // KNOWN_REVIEWER_SLUGS.includes(...). - const detected = ['gemini', 'claude', 'qwen']; + const detected = ['codex', 'claude', 'qwen']; const explicit = resolveReviewerSelection({ - detected, explicitFlags: ['gemini'], allFlag: true, configuredDefaultReviewers: ['claude'], + detected, explicitFlags: ['codex'], allFlag: true, configuredDefaultReviewers: ['claude'], }); assert.equal(explicit.source, 'explicit_flags'); - assert.deepEqual(explicit.selected, ['gemini']); + assert.deepEqual(explicit.selected, ['codex']); const allFlagResult = resolveReviewerSelection({ detected, explicitFlags: [], allFlag: true, configuredDefaultReviewers: ['claude'], @@ -633,8 +638,8 @@ describe('E. Lane fidelity — no translation layer', () => { } } - assert.equal(REVIEWER_LANES.length, 12, 'expected exactly 12 declared descriptor lanes'); - assert.equal(bySlug.size, 12, `expected exactly 12 capabilities declaring a reviewer body, got: ${bySlug.size}`); + assert.equal(REVIEWER_LANES.length, 11, 'expected exactly 11 declared descriptor lanes'); + assert.equal(bySlug.size, 11, `expected exactly 11 capabilities declaring a reviewer body, got: ${bySlug.size}`); // Top-level scalar/array fields compared whole; the two fields that are // themselves nested objects (probe, invoke) are compared sub-field-by- @@ -712,8 +717,8 @@ describe('F. Isolated-security-review regressions', () => { test('slugIsTrimmedRatherThanDropped', () => { // The fix must NOT discard a slug that merely carries incidental whitespace. assert.deepEqual( - deriveReviewerSlugs({ capabilities: { x: { reviewer: { slug: ' gemini ' } } } }), - ['gemini'], + deriveReviewerSlugs({ capabilities: { x: { reviewer: { slug: ' codex ' } } } }), + ['codex'], ); }); @@ -746,7 +751,7 @@ describe('F. Isolated-security-review regressions', () => { // The module under test already imported successfully above; assert the // derived roster is a usable array rather than a partially-initialised value. assert.ok(Array.isArray([...KNOWN_REVIEWER_SLUGS]), 'roster must be iterable after module load'); - assert.equal(KNOWN_REVIEWER_SLUGS.length, 12, 'the real registry still yields the twelve lanes'); + assert.equal(KNOWN_REVIEWER_SLUGS.length, 11, 'the real registry still yields the eleven lanes'); // And the derivation itself is total over the shapes JSON can express. for (const hostile of [null, undefined, [], 0, 'x', { capabilities: null }, { capabilities: [] }]) { assert.doesNotThrow( diff --git a/tests/settings-integrations.test.cjs b/tests/settings-integrations.test.cjs index bd355adeb..9cc352855 100644 --- a/tests/settings-integrations.test.cjs +++ b/tests/settings-integrations.test.cjs @@ -10,7 +10,7 @@ * Covers: * - Artifacts exist (command, workflow, skill stub) with correct frontmatter * - Workflow references the four search API key fields - * - Workflow exposes review.models.{claude,codex,gemini,opencode} routing + * - Workflow exposes review.models.{claude,codex,opencode} routing * - Workflow exposes agent_skills. injection input * - #3651: workflow states the registry-derived review.models settable rule (no * dynamic-pattern claim) and enumerates exactly the registry's settable lanes @@ -101,9 +101,13 @@ describe('#2529 workflow — search integrations', () => { // ─── Content: review.models routing ────────────────────────────────────────── describe('#2529 workflow — review.models routing', () => { - test('workflow references all four reviewer CLIs', () => { + test('workflow references all three reviewer CLIs', () => { + // #4709: the gemini reviewer lane was retired (Google sunset Gemini CLI), and the + // integrations wizard's AskUserQuestion options dropped its "Gemini" choice along with it — + // the workflow's `AskUserQuestion` block at settings-integrations.md:198-200 now offers + // exactly Claude, Codex, OpenCode. const src = fs.readFileSync(WORKFLOW_PATH, 'utf-8'); - for (const cli of ['claude', 'codex', 'gemini', 'opencode']) { + for (const cli of ['claude', 'codex', 'opencode']) { assert.ok( src.includes(`review.models.${cli}`), `workflow must reference review.models.${cli}` @@ -115,7 +119,9 @@ describe('#2529 workflow — review.models routing', () => { // #3651: these pass because the capability registry federates each lane's // modelConfigKey into the valid-key set — NOT via a dynamicKeyPatterns regex // (no such pattern exists; see the #3651 describe below). - for (const cli of ['claude', 'codex', 'gemini', 'opencode']) { + // #4709: gemini dropped from this list along with the retired lane — review.models.gemini + // no longer validates because REVIEWER_LANES no longer declares a gemini modelConfigKey. + for (const cli of ['claude', 'codex', 'opencode']) { assert.ok( isValidConfigKey(`review.models.${cli}`), `review.models.${cli} must pass isValidConfigKey`