From 76d112ce4aff74efe3a13d869e12990bd9ecf72a Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Thu, 4 Dec 2025 15:45:54 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20fix:=20prevent=20Windows=20bash?= =?UTF-8?q?=20windows=20from=20stealing=20focus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Windows, when spawning bash processes (via Git Bash or WSL), the default behavior creates visible console windows that steal focus. Add windowsHide: true to all spawn() calls that run background bash or ssh processes. This prevents the console windows from appearing. The terminal service spawn calls intentionally remain visible since they're meant to open user-facing terminal windows. Fixed locations: - LocalBaseRuntime.ts: exec() and runInitHook() - bashExecutionService.ts: executeStreaming() - SSHRuntime.ts: exec(), execSSHCommand(), and bundle creation _Generated with mux_ --- src/node/runtime/LocalBaseRuntime.ts | 4 ++++ src/node/runtime/SSHRuntime.ts | 12 ++++++++++-- src/node/services/bashExecutionService.ts | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/node/runtime/LocalBaseRuntime.ts b/src/node/runtime/LocalBaseRuntime.ts index bc3dce26c6..a4a57d10e3 100644 --- a/src/node/runtime/LocalBaseRuntime.ts +++ b/src/node/runtime/LocalBaseRuntime.ts @@ -91,6 +91,8 @@ export abstract class LocalBaseRuntime implements Runtime { // NOTE: detached:true does NOT cause bash to wait for background jobs when using 'exit' event // instead of 'close' event. The 'exit' event fires when bash exits, ignoring background children. detached: true, + // Prevent console window from appearing on Windows (WSL bash spawns steal focus otherwise) + windowsHide: true, }); // Wrap in DisposableProcess for automatic cleanup @@ -373,6 +375,8 @@ export abstract class LocalBaseRuntime implements Runtime { ...process.env, ...getInitHookEnv(projectPath, runtimeType), }, + // Prevent console window from appearing on Windows + windowsHide: true, }); proc.stdout.on("data", (data: Buffer) => { diff --git a/src/node/runtime/SSHRuntime.ts b/src/node/runtime/SSHRuntime.ts index 9c624f10df..45d60e5dac 100644 --- a/src/node/runtime/SSHRuntime.ts +++ b/src/node/runtime/SSHRuntime.ts @@ -185,6 +185,8 @@ export class SSHRuntime implements Runtime { // Spawn ssh command const sshProcess = spawn("ssh", sshArgs, { stdio: ["pipe", "pipe", "pipe"], + // Prevent console window from appearing on Windows + windowsHide: true, }); // Wrap in DisposableProcess for automatic cleanup @@ -408,7 +410,10 @@ export class SSHRuntime implements Runtime { sshArgs.push(this.config.host, command); return new Promise((resolve, reject) => { - const proc = spawn("ssh", sshArgs); + const proc = spawn("ssh", sshArgs, { + // Prevent console window from appearing on Windows + windowsHide: true, + }); let stdout = ""; let stderr = ""; let timedOut = false; @@ -591,7 +596,10 @@ export class SSHRuntime implements Runtime { log.debug(`Creating bundle: ${command}`); const bashPath = getBashPath(); - const proc = spawn(bashPath, ["-c", command]); + const proc = spawn(bashPath, ["-c", command], { + // Prevent console window from appearing on Windows + windowsHide: true, + }); const cleanup = streamProcessToLogger(proc, initLogger, { logStdout: false, diff --git a/src/node/services/bashExecutionService.ts b/src/node/services/bashExecutionService.ts index 9f46c455c2..62199a7f6e 100644 --- a/src/node/services/bashExecutionService.ts +++ b/src/node/services/bashExecutionService.ts @@ -138,6 +138,8 @@ export class BashExecutionService { // When bash spawns background processes, detached:true allows killing // the entire group via process.kill(-pid) detached: config.detached ?? true, + // Prevent console window from appearing on Windows (WSL bash spawns steal focus otherwise) + windowsHide: true, }); log.debug(`BashExecutionService: Spawned process with PID ${child.pid ?? "unknown"}`);