diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 14334fddd..c09972049 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed the browser tool executable probe launching the user's installed GUI Chromium on Windows: the `--version` version probe from ecb22957 was Linux-scoped but ran for every platform candidate, so on Windows it could hand off to a running `chrome.exe`, open a normal browser window, then reject the candidate and fall back to cached Chrome for Testing. The probe is now confined to Linux ([#8445](https://github.com/can1357/oh-my-pi/issues/8445)). + ## [17.3.0] - 2026-08-13 ### Breaking Changes diff --git a/packages/coding-agent/src/tools/browser/launch.ts b/packages/coding-agent/src/tools/browser/launch.ts index 63afc8e71..4c10635e1 100644 --- a/packages/coding-agent/src/tools/browser/launch.ts +++ b/packages/coding-agent/src/tools/browser/launch.ts @@ -204,6 +204,15 @@ function isExecutableFile(p: string): boolean { async function isChromiumExecutable(p: string): Promise { if (!isExecutableFile(p)) return false; + // The version probe below launches the candidate. It exists to reject + // non-Chromium `chrome`/`chromium` wrapper scripts that appear on a Linux + // PATH (ecb22957, "validate Linux browser executables"). On Windows and + // macOS the candidates are fixed GUI application paths, not PATH wrappers, + // and executing them is harmful: a GUI `chrome.exe --version` does not print + // to a detached stdout and can hand off to the user's running instance, + // opening/activating a normal browser window (#8445). Confine the probe to + // Linux and trust the executable-file check elsewhere. + if (process.platform !== "linux") return true; try { const probeTimeoutMs = 3000; const proc = Bun.spawn([p, "--version"], { diff --git a/packages/coding-agent/test/tools/browser-launch.test.ts b/packages/coding-agent/test/tools/browser-launch.test.ts index c23a834c3..c29b7f6f6 100644 --- a/packages/coding-agent/test/tools/browser-launch.test.ts +++ b/packages/coding-agent/test/tools/browser-launch.test.ts @@ -138,6 +138,30 @@ describe("browser executable selection", () => { } }); + it("does not launch the candidate to probe its version on Windows (#8445)", async () => { + const tempDir = TempDir.createSync("@browser-probe-win32-"); + try { + const marker = path.join(tempDir.path(), "gui-launched"); + const fakeChrome = path.join(tempDir.path(), "chrome.exe"); + // A GUI chrome.exe handoff: executing it has a side effect (this marker) + // but prints nothing a console version probe would accept. + await Bun.write(fakeChrome, `#!/bin/sh\ntouch "${marker}"\necho "activating existing window"\n`); + fs.chmodSync(fakeChrome, 0o755); + + const platformDescriptor = Object.getOwnPropertyDescriptor(process, "platform"); + Object.defineProperty(process, "platform", { value: "win32", configurable: true }); + try { + await expect(chromiumExecutableProbeForTest(fakeChrome)).resolves.toBe(true); + } finally { + if (platformDescriptor) Object.defineProperty(process, "platform", platformDescriptor); + } + + expect(fs.existsSync(marker)).toBe(false); + } finally { + await tempDir.remove(); + } + }); + it("honors PUPPETEER_EXECUTABLE_PATH before a detected Windows system Chrome", async () => { const tempDir = TempDir.createSync("@browser-executable-"); try {