Skip to content

Commit aa49871

Browse files
cteclaude
andauthored
fix(cli): resolve race condition causing provider switch during mode changes (#11205)
When using slash commands with `mode:` frontmatter (e.g., `/cli-release` with `mode: code`), the CLI would fail with "Could not resolve authentication method" from the Anthropic SDK, even when using a non-Anthropic provider like `--provider roo`. Root cause: In `markWebviewReady()`, the `webviewDidLaunch` message was sent before `updateSettings`, creating a race condition. The `webviewDidLaunch` handler's "first-time init" sync would read `getState()` before CLI-provided settings were applied to the context proxy. Since `getState()` defaults `apiProvider` to "anthropic" when unset, this default was saved to the provider profile. When a slash command triggered `handleModeSwitch()`, it found this corrupted profile with `apiProvider: "anthropic"` (but no API key) and activated it, overwriting the CLI's working roo provider configuration. Fix: 1. Reorder `markWebviewReady()` to send `updateSettings` before `webviewDidLaunch`, ensuring the context proxy has CLI-provided values when the initialization handler runs. 2. Guard the first-time init sync with `checkExistKey(apiConfiguration)` to prevent saving a profile with only the default "anthropic" fallback and no actual API keys configured. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6214f4c commit aa49871

File tree

2 files changed

+19
-9
lines changed

2 files changed

+19
-9
lines changed

apps/cli/src/agent/extension-host.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,12 +428,16 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
428428
public markWebviewReady(): void {
429429
this.isReady = true
430430

431-
// Send initial webview messages to trigger proper extension initialization.
432-
// This is critical for the extension to start sending state updates properly.
433-
this.sendToExtension({ type: "webviewDidLaunch" })
434-
431+
// Apply CLI settings to the runtime config and context proxy BEFORE
432+
// sending webviewDidLaunch. This prevents a race condition where the
433+
// webviewDidLaunch handler's first-time init sync reads default state
434+
// (apiProvider: "anthropic") instead of the CLI-provided settings.
435435
setRuntimeConfigValues("roo-cline", this.initialSettings as Record<string, unknown>)
436436
this.sendToExtension({ type: "updateSettings", updatedSettings: this.initialSettings })
437+
438+
// Now trigger extension initialization. The context proxy should already
439+
// have CLI-provided values when the webviewDidLaunch handler runs.
440+
this.sendToExtension({ type: "webviewDidLaunch" })
437441
}
438442

439443
public isInInitialSetup(): boolean {

src/core/webview/webviewMessageHandler.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -498,12 +498,18 @@ export const webviewMessageHandler = async (
498498
if (!checkExistKey(listApiConfig[0])) {
499499
const { apiConfiguration } = await provider.getState()
500500

501-
await provider.providerSettingsManager.saveConfig(
502-
listApiConfig[0].name ?? "default",
503-
apiConfiguration,
504-
)
501+
// Only save if the current configuration has meaningful settings
502+
// (e.g., API keys). This prevents saving a default "anthropic"
503+
// fallback when no real config exists, which can happen during
504+
// CLI initialization before provider settings are applied.
505+
if (checkExistKey(apiConfiguration)) {
506+
await provider.providerSettingsManager.saveConfig(
507+
listApiConfig[0].name ?? "default",
508+
apiConfiguration,
509+
)
505510

506-
listApiConfig[0].apiProvider = apiConfiguration.apiProvider
511+
listApiConfig[0].apiProvider = apiConfiguration.apiProvider
512+
}
507513
}
508514
}
509515

0 commit comments

Comments
 (0)