fix: expand browser executable home paths

This commit is contained in:
Peter Steinberger
2026-04-25 03:15:50 +01:00
parent 4a7ddd7ff5
commit 95a2c9bcdc
5 changed files with 43 additions and 2 deletions

View File

@@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Providers/OpenAI: separate API-key and Codex sign-in onboarding groups, and avoid replaying stale OpenAI Responses reasoning blocks after a model route switch.
- Browser/config: expand `~` in `browser.executablePath` before Chromium launch, so home-relative custom browser paths no longer fail with `ENOENT`. Fixes #67264. Thanks @Quratulain-bilal.
- Discord/subagents: preserve thread-bound completion delivery by keeping the requester-agent announce path primary and falling back to direct thread sends only when the announce produces no visible output. (#71064) Thanks @DolencLuka.
- Browser/tool: give Chrome MCP existing-session manage calls a longer default timeout, pass explicit tool timeouts through tab management, and recover stale selected-page MCP sessions instead of forcing a manual reset. Thanks @steipete.
- Browser/sandbox: clean up idle tracked tabs opened by primary-agent browser sessions, while preserving active tab reuse and lifecycle cleanup for subagents, cron, and ACP sessions. Fixes #71165. Thanks @dwbutler.

View File

@@ -219,6 +219,7 @@ See [Plugins](/tools/plugin).
- Local managed `openclaw` profiles auto-assign `cdpPort` and `cdpUrl`; only
set `cdpUrl` explicitly for remote CDP.
- Auto-detect order: default browser if Chromium-based → Chrome → Brave → Edge → Chromium → Chrome Canary.
- `browser.executablePath` accepts `~` for your OS home directory.
- Control service: loopback only (port derived from `gateway.port`, default `18791`).
- `extraArgs` appends extra launch flags to local Chromium startup (for example
`--disable-gpu`, window sizing, or debug flags).

View File

@@ -199,7 +199,7 @@ Browser settings live in `~/.openclaw/openclaw.json`.
If your **system default** browser is Chromium-based (Chrome/Brave/Edge/etc),
OpenClaw uses it automatically. Set `browser.executablePath` to override
auto-detection:
auto-detection. `~` expands to your OS home directory:
```bash
openclaw config set browser.executablePath "/usr/bin/google-chrome"

View File

@@ -1,3 +1,5 @@
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import type { BrowserConfig } from "../config/config.js";
import { resolveUserPath } from "../utils.js";
@@ -139,6 +141,30 @@ describe("browser config", () => {
});
});
it("expands tilde-prefixed executablePath with the OS home directory", () => {
const resolved = resolveBrowserConfig({
executablePath: " ~/.local/bin/chromium ",
});
expect(resolved.executablePath).toBe(path.resolve(os.homedir(), ".local/bin/chromium"));
});
it("keeps non-tilde executablePath values unchanged after trimming", () => {
const resolved = resolveBrowserConfig({
executablePath: " ./local-chromium ",
});
expect(resolved.executablePath).toBe("./local-chromium");
});
it("normalizes blank executablePath to undefined", () => {
const resolved = resolveBrowserConfig({
executablePath: " ",
});
expect(resolved.executablePath).toBeUndefined();
});
it("normalizes invalid browser tab cleanup numbers to defaults", () => {
const resolved = resolveBrowserConfig({
tabCleanup: {

View File

@@ -1,3 +1,5 @@
import os from "node:os";
import path from "node:path";
import {
normalizeOptionalString,
normalizeOptionalTrimmedStringList,
@@ -125,6 +127,17 @@ function normalizePositiveInteger(raw: number | undefined, fallback: number): nu
return value <= 0 ? fallback : value;
}
function normalizeExecutablePath(raw: string | undefined): string | undefined {
const value = normalizeOptionalString(raw);
if (!value) {
return undefined;
}
if (!/^~(?=$|[\\/])/.test(value)) {
return value;
}
return path.resolve(value.replace(/^~(?=$|[\\/])/, os.homedir()));
}
function resolveBrowserTabCleanupConfig(
cfg: BrowserConfig | undefined,
): ResolvedBrowserTabCleanupConfig {
@@ -287,7 +300,7 @@ export function resolveBrowserConfig(
const headless = cfg?.headless === true;
const noSandbox = cfg?.noSandbox === true;
const attachOnly = cfg?.attachOnly === true;
const executablePath = normalizeOptionalString(cfg?.executablePath);
const executablePath = normalizeExecutablePath(cfg?.executablePath);
const defaultProfileFromConfig = normalizeOptionalString(cfg?.defaultProfile);
const legacyCdpPort = rawCdpUrl ? cdpInfo.port : undefined;