From 91158c07bec26d08cb87c0f17c0337748c8b05ff Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 11 Jun 2025 19:56:33 -0600 Subject: [PATCH] Fix chatbox losing focus during automated workflows (#4574) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add preserveFocus option to openFile() function to prevent focus theft - Implement automated workflow detection based on task streaming state and auto-approval settings - Preserve chat focus when AI is actively processing to prevent accidental text insertion - Update file mention handling to respect automated workflow state - Add comments to clarify user-initiated vs automated file opening 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/core/mentions/index.ts | 17 ++++++++++++++++- src/core/webview/webviewMessageHandler.ts | 21 ++++++++++++++++++++- src/integrations/misc/open-file.ts | 2 ++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/core/mentions/index.ts b/src/core/mentions/index.ts index 8ae4f7f131..3842f6ea44 100644 --- a/src/core/mentions/index.ts +++ b/src/core/mentions/index.ts @@ -10,6 +10,7 @@ import { getCommitInfo, getWorkingState } from "../../utils/git" import { getWorkspacePath } from "../../utils/path" import { openFile } from "../../integrations/misc/open-file" +import { ClineProvider } from "../webview/ClineProvider" import { extractTextFromFile } from "../../integrations/misc/extract-text" import { diagnosticsToProblemsString } from "../../integrations/diagnostics" @@ -36,7 +37,21 @@ export async function openMention(mention?: string): Promise { if (mention.endsWith("/")) { vscode.commands.executeCommand("revealInExplorer", vscode.Uri.file(absPath)) } else { - openFile(absPath) + // Check if we're in an automated workflow when opening file mentions + const visibleProvider = ClineProvider.getVisibleInstance() + const currentCline = visibleProvider?.getCurrentCline() + const autoApprovalEnabled = visibleProvider?.contextProxy.getValue("autoApprovalEnabled") + + // Detect automated workflow: AI is actively processing, streaming, or auto-approval is enabled + // and there's an active task that hasn't completed reading/processing + const isInAutomatedWorkflow = + currentCline && + (currentCline.isStreaming || + currentCline.isWaitingForFirstChunk || + (autoApprovalEnabled && !currentCline.didCompleteReadingStream) || + (autoApprovalEnabled && currentCline.presentAssistantMessageLocked)) + + openFile(absPath, { preserveFocus: !!isInAutomatedWorkflow }) } } else if (mention === "problems") { vscode.commands.executeCommand("workbench.actions.view.problems") diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 6568b4aaee..bc562b9847 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -426,7 +426,23 @@ export const webviewMessageHandler = async ( openImage(message.text!) break case "openFile": - openFile(message.text!, message.values as { create?: boolean; content?: string; line?: number }) + // Check if we're in an automated workflow (AI is streaming/processing) + const currentCline = provider.getCurrentCline() + const autoApprovalEnabled = getGlobalState("autoApprovalEnabled") + + // Detect automated workflow: AI is actively processing, streaming, or auto-approval is enabled + // and there's an active task that hasn't completed reading/processing + const isInAutomatedWorkflow = + currentCline && + (currentCline.isStreaming || + currentCline.isWaitingForFirstChunk || + (autoApprovalEnabled && !currentCline.didCompleteReadingStream) || + (autoApprovalEnabled && currentCline.presentAssistantMessageLocked)) + + openFile(message.text!, { + ...(message.values as { create?: boolean; content?: string; line?: number }), + preserveFocus: !!isInAutomatedWorkflow, + }) break case "openMention": openMention(message.text) @@ -481,6 +497,7 @@ export const webviewMessageHandler = async ( const customModesFilePath = await provider.customModesManager.getCustomModesFilePath() if (customModesFilePath) { + // User-initiated settings opening, keep focus openFile(customModesFilePath) } @@ -490,6 +507,7 @@ export const webviewMessageHandler = async ( const mcpSettingsFilePath = await provider.getMcpHub()?.getMcpSettingsFilePath() if (mcpSettingsFilePath) { + // User-initiated settings opening, keep focus openFile(mcpSettingsFilePath) } @@ -513,6 +531,7 @@ export const webviewMessageHandler = async ( await fs.writeFile(mcpPath, JSON.stringify({ mcpServers: {} }, null, 2)) } + // User-initiated settings opening, keep focus await openFile(mcpPath) } catch (error) { vscode.window.showErrorMessage(t("mcp:errors.create_json", { error: `${error}` })) diff --git a/src/integrations/misc/open-file.ts b/src/integrations/misc/open-file.ts index 9318e23766..30744958d4 100644 --- a/src/integrations/misc/open-file.ts +++ b/src/integrations/misc/open-file.ts @@ -24,6 +24,7 @@ interface OpenFileOptions { create?: boolean content?: string line?: number + preserveFocus?: boolean } export async function openFile(filePath: string, options: OpenFileOptions = {}) { @@ -148,6 +149,7 @@ export async function openFile(filePath: string, options: OpenFileOptions = {}) await vscode.window.showTextDocument(document, { preview: false, selection, + preserveFocus: options.preserveFocus, }) } catch (error) { if (error instanceof Error) {