diff --git a/cli/src/agents/base.ts b/cli/src/agents/base.ts index d6411d4..f672580 100644 --- a/cli/src/agents/base.ts +++ b/cli/src/agents/base.ts @@ -293,6 +293,9 @@ export class ACP { env: { ...process.env, ...(config.env ?? {}) }, stdio: ["pipe", "pipe", "pipe"], shell: useShell, + // A shell-backed spawn allocates its own console window on Windows, + // which flashes on screen and can steal focus. No-op elsewhere. + windowsHide: true, }, ); diff --git a/cli/src/agents/codex-readonly.ts b/cli/src/agents/codex-readonly.ts index 150b6b5..dd7fa37 100644 --- a/cli/src/agents/codex-readonly.ts +++ b/cli/src/agents/codex-readonly.ts @@ -64,6 +64,7 @@ export async function readCodexThread( const child = spawn(command, ["app-server", "--stdio"], { cwd, stdio: ["pipe", "pipe", "pipe"], + windowsHide: true, }); let stderr = ""; diff --git a/cli/src/filesystem/index.ts b/cli/src/filesystem/index.ts index 5b5f8df..ccf7327 100644 --- a/cli/src/filesystem/index.ts +++ b/cli/src/filesystem/index.ts @@ -711,6 +711,7 @@ export function initFilesystemHandler(conn: Connection, rootDir: string) { cwd: gitRoot, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], // silence stderr + windowsHide: true, }); } catch { // File might not exist in HEAD (new file), return empty diff --git a/cli/src/notify.ts b/cli/src/notify.ts index f31b820..b6903a7 100644 --- a/cli/src/notify.ts +++ b/cli/src/notify.ts @@ -17,16 +17,21 @@ function escapePowerShell(s: string) { } function run(cmd: string, args: string[]) { - execFile(cmd, args, { timeout: 5000 }, (error, _stdout, stderr) => { - if (error) { - logger.debug(`${cmd} failed`, error); - return; - } + execFile( + cmd, + args, + { timeout: 5000, windowsHide: true }, + (error, _stdout, stderr) => { + if (error) { + logger.debug(`${cmd} failed`, error); + return; + } - if (stderr?.trim()) { - logger.debug(`${cmd} stderr: ${stderr.trim()}`); - } - }); + if (stderr?.trim()) { + logger.debug(`${cmd} stderr: ${stderr.trim()}`); + } + }, + ); } export function notify({ title, body }: NotifyArgs): boolean { diff --git a/cli/src/ports.ts b/cli/src/ports.ts index fccb8c5..a61d87d 100644 --- a/cli/src/ports.ts +++ b/cli/src/ports.ts @@ -111,6 +111,7 @@ export function initPortsHandler(conn: Connection) { output = execSync("netstat -ano | findstr LISTENING", { encoding: "utf-8", timeout: 5000, + windowsHide: true, }); const lines = output.trim().split("\n"); @@ -211,7 +212,10 @@ export function initPortsHandler(conn: Connection) { } } } else if (platform === "win32") { - const result = spawnSync("netstat", ["-ano"], { encoding: "utf-8" }); + const result = spawnSync("netstat", ["-ano"], { + encoding: "utf-8", + windowsHide: true, + }); const lines = (result.stdout || "").trim().split("\n"); for (const line of lines) { if (!line.includes("LISTENING")) continue; @@ -221,7 +225,9 @@ export function initPortsHandler(conn: Connection) { const p = parseInt(parts[4], 10); if (localAddr.endsWith(`:${portNum}`)) { if (pid === null) pid = p; - spawnSync("taskkill", ["/F", "/PID", String(p)]); + spawnSync("taskkill", ["/F", "/PID", String(p)], { + windowsHide: true, + }); } } } diff --git a/cli/src/update-and-start.ts b/cli/src/update-and-start.ts index 8ce2898..e93dc14 100644 --- a/cli/src/update-and-start.ts +++ b/cli/src/update-and-start.ts @@ -34,6 +34,7 @@ export function isShellularInstalledGlobally(): Promise { const child = spawn("npm", ["list", "-g", "shellular", "--depth=0"], { stdio: "ignore", shell: process.platform === "win32", + windowsHide: true, }); child.on("close", (code) => { diff --git a/cli/src/update-runner.ts b/cli/src/update-runner.ts index 71d711a..0bd0801 100644 --- a/cli/src/update-runner.ts +++ b/cli/src/update-runner.ts @@ -54,6 +54,7 @@ export async function runSelfUpdate(): Promise { stdio: ["ignore", logFd, logFd], cwd: config.SHELLULAR_DIR, env: process.env, + windowsHide: true, }); child.unref(); } else { diff --git a/cli/src/utils.ts b/cli/src/utils.ts index 0225d57..0c93fae 100644 --- a/cli/src/utils.ts +++ b/cli/src/utils.ts @@ -91,6 +91,7 @@ export function commandExists(command: string): boolean { const result = spawnSync("where", [command], { stdio: "ignore", shell: false, + windowsHide: true, }); return result.status === 0; }