[BUG] IDE extension: retained editor selection is never invalidated when the document closes, and leaks into new conversations
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The IDE extension's current-file/selection chip in the chat input keeps showing a file that is no longer open in the editor, and that stale value leaks into brand-new conversations.
The retained selection lives in extension-host module state and is only ever invalidated under two conditions. From extension.js (v2.1.251):
function XT0($) { return $ === 0 ? "clear" : "retain" }
window.onDidChangeActiveTextEditor(async (X) => {
if (!X) {
if (XT0(window.visibleTextEditors.length) === "retain") return;
RU.bump(); yz = void 0; tM = void 0; Q.fire(void 0); return;
}
...
})
workspace.onDidCloseTextDocument((X) => {
if (!xU(X.uri.scheme)) J.fire({ filePath: X.fileName, uri: X.uri.toString() });
if (X.uri.toString() !== tM) return;
RU.bump(); yz = void 0; tM = void 0; Q.fire(void 0);
})
So the cached selection yz clears only when (a) the active editor becomes undefined at a moment when visibleTextEditors.length === 0, or (b) onDidCloseTextDocument fires with a URI matching the retained one.
Neither reliably happens in normal use:
- Clicking into the Claude tab fires
onDidChangeActiveTextEditor(undefined)and takes the"retain"branch. That part is intentional and correct — you don't want to lose your selection by focusing the chat. - But there is no expiry or revalidation afterwards. If the document is later closed while the active editor is already
undefined, condition (a) never re-evaluates, and condition (b) depends on the host actually disposing theTextDocument— which VS Code/Cursor defer while anything still holds a reference (language servers commonly do). The result is a cached selection that outlives the editor indefinitely.
The leak into new conversations follows from the same state being the source of truth for a fresh tab. The host answers get_current_selection straight from that retained value:
if ($.request.type === "get_current_selection")
return { type: "get_current_selection_response", selection: this.getCurrentSelection() };
and the webview re-applies it to the active session on every visibility change:
G2(() => {
let G = this.comms.connection.value?.isVisible.value;
if (G && Z === !1) _z(() => {
this.activeSession.value?.applySelectionUpdate(this.context.currentSelection.value)
});
Z = G
})
with the include toggle re-initialising to on (let [M, _] = Y1(!0) — useState(true), not persisted). So "New Conversation" / ⇧⌘Esc is not inheriting from the previous conversation — both conversations are reading one stale host-level value, and each new one re-enables sending it.
Net effect: a file the user closed long ago is silently attached to every prompt of every new conversation, and the only remedy is a window reload or an unnoticed per-conversation click.
What Should Happen?
The retained selection should be invalidated when the editor it refers to is no longer open. Concretely, any of:
- Revalidate on read — before answering
get_current_selection(and before re-applying on visibility change), confirm the retained URI is still amongwindow.visibleTextEditors/window.tabGroups, and drop it if not. This fixes the case whereonDidCloseTextDocumentnever fires. - Re-evaluate the
"retain"decision ononDidChangeVisibleTextEditors, not only ononDidChangeActiveTextEditor, so closing the last editor while focus is in the chat still clears. - Don't seed a brand-new conversation from a selection the user never made in that conversation, or at least default
includeSelectionto off when the retained selection predates the conversation.
Related: #24726 requests a persistent setting to disable auto-attach entirely. That's a separate ask — this report is that the existing behaviour is incorrect even for users who want auto-attach, because the attached file is simply wrong.
Steps to Reproduce
- In Cursor (or VS Code), open the Claude Code extension panel and open some source file in an editor tab. The chip in the chat input shows that filename.
- Click into the Claude Code tab so no text editor is active.
- Close the file's editor tab, leaving no text editor visible (e.g. only webview tabs such as Simple Browser and the Claude tabs remain).
- Observe the chip still shows the closed file, with tooltip
Showing Claude your current file selection (<filename>). - Press ⇧⌘Esc (
Claude Code: Open in New Tab) or runClaude Code: New Conversation. - The brand-new conversation shows the same closed file in the chip, toggled on, and sends it as context.
Workaround: Developer: Reload Window resets the host-side cache. Reopening and re-closing the file also clears it when the close event fires.
Is this a regression?
No / Not sure
Claude Code Version
2.1.251 (Claude Code)
Platform
IDE extension (VS Code / Cursor)
Operating System
macOS 26.5 (arm64)
Additional Context
- Extension:
anthropic.claude-code-2.1.251-darwin-arm64 - Host: Cursor 3.18.9 (arm64), extension
engines.vscode: ^1.94.0 - Code references are from the shipped
extension.jsandwebview/index.jsin that extension build; identifiers are minified, so names likeXT0,yz,tMwill differ across builds. - There is no setting to work around this: the extension contributes 15
claudeCode.*settings and none affects selection attachment.