mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
Add experimental durable exe.dev agent environments
Keep one VM per environment with independent lease cgroups, persistent workspaces, immutable runner images, and an explicit experimental gate. Add live compatibility, recovery, browser-preview, and stress campaigns. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
e26d787928
commit
056703424a
56 files changed
+1782
-2062
No files matched your search
@@ -0,0 +1,30 @@
|
||||
import { execFileSync, spawnSync } from "node:child_process";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { computeDaytonaImageContentId, DAYTONA_IMAGE_INPUT_PATHS, extractDaytonaDockerfileFrontendDigest } from "../tests/runner-e2e/daytona-image-content.js";
|
||||
|
||||
const root = path.resolve(import.meta.dirname, "..");
|
||||
const args = process.argv.slice(2);
|
||||
const option = (name: string) => { const i = args.indexOf(name); return i < 0 ? undefined : args[i + 1]; };
|
||||
const dockerfile = await readFile(path.join(root, "docker/exe-dev-runner/Dockerfile"), "utf8");
|
||||
const revision = execFileSync("git", ["rev-parse", "HEAD"], { cwd: root, encoding: "utf8" }).trim();
|
||||
const dirty = execFileSync("git", ["status", "--porcelain"], { cwd: root, encoding: "utf8" }).trim().length > 0;
|
||||
if (dirty && process.env.PAPERCLIP_IMAGE_ALLOW_DIRTY !== "1") throw new Error("Commit the image inputs before building, or explicitly set PAPERCLIP_IMAGE_ALLOW_DIRTY=1 for a development image");
|
||||
// COPY packages includes the workspace graph. Hash every source-owned package
|
||||
// input so changes outside the runner can never reuse an old content tag.
|
||||
const packageInputs = execFileSync("git", ["ls-files", "--cached", "--others", "--exclude-standard", "-z", "packages"], { cwd: root, encoding: "utf8" }).split("\0").filter(Boolean);
|
||||
const contentId = await computeDaytonaImageContentId({
|
||||
repositoryRoot: root,
|
||||
inputPaths: [...new Set([...DAYTONA_IMAGE_INPUT_PATHS.filter((p) => p !== "docker/daytona-runner/Dockerfile" && !p.startsWith("packages/")), ...packageInputs, "server/package.json", "ui/package.json", "cli/package.json", "docker/exe-dev-runner", "scripts/build-exe-dev-image.ts"])].sort(),
|
||||
baseImages: [...dockerfile.matchAll(/^FROM (\S+@sha256:[a-f0-9]{64})/gm)].map((match) => match[1]),
|
||||
frontendDigest: extractDaytonaDockerfileFrontendDigest(dockerfile),
|
||||
});
|
||||
if (args.includes("--content-id")) { console.log(contentId); process.exit(0); }
|
||||
const tag = option("--tag") ?? `ghcr.io/paperclipai/paperclip-exe-runner:experimental-${contentId}`;
|
||||
const build = spawnSync("docker", ["buildx", "build", "--platform", "linux/amd64", "--file", "docker/exe-dev-runner/Dockerfile",
|
||||
"--build-arg", `PAPERCLIP_RUNNER_SOURCE_REVISION=${revision}`,
|
||||
"--build-arg", `PAPERCLIP_RUNNER_CONTENT_ID=${contentId}`,
|
||||
"--tag", tag, ...(args.includes("--push") ? ["--push"] : ["--load"]),
|
||||
...(option("--metadata-file") ? ["--metadata-file", option("--metadata-file")!] : []), "."], { cwd: root, stdio: "inherit" });
|
||||
if (build.error) throw build.error;
|
||||
process.exitCode = build.status ?? 1;
|
||||
@@ -64,7 +64,7 @@ const requiredSourceFragments = [
|
||||
["scripts/install.sh", "DEFAULT_NODE_MAJOR=24"],
|
||||
["docker/agent-runtime/Dockerfile.base", "ARG NODE_VERSION=24"],
|
||||
["packages/adapter-utils/src/sandbox-install-command.ts", "NODE_VERSION=\"v24.11.0\""],
|
||||
["packages/plugins/sandbox-providers/exe-dev/src/plugin.ts", "nodesource.com/setup_24.x"],
|
||||
["docker/exe-dev-runner/Dockerfile", "FROM node:24-bookworm@sha256:"],
|
||||
["packages/plugins/sandbox-providers/modal/src/manifest.ts", 'default: "node:24"'],
|
||||
["cli/esbuild.config.mjs", 'target: "node24"'],
|
||||
["packages/plugins/sdk/src/bundlers.ts", 'target: "node24"'],
|
||||
|
||||
Reference in new issue
Block a user