openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
616 lines (615 loc) • 20.5 kB
JavaScript
import { l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-6kR-86XC.mjs";
import { f as pathExistsSync } from "./fs-safe-CS1DrPTK.mjs";
import "./string-coerce-runtime-B1b8UNzb.mjs";
import "./security-runtime-9ynw5sNI.mjs";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { execFileSync } from "node:child_process";
//#region extensions/browser/src/browser/chrome.executable-probe.ts
const CHROME_VERSION_RE = /\b(\d+)(?:\.\d+){1,3}\b/g;
const BROWSER_VERSION_TIMEOUT_MS = 6e3;
const MAC_PLISTBUDDY_TIMEOUT_MS = 800;
const WINDOWS_FILE_METADATA_TIMEOUT_MS = 4e3;
function execBrowserProbe(command, args, timeoutMs = 1200, maxBuffer = 1048576, extraEnv) {
try {
const output = execFileSync(command, args, {
timeout: timeoutMs,
encoding: "utf8",
maxBuffer,
stdio: [
"ignore",
"pipe",
"ignore"
],
...extraEnv ? { env: {
...process.env,
...extraEnv
} } : {}
});
return normalizeOptionalString(output) ?? null;
} catch {
return null;
}
}
/** Read a browser executable version from platform metadata or a command-line probe. */
function readBrowserVersion(executablePath) {
if (process.platform === "darwin") {
const bundleVersion = readMacBundleBrowserVersion(executablePath);
if (bundleVersion) return bundleVersion;
}
if (process.platform === "win32") return readWindowsBrowserVersion(executablePath);
const output = execBrowserProbe(executablePath, ["--version"], BROWSER_VERSION_TIMEOUT_MS);
if (!output) return null;
return output.replace(/\s+/g, " ").trim();
}
function readMacBundleBrowserVersion(executablePath) {
const appBundlePath = resolveMacAppBundlePath(executablePath);
if (!appBundlePath) return null;
return execBrowserProbe("/usr/libexec/PlistBuddy", [
"-c",
"Print :CFBundleShortVersionString",
path.join(appBundlePath, "Contents", "Info.plist")
], MAC_PLISTBUDDY_TIMEOUT_MS);
}
const WINDOWS_VERSION_DIR_RE = /^\d+(?:\.\d+){1,3}$/;
function readWindowsBrowserVersion(executablePath) {
const configuredSystemRoot = normalizeOptionalString(process.env.SystemRoot);
const systemRoot = configuredSystemRoot && path.win32.isAbsolute(configuredSystemRoot) ? configuredSystemRoot : "C:\\Windows";
const metadataVersion = execBrowserProbe(path.win32.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe"), [
"-NoProfile",
"-NonInteractive",
"-Command",
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo($env:OPENCLAW_BROWSER_EXECUTABLE_PATH).ProductVersion"
], WINDOWS_FILE_METADATA_TIMEOUT_MS, void 0, { OPENCLAW_BROWSER_EXECUTABLE_PATH: executablePath });
if (metadataVersion) return metadataVersion.replace(/\s+/g, " ").trim();
try {
const versionDirs = fs.readdirSync(path.win32.dirname(executablePath), { withFileTypes: true }).filter((entry) => entry.isDirectory() && WINDOWS_VERSION_DIR_RE.test(entry.name));
return versionDirs.length === 1 ? versionDirs[0]?.name ?? null : null;
} catch {
return null;
}
}
function resolveMacAppBundlePath(executablePath) {
const parts = path.normalize(executablePath).split(path.sep);
const appIndex = parts.findIndex((part) => part.endsWith(".app"));
if (appIndex < 0) return null;
return parts.slice(0, appIndex + 1).join(path.sep) || path.sep;
}
/** Parse a major browser version from a raw version string. */
function parseBrowserMajorVersion(rawVersion) {
const match = [...(rawVersion ?? "").matchAll(CHROME_VERSION_RE)].at(-1);
if (!match?.[1]) return null;
const major = Number.parseInt(match[1], 10);
return Number.isFinite(major) ? major : null;
}
//#endregion
//#region extensions/browser/src/browser/chrome.executables.ts
/** Chromium-family executable discovery across supported platforms. */
const PLAYWRIGHT_BROWSERS_PATH_ENV = "PLAYWRIGHT_BROWSERS_PATH";
const DEFAULT_WINDOWS_PROGRAM_FILES = "C:\\Program Files";
const DEFAULT_WINDOWS_PROGRAM_FILES_X86 = "C:\\Program Files (x86)";
const CHROMIUM_BUNDLE_IDS = /* @__PURE__ */ new Set([
"com.google.Chrome",
"com.google.Chrome.beta",
"com.google.Chrome.canary",
"com.google.Chrome.dev",
"com.brave.Browser",
"com.brave.Browser.beta",
"com.brave.Browser.nightly",
"com.microsoft.Edge",
"com.microsoft.EdgeBeta",
"com.microsoft.EdgeDev",
"com.microsoft.EdgeCanary",
"com.microsoft.edgemac",
"com.microsoft.edgemac.beta",
"com.microsoft.edgemac.dev",
"com.microsoft.edgemac.canary",
"org.chromium.Chromium",
"com.vivaldi.Vivaldi",
"com.operasoftware.Opera",
"com.operasoftware.OperaGX",
"com.yandex.desktop.yandex-browser",
"company.thebrowser.Browser"
]);
const CHROMIUM_DESKTOP_IDS = /* @__PURE__ */ new Set([
"google-chrome.desktop",
"google-chrome-beta.desktop",
"google-chrome-unstable.desktop",
"brave-browser.desktop",
"microsoft-edge.desktop",
"microsoft-edge-beta.desktop",
"microsoft-edge-dev.desktop",
"microsoft-edge-canary.desktop",
"chromium.desktop",
"chromium-browser.desktop",
"vivaldi.desktop",
"vivaldi-stable.desktop",
"opera.desktop",
"opera-gx.desktop",
"yandex-browser.desktop",
"org.chromium.Chromium.desktop"
]);
const CHROMIUM_EXE_NAMES = /* @__PURE__ */ new Set([
"chrome.exe",
"msedge.exe",
"brave.exe",
"brave-browser.exe",
"chromium.exe",
"vivaldi.exe",
"opera.exe",
"yandex.exe",
"yandexbrowser.exe",
"google chrome",
"google chrome canary",
"brave browser",
"microsoft edge",
"chromium",
"chrome",
"brave",
"msedge",
"brave-browser",
"google-chrome",
"google-chrome-stable",
"google-chrome-beta",
"google-chrome-unstable",
"microsoft-edge",
"microsoft-edge-beta",
"microsoft-edge-dev",
"microsoft-edge-canary",
"chromium-browser",
"vivaldi",
"vivaldi-stable",
"opera",
"opera-stable",
"opera-gx",
"yandex-browser"
]);
function isExecutable(filePath, platform) {
try {
if (!fs.statSync(filePath).isFile()) return false;
fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
return true;
} catch {
return false;
}
}
function inferKindFromIdentifier(identifier) {
const id = normalizeLowercaseStringOrEmpty(identifier);
if (id.includes("brave")) return "brave";
if (id.includes("edge")) return "edge";
if (id.includes("chromium")) return "chromium";
if (id.includes("canary")) return "canary";
if (id.includes("opera") || id.includes("vivaldi") || id.includes("yandex") || id.includes("thebrowser")) return "chromium";
return "chrome";
}
function detectDefaultChromiumExecutable(platform) {
if (platform === "darwin") return detectDefaultChromiumExecutableMac();
if (platform === "linux") return detectDefaultChromiumExecutableLinux();
if (platform === "win32") return detectDefaultChromiumExecutableWindows();
return null;
}
function detectDefaultChromiumExecutableMac() {
const bundleId = detectDefaultBrowserBundleIdMac();
if (!bundleId || !CHROMIUM_BUNDLE_IDS.has(bundleId)) return null;
const appPathRaw = execBrowserProbe("/usr/bin/osascript", ["-e", `POSIX path of (path to application id "${bundleId}")`]);
if (!appPathRaw) return null;
const appPath = appPathRaw.replace(/\/$/, "");
const exeName = execBrowserProbe("/usr/bin/defaults", [
"read",
path.join(appPath, "Contents", "Info"),
"CFBundleExecutable"
]);
if (!exeName) return null;
const exePath = path.join(appPath, "Contents", "MacOS", exeName);
if (!isExecutable(exePath, "darwin")) return null;
return {
kind: inferKindFromIdentifier(bundleId),
path: exePath
};
}
function detectDefaultBrowserBundleIdMac() {
const plistPath = path.join(os.homedir(), "Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist");
if (!pathExistsSync(plistPath)) return null;
const handlersRaw = execBrowserProbe("/usr/bin/plutil", [
"-extract",
"LSHandlers",
"json",
"-o",
"-",
"--",
plistPath
], 2e3, 5242880);
if (!handlersRaw) return null;
let handlers;
try {
handlers = JSON.parse(handlersRaw);
} catch {
return null;
}
if (!Array.isArray(handlers)) return null;
const resolveScheme = (scheme) => {
let candidate = null;
for (const entry of handlers) {
if (!entry || typeof entry !== "object") continue;
const record = entry;
if (record.LSHandlerURLScheme !== scheme) continue;
const role = typeof record.LSHandlerRoleAll === "string" && record.LSHandlerRoleAll || typeof record.LSHandlerRoleViewer === "string" && record.LSHandlerRoleViewer || null;
if (role) candidate = role;
}
return candidate;
};
return resolveScheme("http") ?? resolveScheme("https");
}
function detectDefaultChromiumExecutableLinux() {
const desktopId = execBrowserProbe("xdg-settings", ["get", "default-web-browser"]) || execBrowserProbe("xdg-mime", [
"query",
"default",
"x-scheme-handler/http"
]);
if (!desktopId) return null;
const trimmed = desktopId.trim();
if (!CHROMIUM_DESKTOP_IDS.has(trimmed)) return null;
const desktopPath = findDesktopFilePath(trimmed);
if (!desktopPath) return null;
const execLine = readDesktopExecLine(desktopPath);
if (!execLine) return null;
const command = extractExecutableFromExecLine(execLine);
if (!command) return null;
const resolved = resolveLinuxExecutablePath(command);
if (!resolved || !isExecutable(resolved, "linux")) return null;
const exeName = normalizeLowercaseStringOrEmpty(path.posix.basename(resolved));
if (!CHROMIUM_EXE_NAMES.has(exeName)) return null;
return {
kind: inferKindFromIdentifier(exeName),
path: resolved
};
}
function detectDefaultChromiumExecutableWindows() {
const progId = readWindowsProgId();
const command = (progId ? readWindowsCommandForProgId(progId) : null) || readWindowsCommandForProgId("http");
if (!command) return null;
const exePath = extractWindowsExecutablePath(expandWindowsEnvVars(command));
if (!exePath) return null;
if (!isExecutable(exePath, "win32")) return null;
const directPath = resolveDirectWindowsBrowserExecutable(exePath);
if (!directPath) return null;
const exeName = normalizeLowercaseStringOrEmpty(path.win32.basename(directPath));
if (!CHROMIUM_EXE_NAMES.has(exeName)) return null;
return {
kind: inferKindFromIdentifier(exeName),
path: directPath
};
}
/** Resolve launchers that hand off to another process into a directly owned browser binary. */
function resolveDirectWindowsBrowserExecutable(executablePath) {
if (normalizeLowercaseStringOrEmpty(path.win32.basename(executablePath)) !== "launcher.exe") return executablePath;
const installDir = path.win32.dirname(executablePath);
try {
const status = JSON.parse(fs.readFileSync(path.win32.join(installDir, "installation_status.json"), "utf8"));
const subfolder = status && typeof status === "object" ? Reflect.get(status, "_subfolder") : null;
if (typeof subfolder !== "string" || !WINDOWS_VERSION_DIR_RE.test(subfolder)) return null;
const candidate = path.win32.join(installDir, subfolder, "opera.exe");
return pathExistsSync(candidate) ? candidate : null;
} catch {
return null;
}
}
function findDesktopFilePath(desktopId) {
return [
path.join(os.homedir(), ".local", "share", "applications", desktopId),
path.join("/usr/local/share/applications", desktopId),
path.join("/usr/share/applications", desktopId),
path.join("/var/lib/snapd/desktop/applications", desktopId)
].find((candidate) => pathExistsSync(candidate)) ?? null;
}
function readDesktopExecLine(desktopPath) {
try {
return fs.readFileSync(desktopPath, "utf8").split(/\r?\n/).find((line) => line.startsWith("Exec="))?.slice(5).trim() ?? null;
} catch {
return null;
}
}
function extractExecutableFromExecLine(execLine) {
const tokens = splitExecLine(execLine);
for (const token of tokens) {
if (!token) continue;
if (token === "env") continue;
if (token.includes("=") && !token.startsWith("/") && !token.includes("\\")) continue;
return token.replace(/^["']|["']$/g, "");
}
return null;
}
function splitExecLine(line) {
const tokens = [];
let current = "";
let inQuotes = false;
let quoteChar = "";
for (const ch of line) {
if ((ch === "\"" || ch === "'") && (!inQuotes || ch === quoteChar)) {
if (inQuotes) {
inQuotes = false;
quoteChar = "";
} else {
inQuotes = true;
quoteChar = ch;
}
continue;
}
if (!inQuotes && /\s/.test(ch)) {
if (current) {
tokens.push(current);
current = "";
}
continue;
}
current += ch;
}
if (current) tokens.push(current);
return tokens;
}
function resolveLinuxExecutablePath(command) {
const cleaned = command.trim().replace(/%[a-zA-Z]/g, "");
if (!cleaned) return null;
if (cleaned.startsWith("/")) return cleaned;
const resolved = execBrowserProbe("which", [cleaned], 800);
return resolved ? resolved.trim() : null;
}
function readWindowsProgId() {
const output = execBrowserProbe("reg", [
"query",
"HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
"/v",
"ProgId"
]);
if (!output) return null;
return output.match(/ProgId\s+REG_\w+\s+(.+)$/im)?.[1]?.trim() || null;
}
function readWindowsCommandForProgId(progId) {
const output = execBrowserProbe("reg", [
"query",
`HKCR\\${progId}\\shell\\open\\command`,
"/ve"
]);
if (!output) return null;
const match = output.match(/REG_\w+\s+(.+)$/im);
return normalizeOptionalString(match?.[1]) ?? null;
}
function resolveWindowsBrowserInstallRoots() {
return {
localAppData: normalizeOptionalString(process.env.LOCALAPPDATA) ?? path.win32.join(os.homedir(), "AppData", "Local"),
programFiles: normalizeOptionalString(process.env.ProgramFiles) ?? DEFAULT_WINDOWS_PROGRAM_FILES,
programFilesX86: normalizeOptionalString(process.env["ProgramFiles(x86)"]) ?? DEFAULT_WINDOWS_PROGRAM_FILES_X86
};
}
function expandWindowsEnvVars(value) {
const installRoots = resolveWindowsBrowserInstallRoots();
const installRootByEnvName = {
localappdata: installRoots.localAppData,
programfiles: installRoots.programFiles,
"programfiles(x86)": installRoots.programFilesX86
};
return value.replace(/%([^%]+)%/g, (_match, name) => {
const key = normalizeOptionalString(name);
if (!key) return _match;
return normalizeOptionalString(process.env[key]) ?? installRootByEnvName[key.toLowerCase()] ?? `%${key}%`;
});
}
function extractWindowsExecutablePath(command) {
const quoted = command.match(/"([^"]+\.exe)"/i);
if (quoted?.[1]) return quoted[1];
const unquoted = command.match(/^\s*(\S+\.exe)(?:\s|$)/i);
if (unquoted?.[1]) return unquoted[1];
return null;
}
function findFirstExecutable(candidates, platform) {
return candidates.find((candidate) => isExecutable(candidate.path, platform)) ?? null;
}
function findFirstChromeExecutable(candidates, platform) {
const candidate = candidates.find((filePath) => isExecutable(filePath, platform));
if (!candidate) return null;
const normalizedPath = normalizeLowercaseStringOrEmpty(candidate);
return {
kind: [
"beta",
"canary",
"sxs",
"unstable"
].some((name) => normalizedPath.includes(name)) ? "canary" : "chrome",
path: candidate
};
}
function findPlaywrightChromiumExecutableCandidatesLinux() {
const candidates = [];
for (const browserPath of getPlaywrightBrowserCachePaths()) for (const entry of readSortedDirNames(browserPath)) {
if (!entry.startsWith("chromium-")) continue;
for (const linuxDir of ["chrome-linux64", "chrome-linux"]) candidates.push({
kind: "chromium",
path: path.join(browserPath, entry, linuxDir, "chrome")
});
}
return candidates;
}
function getPlaywrightBrowserCachePaths() {
const configured = normalizeOptionalString(process.env[PLAYWRIGHT_BROWSERS_PATH_ENV]);
return [.../* @__PURE__ */ new Set([...configured && configured !== "0" ? [configured] : [], path.join(os.homedir(), ".cache", "ms-playwright")])];
}
function readSortedDirNames(dir) {
try {
return fs.readdirSync(dir).toSorted();
} catch {
return [];
}
}
function chromeExecutableCandidatesMac() {
const applications = [
["chrome", "Google Chrome"],
["brave", "Brave Browser"],
["edge", "Microsoft Edge"],
["chromium", "Chromium"],
["canary", "Google Chrome Canary"]
];
const roots = ["/Applications", path.join(os.homedir(), "Applications")];
return applications.flatMap(([kind, name]) => roots.map((root) => ({
kind,
path: path.join(root, `${name}.app`, "Contents", "MacOS", name)
})));
}
/** Find the best Chromium-family executable on Linux. */
function findChromeExecutableLinux() {
return findFirstExecutable([
{
kind: "chrome",
path: "/usr/bin/google-chrome"
},
{
kind: "chrome",
path: "/usr/bin/google-chrome-stable"
},
{
kind: "chrome",
path: "/usr/bin/chrome"
},
{
kind: "chrome",
path: "/opt/google/chrome/chrome"
},
{
kind: "brave",
path: "/usr/bin/brave-browser"
},
{
kind: "brave",
path: "/usr/bin/brave-browser-stable"
},
{
kind: "brave",
path: "/usr/bin/brave"
},
{
kind: "brave",
path: "/snap/bin/brave"
},
{
kind: "brave",
path: "/opt/brave.com/brave/brave-browser"
},
{
kind: "edge",
path: "/usr/bin/microsoft-edge"
},
{
kind: "edge",
path: "/usr/bin/microsoft-edge-stable"
},
{
kind: "chromium",
path: "/usr/bin/chromium"
},
{
kind: "chromium",
path: "/usr/bin/chromium-browser"
},
{
kind: "chromium",
path: "/usr/lib/chromium/chromium"
},
{
kind: "chromium",
path: "/usr/lib/chromium-browser/chromium-browser"
},
{
kind: "chromium",
path: "/snap/bin/chromium"
},
...findPlaywrightChromiumExecutableCandidatesLinux()
], "linux");
}
function findGoogleChromeExecutableLinux() {
return findFirstChromeExecutable([
"/usr/bin/google-chrome",
"/usr/bin/google-chrome-stable",
"/usr/bin/google-chrome-beta",
"/usr/bin/google-chrome-unstable",
"/opt/google/chrome/chrome",
"/snap/bin/google-chrome"
], "linux");
}
function chromeExecutableCandidatesWindows() {
const { localAppData, programFiles, programFilesX86 } = resolveWindowsBrowserInstallRoots();
const browsers = [
[
"chrome",
"Google",
"Chrome",
"Application",
"chrome.exe"
],
[
"brave",
"BraveSoftware",
"Brave-Browser",
"Application",
"brave.exe"
],
[
"edge",
"Microsoft",
"Edge",
"Application",
"msedge.exe"
],
[
"chromium",
"Chromium",
"Application",
"chrome.exe"
],
[
"canary",
"Google",
"Chrome SxS",
"Application",
"chrome.exe"
]
];
const candidates = browsers.map(([kind, ...segments]) => ({
kind,
path: path.win32.join(localAppData, ...segments)
}));
for (const [kind, ...segments] of browsers.slice(0, 3)) for (const root of [programFiles, programFilesX86]) candidates.push({
kind,
path: path.win32.join(root, ...segments)
});
return candidates;
}
function googleChromeCandidatePaths(candidates) {
return candidates.filter(({ kind }) => kind === "chrome" || kind === "canary").map((candidate) => candidate.path);
}
/** Resolve the Google Chrome executable for a named platform when available. */
function resolveGoogleChromeExecutableForPlatform(platform) {
if (platform === "darwin") return findFirstChromeExecutable(googleChromeCandidatePaths(chromeExecutableCandidatesMac()), platform);
if (platform === "linux") return findGoogleChromeExecutableLinux();
if (platform === "win32") return findFirstChromeExecutable(googleChromeCandidatePaths(chromeExecutableCandidatesWindows()), platform);
return null;
}
/** Resolve the preferred Chromium-family executable for a platform. */
function resolveBrowserExecutableForPlatform(resolved, platform) {
if (resolved.executablePath) {
if (!pathExistsSync(resolved.executablePath)) throw new Error(`browser.executablePath not found: ${resolved.executablePath}`);
const directPath = platform === "win32" ? resolveDirectWindowsBrowserExecutable(resolved.executablePath) : resolved.executablePath;
if (!directPath) throw new Error(`browser.executablePath must point to the browser executable, not a handoff launcher: ${resolved.executablePath}`);
return {
kind: "custom",
path: directPath
};
}
const detected = detectDefaultChromiumExecutable(platform);
if (detected) return detected;
if (platform === "darwin") return findFirstExecutable(chromeExecutableCandidatesMac(), platform);
if (platform === "linux") return findChromeExecutableLinux();
if (platform === "win32") return findFirstExecutable(chromeExecutableCandidatesWindows(), platform);
return null;
}
//#endregion
export { readBrowserVersion as i, resolveGoogleChromeExecutableForPlatform as n, parseBrowserMajorVersion as r, resolveBrowserExecutableForPlatform as t };