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>
This commit is contained in:
Chris Estreich 2026-02-04 18:26:41 -08:00 committed by GitHub
parent 6214f4c162
commit aa49871a5d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 9 deletions

View file

@ -428,12 +428,16 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
public markWebviewReady(): void {
this.isReady = true
// Send initial webview messages to trigger proper extension initialization.
// This is critical for the extension to start sending state updates properly.
this.sendToExtension({ type: "webviewDidLaunch" })
// Apply CLI settings to the runtime config and context proxy BEFORE
// sending webviewDidLaunch. This prevents a race condition where the
// webviewDidLaunch handler's first-time init sync reads default state
// (apiProvider: "anthropic") instead of the CLI-provided settings.
setRuntimeConfigValues("roo-cline", this.initialSettings as Record<string, unknown>)
this.sendToExtension({ type: "updateSettings", updatedSettings: this.initialSettings })
// Now trigger extension initialization. The context proxy should already
// have CLI-provided values when the webviewDidLaunch handler runs.
this.sendToExtension({ type: "webviewDidLaunch" })
}
public isInInitialSetup(): boolean {

View file

@ -498,12 +498,18 @@ export const webviewMessageHandler = async (
if (!checkExistKey(listApiConfig[0])) {
const { apiConfiguration } = await provider.getState()
await provider.providerSettingsManager.saveConfig(
listApiConfig[0].name ?? "default",
apiConfiguration,
)
// Only save if the current configuration has meaningful settings
// (e.g., API keys). This prevents saving a default "anthropic"
// fallback when no real config exists, which can happen during
// CLI initialization before provider settings are applied.
if (checkExistKey(apiConfiguration)) {
await provider.providerSettingsManager.saveConfig(
listApiConfig[0].name ?? "default",
apiConfiguration,
)
listApiConfig[0].apiProvider = apiConfiguration.apiProvider
listApiConfig[0].apiProvider = apiConfiguration.apiProvider
}
}
}