Repository navigation
feat(cli): setup-goose — configure Goose for OmniRoute (config.yaml + env recipe) - #4300
Conversation
… env recipe) CLI #10 of the series. `omniroute setup-goose` writes Goose's file-based ~/.config/goose/config.yaml (GOOSE_PROVIDER=openai, GOOSE_MODEL=<model>, OPENAI_HOST=<root, NO /v1 — Goose appends the path itself>), merges to preserve existing keys, and prints the guaranteed env-var recipe (the key lives in the env / OS keyring, never the config). Remote-aware (--remote/--api-key → context → localhost); model via --model or interactive pick. Researched against block/goose: provider openai + OPENAI_HOST base (no /v1). Goose's wire (/v1/chat/completions) already validated → "OK". Tests: resolveGooseTarget (/v1 strip, key), buildGooseConfig (provider/model/host + preserve), buildGooseEnvRecipe (env-ref key). 4 unit tests; cli-i18n green.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Code Review
This pull request introduces the setup-goose CLI command to configure Goose for OmniRoute, along with corresponding documentation updates and unit tests. The feedback suggests improving interactive model selection by prompting the user even if automatic model fetching fails, and wrapping filesystem write operations in a try-catch block to handle potential errors gracefully.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| let model = opts.model; | ||
| if (!model) { | ||
| const ids = await fetchModelIds(host, apiKey); | ||
| if (ids.length && !opts.yes) { | ||
| printInfo(`Examples: ${ids.slice(0, 20).join(", ")}${ids.length > 20 ? " …" : ""}`); | ||
| const prompt = createPrompt(); | ||
| try { | ||
| model = await prompt.ask("Model id for Goose"); | ||
| } finally { | ||
| prompt.close(); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
If the server is offline or returns no models, fetchModelIds will return an empty array. In interactive mode (when --yes is not passed), the current implementation will skip prompting the user entirely and immediately fail with 'A model is required'. We should prompt the user for a model ID even if the automatic fetch returns no examples, allowing them to manually enter the model they wish to use.
| let model = opts.model; | |
| if (!model) { | |
| const ids = await fetchModelIds(host, apiKey); | |
| if (ids.length && !opts.yes) { | |
| printInfo(`Examples: ${ids.slice(0, 20).join(", ")}${ids.length > 20 ? " …" : ""}`); | |
| const prompt = createPrompt(); | |
| try { | |
| model = await prompt.ask("Model id for Goose"); | |
| } finally { | |
| prompt.close(); | |
| } | |
| } | |
| } | |
| let model = opts.model; | |
| if (!model && !opts.yes) { | |
| const ids = await fetchModelIds(host, apiKey); | |
| if (ids.length) { | |
| printInfo(`Examples: ${ids.slice(0, 20).join(", ")}${ids.length > 20 ? " …" : ""}`); | |
| } | |
| const prompt = createPrompt(); | |
| try { | |
| model = await prompt.ask("Model id for Goose"); | |
| } finally { | |
| prompt.close(); | |
| } | |
| } |
| } else { | ||
| mkdirSync(join(configPath, ".."), { recursive: true }); | ||
| writeFileSync(configPath, out, "utf8"); | ||
| printSuccess(`Wrote ${configPath}`); | ||
| } |
There was a problem hiding this comment.
Filesystem write operations (mkdirSync and writeFileSync) can fail due to permission issues, read-only filesystems, or disk space limits. Wrapping these calls in a try/catch block ensures the CLI handles these errors gracefully and prints a user-friendly error message instead of crashing with an unhandled exception.
| } else { | |
| mkdirSync(join(configPath, ".."), { recursive: true }); | |
| writeFileSync(configPath, out, "utf8"); | |
| printSuccess(`Wrote ${configPath}`); | |
| } | |
| } else { | |
| try { | |
| mkdirSync(join(configPath, ".."), { recursive: true }); | |
| writeFileSync(configPath, out, "utf8"); | |
| printSuccess(`Wrote ${configPath}`); | |
| } catch (err) { | |
| printError(`Failed to write config to ${configPath}: ${err.message}`); | |
| return 1; | |
| } | |
| } |
… env recipe) (cheaper-inference#4300) CLI cheaper-inference#10 of the series. `omniroute setup-goose` writes Goose's file-based ~/.config/goose/config.yaml (GOOSE_PROVIDER=openai, GOOSE_MODEL=<model>, OPENAI_HOST=<root, NO /v1 — Goose appends the path itself>), merges to preserve existing keys, and prints the guaranteed env-var recipe (the key lives in the env / OS keyring, never the config). Remote-aware (--remote/--api-key → context → localhost); model via --model or interactive pick. Researched against block/goose: provider openai + OPENAI_HOST base (no /v1). Goose's wire (/v1/chat/completions) already validated → "OK". Tests: resolveGooseTarget (/v1 strip, key), buildGooseConfig (provider/model/host + preserve), buildGooseEnvRecipe (env-ref key). 4 unit tests; cli-i18n green.
What
CLI #10.
omniroute setup-goosewrites Goose's~/.config/goose/config.yaml(GOOSE_PROVIDER=openai,GOOSE_MODEL,OPENAI_HOST= root, NO/v1— Goose appends the path) + prints the env recipe (key via env/keyring, not the file). Merges; remote-aware.Validation
setup-goose --remote --dry-run --model glm/glm-5-turbo→ correct config + recipe./v1/chat/completions) already validated → "OK". 4 unit tests;check:cli-i18n✓.Series: …Roo #4292 · Crush #4298 · Goose (this). Next: Qwen Code, Gemini CLI, Aider.
🤖 Generated with Claude Code