import { spawnSync } from "node:child_process"; import { existsSync } from "node:fs"; import { enableCompileCache, getCompileCacheDir } from "node:module"; import path from "node:path"; export function resolveEntryInstallRoot(entryFile: string): string { const entryDir = path.dirname(entryFile); const entryParent = path.basename(entryDir); return entryParent === "dist" || entryParent === "src" ? path.dirname(entryDir) : entryDir; } export function isSourceCheckoutInstallRoot(installRoot: string): boolean { return ( existsSync(path.join(installRoot, ".git")) || existsSync(path.join(installRoot, "src", "entry.ts")) ); } function isNodeCompileCacheDisabled(env: NodeJS.ProcessEnv | undefined): boolean { return env?.NODE_DISABLE_COMPILE_CACHE !== undefined; } function isNodeCompileCacheRequested(env: NodeJS.ProcessEnv | undefined): boolean { return env?.NODE_COMPILE_CACHE !== undefined && !isNodeCompileCacheDisabled(env); } export function shouldEnableOpenClawCompileCache(params: { env?: NodeJS.ProcessEnv; installRoot: string; }): boolean { if (isNodeCompileCacheDisabled(params.env)) { return false; } return !isSourceCheckoutInstallRoot(params.installRoot); } export type OpenClawCompileCacheRespawnPlan = { command: string; args: string[]; env: NodeJS.ProcessEnv; }; export function buildOpenClawCompileCacheRespawnPlan(params: { currentFile: string; env?: NodeJS.ProcessEnv; execArgv?: string[]; execPath?: string; installRoot: string; argv?: string[]; compileCacheDir?: string; }): OpenClawCompileCacheRespawnPlan | undefined { const env = params.env ?? process.env; if (!isSourceCheckoutInstallRoot(params.installRoot)) { return undefined; } if (env.OPENCLAW_SOURCE_COMPILE_CACHE_RESPAWNED === "1") { return undefined; } if (!params.compileCacheDir && !isNodeCompileCacheRequested(env)) { return undefined; } const nextEnv: NodeJS.ProcessEnv = { ...env, NODE_DISABLE_COMPILE_CACHE: "1", OPENCLAW_SOURCE_COMPILE_CACHE_RESPAWNED: "1", }; delete nextEnv.NODE_COMPILE_CACHE; return { command: params.execPath ?? process.execPath, args: [ ...(params.execArgv ?? process.execArgv), params.currentFile, ...(params.argv ?? process.argv).slice(2), ], env: nextEnv, }; } export function respawnWithoutOpenClawCompileCacheIfNeeded(params: { currentFile: string; installRoot: string; }): boolean { const plan = buildOpenClawCompileCacheRespawnPlan({ currentFile: params.currentFile, installRoot: params.installRoot, compileCacheDir: getCompileCacheDir?.(), }); if (!plan) { return false; } const result = spawnSync(plan.command, plan.args, { stdio: "inherit", env: plan.env, }); if (result.error) { throw result.error; } process.exit(result.status ?? 1); return true; } export function enableOpenClawCompileCache(params: { env?: NodeJS.ProcessEnv; installRoot: string; }): void { if (!shouldEnableOpenClawCompileCache(params)) { return; } try { enableCompileCache(); } catch { // Best-effort only; never block startup. } }