diff --git a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts index 88916ffbf0..eb07c5bfa4 100644 --- a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts +++ b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts @@ -634,10 +634,39 @@ it("derives the ACPX package authority only from the verified dist/cli layout", ).toThrow("ACPX sidecar must use the provider package dist/cli layout"); }); -it("keeps a deployed ACPX package inside its pnpm-owned dependency root", async () => { +it("keeps a self-rooted pnpm deployment inside its dependency authority", async () => { const deploymentRoot = await mkdtemp( join(tmpdir(), "paperclip-deployed-provider-root-"), ); + const deployedPackageRoot = deploymentRoot; + await mkdir(join(deployedPackageRoot, "dist", "cli"), { recursive: true }); + await mkdir(join(deploymentRoot, "node_modules", ".pnpm"), { + recursive: true, + }); + try { + expect( + runnerdLaunchProfileInternals.acpxProviderPackageAuthority( + join( + deployedPackageRoot, + "dist", + "cli", + "acpx-runtime-sidecar.cjs", + ), + deployedPackageRoot, + ), + ).toEqual({ + root: deploymentRoot, + manifest: join(deployedPackageRoot, "package.json"), + }); + } finally { + await rm(deploymentRoot, { recursive: true, force: true }); + } +}); + +it("keeps a scoped npm-installed package inside its portable dependency root", async () => { + const deploymentRoot = await mkdtemp( + join(tmpdir(), "paperclip-npm-provider-root-"), + ); const deployedPackageRoot = join( deploymentRoot, "node_modules", @@ -645,9 +674,6 @@ it("keeps a deployed ACPX package inside its pnpm-owned dependency root", async "paperclip-runner", ); await mkdir(join(deployedPackageRoot, "dist", "cli"), { recursive: true }); - await mkdir(join(deploymentRoot, "node_modules", ".pnpm"), { - recursive: true, - }); try { expect( runnerdLaunchProfileInternals.acpxProviderPackageAuthority( diff --git a/packages/paperclip-runner/src/live/runnerd-codex-transport.ts b/packages/paperclip-runner/src/live/runnerd-codex-transport.ts index 4bf3965bfe..6802992972 100644 --- a/packages/paperclip-runner/src/live/runnerd-codex-transport.ts +++ b/packages/paperclip-runner/src/live/runnerd-codex-transport.ts @@ -1568,17 +1568,20 @@ function acpxProviderPackageAuthority( } const sidecarPackageRoot = resolve(cliDirectory, "../.."); // A local source build lives at /packages/paperclip-runner and - // resolves dependencies from /node_modules. A `pnpm deploy` - // package lives at /node_modules/@paperclipai/paperclip-runner, - // beside /node_modules/.pnpm. The provider verifier receives the - // directory that owns node_modules, so step out one more level only for the - // deployed shape. + // resolves dependencies from /node_modules. `pnpm deploy` makes + // the package itself the deployment root and owns /node_modules/.pnpm. + // The older npm-installed portable shape nests the scoped package at + // /node_modules/@paperclipai/paperclip-runner. The verifier always + // receives the directory that owns node_modules, regardless of which + // portable shape launched the already-authenticated sidecar. const sourceDependencyRoot = resolve(ownerPackageRoot, "../.."); const localDependencyRoot = existsSync( - resolve(sourceDependencyRoot, ".pnpm"), - ) - ? resolve(sourceDependencyRoot, "..") - : sourceDependencyRoot; + resolve(ownerPackageRoot, "node_modules", ".pnpm"), + ) + ? ownerPackageRoot + : basename(sourceDependencyRoot) === "node_modules" + ? resolve(sourceDependencyRoot, "..") + : sourceDependencyRoot; return sidecarPackageRoot === ownerPackageRoot ? { root: localDependencyRoot,