From b54c1c5848f9f30956103ce82c14863ec0b043d4 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 14 Sep 2026 03:03:44 -0400 Subject: [PATCH] fix(#4709): retire the Gemini CLI reviewer lane (#4716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(#4709): retire the Gemini CLI reviewer lane Google stopped serving Gemini CLI for the free/Pro/Ultra tiers on 2026-06-18 — the same sunset that removed the gemini RUNTIME in #1928 (shipped 1.8.0). GSD targets solo developers, so those tiers ARE the user path: the lane spawned `gemini {{model}} -p -`, a binary that no longer answers for the majority of users, and five locales documented it as a supported choice. The lane was re-created after #1928 by the reviewer-lane-as-manifest-data work (6a9babda69, #2798/#2837, ADR-2782). Per the maintainer that re-creation was an error in that buildout rather than a considered decision, so this corrects a mistake and needs no ADR-2782 amendment. Reviewer roster: 12 lanes / 13 flags -> 11 lanes / 12 flags. TWO sources of truth had to be removed, not one. Deleting capabilities/gemini/capability.json left the capability registry at 11 lanes while src/review-lane-descriptor.cts's hand-maintained REVIEWER_LANES array still carried its own complete gemini entry at 12 — precisely the disagreement checkReviewerLaneParity exists to catch. Both are gone; both parity checkers now run clean against the real tree (lane parity ok/0 violations, docs parity 0 violations). Surfaces stripped of the dead flag: - capabilities/gemini/ deleted; registry and capability-matrix regenerated - src/review-lane-descriptor.cts: REVIEWER_LANES entry, docblock count, and the three doc comments that used --gemini as a live example - commands/gsd/{review,plan-review-convergence,autonomous,progress}.md and the four matching skills/*/SKILL.md: argument-hint frontmatter and flag bullets - gsd-core/workflows/help/modes/{full,full.compact}.md: /gsd-help signatures, the detected-CLI list, and the reviewer-title list - gsd-core/workflows/settings-integrations.md: the integrations wizard no longer offers "Gemini" as a model option, and the settable-keys list drops it - gsd-core/workflows/review.md: the `command -v gemini` probe, the --gemini flag, the roster frontmatter, the install pointer to the sunset repo, and the jq-less / precedence / self-skip lane lists - gsd-core/workflows/sync-skills.md: "two runtimes (grok, gemini) resolve to ANOTHER runtime's skills root" is now one runtime; gemini never aliased anything, it fell through canonicalizeRuntimeName to a fail-closed default - docs/{CONFIGURATION,COMMANDS,CLI-TOOLS}.md, docs/reference/capability-matrix.md, docs/how-to/set-up-cross-ai-review.md — including its `npm install -g @google/gemini-cli` instruction and the two rows recommending --gemini - docs/features/{cross-ai-peer-review,opt-in-parallel-reviewer-lanes}.md as the generator inputs behind docs/FEATURES.md, plus the three locale FEATURES.md signature lines the docs-parity gate covers (the #2781 class: a flag change that never reaches the mirrors) Counts reconciled against measurement rather than arithmetic: 8 timeout keys of 11 lanes, 11 budget keys, 9 model keys, and four hardcoded literals in tests/reviewer-lane-declarations.test.cjs (NEW_LANE_ONLY_IDS 5->4, LITERAL_ROSTER 12->11, two roster counts 12->11). BEHAVIOR CHANGE, accepted deliberately: `gsd config-set review.models.gemini` now errors with "Unknown config key". An existing key already in .planning/config.json still parses and is simply never read, so no project fails to load. This is the repo's own documented policy for exactly this case (docs/CONFIGURATION.md:327 — "a key left over from a removed reviewer validated silently and was never read. Such a key is now rejected by config-set"), so no installer migration ships. Note my first measurement of this was WRONG: I tested config-get, which reads undeclared keys fine, and generalised. Read and write are different surfaces and gave different answers. Antigravity is untouched throughout — its --antigravity/--agy flags, review.models.agy, ~/.gemini/antigravity configHome, ~/.gemini/config global skills root (#3738), hookEvents "gemini", GEMINI.md instruction file, and every gemini-* model id it actually runs on. Refs #4709 Co-Authored-By: Claude Opus 5 * chore(#4709): changeset for the reviewer-lane retirement Type Removed: the --gemini flag and its three config keys are user-visible surface that no longer exists. Refs #4709 Co-Authored-By: Claude Opus 5 * fix(#4709): close the 24 test failures and the locale-doc gap the gates found An adversarial review and a full matrix run between them found substantially more fallout than inspection had. All of it is this PR's own, and all of it is fixed rather than waved off. THE MATRIX RUN FOUND 24 FAILURES ACROSS 6 FILES. Inspection had predicted two. The dominant class was a test helper that looks up a lane by slug and throws `no declared lane 'gemini'`: - tests/feat-2483-review-claude-mds-guard.test.cjs (6) — used gemini as the "other declared first-party lane" to contrast against claude's env suppression. Now qwen, verified from source as a lane that declares no `env` (only claude does), so the contrast still holds. - tests/review-lane-descriptor.test.cjs (6) — the duplicate-flag and duplicate-section fixtures deliberately COLLIDED with a real declared lane to prove the parity checker reports a duplicate. `--gemini`/`Gemini` no longer collide with anything, so the checker reported `descriptor_lane_not_in_registry:acme` instead and the tests proved nothing. Now collide with `--codex`/`Codex`, reproduced against the real checker. - tests/review-reviewer-selection.test.cjs (3) — these distinguish KNOWN-but- undetected from UNKNOWN. gemini flipped categories, inverting what they proved. The known case now uses qwen; `__nope__` stays the unknown fixture. - tests/review-default-reviewers-resolution.test.cjs (2), and tests/settings-integrations.test.cjs (3) — the wizard now offers three reviewer CLIs, not four, so the test and its name say three. - Two count assertions the earlier sweep missed outright: reviewer-lane-declarations.test.cjs:359 (`length, 12`) and reviewer-docs-parity.test.cjs:681 (`>= 12`). THE LOCALE-DOC GAP, and why the parity gate stayed green over it. All four locale mirrors still documented `--gemini` as a live reviewer flag. The docs-parity checker asserts the PRESENCE of every current flag and never the ABSENCE of a retired one, so "0 violations" was never evidence those files were clean — my earlier reading of it as such was wrong. This is the #2781 locale-drift class in the opposite direction. Fixed across 12 locale files: COMMANDS.md flag lists and table rows, CONFIGURATION.md `review.models.gemini` rows and reviewer prose, CLI-TOOLS.md config examples, and set-up-cross-ai-review.md including its install block and its which-reviewer-to-choose row, which now recommends Antigravity. ALSO FOUND, and instructive about my own method: docs/CONFIGURATION.md:297 still carried a `review.models.gemini` row. My sweep had missed it because my grep excluded lines matching `gemini-[0-9]` to spare Google's model ids — and that row's example value is `"gemini-2.5-pro"` on the same line. The exclusion built to avoid false positives created a false negative. Remaining comment/example sites: src/review-reviewer-selection.cts:309 and src/config.cts:598 named the dead flag and key as examples; gsd-core/references/planning-config.md:269 likewise; and review-reviewer-selection.cts:22 claimed in the PRESENT tense that gemini is a lane-only reviewer capability. Line 38 of that same docblock says "Before this phase the five non-runtime reviewers (gemini, ...)" and is left exactly as is — that is past-tense history, and rewriting it would falsify the record. Deliberately still deferred to Phase 4, because it is the RUNTIME axis rather than the reviewer lane: the locale install-on-your-runtime.md `--gemini --global` instructions, the USER-GUIDE colon-form notes, and the ARCHITECTURE runtime-detection flag lists. Both parity checkers green against the real tree; lint:ci exit 0. Refs #4709 Co-Authored-By: Claude Opus 5 * chore(#4709): backfill the changeset PR number pr: 0 -> 4716, now that the PR exists. Never guessed ahead of the number. Refs #4709 Co-Authored-By: Claude Opus 5 --------- Co-authored-by: sim Co-authored-by: Claude Opus 5 --- .changeset/agile-ibex-chatter.md | 5 + capabilities/gemini/capability.json | 63 ----------- commands/gsd/autonomous.md | 2 +- commands/gsd/plan-review-convergence.md | 7 +- commands/gsd/progress.md | 2 +- commands/gsd/review.md | 5 +- docs/CLI-TOOLS.md | 2 +- docs/COMMANDS.md | 17 ++- docs/CONFIGURATION.md | 20 ++-- docs/FEATURES.md | 6 +- docs/features/cross-ai-peer-review.md | 4 +- .../opt-in-parallel-reviewer-lanes.md | 2 +- docs/how-to/run-phases-autonomously.md | 2 +- docs/how-to/set-up-cross-ai-review.md | 19 ++-- docs/ja-JP/CLI-TOOLS.md | 2 +- docs/ja-JP/COMMANDS.md | 11 +- docs/ja-JP/FEATURES.md | 2 +- docs/ja-JP/how-to/set-up-cross-ai-review.md | 19 ++-- docs/ko-KR/CLI-TOOLS.md | 2 +- docs/ko-KR/COMMANDS.md | 11 +- docs/ko-KR/FEATURES.md | 2 +- docs/ko-KR/how-to/set-up-cross-ai-review.md | 19 ++-- docs/pt-BR/CLI-TOOLS.md | 2 +- docs/pt-BR/COMMANDS.md | 11 +- docs/pt-BR/CONFIGURATION.md | 14 ++- docs/pt-BR/how-to/set-up-cross-ai-review.md | 19 ++-- docs/reference/capability-matrix.md | 3 +- docs/zh-CN/CLI-TOOLS.md | 2 +- docs/zh-CN/COMMANDS.md | 11 +- docs/zh-CN/CONFIGURATION.md | 14 ++- docs/zh-CN/FEATURES.md | 2 +- docs/zh-CN/how-to/set-up-cross-ai-review.md | 19 ++-- gsd-core/bin/lib/capability-registry.cjs | 85 --------------- gsd-core/references/planning-config.md | 2 +- gsd-core/workflows/help/modes/full.compact.md | 4 +- gsd-core/workflows/help/modes/full.md | 8 +- gsd-core/workflows/plan-review-convergence.md | 2 +- gsd-core/workflows/review.md | 19 ++-- gsd-core/workflows/settings-integrations.md | 3 +- gsd-core/workflows/sync-skills.md | 4 +- skills/gsd-autonomous/SKILL.md | 2 +- skills/gsd-plan-review-convergence/SKILL.md | 7 +- skills/gsd-progress/SKILL.md | 2 +- skills/gsd-review/SKILL.md | 5 +- src/config.cts | 2 +- src/review-lane-descriptor.cts | 40 ++----- src/review-reviewer-selection.cts | 4 +- tests/adr-15-progress-converge.test.cjs | 2 +- tests/autonomous-converge.test.cjs | 2 +- tests/config.test.cjs | 22 ++-- ...feat-2483-review-claude-mds-guard.test.cjs | 12 +-- tests/gemini-runtime-removed.test.cjs | 100 ++++++++++++++++++ tests/plan-review-convergence.test.cjs | 16 +-- ...view-default-reviewers-resolution.test.cjs | 18 ++-- tests/review-lane-descriptor.test.cjs | 12 +-- tests/review-lane-invocation.test.cjs | 21 ++-- tests/review-lane-runner.test.cjs | 90 ++++++++-------- tests/review-model-config.test.cjs | 33 ++---- tests/review-reviewer-selection.test.cjs | 18 +++- tests/reviewer-config-federation.test.cjs | 1 - tests/reviewer-docs-parity.test.cjs | 18 ++-- tests/reviewer-lane-declarations.test.cjs | 33 +++--- tests/settings-integrations.test.cjs | 14 ++- 63 files changed, 414 insertions(+), 508 deletions(-) create mode 100644 .changeset/agile-ibex-chatter.md delete mode 100644 capabilities/gemini/capability.json 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`