Windows: a console window opens and steals keyboard focus while typing an @-mention in the Claude panel (VS Code extension)

Status Open
Reported on v2.1.241
Maintainer reply None cached
Activity 0 comments · opened Aug 23, 2026

<!-- SUGGESTED TITLE:
Windows: a console window opens and steals keyboard focus while typing an @-mention in the Claude panel (VS Code extension)
-->

Summary

On Windows, typing an @-mention in the Claude Code panel pops up a console window that takes the foreground, swallowing the next keystrokes. It happens repeatedly while typing, because the file-search helper spawns rg.exe per invocation.

The cause is a single missing option: the execFile call that runs ripgrep for @-mention / fuzzy file search does not pass windowsHide: true. Node defaults that option to false, and the VS Code extension host is a GUI process with no console to inherit, so Windows allocates a brand-new visible console for the child.

This is specific to the VS Code extension. The same call from the terminal CLI inherits the terminal's existing console and is invisible.

Environment

| | |
|---|---|
| Extension | anthropic.claude-code 2.1.241 (win32-x64) |
| VS Code | 1.134.0 (x64) |
| OS | Windows 11 Pro, build 10.0.26200 |
| Default terminal application | Windows Terminal (Windows 11 default) |
| Mode | Native panel (not claudeCode.useTerminal) |

Steps to reproduce

  1. On Windows 11 with Windows Terminal as the default terminal application (Settings → System → For developers → Terminal), open a reasonably large repository in VS Code.
  2. Open the Claude Code panel.
  3. Type @ in the prompt box, then keep typing a few characters of a filename.
  4. Watch the desktop, not the panel.

Actual: one or more console windows open, sit on top of the editor for roughly two seconds each, take the foreground, and close. Keystrokes typed during that window land in the console instead of the prompt box. With Windows Terminal as the default, the popup is a full Terminal window, not a brief flash.

Expected: the file search runs invisibly. No window, no focus change.

Measurement

Runtime probe, measured 2026-08-23 on Windows 11 Pro 26200. A parent process was created with DETACHED_PROCESS so that GetConsoleWindow() == 0, reproducing the extension host's state, and it spawned a console-subsystem child twice:

NO windowsHide (flags = 0)              childPid=66360   hwnd=0x3610D4   visible=True
windowsHide = true (CREATE_NO_WINDOW)   childPid=78716   hwnd=0x0        visible=False

windowsHide: true is what libuv maps to CREATE_NO_WINDOW + STARTF_USESHOWWINDOW / SW_HIDE. Without it, the console window is created and shown.

Severity depends on the default terminal application, also measured 2026-08-23:

| Default terminal application | Window lifetime | Took foreground |
|---|---|---|
| Windows Terminal (Windows 11 default) | 2340 ms | 8 / 8 samples |
| Legacy Console Host (conhost.exe) | 30 ms | 0 / 3 samples |

So on a stock Windows 11 install this is a two-second focus theft per search, not the sub-frame flash it is often described as.

Where it is

Static analysis of the shipped, minified extension.js from the 2.1.241 win32-x64 VSIX (2,947,529 bytes) — read from the bundle, not verified at runtime by symbol. Names are post-minification; the character offset is a pointer to the source location, not a patch target.

The @-mention file search builds ripgrep arguments and calls a helper:

// ~char 2807944
async function JMe(e, t, r) {
  let n = ["--files", "--follow", "--hidden"];
  if (!(Gn("respectGitIgnore") ?? !0)) n.push("--no-ignore-vcs");
  // ...builds `--glob !<pattern>` entries from search.exclude / files.exclude
  let o = await wvr(n, t);
  // ...fuzzy-matches
}

and the helper spawns ripgrep with no windowsHide:

// ~char 2806166  <-- the defect
async function wvr(e, t) {
  return new Promise((r, n) => {
    SM.execFile(Svr(), e, { cwd: t, maxBuffer: xvr, timeout: Evr }, (i, o) => { /* ... */ })
  })
}

Svr() resolves to rg.exe on Windows, and is a memoised probe that itself runs an unhidden execFileSync (rg --version) at ~char 2806047 — one extra window on the first search of a session.

Why the VS Code extension and not the CLI

A console-subsystem executable started from a process that has a console inherits it and creates no window. The terminal CLI always has one. The VS Code extension host is a GUI process with GetConsoleWindow() == 0, so Windows has to create a new console for the child — and on Windows 11 the console host is Windows Terminal, which opens as a real, focus-taking window.

This is why the same code is silent under the CLI entrypoint and loud under the extension. It also means the extension cannot rely on the CLI's behaviour as evidence that a call site is safe.

Fix

One option on one call:

SM.execFile(Svr(), e, { cwd: t, maxBuffer: xvr, timeout: Evr, windowsHide: true }, ...)

and the same on the --version probe at ~char 2806047.

There is no user-side workaround: no extension setting and no environment variable in the bundle sets windowsHide, and processWrapper / CLAUDE_CODE_PROCESS_WRAPPER covers only the background-agent supervisor and the sessions and workers it hosts — not these helper spawns.

Related

  • #87860 — same call site, different defect: the @-mention search spawns unbounded ripgrep processes with no debounce, cache or cancellation (605 processes in ~2 min, observed on macOS). The two compound on Windows: every one of those processes is also a console window. Fixing #87860 would reduce the number of windows; only windowsHide removes them.
  • There are many reports of console windows on Windows from the CLI side (#14828, #73709, #73901, #87394 and others). This report is deliberately narrower: it is one call site in the VS Code extension, triggered by typing, with a one-line fix.

View original on GitHub ↗