From 4dc13aa32c23ebad74247564c343b4fc13eb48c3 Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 12 Oct 2026 13:13:05 -0500 Subject: [PATCH] fix(runner): match image and native provider pack contents Co-Authored-By: Paperclip --- packages/paperclip-runner/package.json | 2 +- .../scripts/build-provider-pack.mjs | 2 + .../scripts/provider-pack-runtime-tree.mjs | 9 +++++ .../provider-pack-runtime-tree.test.mjs | 39 +++++++++++++++++++ tests/runner-e2e/daytona-image-content.ts | 1 + 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 packages/paperclip-runner/scripts/provider-pack-runtime-tree.mjs create mode 100644 packages/paperclip-runner/scripts/provider-pack-runtime-tree.test.mjs diff --git a/packages/paperclip-runner/package.json b/packages/paperclip-runner/package.json index f962fe6c20b..85bd19bbfdb 100644 --- a/packages/paperclip-runner/package.json +++ b/packages/paperclip-runner/package.json @@ -81,7 +81,7 @@ "typecheck:browser": "tsc -p tsconfig.browser.json --noEmit", "test": "pnpm run test:typescript && pnpm run test:rust", "test:typescript": "pnpm run test:typescript:prep && vitest run", - "test:typescript:prep": "pnpm run ensure:eval-build-deps && pnpm run build:rust && node --test test/protocol-contract.test.mjs test/acpx-sidecar-contract.test.mjs test/acpx-codex-package-contract.test.mjs test/acpx-model-selection-package-contract.test.mjs test/acpx-message-boundaries-package-contract.test.mjs test/acpx-rich-extensions-package-contract.test.mjs test/acpx-pi-receipt-package-contract.test.mjs test/acpx-response-delivery-package-contract.test.mjs scripts/candidate-provider-pack.test.mjs scripts/cursor-provisioner-layout.test.mjs scripts/release-provider-pack.test.mjs scripts/aws-agentcore-provisioning.test.mjs scripts/build-verified-provider-entrypoints.test.mjs scripts/local-provider-smoke-environment.test.mjs scripts/materialize-opencode-binary.test.mjs scripts/installed-package-pack.test.mjs scripts/runner-package-executable.test.mjs scripts/stage-runner-binary.test.mjs", + "test:typescript:prep": "pnpm run ensure:eval-build-deps && pnpm run build:rust && node --test test/protocol-contract.test.mjs test/acpx-sidecar-contract.test.mjs test/acpx-codex-package-contract.test.mjs test/acpx-model-selection-package-contract.test.mjs test/acpx-message-boundaries-package-contract.test.mjs test/acpx-rich-extensions-package-contract.test.mjs test/acpx-pi-receipt-package-contract.test.mjs test/acpx-response-delivery-package-contract.test.mjs scripts/candidate-provider-pack.test.mjs scripts/cursor-provisioner-layout.test.mjs scripts/release-provider-pack.test.mjs scripts/provider-pack-runtime-tree.test.mjs scripts/aws-agentcore-provisioning.test.mjs scripts/build-verified-provider-entrypoints.test.mjs scripts/local-provider-smoke-environment.test.mjs scripts/materialize-opencode-binary.test.mjs scripts/installed-package-pack.test.mjs scripts/runner-package-executable.test.mjs scripts/stage-runner-binary.test.mjs", "test:typescript:vitest": "node ./scripts/run-pr-vitest-lane.mjs", "test:rust": "cargo test --release --manifest-path runner/Cargo.toml --locked --workspace", "test:codex": "cargo test --manifest-path runner/Cargo.toml --locked -p paperclip-runner-core --test codex_provider", diff --git a/packages/paperclip-runner/scripts/build-provider-pack.mjs b/packages/paperclip-runner/scripts/build-provider-pack.mjs index a58e8cb3156..9925bd7ff67 100644 --- a/packages/paperclip-runner/scripts/build-provider-pack.mjs +++ b/packages/paperclip-runner/scripts/build-provider-pack.mjs @@ -22,6 +22,7 @@ import { fileURLToPath } from "node:url"; import { parseProviderPackArguments, materializeCandidateProviderPack, providerPackProviders, providerPackManifestFields } from "./candidate-provider-pack.mjs"; import { buildNodeStartupTimeout } from "./build-node-startup-timeout.mjs"; import { writePortableExecutableShim, writePortableCopilotShims } from "./provider-pack-executable-shims.mjs"; +import { removeControllerArtifactsFromProviderPack } from "./provider-pack-runtime-tree.mjs"; const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const workspaceRoot = resolve(packageRoot, "../.."); @@ -117,6 +118,7 @@ try { if (deployed.status !== 0) { throw new Error(`pnpm deploy failed with exit code ${deployed.status}`); } + removeControllerArtifactsFromProviderPack(temporaryRoot); // Fail the image build if a bridge silently brings back an older/private // provider CLI. A direct dependency alone does not deduplicate pnpm's graph. diff --git a/packages/paperclip-runner/scripts/provider-pack-runtime-tree.mjs b/packages/paperclip-runner/scripts/provider-pack-runtime-tree.mjs new file mode 100644 index 00000000000..70cbf48bcdd --- /dev/null +++ b/packages/paperclip-runner/scripts/provider-pack-runtime-tree.mjs @@ -0,0 +1,9 @@ +import { rmSync } from "node:fs"; +import { join } from "node:path"; + +/** Daemons and remote pack identities are assembled separately from provider code. */ +export function removeControllerArtifactsFromProviderPack(packRoot) { + for (const directory of ["bin", "remote-provider-packs"]) { + rmSync(join(packRoot, "dist", directory), { recursive: true, force: true }); + } +} diff --git a/packages/paperclip-runner/scripts/provider-pack-runtime-tree.test.mjs b/packages/paperclip-runner/scripts/provider-pack-runtime-tree.test.mjs new file mode 100644 index 00000000000..83c64819f68 --- /dev/null +++ b/packages/paperclip-runner/scripts/provider-pack-runtime-tree.test.mjs @@ -0,0 +1,39 @@ +import assert from "node:assert/strict"; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; +import { removeControllerArtifactsFromProviderPack } from "./provider-pack-runtime-tree.mjs"; + +test("image and native producer packs retain identical provider outputs despite different controller artifacts", () => { + const root = mkdtempSync(join(tmpdir(), "provider-pack-producers-")); + try { + const packs = [join(root, "image"), join(root, "native")]; + for (const pack of packs) { + mkdirSync(join(pack, "dist", "cli"), { recursive: true }); + writeFileSync(join(pack, "dist", "cli", "acpx-runtime-sidecar.cjs"), "identical provider bridge\n"); + } + mkdirSync(join(packs[1], "dist", "bin")); + writeFileSync(join(packs[1], "dist", "bin", "paperclip-runnerd"), "host-specific daemon"); + mkdirSync(join(packs[1], "dist", "remote-provider-packs")); + writeFileSync(join(packs[1], "dist", "remote-provider-packs", "prior-pack.json"), "earlier release identity"); + for (const pack of packs) { + removeControllerArtifactsFromProviderPack(pack); + assert.deepEqual(readdirSync(join(pack, "dist")), ["cli"]); + assert.equal(readFileSync(join(pack, "dist", "cli", "acpx-runtime-sidecar.cjs"), "utf8"), "identical provider bridge\n"); + } + } finally { rmSync(root, { recursive: true, force: true }); } +}); + +test("removing an owned controller-artifact link preserves its external target", () => { + const root = mkdtempSync(join(tmpdir(), "provider-pack-controller-link-")); + try { + const pack = join(root, "pack"), outside = join(root, "outside"); + mkdirSync(join(pack, "dist"), { recursive: true }); mkdirSync(outside); + writeFileSync(join(outside, "preserved"), "original"); + symlinkSync(outside, join(pack, "dist", "bin")); + removeControllerArtifactsFromProviderPack(pack); + assert.equal(existsSync(join(pack, "dist", "bin")), false); + assert.equal(readFileSync(join(outside, "preserved"), "utf8"), "original"); + } finally { rmSync(root, { recursive: true, force: true }); } +}); diff --git a/tests/runner-e2e/daytona-image-content.ts b/tests/runner-e2e/daytona-image-content.ts index 4ccda56aa2a..ef526f14e84 100644 --- a/tests/runner-e2e/daytona-image-content.ts +++ b/tests/runner-e2e/daytona-image-content.ts @@ -45,6 +45,7 @@ export const DAYTONA_IMAGE_INPUT_PATHS = [ "packages/paperclip-runner/scripts/materialize-cursor-distribution.mjs", "packages/paperclip-runner/scripts/cursor-runtime-patch.mjs", "packages/paperclip-runner/scripts/build-verified-provider-entrypoints.mjs", + "packages/paperclip-runner/scripts/provider-pack-runtime-tree.mjs", "packages/paperclip-runner/scripts/generate-acpx-sidecar-contract.mjs", "packages/paperclip-runner/scripts/generate-protocol-schema-module.mjs", "packages/paperclip-runner/scripts/materialize-pi-distribution.mjs",