UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

96 lines (95 loc) 3.81 kB
import { t as resolveNodeHostExecutable } from "./node-host-HHgJTfC5.js"; import { t as resolveClaudeCatalogHomeDir } from "./session-catalog-home-DC4c4SgQ.js"; import fs from "node:fs"; import path from "node:path"; //#region extensions/anthropic/session-catalog-executable.ts const BROKEN_NPM_SHIM_MARKER = "Error: claude native binary not installed."; const BROKEN_NPM_INSTALL_HINT = "node_modules/@anthropic-ai/claude-code/install.cjs"; const CLAUDE_PACKAGE_SHIM_TARGET = /(?:\$basedir|%dp0%)\/([^"'\r\n]*?node_modules\/@anthropic-ai\/claude-code\/bin\/claude\.exe)/giu; const MAX_SHIM_PROBE_BYTES = 4096; let cachedNativeReplacement; function readSmallExecutableSource(executable) { try { const realPath = fs.realpathSync(executable); if (fs.statSync(realPath).size > MAX_SHIM_PROBE_BYTES) return; return { realPath, source: fs.readFileSync(realPath, "utf8") }; } catch { return; } } function isFailedClaudeNpmPlaceholder(source) { return source.includes(BROKEN_NPM_SHIM_MARKER) && source.includes(BROKEN_NPM_INSTALL_HINT); } function isBrokenClaudeNpmShim(executable) { const shim = readSmallExecutableSource(executable); if (!shim) return false; if (isFailedClaudeNpmPlaceholder(shim.source)) return true; const normalizedSource = shim.source.replaceAll("\\", "/"); const baseDirectories = /* @__PURE__ */ new Set([path.dirname(executable), path.dirname(shim.realPath)]); for (const match of normalizedSource.matchAll(CLAUDE_PACKAGE_SHIM_TARGET)) { const relativeTarget = match[1]; if (!relativeTarget) continue; for (const baseDirectory of baseDirectories) { const target = readSmallExecutableSource(path.resolve(baseDirectory, relativeTarget)); if (target && isFailedClaudeNpmPlaceholder(target.source)) return true; } } return false; } function resolveExecutableFromDirectory(directory, env) { const resolution = resolveNodeHostExecutable("claude", { env, pathEnv: directory, strategy: "direct" }); return resolution && !isBrokenClaudeNpmShim(resolution.executable) ? resolution.executable : void 0; } function resolveClaudeDesktopExecutable(homeDir, env) { if (process.platform !== "darwin") return; const versionsRoot = path.join(homeDir, "Library", "Application Support", "Claude", "claude-code"); let versions; try { versions = fs.readdirSync(versionsRoot, { withFileTypes: true }); } catch { return; } versions.sort((left, right) => right.name.localeCompare(left.name, void 0, { numeric: true, sensitivity: "base" })); for (const version of versions) { if (!version.isDirectory()) continue; const executable = resolveExecutableFromDirectory(path.join(versionsRoot, version.name, "claude.app", "Contents", "MacOS"), env); if (executable) return executable; } } function resolveNativeReplacement(env) { const homeDir = resolveClaudeCatalogHomeDir(env); const cacheKey = `${process.platform}\0${homeDir}`; if (cachedNativeReplacement?.key === cacheKey) return cachedNativeReplacement.executable ?? void 0; const executable = resolveExecutableFromDirectory(path.join(homeDir, ".local", "bin"), env) ?? resolveClaudeDesktopExecutable(homeDir, env); cachedNativeReplacement = { key: cacheKey, executable: executable ?? null }; return executable; } function resolveClaudeTerminalExecutable(env = process.env) { const shellResolution = resolveNodeHostExecutable("claude", { env, pathEnv: env.PATH ?? env.Path ?? "", strategy: "prefer" }); if (shellResolution && !isBrokenClaudeNpmShim(shellResolution.executable)) return shellResolution; const nativeExecutable = resolveNativeReplacement(env); if (!nativeExecutable) return; return { executable: nativeExecutable, ...shellResolution?.pathEnv ? { pathEnv: shellResolution.pathEnv } : {} }; } //#endregion export { resolveClaudeTerminalExecutable as t };