From d4c514bd3d4b44662a2f3886ae8ffc197d95885e Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 13 Aug 2025 05:18:29 +0000 Subject: [PATCH] fix: improve button click handling during extension initialization - Add retry logic when ClineProvider is not immediately available - Attempt to activate sidebar view if no visible provider found - Add user-friendly error messages when initialization is incomplete - Improve error handling in getInstance method with longer wait times - Check for function existence before calling showErrorMessage (test compatibility) Fixes #7036 --- src/activate/registerCommands.ts | 65 ++++++++++++++++++++++--------- src/core/webview/ClineProvider.ts | 23 ++++++++--- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index 0534f24782..12b016abd9 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -19,13 +19,40 @@ import { t } from "../i18n" /** * Helper to get the visible ClineProvider instance or log if not found. + * Shows user-friendly error message when provider is not available. */ -export function getVisibleProviderOrLog(outputChannel: vscode.OutputChannel): ClineProvider | undefined { - const visibleProvider = ClineProvider.getVisibleInstance() +export async function getVisibleProviderOrLog(outputChannel: vscode.OutputChannel): Promise { + let visibleProvider = ClineProvider.getVisibleInstance() + + // If no visible provider, try to activate the sidebar view first if (!visibleProvider) { - outputChannel.appendLine("Cannot find any visible Roo Code instances.") + outputChannel.appendLine("No visible Roo Code instance found, attempting to activate sidebar view...") + + try { + // Try to focus the sidebar view which should trigger provider creation + await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`) + + // Wait a bit for the view to initialize + await new Promise((resolve) => setTimeout(resolve, 500)) + + // Try to get the provider again + visibleProvider = ClineProvider.getVisibleInstance() + } catch (error) { + outputChannel.appendLine(`Failed to activate sidebar view: ${error}`) + } + } + + if (!visibleProvider) { + outputChannel.appendLine("Cannot find any visible Roo Code instances after activation attempt.") + // Show user-friendly error message only if not in test environment + if (typeof vscode.window.showErrorMessage === "function") { + vscode.window.showErrorMessage( + "Roo Code is still initializing. Please wait a moment and try again, or restart VS Code if the issue persists.", + ) + } return undefined } + return visibleProvider } @@ -74,8 +101,8 @@ export const registerCommands = (options: RegisterCommandOptions) => { const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOptions): Record => ({ activationCompleted: () => {}, - accountButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + accountButtonClicked: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return @@ -86,7 +113,7 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt visibleProvider.postMessageToWebview({ type: "action", action: "accountButtonClicked" }) }, plusButtonClicked: async () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return @@ -101,8 +128,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt // This ensures the focus happens after the view has switched await visibleProvider.postMessageToWebview({ type: "action", action: "focusInput" }) }, - mcpButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + mcpButtonClicked: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return @@ -112,8 +139,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) }, - promptsButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + promptsButtonClicked: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return @@ -129,8 +156,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt return openClineInNewTab({ context, outputChannel }) }, openInNewTab: () => openClineInNewTab({ context, outputChannel }), - settingsButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + settingsButtonClicked: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return @@ -142,8 +169,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt // Also explicitly post the visibility message to trigger scroll reliably visibleProvider.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) }, - historyButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + historyButtonClicked: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return @@ -153,8 +180,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt visibleProvider.postMessageToWebview({ type: "action", action: "historyButtonClicked" }) }, - marketplaceButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + marketplaceButtonClicked: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) return visibleProvider.postMessageToWebview({ type: "action", action: "marketplaceButtonClicked" }) }, @@ -178,7 +205,7 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt await promptForCustomStoragePath() }, importSettings: async (filePath?: string) => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return } @@ -212,8 +239,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt outputChannel.appendLine(`Error focusing panel: ${error}`) } }, - acceptInput: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + acceptInput: async () => { + const visibleProvider = await getVisibleProviderOrLog(outputChannel) if (!visibleProvider) { return diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index e6817e1825..33845d5bf3 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -469,15 +469,26 @@ export class ClineProvider // If no visible provider, try to show the sidebar view if (!visibleProvider) { - await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`) - // Wait briefly for the view to become visible - await delay(100) - visibleProvider = ClineProvider.getVisibleInstance() + try { + await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`) + // Wait a bit longer for the view to become visible and initialize + await delay(500) + visibleProvider = ClineProvider.getVisibleInstance() + + // If still not visible, wait a bit more as initialization might be slow + if (!visibleProvider) { + await delay(500) + visibleProvider = ClineProvider.getVisibleInstance() + } + } catch (error) { + console.error(`Failed to activate Roo Code sidebar: ${error}`) + } } - // If still no visible provider, return + // If still no visible provider, return undefined if (!visibleProvider) { - return + console.warn("Could not get or create a visible ClineProvider instance") + return undefined } return visibleProvider