UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

188 lines (187 loc) • 7.5 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { w as root } from "./fs-safe-BUXBSN-4.mjs"; import { t as createSubsystemLogger } from "./subsystem-I-uqdx4f.mjs"; import { c as requireGit, f as runGit } from "./git-BhBtDGVR.mjs"; import { a as requireWorktreeDiskSpace, t as WORKTREE_SETUP_HEADROOM_BYTES } from "./capacity-DNhE5np7.mjs"; import { t as withWorktreeGitConfig } from "./checkout-git-config-duaPg5cH.mjs"; import { a as detectWorktreeFilesystemBackend, r as prepareWorktreeTemplate } from "./template-cache-hZSQgjz-.mjs"; import { n as resolveSandboxDependencyTemplateIdentity, t as prepareSandboxDependencyTemplate } from "./dependency-template-CEoDJy7u.mjs"; import { t as prepareLocalWorkspaceCheckout } from "./local-workspace-checkout-DFfL-aGw.mjs"; import path from "node:path"; import fs from "node:fs/promises"; import { createHash } from "node:crypto"; import { parse as parse$1 } from "yaml"; //#region src/gateway/worker-environments/local-workspace-template.ts const log = createSubsystemLogger("agents/worktrees"); const digest = (value) => createHash("sha256").update(value).digest("hex"); async function hasContainedVirtualStore(directory, workdir) { try { const { buffer } = await (await root(directory)).read("node_modules/.modules.yaml", { symlinks: "reject", maxBytes: 1048576 }); const manifest = parse$1(buffer.toString("utf8")); if (!isRecord(manifest) || typeof manifest.virtualStoreDir !== "string") return false; const modules = path.posix.resolve(workdir, "node_modules"); const relative = path.posix.relative(modules, path.posix.resolve(modules, manifest.virtualStoreDir)); return relative !== ".." && !relative.startsWith("../") && !path.posix.isAbsolute(relative); } catch { return false; } } /** Only dependencies may survive installation; repository setup outputs remain private. */ async function validateTemplate(directory, commit, guard, trim = false) { return await withWorktreeGitConfig(directory, true, { signal: guard.signal, beforeRun: guard.commitGuard }, async (git) => { const result = await git.run(directory, [ "status", "--porcelain=v2", "--branch", "-z", "--untracked-files=normal", "--ignored=matching" ], { signal: guard.signal, beforeRun: guard.commitGuard, killProcessTree: true }); const fields = result.stdout.split("\0"); if (result.code !== 0 || result.termination !== "exit" || result.stdoutTruncatedBytes || fields.pop() !== "") return false; const heads = fields.filter((field) => field.startsWith("# branch.oid ")); if (heads.length !== 1 || heads[0] !== `# branch.oid ${commit}`) return false; for (const field of fields) { if (field.startsWith("# ")) continue; if (!field.startsWith("! ") && !field.startsWith("? ")) return false; const relative = field.slice(2); const parts = relative.replace(/\/$/u, "").split("/"); if (parts.some((part) => !part || part === "." || part === "..") || path.isAbsolute(relative)) return false; const target = path.join(directory, ...parts); const modulesIndex = parts.indexOf("node_modules"); if (modulesIndex !== -1) { if (!(await fs.lstat(path.join(directory, ...parts.slice(0, modulesIndex + 1)))).isDirectory()) return false; continue; } if (!trim) return false; guard.commitGuard(); await fs.rm(target, { recursive: true, force: true }); } return true; }); } /** The caller holds allocation before projection custody, matching removal's lock order. */ async function cloneLocalWorkspaceTemplate(params) { const { guard } = params; const backend = await detectWorktreeFilesystemBackend(path.dirname(params.destination), guard); if (!backend) return false; const gitOptions = { signal: guard.signal, beforeRun: guard.commitGuard, killProcessTree: true }; const lockfile = await runGit(params.source, ["show", `${params.baseCommit}:pnpm-lock.yaml`], gitOptions); if (lockfile.code !== 0 || lockfile.stdoutTruncatedBytes) { log.debug("sandbox dependency template skipped: no complete pnpm lockfile at the selected commit"); return false; } const identity = await resolveSandboxDependencyTemplateIdentity(params.sandbox, { signal: guard.signal, assertCurrent: guard.commitGuard }); if (!identity) { log.debug("sandbox dependency template skipped: local image identity unavailable"); return false; } const commonDir = path.resolve(params.source, await requireGit(params.source, ["rev-parse", "--git-common-dir"], gitOptions)); const prepareSource = async (directory) => { requireWorktreeDiskSpace([{ path: params.templateRoot, bytes: WORKTREE_SETUP_HEADROOM_BYTES }], "sandbox dependency template"); await backend.createTemplate(directory, guard); await prepareLocalWorkspaceCheckout({ source: params.source, destination: directory, temporaryRoot: params.temporaryRoot, baseCommit: params.baseCommit, branch: "openclaw-template", signal: guard.signal, assertCurrent: guard.commitGuard }); }; const record = await prepareWorktreeTemplate({ env: params.env, now: Date.now, options: guard, cacheKey: digest(`sandbox-v1\n${commonDir}\n${params.templateRoot}\n${identity.key}`), contentKey: digest(`${params.baseCommit}\n${digest(lockfile.stdout)}\n${identity.key}`), repoRoot: params.repoRoot, commonDir, worktreeRoot: params.templateRoot, sourceCommit: params.baseCommit, backend: `sandbox-${backend.id}`, requireSpace: () => requireWorktreeDiskSpace([{ path: params.templateRoot, bytes: WORKTREE_SETUP_HEADROOM_BYTES }], "sandbox dependency template"), validate: (existing) => validateTemplate(existing.path, params.baseCommit, guard), prepare: async (preparing) => { await prepareSource(preparing.path); const result = await prepareSandboxDependencyTemplate({ directory: preparing.path, cfg: params.sandbox, scopeKey: preparing.id, identity, signal: guard.signal, assertCurrent: guard.commitGuard, rollbackGuard: guard.rollbackGuard }); let reason = result.installed ? void 0 : result.reason; if (result.installed) { const contained = await hasContainedVirtualStore(preparing.path, identity.docker.workdir); guard.commitGuard(); if (contained && await validateTemplate(preparing.path, params.baseCommit, guard, true)) { log.info("sandbox dependency template prepared for the selected commit"); return; } reason = contained ? "installation changed tracked source" : "pnpm virtual store is outside node_modules or unavailable"; } log.warn(`sandbox dependency template using source-only fallback: ${reason}`); guard.commitGuard(); await fs.rm(preparing.path, { recursive: true, force: true }); await prepareSource(preparing.path); } }); if (!record) return false; guard.commitGuard(); requireWorktreeDiskSpace([{ path: params.destination, bytes: backend.id === "btrfs" ? backend.estimateCloneBytes(0, 0) : WORKTREE_SETUP_HEADROOM_BYTES }], "sandbox workspace clone"); try { await backend.cloneTemplate(record.path, params.destination, guard); } catch { guard.commitGuard(); await fs.rm(params.destination, { recursive: true, force: true }); log.warn("sandbox dependency snapshot unavailable; using source-only checkout"); return false; } await requireGit(params.destination, [ "branch", "-m", params.branch ], gitOptions); return true; } //#endregion export { cloneLocalWorkspaceTemplate };