refactor(browser): share chrome resolution helpers

This commit is contained in:
Peter Steinberger
2026-01-08 02:18:43 +00:00
parent 697f78e06b
commit 0d34f330b8
2 changed files with 48 additions and 19 deletions

View File

@@ -10,6 +10,7 @@ import {
findChromeExecutableMac,
findChromeExecutableWindows,
isChromeReachable,
resolveBrowserExecutableForPlatform,
stopClawdChrome,
} from "./chrome.js";
import {
@@ -185,6 +186,29 @@ describe("browser chrome helpers", () => {
exists.mockRestore();
});
it("resolves Windows executables without LOCALAPPDATA", () => {
vi.stubEnv("LOCALAPPDATA", "");
vi.stubEnv("ProgramFiles", "C:\\Program Files");
vi.stubEnv("ProgramFiles(x86)", "C:\\Program Files (x86)");
const marker = path.win32.join(
"Program Files",
"Google",
"Chrome",
"Application",
"chrome.exe",
);
const exists = vi
.spyOn(fs, "existsSync")
.mockImplementation((p) => String(p).includes(marker));
const exe = resolveBrowserExecutableForPlatform(
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
"win32",
);
expect(exe?.kind).toBe("chrome");
expect(exe?.path).toMatch(/chrome\.exe$/);
exists.mockRestore();
});
it("reports reachability based on /json/version", async () => {
vi.stubGlobal(
"fetch",

View File

@@ -41,6 +41,16 @@ function exists(filePath: string) {
}
}
function findFirstExecutable(
candidates: Array<BrowserExecutable>,
): BrowserExecutable | null {
for (const candidate of candidates) {
if (exists(candidate.path)) return candidate;
}
return null;
}
export function findChromeExecutableMac(): BrowserExecutable | null {
const candidates: Array<BrowserExecutable> = [
{
@@ -78,11 +88,7 @@ export function findChromeExecutableMac(): BrowserExecutable | null {
},
];
for (const candidate of candidates) {
if (exists(candidate.path)) return candidate;
}
return null;
return findFirstExecutable(candidates);
}
export function findChromeExecutableLinux(): BrowserExecutable | null {
@@ -95,11 +101,7 @@ export function findChromeExecutableLinux(): BrowserExecutable | null {
{ kind: "chrome", path: "/usr/bin/chrome" },
];
for (const candidate of candidates) {
if (exists(candidate.path)) return candidate;
}
return null;
return findFirstExecutable(candidates);
}
export function findChromeExecutableWindows(): BrowserExecutable | null {
@@ -165,15 +167,12 @@ export function findChromeExecutableWindows(): BrowserExecutable | null {
),
});
for (const candidate of candidates) {
if (exists(candidate.path)) return candidate;
}
return null;
return findFirstExecutable(candidates);
}
function resolveBrowserExecutable(
export function resolveBrowserExecutableForPlatform(
resolved: ResolvedBrowserConfig,
platform: NodeJS.Platform,
): BrowserExecutable | null {
if (resolved.executablePath) {
if (!exists(resolved.executablePath)) {
@@ -184,12 +183,18 @@ function resolveBrowserExecutable(
return { kind: "custom", path: resolved.executablePath };
}
if (process.platform === "darwin") return findChromeExecutableMac();
if (process.platform === "linux") return findChromeExecutableLinux();
if (process.platform === "win32") return findChromeExecutableWindows();
if (platform === "darwin") return findChromeExecutableMac();
if (platform === "linux") return findChromeExecutableLinux();
if (platform === "win32") return findChromeExecutableWindows();
return null;
}
function resolveBrowserExecutable(
resolved: ResolvedBrowserConfig,
): BrowserExecutable | null {
return resolveBrowserExecutableForPlatform(resolved, process.platform);
}
export function resolveClawdUserDataDir(
profileName = DEFAULT_CLAWD_BROWSER_PROFILE_NAME,
) {