Skip to content

Commit 91158c0

Browse files
hannesrudolphclaude
andcommitted
Fix chatbox losing focus during automated workflows (#4574)
- 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 <[email protected]>
1 parent 395f55b commit 91158c0

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

src/core/mentions/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getCommitInfo, getWorkingState } from "../../utils/git"
1010
import { getWorkspacePath } from "../../utils/path"
1111

1212
import { openFile } from "../../integrations/misc/open-file"
13+
import { ClineProvider } from "../webview/ClineProvider"
1314
import { extractTextFromFile } from "../../integrations/misc/extract-text"
1415
import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
1516

@@ -36,7 +37,21 @@ export async function openMention(mention?: string): Promise<void> {
3637
if (mention.endsWith("/")) {
3738
vscode.commands.executeCommand("revealInExplorer", vscode.Uri.file(absPath))
3839
} else {
39-
openFile(absPath)
40+
// Check if we're in an automated workflow when opening file mentions
41+
const visibleProvider = ClineProvider.getVisibleInstance()
42+
const currentCline = visibleProvider?.getCurrentCline()
43+
const autoApprovalEnabled = visibleProvider?.contextProxy.getValue("autoApprovalEnabled")
44+
45+
// Detect automated workflow: AI is actively processing, streaming, or auto-approval is enabled
46+
// and there's an active task that hasn't completed reading/processing
47+
const isInAutomatedWorkflow =
48+
currentCline &&
49+
(currentCline.isStreaming ||
50+
currentCline.isWaitingForFirstChunk ||
51+
(autoApprovalEnabled && !currentCline.didCompleteReadingStream) ||
52+
(autoApprovalEnabled && currentCline.presentAssistantMessageLocked))
53+
54+
openFile(absPath, { preserveFocus: !!isInAutomatedWorkflow })
4055
}
4156
} else if (mention === "problems") {
4257
vscode.commands.executeCommand("workbench.actions.view.problems")

src/core/webview/webviewMessageHandler.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,23 @@ export const webviewMessageHandler = async (
426426
openImage(message.text!)
427427
break
428428
case "openFile":
429-
openFile(message.text!, message.values as { create?: boolean; content?: string; line?: number })
429+
// Check if we're in an automated workflow (AI is streaming/processing)
430+
const currentCline = provider.getCurrentCline()
431+
const autoApprovalEnabled = getGlobalState("autoApprovalEnabled")
432+
433+
// Detect automated workflow: AI is actively processing, streaming, or auto-approval is enabled
434+
// and there's an active task that hasn't completed reading/processing
435+
const isInAutomatedWorkflow =
436+
currentCline &&
437+
(currentCline.isStreaming ||
438+
currentCline.isWaitingForFirstChunk ||
439+
(autoApprovalEnabled && !currentCline.didCompleteReadingStream) ||
440+
(autoApprovalEnabled && currentCline.presentAssistantMessageLocked))
441+
442+
openFile(message.text!, {
443+
...(message.values as { create?: boolean; content?: string; line?: number }),
444+
preserveFocus: !!isInAutomatedWorkflow,
445+
})
430446
break
431447
case "openMention":
432448
openMention(message.text)
@@ -481,6 +497,7 @@ export const webviewMessageHandler = async (
481497
const customModesFilePath = await provider.customModesManager.getCustomModesFilePath()
482498

483499
if (customModesFilePath) {
500+
// User-initiated settings opening, keep focus
484501
openFile(customModesFilePath)
485502
}
486503

@@ -490,6 +507,7 @@ export const webviewMessageHandler = async (
490507
const mcpSettingsFilePath = await provider.getMcpHub()?.getMcpSettingsFilePath()
491508

492509
if (mcpSettingsFilePath) {
510+
// User-initiated settings opening, keep focus
493511
openFile(mcpSettingsFilePath)
494512
}
495513

@@ -513,6 +531,7 @@ export const webviewMessageHandler = async (
513531
await fs.writeFile(mcpPath, JSON.stringify({ mcpServers: {} }, null, 2))
514532
}
515533

534+
// User-initiated settings opening, keep focus
516535
await openFile(mcpPath)
517536
} catch (error) {
518537
vscode.window.showErrorMessage(t("mcp:errors.create_json", { error: `${error}` }))

src/integrations/misc/open-file.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface OpenFileOptions {
2424
create?: boolean
2525
content?: string
2626
line?: number
27+
preserveFocus?: boolean
2728
}
2829

2930
export async function openFile(filePath: string, options: OpenFileOptions = {}) {
@@ -148,6 +149,7 @@ export async function openFile(filePath: string, options: OpenFileOptions = {})
148149
await vscode.window.showTextDocument(document, {
149150
preview: false,
150151
selection,
152+
preserveFocus: options.preserveFocus,
151153
})
152154
} catch (error) {
153155
if (error instanceof Error) {

0 commit comments

Comments
 (0)