UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

302 lines (301 loc) 11.3 kB
import { A as isBunRuntime, j as isNodeRuntime } from "./argv-CnfL__6a.js"; import { n as findFirstAccessibleGatewayEntrypoint, r as isGatewayDistEntrypointPath, t as buildGatewayDistEntrypointCandidates } from "./gateway-entrypoint-37bdaChq.js"; import { a as resolveSystemNodeInfo, i as resolvePreferredNodePath, r as renderSystemNodeWarning } from "./runtime-paths-DS_J3TGI.js"; import fs, { constants } from "node:fs"; import path from "node:path"; import fs$1 from "node:fs/promises"; import { execFileSync } from "node:child_process"; //#region src/daemon/program-args.ts /** Builds runtime command arguments for gateway and node service installs. */ const OPENCLAW_WRAPPER_ENV_KEY = "OPENCLAW_WRAPPER"; async function resolveCliEntrypointPathForService() { const argv1 = process.argv[1]; if (!argv1) throw new Error("Unable to resolve CLI entrypoint path"); const normalized = path.resolve(argv1); const resolvedPath = await resolveRealpathSafe(normalized); if (isGatewayDistEntrypointPath(resolvedPath)) { const preferredDistEntrypoint = await findFirstAccessibleGatewayEntrypoint(buildGatewayDistEntrypointCandidates(normalized, resolvedPath), async (candidate) => { try { await fs$1.access(candidate); return true; } catch { return false; } }); if (preferredDistEntrypoint) return preferredDistEntrypoint; if (isGatewayDistEntrypointPath(normalized) && normalized !== resolvedPath) try { await fs$1.access(normalized); return normalized; } catch {} return resolvedPath; } const distCandidates = buildDistCandidates(resolvedPath, normalized); for (const candidate of distCandidates) try { await fs$1.access(candidate); return candidate; } catch {} throw new Error(`Cannot find built CLI at ${distCandidates.join(" or ")}. Run "pnpm build" first, or use dev mode.`); } async function resolveRealpathSafe(inputPath) { try { return await fs$1.realpath(inputPath); } catch { return inputPath; } } function buildDistCandidates(...inputs) { const candidates = []; const seen = /* @__PURE__ */ new Set(); for (const inputPath of inputs) { if (!inputPath) continue; const baseDir = path.dirname(inputPath); appendDistCandidates(candidates, seen, path.resolve(baseDir, "..")); appendDistCandidates(candidates, seen, baseDir); appendNodeModulesBinCandidates(candidates, seen, inputPath); } return candidates; } function appendDistCandidates(candidates, seen, baseDir) { const distDir = path.resolve(baseDir, "dist"); const distEntries = [ path.join(distDir, "index.js"), path.join(distDir, "index.mjs"), path.join(distDir, "entry.js"), path.join(distDir, "entry.mjs") ]; for (const entry of distEntries) { if (seen.has(entry)) continue; seen.add(entry); candidates.push(entry); } } function appendNodeModulesBinCandidates(candidates, seen, inputPath) { const parts = inputPath.split(path.sep); const binIndex = parts.lastIndexOf(".bin"); if (binIndex <= 0) return; if (parts[binIndex - 1] !== "node_modules") return; const binName = path.basename(inputPath); const nodeModulesDir = parts.slice(0, binIndex).join(path.sep); appendDistCandidates(candidates, seen, path.join(nodeModulesDir, binName)); } function resolveRepoRootForDev() { const argv1 = process.argv[1]; if (!argv1) throw new Error("Unable to resolve repo root"); const parts = path.resolve(argv1).split(path.sep); const srcIndex = parts.lastIndexOf("src"); if (srcIndex === -1) throw new Error("Dev mode requires running from repo (src/entry.ts)"); return parts.slice(0, srcIndex).join(path.sep); } async function resolveBunPath() { return await resolveBinaryPath("bun"); } async function resolveNodePath() { return await resolveBinaryPath("node"); } async function resolveBinaryPath(binary) { const cmd = process.platform === "win32" ? "where" : "which"; try { const resolved = execFileSync(cmd, [binary], { encoding: "utf8" }).trim().split(/\r?\n/)[0]?.trim(); if (!resolved) throw new Error("empty"); await fs$1.access(resolved); return resolved; } catch { if (binary === "bun") throw new Error("Bun not found in PATH. Install bun: https://bun.sh"); throw new Error("Node not found in PATH. Install Node 24 (recommended) or Node 22 LTS (22.19+)."); } } async function resolveOpenClawWrapperPath(inputPath) { const trimmed = inputPath?.trim(); if (!trimmed) return; const resolved = path.resolve(trimmed); try { if (!(await fs$1.stat(resolved)).isFile()) throw new Error("not a regular file"); await fs$1.access(resolved, constants.X_OK); } catch (error) { const detail = error instanceof Error ? ` (${error.message})` : ""; throw new Error(`${OPENCLAW_WRAPPER_ENV_KEY} must point to an executable file: ${resolved}${detail}`, { cause: error }); } return resolved; } async function resolveCliProgramArguments(params) { const wrapperPath = await resolveOpenClawWrapperPath(params.wrapperPath); if (wrapperPath) return { programArguments: [wrapperPath, ...params.args] }; const execPath = process.execPath; const runtime = params.runtime ?? "auto"; if (runtime === "node") return { programArguments: [ params.nodePath ?? (isNodeRuntime(execPath) ? execPath : await resolveNodePath()), await resolveCliEntrypointPathForService(), ...params.args ] }; if (runtime === "bun") { if (params.dev) { const repoRoot = resolveRepoRootForDev(); const devCliPath = path.join(repoRoot, "src", "entry.ts"); await fs$1.access(devCliPath); return { programArguments: [ isBunRuntime(execPath) ? execPath : await resolveBunPath(), devCliPath, ...params.args ], workingDirectory: repoRoot }; } return { programArguments: [ isBunRuntime(execPath) ? execPath : await resolveBunPath(), await resolveCliEntrypointPathForService(), ...params.args ] }; } if (!params.dev) try { return { programArguments: [ execPath, await resolveCliEntrypointPathForService(), ...params.args ] }; } catch (error) { if (!isNodeRuntime(execPath)) return { programArguments: [execPath, ...params.args] }; throw error; } const repoRoot = resolveRepoRootForDev(); const devCliPath = path.join(repoRoot, "src", "entry.ts"); await fs$1.access(devCliPath); if (isBunRuntime(execPath)) return { programArguments: [ execPath, devCliPath, ...params.args ], workingDirectory: repoRoot }; return { programArguments: [ await resolveBunPath(), devCliPath, ...params.args ], workingDirectory: repoRoot }; } async function resolveGatewayProgramArguments(params) { return resolveCliProgramArguments({ args: [ "gateway", "--port", String(params.port) ], dev: params.dev, runtime: params.runtime, nodePath: params.nodePath, wrapperPath: params.wrapperPath }); } async function resolveNodeProgramArguments(params) { const args = [ "node", "run", "--host", params.host, "--port", String(params.port) ]; if (params.tls || params.tlsFingerprint) args.push("--tls"); if (params.tlsFingerprint) args.push("--tls-fingerprint", params.tlsFingerprint); if (params.nodeId) args.push("--node-id", params.nodeId); if (params.displayName) args.push("--display-name", params.displayName); return resolveCliProgramArguments({ args, dev: params.dev, runtime: params.runtime, nodePath: params.nodePath }); } //#endregion //#region src/commands/daemon-install-runtime-warning.ts /** Warn when daemon install will use a system Node path that may be unsuitable. */ async function emitNodeRuntimeWarning(params) { if (params.runtime !== "node") return; const warning = renderSystemNodeWarning(await resolveSystemNodeInfo({ env: params.env }), params.nodeProgram); if (warning) params.warn?.(warning, params.title); } //#endregion //#region src/commands/daemon-install-plan.shared.ts /** Detect source-checkout dev mode from the current CLI entrypoint. */ function resolveGatewayDevMode(argv = process.argv) { const normalizedEntry = argv[1]?.replaceAll("\\", "/"); return normalizedEntry?.includes("/src/") && normalizedEntry.endsWith(".ts"); } /** Resolve dev-mode and Node path inputs for daemon service install planning. */ async function resolveDaemonInstallRuntimeInputs(params) { return { devMode: params.devMode ?? resolveGatewayDevMode(), nodePath: params.nodePath ?? await resolvePreferredNodePath({ env: params.env, runtime: params.runtime }) }; } /** Emit runtime warnings for daemon install command arguments. */ async function emitDaemonInstallRuntimeWarning(params) { await emitNodeRuntimeWarning({ env: params.env, runtime: params.runtime, nodeProgram: params.programArguments[0], warn: params.warn, title: params.title }); } /** Return the Node binary directory that should be added to daemon PATH. */ function resolveDaemonNodeBinDir(nodePath) { const trimmed = nodePath?.trim(); if (!trimmed || !path.isAbsolute(trimmed)) return; return [path.dirname(trimmed)]; } function isOpenClawCommandBasename(basename, platform) { if (basename === "openclaw") return true; if (platform === "win32") return basename === "openclaw.cmd" || basename === "openclaw.ps1" || basename === "openclaw.exe"; return false; } function safeRealpathSync(inputPath, realpathSync) { if (!inputPath) return; try { return realpathSync(inputPath); } catch { return; } } function addUniquePathDir(dirs, dir) { if (!dir || !path.isAbsolute(dir) || dirs.includes(dir)) return; dirs.push(dir); } /** Resolve the OpenClaw CLI binary directory from argv/PATH for daemon PATH. */ function resolveDaemonOpenClawBinDir(params = {}) { const platform = params.platform ?? process.platform; const argv = params.argv ?? process.argv; const env = params.env ?? process.env; const existsSync = params.existsSync ?? fs.existsSync; const realpathSync = params.realpathSync ?? fs.realpathSync.native; const argv1 = argv[1]?.trim(); const dirs = []; if (argv1 && path.isAbsolute(argv1) && isOpenClawCommandBasename(path.basename(argv1), platform)) addUniquePathDir(dirs, path.dirname(argv1)); const argvRealpath = path.isAbsolute(argv1 ?? "") ? safeRealpathSync(argv1, realpathSync) : void 0; for (const rawSegment of (env.PATH ?? "").split(path.delimiter)) { const segment = rawSegment.trim(); if (!path.isAbsolute(segment)) continue; const candidate = path.join(segment, platform === "win32" ? "openclaw.cmd" : "openclaw"); if (!existsSync(candidate)) continue; const candidateRealpath = safeRealpathSync(candidate, realpathSync); if (argvRealpath && candidateRealpath && candidateRealpath !== argvRealpath) continue; addUniquePathDir(dirs, segment); } return dirs.length > 0 ? dirs : void 0; } /** Merge Node and OpenClaw binary directories for the daemon service PATH. */ function resolveDaemonServicePathDirs(params) { const dirs = []; for (const dir of resolveDaemonNodeBinDir(params.nodePath) ?? []) addUniquePathDir(dirs, dir); for (const dir of resolveDaemonOpenClawBinDir(params) ?? []) addUniquePathDir(dirs, dir); return dirs.length > 0 ? dirs : void 0; } //#endregion export { OPENCLAW_WRAPPER_ENV_KEY as a, resolveOpenClawWrapperPath as c, resolveDaemonServicePathDirs as i, resolveDaemonInstallRuntimeInputs as n, resolveGatewayProgramArguments as o, resolveDaemonNodeBinDir as r, resolveNodeProgramArguments as s, emitDaemonInstallRuntimeWarning as t };