feat(cli): setup-cline — configure Cline for OmniRoute (CLI files + VS Code hints) - #4280
Conversation
…S Code hints) CLI #4 of the series. Cline's VS Code extension keeps config in opaque VS Code globalStorage (not file-writable); its CLI/standalone mode reads ~/.cline/data/. `omniroute setup-cline`: - writes ~/.cline/data/globalState.json (act/planModeApiProvider=openai, openAiBaseUrl = ROOT url WITHOUT /v1 — Cline appends /v1/chat/completions — openAiModelId + planModeOpenAiModelId) and ~/.cline/data/secrets.json (openAiApiKey), both merged to preserve existing state. Matches the dashboard cli-tools/cline-settings schema. - remote-aware (--remote/--api-key → active context → localhost). - model resolved via --model or an interactive pick from /v1/models (Cline has no model auto-discovery). - prints the exact VS Code extension settings (Base URL/key/model) to paste, since the extension's storage can't be written directly. Researched against the current Cline docs (saoudrizwan.claude-dev): confirmed the openai-compatible keys, the Plan/Act split, and that openAiBaseUrl must be the ROOT (no /v1). Cline's wire (/v1/chat/completions) already validated → "OK". Tests: buildClineGlobalState (provider+root+model, merge-preserve), buildClineSecrets (key + placeholder), resolveClineTarget (/v1 strip, key win). 6 unit tests; check: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-cline CLI command to configure the Cline AI coding agent for OmniRoute, along with associated unit tests and documentation updates. The review feedback identifies a few key improvements: preserving existing API keys in secrets.json instead of overwriting them with a fallback placeholder when no new key is provided, registering the missing --context option in the CLI command definition, and adding a unit test to verify key preservation.
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.
| export function buildClineSecrets(existing, { apiKey }) { | ||
| return { ...(existing || {}), openAiApiKey: apiKey || "sk_omniroute" }; | ||
| } |
There was a problem hiding this comment.
If apiKey is not provided (e.g., when running the command without an active context or environment variable), buildClineSecrets will overwrite any existing openAiApiKey in secrets.json with the fallback placeholder 'sk_omniroute'. To prevent losing an already configured key, we should fall back to the existing key if present before using the placeholder.
| export function buildClineSecrets(existing, { apiKey }) { | |
| return { ...(existing || {}), openAiApiKey: apiKey || "sk_omniroute" }; | |
| } | |
| export function buildClineSecrets(existing, { apiKey }) { | |
| return { ...(existing || {}), openAiApiKey: apiKey || existing?.openAiApiKey || "sk_omniroute" }; | |
| } |
| .option("--port <port>", "Local OmniRoute port (ignored when --remote is set)", "20128") | ||
| .option("--remote <url>", "Remote OmniRoute URL, e.g. http://192.168.0.15:20128") | ||
| .option("--api-key <key>", "OmniRoute API key (defaults to OMNIROUTE_API_KEY env var)") | ||
| .option("--model <id>", "Model id for Cline (required unless picked interactively)") | ||
| .option("--cline-dir <dir>", "Cline data dir (default: ~/.cline/data)") | ||
| .option("--yes", "Non-interactive: do not prompt (requires --model)") | ||
| .option("--dry-run", "Print what would be written without touching the filesystem") |
There was a problem hiding this comment.
The resolveClineTarget function attempts to read opts.context to resolve the active context, but the --context option is not registered in the CLI command definition. Adding the --context <name> option allows users to specify a context directly from the command line.
.option("--port <port>", "Local OmniRoute port (ignored when --remote is set)", "20128")
.option("--remote <url>", "Remote OmniRoute URL, e.g. http://192.168.0.15:20128")
.option("--context <name>", "OmniRoute context name")
.option("--api-key <key>", "OmniRoute API key (defaults to OMNIROUTE_API_KEY env var)")
.option("--model <id>", "Model id for Cline (required unless picked interactively)")
.option("--cline-dir <dir>", "Cline data dir (default: ~/.cline/data)")
.option("--yes", "Non-interactive: do not prompt (requires --model)")
.option("--dry-run", "Print what would be written without touching the filesystem")| test("buildClineSecrets falls back to a placeholder when no key", () => { | ||
| assert.equal(buildClineSecrets({}, { apiKey: "" }).openAiApiKey, "sk_omniroute"); | ||
| }); |
There was a problem hiding this comment.
Add a unit test to verify that buildClineSecrets preserves the existing key when no new key is provided.
| test("buildClineSecrets falls back to a placeholder when no key", () => { | |
| assert.equal(buildClineSecrets({}, { apiKey: "" }).openAiApiKey, "sk_omniroute"); | |
| }); | |
| test("buildClineSecrets falls back to a placeholder when no key", () => { | |
| assert.equal(buildClineSecrets({}, { apiKey: "" }).openAiApiKey, "sk_omniroute"); | |
| }); | |
| test("buildClineSecrets preserves existing key if no new key is provided", () => { | |
| const sec = buildClineSecrets({ openAiApiKey: "existing-key" }, { apiKey: "" }); | |
| assert.equal(sec.openAiApiKey, "existing-key"); | |
| }); |
…S Code hints) (diegosouzapw#4280) CLI diegosouzapw#4 of the series. Cline's VS Code extension keeps config in opaque VS Code globalStorage (not file-writable); its CLI/standalone mode reads ~/.cline/data/. `omniroute setup-cline`: - writes ~/.cline/data/globalState.json (act/planModeApiProvider=openai, openAiBaseUrl = ROOT url WITHOUT /v1 — Cline appends /v1/chat/completions — openAiModelId + planModeOpenAiModelId) and ~/.cline/data/secrets.json (openAiApiKey), both merged to preserve existing state. Matches the dashboard cli-tools/cline-settings schema. - remote-aware (--remote/--api-key → active context → localhost). - model resolved via --model or an interactive pick from /v1/models (Cline has no model auto-discovery). - prints the exact VS Code extension settings (Base URL/key/model) to paste, since the extension's storage can't be written directly. Researched against the current Cline docs (saoudrizwan.claude-dev): confirmed the openai-compatible keys, the Plan/Act split, and that openAiBaseUrl must be the ROOT (no /v1). Cline's wire (/v1/chat/completions) already validated → "OK". Tests: buildClineGlobalState (provider+root+model, merge-preserve), buildClineSecrets (key + placeholder), resolveClineTarget (/v1 strip, key win). 6 unit tests; check:cli-i18n green.
What
CLI #4 of the series.
omniroute setup-clineconfigures the Cline AI agent to use OmniRoute.Cline is special: its VS Code extension keeps config in VS Code's opaque globalStorage (not file-writable), while its CLI/standalone mode reads
~/.cline/data/. So this command does both (per owner decision):~/.cline/data/globalState.json(act/planModeApiProvider=openai,openAiBaseUrl= ROOT url without/v1— Cline appends/v1/chat/completions—openAiModelId+planModeOpenAiModelId) and~/.cline/data/secrets.json(openAiApiKey), merged to preserve existing state. Matches the dashboardcli-tools/cline-settingsschema.--remote/--api-key→ active context → localhost); model via--modelor interactive pick from/v1/models(no auto-discovery in Cline).Researched against current Cline docs (
saoudrizwan.claude-dev): confirmed the OpenAI-compatible keys, the Plan/Act split, and thatopenAiBaseUrlmust be the root (no/v1).Validation
setup-cline --remote --dry-run --model glm/glm-5-turbo→ correctglobalState+secrets+ UI hints./v1/chat/completions) already validated end-to-end → "OK".check:cli-i18n✓.Establishes the strategy for the remaining VS Code extensions (Kilo, Continue, Roo).
🤖 Generated with Claude Code