openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
116 lines (115 loc) • 8.57 kB
JavaScript
import { l as normalizeOptionalString } from "../../string-coerce-1VuiLaaR.mjs";
import { r as asNullableRecord } from "../../record-coerce-TIsquoVR.mjs";
import { t as CONFIG_DIR } from "../../utils-CitNzLyF.mjs";
import { t as formatCliCommand } from "../../command-format-DwEdrDKL.mjs";
import { t as note } from "../../note-Bi0VsI6R.mjs";
import "../../string-coerce-runtime-BbIJhy7G.mjs";
import "../../text-utility-runtime-BB0hWeEg.mjs";
import "../../cli-runtime-CphihcPm.mjs";
import { i as resolveBrowserConfig, r as isLocalManagedProfile, s as resolveProfile, t as getManagedBrowserMissingDisplayError } from "../../config-NGx7eSU6.mjs";
import { t as getBrowserProfileCapabilities } from "../../profile-capabilities-DXuiwiC6.mjs";
import { i as readBrowserVersion, n as resolveGoogleChromeExecutableForPlatform, r as parseBrowserMajorVersion, t as resolveBrowserExecutableForPlatform } from "../../chrome.executables-BVeaoQFk.mjs";
import fs from "node:fs";
import path from "node:path";
//#region extensions/browser/src/doctor-browser.ts
const CHROME_MCP_MIN_MAJOR = 144;
const REMOTE_DEBUGGING_PAGES = [
"chrome://inspect/#remote-debugging",
"brave://inspect/#remote-debugging",
"edge://inspect/#remote-debugging"
].join(", ");
function collectBrowserDoctorProfiles(cfg, resolved) {
const browser = asNullableRecord(cfg.browser);
const names = new Set(Object.keys(asNullableRecord(browser?.profiles) ?? {}));
const defaultProfile = normalizeOptionalString(browser?.defaultProfile);
if (defaultProfile) names.add(defaultProfile);
const profiles = [...names].flatMap((name) => {
const profile = resolveProfile(resolved, name);
return profile ? [profile] : [];
}).toSorted((left, right) => left.name.localeCompare(right.name));
return {
managed: profiles.filter(isLocalManagedProfile),
chromeMcp: profiles.filter((profile) => getBrowserProfileCapabilities(profile).usesChromeMcp && !profile.cdpUrl)
};
}
async function noteChromeMcpBrowserReadiness(cfg, deps) {
const noteFn = deps?.noteFn ?? note;
const platform = process.platform;
const resolved = resolveBrowserConfig(cfg.browser, cfg);
const { managed: managedProfiles, chromeMcp: profiles } = collectBrowserDoctorProfiles(cfg, resolved);
const managedProfileLabel = managedProfiles.map((profile) => profile.name).join(", ");
if (resolved.enabled && resolved.extensionRelay.allowLegacyAuth) noteFn([
"- Legacy Browser Relay Authentication is enabled (browser.extensionRelay.allowLegacyAuth=true).",
"- Update paired Chrome extensions and external CDP clients to Browser Relay Authentication v2, then set browser.extensionRelay.allowLegacyAuth=false.",
"- V2 clients never downgrade to legacy authentication."
].join("\n"), "Browser relay authentication");
if (fs.existsSync(path.join(CONFIG_DIR, "browser", "chrome-extension"))) noteFn([
"- Chrome extension native bootstrap was not inspected; registration status is unavailable in Doctor.",
`- Run ${formatCliCommand("openclaw browser extension status --json")} to inspect it explicitly; this may request browser profile access.`,
`- Run ${formatCliCommand("openclaw browser extension install")} if setup or repair is needed.`
].join("\n"), "Browser extension bootstrap");
if (platform === "darwin") noteFn([
`- System browser profile cookie import is ${cfg.browser?.allowSystemProfileImport !== false ? "enabled" : "disabled"} (browser.allowSystemProfileImport).`,
"- System browser profile discovery skipped by Doctor; importable cookie database count is unavailable.",
"- Doctor does not access the macOS Keychain; importing asks for consent separately."
].join("\n"), "Browser");
const managedExecutables = /* @__PURE__ */ new Map();
const missingExecutableProfiles = managedProfiles.filter((profile) => {
const executablePath = profile.executablePath;
if (!managedExecutables.has(executablePath)) managedExecutables.set(executablePath, resolveBrowserExecutableForPlatform({
...resolved,
executablePath
}, platform));
return !managedExecutables.get(executablePath);
});
const missingDisplay = managedProfiles.map((profile) => getManagedBrowserMissingDisplayError(resolved, profile, {
platform,
env: process.env
})).filter((error) => error !== null);
const shouldWarnRootNoSandbox = platform === "linux" && managedProfiles.length > 0 && !resolved.noSandbox && process.getuid?.() === 0;
if (missingExecutableProfiles.length > 0) noteFn([
`- OpenClaw-managed browser profile(s) are configured: ${missingExecutableProfiles.map((profile) => profile.name).join(", ")}.`,
"- No Chromium-based browser executable was found on this host for OpenClaw-managed launch.",
"- Install Chrome, Chromium, Brave, Edge, or set browser.executablePath explicitly."
].join("\n"), "Browser");
if (missingDisplay.length > 0 || shouldWarnRootNoSandbox) {
const lines = [`- OpenClaw-managed browser profile(s) are configured: ${managedProfileLabel}.`];
if (missingDisplay.length > 0) lines.push(...missingDisplay.every((error) => error.headlessSource === "config") ? ["- No DISPLAY or WAYLAND_DISPLAY is set, and browser.headless is false. Managed browser launch needs a desktop session, Xvfb, or browser.headless: true."] : missingDisplay.map((error) => `- ${error.message}`));
if (shouldWarnRootNoSandbox) lines.push("- The Gateway is running as root and browser.noSandbox is false. Chromium commonly requires browser.noSandbox: true in container/root runtimes.");
noteFn(lines.join("\n"), "Browser");
}
if (profiles.length === 0) return;
const explicitProfiles = profiles.filter((profile) => profile.userDataDir);
const autoConnectProfiles = profiles.filter((profile) => !profile.userDataDir);
const profileLabel = profiles.map((profile) => profile.name).join(", ");
const autoConnect = autoConnectProfiles.length > 0;
const chrome = autoConnect ? resolveGoogleChromeExecutableForPlatform(platform) : null;
const lines = [`- Chrome MCP existing-session is configured for profile(s): ${profileLabel}.`];
if (!autoConnect) lines.push("- These profiles use an explicit Chromium user data directory instead of Chrome's default auto-connect path.", `- Verify the matching Chromium-based browser is version ${CHROME_MCP_MIN_MAJOR}+ on the same host as the Gateway or node.`);
else if (!chrome) {
const autoProfileLabel = autoConnectProfiles.map((profile) => profile.name).join(", ");
lines.push(`- Google Chrome was not found on this host for auto-connect profile(s): ${autoProfileLabel}. OpenClaw does not bundle Chrome.`, `- Install Google Chrome ${CHROME_MCP_MIN_MAJOR}+ on the same host as the Gateway or node, or set browser.profiles.<name>.userDataDir for a different Chromium-based browser.`);
} else {
const versionRaw = readBrowserVersion(chrome.path);
const major = parseBrowserMajorVersion(versionRaw);
lines.push(`- Chrome path: ${chrome.path}`);
if (!versionRaw || major === null) lines.push(`- Could not determine the installed Chrome version. Chrome MCP requires Google Chrome ${CHROME_MCP_MIN_MAJOR}+ on this host.`);
else if (major < CHROME_MCP_MIN_MAJOR) lines.push(`- Detected Chrome ${versionRaw}, which is too old for Chrome MCP existing-session attach. Upgrade to Chrome ${CHROME_MCP_MIN_MAJOR}+.`);
else lines.push(`- Detected Chrome ${versionRaw}.`);
}
lines.push(`- Enable remote debugging in ${autoConnect ? "the browser inspect page" : "that browser's inspect page"} (${REMOTE_DEBUGGING_PAGES}).`, "- Keep the browser running and accept the attach consent prompt the first time OpenClaw connects.");
if (autoConnect && !chrome) lines.push("- Docker, headless, and sandbox browser flows stay on raw CDP; this check only applies to host-local Chrome MCP attach.");
if (autoConnect && explicitProfiles.length > 0) lines.push(`- Profiles with explicit userDataDir ${chrome ? "still need manual validation of the matching Chromium-based browser" : "skip Chrome auto-detection"}: ${explicitProfiles.map((profile) => profile.name).join(", ")}.`);
noteFn(lines.join("\n"), "Browser");
}
/** Leave discovery-dependent native-host repair to explicit extension setup. */
async function maybeRepairOwnedChromeExtensionNativeHosts() {
return {
status: "skipped",
reason: "Doctor does not inspect personal browser profiles",
changes: [],
warnings: [`Chrome extension native-host repair skipped: Doctor does not inspect personal browser profiles. Run ${formatCliCommand("openclaw browser extension install")} to repair explicitly.`]
};
}
//#endregion
export { maybeRepairOwnedChromeExtensionNativeHosts, noteChromeMcpBrowserReadiness };