feat(runner): qualify native Codex platforms and cache hosted builds

Extract the tested runtime and installed-package prerequisite without changing agent creation defaults or experimental gates.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-12 15:15:01 -05:00
1 parent 7d9b93aee2
commit ddcd746eb6
40 files changed
+3474 -565

No files matched your search

@@ -9,9 +9,10 @@ import {
buildNativeRunnerArguments,
buildNativeRunnerPreparePayload,
resolvePaperclipRunnerBinary,
resolveRemotePaperclipRunnerBinary,
} from "./native-codex-runner.js";
afterEach(() => vi.restoreAllMocks());
afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); vi.unstubAllEnvs(); });
describe("installed runner selection", () => {
it("uses the runner's platform-aware packaged selection", async () => {
@@ -45,6 +46,121 @@ describe("installed runner selection", () => {
});
});
describe("selected remote daemon target", () => {
function header(target: string) {
const bytes = Buffer.alloc(64);
if (target.startsWith("darwin")) {
bytes.writeUInt32LE(0xfeedfacf); bytes.writeUInt32LE(target.endsWith("arm64") ? 0x0100000c : 0x01000007, 4);
} else {
bytes.set([0x7f, 0x45, 0x4c, 0x46, 2, 1]); bytes.writeUInt16LE(target.endsWith("arm64") ? 183 : 62, 18);
}
return bytes;
}
const remote = (stdout: string, overrides = {}) => ({ execute: vi.fn(async () => ({ exitCode: 0, signal: null, timedOut: false, stdout, stderr: "", pid: null, startedAt: null, ...overrides })) });
it.each([
["Linux", "aarch64", "linux", "arm64"], ["Linux", "x86_64", "linux", "x64"],
["Darwin", "arm64", "darwin", "arm64"], ["Darwin", "x86_64", "darwin", "x64"],
] as const)("uses the packaged %s/%s daemon independent of the controller", async (os, arch, platform, architecture) => {
const root = await mkdtemp(join(tmpdir(), "paperclip-ssh-daemon-"));
const binary = join(root, "paperclip-runnerd");
try {
await writeFile(binary, header(`${platform}-${architecture}`));
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary").mockReturnValue(binary);
const target = remote(`${os}\n${arch}\n`);
expect(await resolveRemotePaperclipRunnerBinary({ runner: target, remoteCwd: "/selected-workspace" })).toBe(binary);
expect(select).toHaveBeenCalledExactlyOnceWith(platform, architecture);
expect(target.execute).toHaveBeenCalledExactlyOnceWith({ command: "sh", args: ["-c", "uname -s; uname -m"], cwd: "/selected-workspace", bypassSession: true, timeoutMs: 10_000 });
} finally { await rm(root, { recursive: true, force: true }); }
});
it.each(["arm64", "x64"].flatMap(controllerArch => ["arm64", "x64"].map(targetArch => ({ controllerArch, targetArch }))))(
"selects the actual Linux $targetArch sandbox bytes on a Mac $controllerArch controller", async ({ controllerArch, targetArch }) => {
const root = await mkdtemp(join(tmpdir(), "paperclip-sandbox-daemon-"));
const binary = join(root, "paperclip-runnerd");
try {
vi.stubGlobal("process", { ...process, platform: "darwin", arch: controllerArch });
await writeFile(binary, header(`linux-${targetArch}`));
const controllerBinary = join(root, "controller-runnerd");
await writeFile(controllerBinary, header(`darwin-${controllerArch}`), { mode: 0o700 });
vi.stubEnv("PAPERCLIP_RUNNER_BINARY", controllerBinary);
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary").mockReturnValue(binary);
const target = remote(`Linux\n${targetArch === "arm64" ? "aarch64" : "x86_64"}\n`);
expect(await resolveRemotePaperclipRunnerBinary({ runner: target, remoteCwd: "/sandbox-workspace" })).toBe(binary);
expect(select).toHaveBeenCalledExactlyOnceWith("linux", targetArch);
expect(target.execute).toHaveBeenCalledExactlyOnceWith({ command: "sh", args: ["-c", "uname -s; uname -m"], cwd: "/sandbox-workspace", bypassSession: true, timeoutMs: 10_000 });
} finally { await rm(root, { recursive: true, force: true }); }
},
);
it.each(["linux", "darwin"].flatMap(platform => ["arm64", "x64"].map(architecture => ({ platform, architecture }))))(
"prefers the supervisor's fresh $platform/$architecture override for the same-host target", async ({ platform, architecture }) => {
const root = await mkdtemp(join(tmpdir(), "paperclip-same-host-daemon-"));
try {
vi.stubGlobal("process", { ...process, platform, arch: architecture });
const fresh = join(root, "fresh-runnerd"), stale = join(root, "stale-packaged-runnerd");
await writeFile(fresh, Buffer.concat([header(`${platform}-${architecture}`), Buffer.from("fresh")]), { mode: 0o700 });
await writeFile(stale, Buffer.concat([header(`${platform}-${architecture}`), Buffer.from("stale")]), { mode: 0o700 });
vi.stubEnv("PAPERCLIP_RUNNER_BINARY", fresh);
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary").mockReturnValue(stale);
const target = remote(`${platform === "linux" ? "Linux" : "Darwin"}\n${architecture === "arm64" ? "arm64" : "x86_64"}\n`);
expect(await resolveRemotePaperclipRunnerBinary({ runner: target, remoteCwd: "/workspace" })).toBe(fresh);
expect(select).not.toHaveBeenCalled();
} finally { await rm(root, { recursive: true, force: true }); }
},
);
it.each(["missing", "relative", "malformed", "wrong-architecture"])("retains same-host override policy and target validation (%s)", async scenario => {
const root = await mkdtemp(join(tmpdir(), "paperclip-same-host-daemon-"));
try {
vi.stubGlobal("process", { ...process, platform: "linux", arch: "x64" });
const override = join(root, "configured-runnerd"), fallback = join(root, "packaged-runnerd");
if (scenario !== "missing") await writeFile(override, scenario === "malformed" ? Buffer.alloc(64) : header("linux-arm64"), { mode: 0o700 });
await writeFile(fallback, header("linux-x64"), { mode: 0o700 });
vi.stubEnv("PAPERCLIP_RUNNER_BINARY", scenario === "relative" ? "relative-runnerd" : override);
vi.spyOn(runner, "defaultCapabilityRunnerdBinary").mockReturnValue(fallback);
const request = resolveRemotePaperclipRunnerBinary({ runner: remote("Linux\nx86_64\n"), remoteCwd: "/workspace" });
if (scenario === "missing") expect(await request).toBe(fallback);
else await expect(request).rejects.toThrow(scenario === "relative" ? "PAPERCLIP_RUNNER_BINARY must be an absolute path" : "runner_remote_artifact_platform_mismatch");
} finally { await rm(root, { recursive: true, force: true }); }
});
it("ignores a relative controller override when the actual target differs", async () => {
const root = await mkdtemp(join(tmpdir(), "paperclip-cross-host-daemon-"));
try {
vi.stubGlobal("process", { ...process, platform: "darwin", arch: "arm64" });
vi.stubEnv("PAPERCLIP_RUNNER_BINARY", "relative-controller-runnerd");
const binary = join(root, "linux-runnerd");
await writeFile(binary, header("linux-arm64"));
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary").mockReturnValue(binary);
expect(await resolveRemotePaperclipRunnerBinary({ runner: remote("Linux\naarch64\n"), remoteCwd: "/workspace" })).toBe(binary);
expect(select).toHaveBeenCalledExactlyOnceWith("linux", "arm64");
} finally { await rm(root, { recursive: true, force: true }); }
});
it.each(["matching", "wrong-architecture", "malformed", "missing"])("verifies an explicit controller-owned remote artifact (%s)", async scenario => {
const root = await mkdtemp(join(tmpdir(), "paperclip-ssh-daemon-"));
const binary = join(root, "configured-runnerd");
try {
vi.stubGlobal("process", { ...process, platform: "linux", arch: "arm64" });
vi.stubEnv("PAPERCLIP_RUNNER_BINARY", "invalid-relative-controller-override");
if (scenario !== "missing") await writeFile(binary, scenario === "malformed" ? Buffer.alloc(64) : header(scenario === "matching" ? "linux-arm64" : "linux-x64"));
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary");
const request = resolveRemotePaperclipRunnerBinary({ runner: remote("Linux\naarch64\n"), remoteCwd: "/workspace", configuredPath: binary });
if (scenario === "matching") expect(await request).toBe(binary);
else await expect(request).rejects.toThrow(scenario === "missing" ? "runner_remote_artifact_unavailable" : "runner_remote_artifact_platform_mismatch");
expect(select).not.toHaveBeenCalled();
} finally { await rm(root, { recursive: true, force: true }); }
});
it("keeps missing package targets actionable without a controller or legacy fallback", async () => {
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary").mockImplementation(() => { throw new Error("runner_remote_artifact_unavailable: install the matching release"); });
await expect(resolveRemotePaperclipRunnerBinary({ runner: remote("Linux\naarch64\n"), remoteCwd: "/workspace" })).rejects.toThrow("runner_remote_artifact_unavailable");
expect(select).toHaveBeenCalledExactlyOnceWith("linux", "arm64");
});
it.each([
["Linux\naarch64\n", { exitCode: 1 }], ["Linux\naarch64\n", { timedOut: true }],
["Linux\nriscv64\n", {}], ["FreeBSD\nx86_64\n", {}], ["", {}],
])("fails a missing, failed or unsupported platform probe (%s)", async (stdout, overrides) => {
const select = vi.spyOn(runner, "defaultCapabilityRunnerdBinary");
await expect(resolveRemotePaperclipRunnerBinary({ runner: remote(stdout as string, overrides), remoteCwd: "/workspace" })).rejects.toThrow("runner_remote_artifact_platform_mismatch");
expect(select).not.toHaveBeenCalled();
});
});
describe("buildNativeRunnerArguments", () => {
it("binds every durable identity without exposing the bootstrap ticket", () => {
const args = buildNativeRunnerArguments({
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
import { and, eq } from "drizzle-orm";
import type { AdapterExecutionResult } from "@paperclipai/adapter-utils";
import type { CommandManagedRuntimeRunner } from "@paperclipai/adapter-utils/command-managed-runtime";
import type { Db } from "@paperclipai/db";
import { agentSessionGoalActions, agentTaskSessions } from "@paperclipai/db";
@@ -14,6 +15,7 @@ import { failRunnerGoalAction } from "../runner-goals.js";
import {
createPaperclipRunnerAuthorizedToolSet,
defaultCapabilityRunnerdBinary,
runnerBinaryTarget,
type PaperclipSemanticToolDefinition,
} from "../../vendor/paperclip-runner/index.js";
import { runnerPrpCoordinator } from "./runner-prp-coordinator.js";
@@ -206,6 +208,38 @@ export function resolvePaperclipRunnerBinary(
);
}
/** Select controller-owned bytes for the actual remote host, never its controller. */
export async function resolveRemotePaperclipRunnerBinary(input: {
runner: CommandManagedRuntimeRunner;
remoteCwd: string;
configuredPath?: string | null;
}): Promise<string> {
const probe = await input.runner.execute({ command: "sh", args: ["-c", "uname -s; uname -m"],
cwd: input.remoteCwd, bypassSession: true, timeoutMs: 10_000 });
const [os, arch] = probe.stdout.trim().split(/\r?\n/);
const platform = os === "Linux" ? "linux" : os === "Darwin" ? "darwin" : null;
const architecture = arch === "x86_64" ? "x64" : arch === "aarch64" || arch === "arm64" ? "arm64" : null;
if (probe.exitCode !== 0 || probe.timedOut || !platform || !architecture) {
throw new Error("runner_remote_artifact_platform_mismatch: could not identify a supported remote OS and architecture; check the selected execution environment and retry");
}
const configured = input.configuredPath?.trim();
if (configured && !isAbsolute(configured)) throw new Error("PAPERCLIP_RUNNER_REMOTE_BINARY_PATH must be an absolute path");
// A same-host sandbox can use the supervisor's fresh development artifact.
// Cross-platform targets must never inherit the controller's override.
const controllerOverride = platform === process.platform && architecture === process.arch
? process.env.PAPERCLIP_RUNNER_BINARY : undefined;
const binary = configured || (controllerOverride
? resolvePaperclipRunnerBinary(controllerOverride)
: defaultCapabilityRunnerdBinary(platform, architecture));
let bytes: Buffer;
try { bytes = readFileSync(binary); }
catch (cause) { throw new Error(`runner_remote_artifact_unavailable: install the Paperclip release containing the ${platform}-${architecture} daemon or configure PAPERCLIP_RUNNER_REMOTE_BINARY_PATH`, { cause }); }
if (runnerBinaryTarget(bytes) !== `${platform}-${architecture}`) {
throw new Error(`runner_remote_artifact_platform_mismatch: the selected daemon does not match ${platform}-${architecture}; install the matching Paperclip release or configure PAPERCLIP_RUNNER_REMOTE_BINARY_PATH`);
}
return binary;
}
export function buildNativeRunnerArguments(input: {
connectUrl: string;
stateDirectory: string;
@@ -206,6 +206,7 @@ const state = vi.hoisted(() => ({
bundledPackManifestPath: null as string | null,
bundledRunnerBinary: null as string | null,
resolveRunnerBinary: vi.fn(() => "/tmp/paperclip-runnerd"),
resolveRemoteRunnerBinary: vi.fn(async (input: { configuredPath?: string | null }) => input.configuredPath || "/tmp/paperclip-runnerd"),
release: null as null | (() => void),
}));
@@ -300,6 +301,7 @@ vi.mock("../issue-recovery-actions.js", () => ({
vi.mock("./native-codex-runner.js", () => ({
resolvePaperclipRunnerBinary: state.resolveRunnerBinary,
resolveRemotePaperclipRunnerBinary: state.resolveRemoteRunnerBinary,
}));
import {
@@ -373,6 +375,7 @@ beforeEach(() => {
state.bundledRunnerBinary = null;
state.createAssignedMcpTools.mockReset();
state.resolveRunnerBinary.mockReset().mockReturnValue("/tmp/paperclip-runnerd");
state.resolveRemoteRunnerBinary.mockReset().mockImplementation(async (input: { configuredPath?: string | null }) => input.configuredPath || "/tmp/paperclip-runnerd");
state.resolveCurrentWakeCommentsBinding.mockReset().mockResolvedValue(null);
state.assertCurrentWakeCommentsRead.mockReset().mockResolvedValue(undefined);
});
@@ -12203,22 +12206,20 @@ describe("runnerd provider runtime wiring", () => {
it.each([
...["current", "preinstalled-exact", "preinstalled-mismatch", "preinstalled-error", "preinstalled-timeout", "stale", "missing", "retained", "retained-mismatch", "retained-error", "retained-timeout", "retained-explicit"]
.map((image) => ({ image, version: "0.160.0", compatible: true })),
.map((image) => ({ image, version: "0.160.0" })),
...["0.149.0", "0.149.1", "0.153.4", "0.156.0", "0.160.1"]
.map((version) => ({ image: "current", version, compatible: true })),
.map((version) => ({ image: "current", version })),
...["0.148.9", "0.161.0", "1.0.0", "0.160.0-alpha.1", "unknown"]
.map((version) => ({ image: "current", version, compatible: false })),
])("uses shared Codex and the server-owned replacement artifact (image=$image, Codex=$version)", async ({ image, version, compatible }) => {
.map((version) => ({ image: "current", version })),
])("uses shared Codex and the server-owned replacement artifact (image=$image, Codex=$version)", async ({ image, version }) => {
const retained = image.startsWith("retained");
const exactRetained = image === "retained" || image === "retained-explicit";
const needsReplacement = image !== "current" && image !== "preinstalled-exact" && !exactRetained;
// The mocked remote executes metadata probes; artifact staging only needs bytes.
// Keep this regression independent of a locally compiled Rust runner binary.
const controllerArtifact = join(isolatedStateDirectory, "paperclip-runnerd");
if (needsReplacement || retained || image === "preinstalled-exact") {
await writeFile(controllerArtifact, "fixture runner artifact");
state.resolveRunnerBinary.mockReturnValueOnce(controllerArtifact);
}
await writeFile(controllerArtifact, "fixture runner artifact");
state.resolveRemoteRunnerBinary.mockResolvedValue(controllerArtifact);
const onLog = vi.fn(async () => undefined);
const syncIn = vi.fn(async () => undefined);
const remoteExecute = vi.fn(
@@ -12300,16 +12301,10 @@ describe("runnerd provider runtime wiring", () => {
controlPlaneRegistration: (authority: unknown) => Promise<unknown>;
};
await expect(transport.controlPlaneRegistration({})).rejects.toThrow(
compatible ? "reached-preinstalled-codex-verification" : "runner_remote_provider_artifact_incompatible: supported Codex versions >=0.149.0 <0.161.0",
"reached-preinstalled-codex-verification",
);
if (!compatible) {
expect(syncIn).not.toHaveBeenCalled();
expect(remoteExecute.mock.calls.some(([call]) => call.command === "npm" || call.args?.[1]?.includes("paperclip_codex_launcher_tmp"))).toBe(false);
expect(onLog).not.toHaveBeenCalledWith("stderr", expect.stringContaining("using compatible Codex"));
return;
}
if (version !== "0.160.0") {
expect(onLog).toHaveBeenCalledWith("stderr", expect.stringContaining(`using compatible Codex ${version}`));
expect(onLog).toHaveBeenCalledWith("stderr", expect.stringContaining(`using installed Codex ${version === "unknown" || version.includes("alpha") ? "unrecognized version" : version}`));
}
if (needsReplacement) {
expect(transport.runnerBinary).toBe(controllerArtifact);
@@ -12355,12 +12350,9 @@ describe("runnerd provider runtime wiring", () => {
].map((scenario) => ({ ...scenario, recover: false })),
{ version: "0.156.0", model: "gpt-6.1-sol", floor: null, recover: true },
{ version: "0.158.0", model: "gpt-6.1-sol", floor: null, recover: true },
])("verifies sandbox Codex $version against the prepared $model selection (floor=$floor, recover=$recover)", async ({ version, model, floor, recover }) => {
// A preinstalled Codex inside the compatibility window can still be too
// old for the configured model: the ChatGPT backend rejects every turn
// with "not supported when using Codex with a ChatGPT account". The
// verifier names the stale image instead of letting the run fail as an
// account problem.
])("lets sandbox Codex $version reach actual model verification ($model, recover=$recover)", async ({ version, model, recover }) => {
// Version metadata is diagnostic. A working app-server reaches the model
// turn instead of being rejected or replaced by a static CLI version floor.
const preparedModel = recover ? resolvePaperclipRunnerNativeProviderInput({
backend: "codex_app_server", adapterConfig: { provider: "codex", model }, codexCliVersion: version,
}).model : model;
@@ -12430,32 +12422,33 @@ describe("runnerd provider runtime wiring", () => {
);
}
await expect(transport.controlPlaneRegistration({})).rejects.toThrow(
floor
? `runner_remote_provider_artifact_incompatible: ${model} requires Codex ${floor} or newer with ChatGPT sign-in, received ${version} from the sandbox image; promote a sandbox image with Codex 0.160.0 or configure PAPERCLIP_RUNNER_REMOTE_CODEX_NPM_SPEC=@openai/codex@0.160.0`
: "reached-preinstalled-codex-verification",
"reached-preinstalled-codex-verification",
);
if (floor) {
// No npm spec is configured, so there is no fallback install; the run
// fails before launch instead of running against the stale CLI.
expect(remoteExecute.mock.calls.some(([call]) => call.command === "npm")).toBe(false);
expect(remoteExecute.mock.calls.some(([call]) => call.args?.[1]?.includes("paperclip_codex_launcher_tmp"))).toBe(false);
}
expect(remoteExecute.mock.calls.some(([call]) => call.command === "npm")).toBe(false);
});
it("binds a remote launch to the configured controller-owned runner artifact", async () => {
it.each(["ssh", "sandbox"].flatMap(transport => ["explicit", "linux-arm64", "linux-x64", "missing", "mismatch"].map(mode => ({ transport, mode }))))
("binds a $transport launch to the selected controller-owned runner artifact ($mode)", async ({ transport, mode }) => {
const remoteCwd = "/home/daytona/paperclip-workspace";
const controllerArtifact = "/controller/artifacts/paperclip-runnerd";
const controllerArtifact = `/controller/artifacts/${mode}/paperclip-runnerd`;
const explicit = mode === "explicit" || mode === "missing" || mode === "mismatch";
const error = mode === "missing" ? "runner_remote_artifact_unavailable" : mode === "mismatch" ? "runner_remote_artifact_platform_mismatch" : null;
if (error) state.resolveRemoteRunnerBinary.mockRejectedValue(new Error(error));
else state.resolveRemoteRunnerBinary.mockResolvedValue(controllerArtifact);
const remoteExecution = {
...execution,
binding: { ...execution.binding, runId: "run-remote-runner-artifact" },
workspace: { ...execution.workspace, cwd: "/host/paperclip-workspace" },
} as NativeExecutionInputV1;
await createRunnerdBackend({
const backend = createRunnerdBackend({
db: leaseDb(remoteExecution),
execution: remoteExecution,
runnerInstanceId: "runner",
runnerExecutionTarget: {
runnerExecutionTarget: transport === "sandbox" ? {
kind: "remote", transport: "sandbox", providerKey: "test", remoteCwd, runner: { execute: vi.fn() },
} : {
kind: "remote",
transport: "ssh",
remoteCwd,
@@ -12470,14 +12463,26 @@ describe("runnerd provider runtime wiring", () => {
strictHostKeyChecking: true,
},
},
runnerRemoteBinaryPath: controllerArtifact,
...(explicit ? { runnerRemoteBinaryPath: controllerArtifact } : {}),
});
if (error) {
await expect(backend).rejects.toThrow(error);
expect(state.resolveRemoteRunnerBinary).toHaveBeenCalledWith(expect.objectContaining({ remoteCwd, configuredPath: controllerArtifact }));
expect(state.resolveRunnerBinary).not.toHaveBeenCalled();
expect(state.createBackend).not.toHaveBeenCalled();
expect(state.createTransport).not.toHaveBeenCalled();
return;
}
await backend;
state.createTransport.mockClear();
state.createBackend.mock.calls.at(-1)![1].codexTransportFactory!();
expect(state.createTransport).toHaveBeenCalledWith(
expect.objectContaining({ runnerBinary: controllerArtifact }),
);
expect(state.resolveRemoteRunnerBinary).toHaveBeenCalledWith(expect.objectContaining({ remoteCwd, configuredPath: explicit ? controllerArtifact : undefined }));
expect(state.resolveRunnerBinary).not.toHaveBeenCalled();
});
it.each([
@@ -18,11 +18,7 @@ import { copyBackGrokAuth } from "@paperclipai/adapter-grok-local/server";
import { inferOpenAiCompatibleBiller, type AdapterUsageCheckpoint } from "@paperclipai/adapter-utils";
import { createAgentIdentityRedactor } from "../agent-identity-redaction.js";
import {
isSupportedRemoteCodexVersion,
parseCodexCliVersion,
REMOTE_CODEX_SUPPORTED_RANGE,
} from "./codex-runtime-compatibility.js";
import { parseCodexCliVersion } from "./codex-runtime-compatibility.js";
import { createNativeToolTrace, type NativeToolTrace } from "./native-tool-trace.js";
import { createNativeProviderFailureObservation } from "./native-provider-failure.js";
import { createNativeGitHubAccess, type NativeGitHubAccess } from "./native-github-access.js";
@@ -31,11 +27,6 @@ import { bindManagedNativeCredentialTurn, completeManagedNativeCredentialTurn }
import { createLocalNativeQuestionBridge } from "./local-native-question-bridge.js";
import { readVerifiedRemoteWorkspaceFile } from "./remote-deliverable-file.js";
import { copyBackCodexAuth } from "@paperclipai/adapter-codex-local/server";
import {
codexCliVersionAtLeast,
minimumCodexCliVersionForModel,
normalizeCodexModel,
} from "@paperclipai/adapter-codex-local";
import { nativeCompletionFeedback } from "./native-completion-feedback.js";
import { hasAcknowledgedNativeReassignmentStopIntent, hasAcknowledgedNativeStopIntent } from "../acknowledged-native-stop.js";
import { stoppedCodexTurnIsTextOnly } from "./stopped-codex-turn.js";
@@ -181,7 +172,7 @@ import {
} from "./status-arbiter.js";
import { conflict, HttpError } from "../../errors.js";
import { redactSensitiveText } from "../../redaction.js";
import { resolvePaperclipRunnerBinary } from "./native-codex-runner.js";
import { resolvePaperclipRunnerBinary, resolveRemotePaperclipRunnerBinary } from "./native-codex-runner.js";
import {
createNativeRunTrace,
isNativeRunRootHistoricalSpan,
@@ -10193,7 +10184,7 @@ export function assertRemoteRunnerBuildMetadata(
}
}
async function stageRemoteRunnerFile(input: {
export async function stageRemoteRunnerFile(input: {
target: Extract<AdapterExecutionTarget, { kind: "remote" }>;
runner: CommandManagedRuntimeRunner;
sourcePath: string;
@@ -10585,7 +10576,7 @@ export async function syncRemoteRunnerDirectoryOut(input: {
}
}
async function readRemoteRunnerState(input: {
export async function readRemoteRunnerState(input: {
runner: CommandManagedRuntimeRunner;
stateDirectory: string;
}): Promise<Record<string, unknown>> {
@@ -11560,7 +11551,10 @@ async function createRunnerdBackendWithinSessionClaim(
// filesystem; the remote launcher separately owns the sandbox command path.
// When an explicit remote artifact is configured, prepareRemoteRunner stages
// these exact bytes at remoteBinary before launch.
const controllerRunnerBinary = remoteTarget
const targetMatchedCodexArtifact = remoteTarget !== null && input.execution.provider.kind === "codex";
const controllerRunnerBinary = targetMatchedCodexArtifact
? await resolveRemotePaperclipRunnerBinary({ runner: remoteCommandRunner!, remoteCwd: remoteTarget.remoteCwd, configuredPath: input.runnerRemoteBinaryPath })
: remoteTarget
? input.runnerRemoteBinaryPath?.trim() || remotePiCompanion?.runnerBinary || (useBundledRemoteImageAssets ? bundledRemoteRunnerBinary() : resolvePaperclipRunnerBinary())
: resolvePaperclipRunnerBinary();
const explicitRemoteCodex = input.runnerRemoteCodexPath?.trim() || null;
@@ -11651,76 +11645,6 @@ async function createRunnerdBackendWithinSessionClaim(
})
: Promise.resolve();
const verifyRemoteRunner = async (
requiredMode: "dial_wss" | "listen_ws",
executable = remoteBinary,
) => {
if (!remoteTarget || !remoteCommandRunner || !executable) return;
const metadataResult = await remoteCommandRunner.execute({
command: executable,
args: ["--build-metadata"],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 30_000,
});
if (metadataResult.exitCode !== 0 || metadataResult.timedOut) {
throw new Error("runner_remote_artifact_verification_failed");
}
let metadata: Record<string, unknown>;
try {
metadata = JSON.parse(metadataResult.stdout) as Record<string, unknown>;
} catch (error) {
throw new Error("runner_remote_artifact_metadata_invalid", {
cause: error,
});
}
assertRemoteRunnerBuildMetadata(metadata, requiredMode);
};
const reportedCodexVersions = new Set<string>();
const verifyRemoteCodex = async (executable = remoteCodexBinary) => {
if (!remoteTarget || !remoteCommandRunner || !executable) return;
const versionResult = await remoteCommandRunner.execute({
command: executable,
args: ["--version"],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 30_000,
});
if (versionResult.exitCode !== 0 || versionResult.timedOut) {
throw new Error("runner_remote_codex_artifact_verification_failed");
}
const versionOutput = `${versionResult.stdout}\n${versionResult.stderr}`;
const version = parseCodexCliVersion(versionOutput);
if (!version || !isSupportedRemoteCodexVersion(version)) {
throw new Error(
`runner_remote_provider_artifact_incompatible: supported Codex versions ${REMOTE_CODEX_SUPPORTED_RANGE}, received ${version ?? "an unrecognized or prerelease version"}; install a supported stable Codex release or configure PAPERCLIP_RUNNER_REMOTE_CODEX_NPM_SPEC=@openai/codex@${REMOTE_PROVIDER_PACK_PINS.codex}`,
);
}
// A Codex inside the compatibility window can still be too old for the
// configured model: the ChatGPT backend rejects a model from clients
// below the model's floor on every turn. Fail before launch with the
// exact gap, so a stale sandbox image is not reported as an account
// problem. When a preinstalled Codex fails here and an npm spec is
// configured, the caller falls back to installing the pinned release.
const configuredModel = input.execution.provider.kind === "codex"
? input.execution.provider.model
: null;
const modelMinimum = minimumCodexCliVersionForModel(configuredModel);
if (modelMinimum && !codexCliVersionAtLeast(version, modelMinimum)) {
throw new Error(
`runner_remote_provider_artifact_incompatible: ${normalizeCodexModel(configuredModel)} requires Codex ${modelMinimum} or newer with ChatGPT sign-in, received ${version} from the sandbox image; promote a sandbox image with Codex ${REMOTE_PROVIDER_PACK_PINS.codex} or configure PAPERCLIP_RUNNER_REMOTE_CODEX_NPM_SPEC=@openai/codex@${REMOTE_PROVIDER_PACK_PINS.codex}`,
);
}
if (version !== REMOTE_PROVIDER_PACK_PINS.codex && !reportedCodexVersions.has(version)) {
reportedCodexVersions.add(version);
await input.onLog?.(
"stderr",
`[paperclip-runner] using compatible Codex ${version} (supported ${REMOTE_CODEX_SUPPORTED_RANGE}; install pin ${REMOTE_PROVIDER_PACK_PINS.codex})\n`,
);
}
};
const verifyRemoteProviderPack = async (packRoot: string) => {
if (!remoteTarget || !remoteCommandRunner || !expectedProviderPackManifest)
return;
@@ -11805,41 +11729,20 @@ async function createRunnerdBackendWithinSessionClaim(
return parseRemoteExecutableCandidate(result.stdout);
};
// Image policy: keep one latest stable CLI installation shared by native and
// local adapters. Preferred bin entries must point to that same installation;
// never bake an older global CLI alongside a private runner-only version.
const discoverPreinstalledExecutable = async (
name: "paperclip-runnerd" | "codex",
) => {
if (!remoteTarget || !remoteCommandRunner) return null;
return discoverRemoteExecutable(remoteCommandRunner, remoteTarget.remoteCwd, name);
};
const linkPreinstalledExecutable = async (
sourcePath: string,
targetPath: string,
) => {
if (!remoteTarget || !remoteCommandRunner) return;
const escapedSource = sourcePath.replaceAll("'", "'\\''");
const escapedTarget = targetPath.replaceAll("'", "'\\''");
const escapedDirectory = posix.dirname(targetPath).replaceAll("'", "'\\''");
const result = await remoteCommandRunner.execute({
command: "sh",
args: [
"-c",
targetPath === remoteCodexBinary
? buildRemoteCodexLauncherCommand(sourcePath, targetPath)
: `umask 077; mkdir -p '${escapedDirectory}' && ` +
`ln -sfn '${escapedSource}' '${escapedTarget}'`,
],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 10_000,
});
if (result.exitCode !== 0 || result.timedOut) {
throw new Error("runner_remote_preinstalled_link_failed");
}
const remoteNativeArtifacts = remoteTarget && remoteCommandRunner && remoteBinary && remoteRuntimeRoot
? createRemoteNativeArtifactPreparation({
target: remoteTarget, runner: remoteCommandRunner, remoteBinary, controllerRunnerBinary,
remoteRuntimeRoot, remoteCodexBinary, runnerRemoteBinaryPath: input.runnerRemoteBinaryPath,
runnerRemoteCodexPath: input.runnerRemoteCodexPath, runnerRemoteCodexNpmSpec: input.runnerRemoteCodexNpmSpec,
model: input.execution.provider.kind === "codex" ? input.execution.provider.model : null,
reuseRetainedRunner: sandboxLeaseAcquisition?.outcome === "resumed", targetPlatformArtifactVerified: remotePiCompanion !== null || useBundledRemoteImageAssets || targetMatchedCodexArtifact,
trace: input.trace, onLog: input.onLog,
})
: null;
const verifyRemoteRunner = async (mode: "dial_wss" | "listen_ws", executable?: string | null) => {
if (remoteNativeArtifacts) await remoteNativeArtifacts.verifyRemoteRunner(mode, executable ?? undefined);
};
const verifyRemoteCodex = async () => { await remoteNativeArtifacts?.verifyRemoteCodex(); };
const prepareRemoteRunner = async (
requiredMode: "dial_wss" | "listen_ws",
@@ -11861,234 +11764,7 @@ async function createRunnerdBackendWithinSessionClaim(
remotePrepared = true;
return;
}
// Compatibility metadata does not prove artifact identity. Reuse only the
// exact controller-owned bytes when the controller artifact is available.
const matchesControllerRunnerArtifact = async (executable: string): Promise<boolean> => {
const expected = createHash("sha256")
.update(readFileSync(controllerRunnerBinary))
.digest("hex");
try {
const probe = await remoteCommandRunner.execute({
command: "sh",
args: [
"-c",
'test -x "$1" || exit 1; if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1"; else shasum -a 256 "$1"; fi',
"paperclip-runner-artifact",
executable,
],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 10_000,
});
return probe.exitCode === 0 && !probe.timedOut &&
/^[a-f0-9]{64}\s/.test(probe.stdout) &&
probe.stdout.trim().split(/\s+/)[0] === expected;
} catch {
// An unavailable checksum uses the verified staging path.
return false;
}
};
let runnerArtifactPrepared = false;
if (
sandboxLeaseAcquisition?.outcome === "resumed" &&
existsSync(controllerRunnerBinary)
) {
runnerArtifactPrepared = await measureNativeRunnerSpan(
input.trace,
"runner.artifact.verify_retained",
() => matchesControllerRunnerArtifact(remoteBinary),
);
}
const explicitRemoteBinary = input.runnerRemoteBinaryPath?.trim() || null;
if (!runnerArtifactPrepared && mayUsePreinstalledRunnerArtifact(explicitRemoteBinary)) {
const preinstalledRunner = await measureNativeRunnerSpan(
input.trace,
"runner.artifact.discover",
() => discoverPreinstalledExecutable("paperclip-runnerd"),
);
if (preinstalledRunner) {
try {
await measureNativeRunnerSpan(
input.trace,
"runner.artifact.verify_preinstalled",
() => verifyRemoteRunner(requiredMode, preinstalledRunner),
);
if (existsSync(controllerRunnerBinary) &&
!await matchesControllerRunnerArtifact(preinstalledRunner)) {
throw new Error("runner_remote_preinstalled_artifact_mismatch");
}
await measureNativeRunnerSpan(
input.trace,
"runner.artifact.link",
() => linkPreinstalledExecutable(preinstalledRunner, remoteBinary),
);
runnerArtifactPrepared = true;
await input.onLog?.(
"stderr",
"[paperclip-runner] using preinstalled runnerd from the sandbox image\n",
);
} catch {
runnerArtifactPrepared = false;
}
}
}
if (!runnerArtifactPrepared) {
// Upload the same artifact used for the controller identity. The server
// vendors the runner under vendor/paperclip-runner/bin, so the package
// development fallback cannot locate it in a deployed server.
const sourceBinary = controllerRunnerBinary;
if (!existsSync(sourceBinary)) {
throw new Error("runner_remote_artifact_unavailable");
}
if (!explicitRemoteBinary && !remotePiCompanion && !useBundledRemoteImageAssets) {
const platform = await remoteCommandRunner.execute({
command: "sh",
args: ["-c", "uname -s; uname -m"],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 10_000,
});
const [remoteOs = "", remoteArch = ""] = platform.stdout
.trim()
.split(/\r?\n/);
const localOs =
process.platform === "darwin"
? "Darwin"
: process.platform === "linux"
? "Linux"
: process.platform;
const localArch =
process.arch === "x64"
? "x86_64"
: process.arch === "arm64"
? "aarch64"
: process.arch;
const archMatches =
remoteArch === localArch ||
(localArch === "aarch64" && remoteArch === "arm64");
if (
platform.exitCode !== 0 ||
platform.timedOut ||
remoteOs !== localOs ||
!archMatches
) {
throw new Error(
"runner_remote_artifact_platform_mismatch: configure PAPERCLIP_RUNNER_REMOTE_BINARY_PATH for the remote OS and architecture",
);
}
}
await stageRemoteRunnerFile({
target: remoteTarget,
runner: remoteCommandRunner,
sourcePath: sourceBinary,
targetPath: remoteBinary,
mode: 0o700,
});
}
await measureNativeRunnerSpan(input.trace, "runner.artifact.verify", () =>
verifyRemoteRunner(requiredMode),
);
if (remoteCodexBinary && explicitRemoteCodex) {
if (!existsSync(explicitRemoteCodex)) {
throw new Error("runner_remote_codex_artifact_unavailable");
}
await stageRemoteRunnerFile({
target: remoteTarget,
runner: remoteCommandRunner,
sourcePath: explicitRemoteCodex,
targetPath: remoteCodexBinary,
mode: 0o700,
});
await verifyRemoteCodex();
}
if (remoteCodexBinary && remoteCodexNpmSpec) {
let usedPreinstalledCodex = false;
const preinstalledCodex = await measureNativeRunnerSpan(
input.trace,
"harness.artifact.discover",
() => discoverPreinstalledExecutable("codex"),
);
if (preinstalledCodex) {
try {
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify_preinstalled",
() => verifyRemoteCodex(preinstalledCodex),
);
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.link",
() =>
linkPreinstalledExecutable(preinstalledCodex, remoteCodexBinary),
);
usedPreinstalledCodex = true;
await input.onLog?.(
"stderr",
"[paperclip-runner] using preinstalled Codex from the sandbox image\n",
);
} catch {
usedPreinstalledCodex = false;
}
}
if (!usedPreinstalledCodex) {
const installRoot = posix.join(
remoteRuntimeRoot!,
"harnesses",
"codex",
);
const installResult = await remoteCommandRunner.execute({
command: "npm",
args: [
"install",
"--prefix",
installRoot,
"--no-audit",
"--no-fund",
remoteCodexNpmSpec,
],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 180_000,
});
if (installResult.exitCode !== 0 || installResult.timedOut) {
throw new Error("runner_remote_codex_install_failed");
}
}
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify",
() => verifyRemoteCodex(),
);
}
if (remoteCodexBinary && !explicitRemoteCodex && !remoteCodexNpmSpec) {
const preinstalledCodex = await measureNativeRunnerSpan(
input.trace,
"harness.artifact.discover",
() => discoverPreinstalledExecutable("codex"),
);
if (!preinstalledCodex) {
throw new Error(
"runner_remote_codex_artifact_unavailable: install codex in the sandbox image or configure PAPERCLIP_RUNNER_REMOTE_CODEX_NPM_SPEC",
);
}
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify_preinstalled",
() => verifyRemoteCodex(preinstalledCodex),
);
await measureNativeRunnerSpan(input.trace, "harness.artifact.link", () =>
linkPreinstalledExecutable(preinstalledCodex, remoteCodexBinary),
);
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify",
() => verifyRemoteCodex(),
);
await input.onLog?.(
"stderr",
"[paperclip-runner] using preinstalled Codex from the sandbox image\n",
);
}
await remoteNativeArtifacts?.prepare(requiredMode);
if (
requiresRemoteProviderPack &&
expectedProviderPackManifest &&
@@ -13712,3 +13388,350 @@ async function createRunnerdBackendWithinSessionClaim(
},
} satisfies NativeSessionBackend & { bindManagedSession(session: NativeSession): NativeSession };
}
/** Shared task/setup preparation; setup exercises the same remote artifact contract. */
export function createRemoteNativeArtifactPreparation(input: {
target: Extract<AdapterExecutionTarget, { kind: "remote" }>;
runner: CommandManagedRuntimeRunner;
remoteBinary: string;
controllerRunnerBinary: string;
remoteRuntimeRoot: string;
remoteCodexBinary?: string | null;
runnerRemoteBinaryPath?: string | null;
runnerRemoteCodexPath?: string | null;
runnerRemoteCodexNpmSpec?: string | null;
model?: string | null;
reuseRetainedRunner?: boolean;
/** The selected Pi companion or bundled provider image verifies its target-platform artifact. */
targetPlatformArtifactVerified?: boolean;
trace?: NativeRunTrace;
onLog?: (stream: "stdout" | "stderr", chunk: string) => Promise<void>;
}) {
const remoteTarget = input.target;
const remoteCommandRunner = input.runner;
const { remoteBinary, controllerRunnerBinary, remoteRuntimeRoot } = input;
const remoteCodexBinary = input.remoteCodexBinary ?? null;
const explicitRemoteCodex = input.runnerRemoteCodexPath?.trim() || null;
const remoteCodexNpmSpec = input.runnerRemoteCodexNpmSpec?.trim() || null;
if (explicitRemoteCodex && remoteCodexNpmSpec) throw new Error("runner_remote_codex_source_conflict");
const verifyRemoteRunner = async (
requiredMode: "dial_wss" | "listen_ws",
executable = remoteBinary,
) => {
if (!remoteTarget || !remoteCommandRunner || !executable) return;
const metadataResult = await remoteCommandRunner.execute({
command: executable,
args: ["--build-metadata"],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 30_000,
});
if (metadataResult.exitCode !== 0 || metadataResult.timedOut) {
throw new Error("runner_remote_artifact_verification_failed");
}
let metadata: Record<string, unknown>;
try {
metadata = JSON.parse(metadataResult.stdout) as Record<string, unknown>;
} catch (error) {
throw new Error("runner_remote_artifact_metadata_invalid", {
cause: error,
});
}
assertRemoteRunnerBuildMetadata(metadata, requiredMode);
};
const reportedCodexVersions = new Set<string | null>();
const verifyRemoteCodex = async (executable = remoteCodexBinary) => {
if (!remoteTarget || !remoteCommandRunner || !executable) return;
const versionResult = await remoteCommandRunner.execute({
command: executable,
args: ["--version"],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 30_000,
});
if (versionResult.exitCode !== 0 || versionResult.timedOut) {
throw new Error("runner_remote_codex_artifact_verification_failed");
}
const versionOutput = `${versionResult.stdout}\n${versionResult.stderr}`;
const version = parseCodexCliVersion(versionOutput);
// The install pin describes our tested image, not a CLI admission rule.
// Ordinary installations reach the real app-server/model probe; a version
// difference alone must neither fail setup nor replace a working CLI.
if (version !== REMOTE_PROVIDER_PACK_PINS.codex && !reportedCodexVersions.has(version)) {
reportedCodexVersions.add(version);
await input.onLog?.(
"stderr",
`[paperclip-runner] using installed Codex ${version ?? "unrecognized version"} (image install pin ${REMOTE_PROVIDER_PACK_PINS.codex}); compatibility is checked by the native app-server\n`,
);
}
};
// Image policy: keep one latest stable CLI installation shared by native and
// local adapters. Preferred bin entries must point to that same installation;
// never bake an older global CLI alongside a private runner-only version.
const discoverPreinstalledExecutable = async (
name: "paperclip-runnerd" | "codex",
) => {
if (!remoteTarget || !remoteCommandRunner) return null;
return discoverRemoteExecutable(remoteCommandRunner, remoteTarget.remoteCwd, name);
};
const linkPreinstalledExecutable = async (
sourcePath: string,
targetPath: string,
) => {
if (!remoteTarget || !remoteCommandRunner) return;
const escapedSource = sourcePath.replaceAll("'", "'\\''");
const escapedTarget = targetPath.replaceAll("'", "'\\''");
const escapedDirectory = posix.dirname(targetPath).replaceAll("'", "'\\''");
const result = await remoteCommandRunner.execute({
command: "sh",
args: [
"-c",
targetPath === remoteCodexBinary
? buildRemoteCodexLauncherCommand(sourcePath, targetPath)
: `umask 077; mkdir -p '${escapedDirectory}' && ` +
`ln -sfn '${escapedSource}' '${escapedTarget}'`,
],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 10_000,
});
if (result.exitCode !== 0 || result.timedOut) {
throw new Error("runner_remote_preinstalled_link_failed");
}
};
const prepare = async (requiredMode: "dial_wss" | "listen_ws") => {
// Compatibility metadata does not prove artifact identity. Reuse only the
// exact controller-owned bytes when the controller artifact is available.
const matchesControllerRunnerArtifact = async (executable: string): Promise<boolean> => {
const expected = createHash("sha256")
.update(readFileSync(controllerRunnerBinary))
.digest("hex");
try {
const probe = await remoteCommandRunner.execute({
command: "sh",
args: [
"-c",
'test -x "$1" || exit 1; if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1"; else shasum -a 256 "$1"; fi',
"paperclip-runner-artifact",
executable,
],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 10_000,
});
return probe.exitCode === 0 && !probe.timedOut &&
/^[a-f0-9]{64}\s/.test(probe.stdout) &&
probe.stdout.trim().split(/\s+/)[0] === expected;
} catch {
// An unavailable checksum uses the verified staging path.
return false;
}
};
let runnerArtifactPrepared = false;
if (
input.reuseRetainedRunner === true &&
existsSync(controllerRunnerBinary)
) {
runnerArtifactPrepared = await measureNativeRunnerSpan(
input.trace,
"runner.artifact.verify_retained",
() => matchesControllerRunnerArtifact(remoteBinary),
);
}
const explicitRemoteBinary = input.runnerRemoteBinaryPath?.trim() || null;
if (!runnerArtifactPrepared && mayUsePreinstalledRunnerArtifact(explicitRemoteBinary)) {
const preinstalledRunner = await measureNativeRunnerSpan(
input.trace,
"runner.artifact.discover",
() => discoverPreinstalledExecutable("paperclip-runnerd"),
);
if (preinstalledRunner) {
try {
await measureNativeRunnerSpan(
input.trace,
"runner.artifact.verify_preinstalled",
() => verifyRemoteRunner(requiredMode, preinstalledRunner),
);
if (existsSync(controllerRunnerBinary) &&
!await matchesControllerRunnerArtifact(preinstalledRunner)) {
throw new Error("runner_remote_preinstalled_artifact_mismatch");
}
await measureNativeRunnerSpan(
input.trace,
"runner.artifact.link",
() => linkPreinstalledExecutable(preinstalledRunner, remoteBinary),
);
runnerArtifactPrepared = true;
await input.onLog?.(
"stderr",
"[paperclip-runner] using preinstalled runnerd from the sandbox image\n",
);
} catch {
runnerArtifactPrepared = false;
}
}
}
if (!runnerArtifactPrepared) {
// Upload the same artifact used for the controller identity. The server
// vendors the runner under vendor/paperclip-runner/bin, so the package
// development fallback cannot locate it in a deployed server.
const sourceBinary = controllerRunnerBinary;
if (!existsSync(sourceBinary)) {
throw new Error("runner_remote_artifact_unavailable");
}
if (!explicitRemoteBinary && !input.targetPlatformArtifactVerified) {
const platform = await remoteCommandRunner.execute({
command: "sh",
args: ["-c", "uname -s; uname -m"],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 10_000,
});
const [remoteOs = "", remoteArch = ""] = platform.stdout
.trim()
.split(/\r?\n/);
const localOs =
process.platform === "darwin"
? "Darwin"
: process.platform === "linux"
? "Linux"
: process.platform;
const localArch =
process.arch === "x64"
? "x86_64"
: process.arch === "arm64"
? "aarch64"
: process.arch;
const archMatches =
remoteArch === localArch ||
(localArch === "aarch64" && remoteArch === "arm64");
if (
platform.exitCode !== 0 ||
platform.timedOut ||
remoteOs !== localOs ||
!archMatches
) {
throw new Error(
"runner_remote_artifact_platform_mismatch: configure PAPERCLIP_RUNNER_REMOTE_BINARY_PATH for the remote OS and architecture",
);
}
}
await stageRemoteRunnerFile({
target: remoteTarget,
runner: remoteCommandRunner,
sourcePath: sourceBinary,
targetPath: remoteBinary,
mode: 0o700,
});
}
await measureNativeRunnerSpan(input.trace, "runner.artifact.verify", () =>
verifyRemoteRunner(requiredMode),
);
if (remoteCodexBinary && explicitRemoteCodex) {
if (!existsSync(explicitRemoteCodex)) {
throw new Error("runner_remote_codex_artifact_unavailable");
}
await stageRemoteRunnerFile({
target: remoteTarget,
runner: remoteCommandRunner,
sourcePath: explicitRemoteCodex,
targetPath: remoteCodexBinary,
mode: 0o700,
});
await verifyRemoteCodex();
}
if (remoteCodexBinary && remoteCodexNpmSpec) {
let usedPreinstalledCodex = false;
const preinstalledCodex = await measureNativeRunnerSpan(
input.trace,
"harness.artifact.discover",
() => discoverPreinstalledExecutable("codex"),
);
if (preinstalledCodex) {
try {
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify_preinstalled",
() => verifyRemoteCodex(preinstalledCodex),
);
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.link",
() =>
linkPreinstalledExecutable(preinstalledCodex, remoteCodexBinary),
);
usedPreinstalledCodex = true;
await input.onLog?.(
"stderr",
"[paperclip-runner] using preinstalled Codex from the sandbox image\n",
);
} catch {
usedPreinstalledCodex = false;
}
}
if (!usedPreinstalledCodex) {
const installRoot = posix.join(
remoteRuntimeRoot!,
"harnesses",
"codex",
);
const installResult = await remoteCommandRunner.execute({
command: "npm",
args: [
"install",
"--prefix",
installRoot,
"--no-audit",
"--no-fund",
remoteCodexNpmSpec,
],
cwd: remoteTarget.remoteCwd,
bypassSession: true,
timeoutMs: 180_000,
});
if (installResult.exitCode !== 0 || installResult.timedOut) {
throw new Error("runner_remote_codex_install_failed");
}
}
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify",
() => verifyRemoteCodex(),
);
}
if (remoteCodexBinary && !explicitRemoteCodex && !remoteCodexNpmSpec) {
const preinstalledCodex = await measureNativeRunnerSpan(
input.trace,
"harness.artifact.discover",
() => discoverPreinstalledExecutable("codex"),
);
if (!preinstalledCodex) {
throw new Error(
"runner_remote_codex_artifact_unavailable: install codex in the sandbox image or configure PAPERCLIP_RUNNER_REMOTE_CODEX_NPM_SPEC",
);
}
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify_preinstalled",
() => verifyRemoteCodex(preinstalledCodex),
);
await measureNativeRunnerSpan(input.trace, "harness.artifact.link", () =>
linkPreinstalledExecutable(preinstalledCodex, remoteCodexBinary),
);
await measureNativeRunnerSpan(
input.trace,
"harness.artifact.verify",
() => verifyRemoteCodex(),
);
await input.onLog?.(
"stderr",
"[paperclip-runner] using preinstalled Codex from the sandbox image\n",
);
}
};
return { prepare, verifyRemoteRunner, verifyRemoteCodex };
}