diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0f7a465..ca6334475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ - Status: add provider usage snapshots to `/status`, `clawdbot status --usage`, and the macOS menu bar. - Build: fix macOS packaging QR smoke test for the bun-compiled relay. Thanks @dbhurley for PR #358. - Browser: fix `browser snapshot`/`browser act` timeouts under Bun by patching Playwright’s CDP WebSocket selection. Thanks @azade-c for PR #307. +- Browser: detect Chrome/Chromium installs on Windows for the browser tool. Thanks @mrdbstn for PR #439. - Browser: add `--browser-profile` flag and honor profile in tabs routes + browser tool. Thanks @jamesgroat for PR #324. - Gmail: include tailscale command exit codes/output when hook setup fails (easier debugging). - Telegram: stop typing after tool results. Thanks @AbhisekBasu1 for PR #322. diff --git a/src/browser/chrome.test.ts b/src/browser/chrome.test.ts index ddcea3a7d..5fbeae69f 100644 --- a/src/browser/chrome.test.ts +++ b/src/browser/chrome.test.ts @@ -136,6 +136,7 @@ describe("browser chrome profile decoration", () => { describe("browser chrome helpers", () => { afterEach(() => { + vi.unstubAllEnvs(); vi.unstubAllGlobals(); vi.restoreAllMocks(); }); @@ -157,6 +158,7 @@ describe("browser chrome helpers", () => { }); it("picks the first existing Chrome candidate on Windows", () => { + vi.stubEnv("LOCALAPPDATA", "C:\\Users\\Test\\AppData\\Local"); const exists = vi .spyOn(fs, "existsSync") .mockImplementation((p) => String(p).includes("Chrome SxS")); @@ -167,8 +169,7 @@ describe("browser chrome helpers", () => { }); it("finds Chrome in Program Files on Windows", () => { - // Use path.join to match how the function builds paths (cross-platform) - const marker = path.join("Program Files", "Google", "Chrome"); + const marker = path.win32.join("Program Files", "Google", "Chrome"); const exists = vi .spyOn(fs, "existsSync") .mockImplementation((p) => String(p).includes(marker)); diff --git a/src/browser/chrome.ts b/src/browser/chrome.ts index 9979f803b..f8bf48eb2 100644 --- a/src/browser/chrome.ts +++ b/src/browser/chrome.ts @@ -109,57 +109,61 @@ export function findChromeExecutableWindows(): BrowserExecutable | null { const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)"; - const candidates: Array = [ + const joinWin = path.win32.join; + const candidates: Array = []; + + if (localAppData) { // Chrome Canary (user install) - { + candidates.push({ kind: "canary", - path: path.join( + path: joinWin( localAppData, "Google", "Chrome SxS", "Application", "chrome.exe", ), - }, + }); // Chromium (user install) - { + candidates.push({ kind: "chromium", - path: path.join(localAppData, "Chromium", "Application", "chrome.exe"), - }, + path: joinWin(localAppData, "Chromium", "Application", "chrome.exe"), + }); // Chrome (user install) - { + candidates.push({ kind: "chrome", - path: path.join( + path: joinWin( localAppData, "Google", "Chrome", "Application", "chrome.exe", ), - }, - // Chrome (system install, 64-bit) - { - kind: "chrome", - path: path.join( - programFiles, - "Google", - "Chrome", - "Application", - "chrome.exe", - ), - }, - // Chrome (system install, 32-bit on 64-bit Windows) - { - kind: "chrome", - path: path.join( - programFilesX86, - "Google", - "Chrome", - "Application", - "chrome.exe", - ), - }, - ]; + }); + } + + // Chrome (system install, 64-bit) + candidates.push({ + kind: "chrome", + path: joinWin( + programFiles, + "Google", + "Chrome", + "Application", + "chrome.exe", + ), + }); + // Chrome (system install, 32-bit on 64-bit Windows) + candidates.push({ + kind: "chrome", + path: joinWin( + programFilesX86, + "Google", + "Chrome", + "Application", + "chrome.exe", + ), + }); for (const candidate of candidates) { if (exists(candidate.path)) return candidate;