* fix(#2832): gsd-sdk auto detects Codex runtime correctly Two-part fix for #2832 (gsd-sdk auto silently routing non-Claude runtime projects through the Claude Agent SDK): 1. Runtime gate at the `auto` entry point. New `runtime-gate.ts` exports `assertRuntimeSupportsAutoMode(config)` which throws an actionable error when `GSD_RUNTIME` / `config.runtime` resolves to a non-Claude runtime (codex, gemini, opencode, etc.). The autonomous orchestrator only knows how to drive `@anthropic-ai/claude-agent-sdk` today; failing fast with a clear pointer at the in-session slash commands beats the previous instant `[FAILED] $0.00 0.1s` flake. Wired into `cli.ts` before the GSD/InitRunner construction. 2. Runtime-aware `resolveModel()` in `session-runner.ts`. The profile -> id map (`balanced -> claude-sonnet-4-6`, etc.) was applied unconditionally, so even with `runtime: codex` and `resolve_model_ids: omit` the SDK forced a Claude id into `query()`. Now the profile map only fires when the runtime is Claude and the explicit `resolve_model_ids: "omit"` knob short-circuits to undefined, mirroring `query/config-query.ts`. Tests (vitest, sdk/src): - runtime-gate.test.ts (8 cases): claude / unset / unknown pass; codex, gemini, opencode throw; GSD_RUNTIME wins over config.runtime; error message references #2832 and the slash-command workaround. - session-runner.test.ts (4 new cases under "resolveModel runtime awareness (#2832)"): codex runtime + balanced profile -> no model injected; resolve_model_ids: omit -> no model; claude runtime still resolves to claude-sonnet-4-6 (no regression); explicit options.model wins on any runtime. * fix(#2832): address CR — env-precedence in resolveModel + accurate source attribution Two CodeRabbit findings on PR #2844: 1. session-runner.ts:resolveModel() (Major) — read runtime via detectRuntime() so GSD_RUNTIME env precedence is honored. Without this, a Codex run with a Claude-shaped config still fell into the Claude-only profile-id branch. 2. runtime-gate.ts:assertRuntimeSupportsAutoMode() (Minor) — when GSD_RUNTIME holds an unsupported value, detectRuntime() falls through to config but the source label still reported the discarded env value. Fix: validate env against SUPPORTED_RUNTIMES before attributing the source. Tests added for both: env-precedence in session-runner, source attribution in runtime-gate. 17/17 pass.
53 lines
2.5 KiB
TypeScript
53 lines
2.5 KiB
TypeScript
/**
|
|
* Runtime gate — guards entry points that only support the Claude runtime.
|
|
*
|
|
* The autonomous SDK orchestrator (`gsd-sdk auto`) currently drives plan
|
|
* execution through `@anthropic-ai/claude-agent-sdk`. It has no Codex /
|
|
* Gemini / OpenCode dispatcher today, so silently routing a non-Claude
|
|
* project's autonomous run through the Claude path is incorrect: it picks
|
|
* Claude models, hits Claude APIs, and confuses users debugging "why is my
|
|
* Codex run choosing claude-sonnet-4-6?" (issue #2832).
|
|
*
|
|
* Fail fast with an actionable error instead. The fix surfaces the limitation
|
|
* up front and points users at the supported in-session GSD slash commands
|
|
* for non-Claude runtimes.
|
|
*/
|
|
import { detectRuntime, SUPPORTED_RUNTIMES, type Runtime } from './query/helpers.js';
|
|
|
|
/**
|
|
* Throw a clear error when the active runtime is not Claude.
|
|
*
|
|
* Precedence mirrors `detectRuntime`: `GSD_RUNTIME` env var > `config.runtime`
|
|
* > `'claude'`. Unknown / missing runtime values default to Claude (the
|
|
* historical behavior) so existing Claude users are unaffected.
|
|
*
|
|
* @param config Project config (with optional `runtime` field).
|
|
* @throws Error with a runtime-specific actionable message when non-Claude.
|
|
*/
|
|
export function assertRuntimeSupportsAutoMode(config?: Record<string, unknown> | { runtime?: unknown }): void {
|
|
const cfg = (config ?? {}) as Record<string, unknown>;
|
|
const runtime: Runtime = detectRuntime({ runtime: cfg.runtime });
|
|
if (runtime === 'claude') return;
|
|
|
|
// Source attribution must reflect what `detectRuntime()` actually used:
|
|
// a `GSD_RUNTIME` value that isn't in SUPPORTED_RUNTIMES falls through to
|
|
// the config tier, so reporting it as the source would be misleading.
|
|
const env = process.env.GSD_RUNTIME;
|
|
const envIsSupported =
|
|
typeof env === 'string' && (SUPPORTED_RUNTIMES as readonly string[]).includes(env);
|
|
const source = envIsSupported
|
|
? `GSD_RUNTIME=${env}`
|
|
: `config.runtime="${String(cfg.runtime ?? '')}"`;
|
|
|
|
throw new Error(
|
|
`gsd-sdk auto currently supports the Claude runtime only ` +
|
|
`(detected runtime=${runtime} via ${source}). ` +
|
|
`Autonomous terminal runs through the Claude Agent SDK; non-Claude ` +
|
|
`runtimes (Codex, Gemini, OpenCode, etc.) must drive GSD via the ` +
|
|
`in-session slash commands (e.g. /gsd-discuss-phase, /gsd-plan-phase, ` +
|
|
`/gsd-execute-phase) until issue #2832 lands a multi-runtime executor. ` +
|
|
`To run on Claude anyway, unset GSD_RUNTIME and set runtime: "claude" ` +
|
|
`in .planning/config.json.`,
|
|
);
|
|
}
|