Skip to content

Update pnpm to 12.5.1 - #764

Merged
bryan-minimal merged 4 commits into
mainfrom
pnpm-12.5.1-native
Sep 28, 2026
Merged

bryan-minimal merged 4 commits into
mainfrom
pnpm-12.5.1-native

Conversation

@bryan-minimal

@bryan-minimal bryan-minimal commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Summary

Upgrades packages/pnpm from 11.21.0 to 12.5.1. This is a repackage, not a plain version bump.

Why: pnpm 12 is a native (Rust) binary. The npm pnpm tarball is now only a wrapper around it. Its package/pnpm is an sh placeholder that hands over to bin/pnpm.mjs, and that script runs the binary from @pnpm/exe.<os>-<arch>. If that package isn't installed, it downloads the binary from the registry on first run. That must never happen in a sandbox. The old build.sh also chmods and symlinks bin/*.cjs, and those files no longer exist in 12.x, so a naive bump fails.

Changes

packages/pnpm

  • Sources. The native binary now comes per-arch from @pnpm/exe.linux-x64 / @pnpm/exe.linux-arm64, using the match { { arch = 'Amd64, .. } => ... } target pattern from deno. The pnpm wrapper tarball is still fetched, but only for its dist/ payload.
  • Layout. Mirrors what upstream's install.js produces: the native binary is placed over the pnpm placeholder in usr/libexec/pnpm/, with dist/ beside it. The binary finds its bundled node-gyp at <dir of current_exe>/dist/node-gyp-bin (crates/executor/src/bundled_node_gyp.rs) and puts it on lifecycle scripts' PATH. Without dist/, native-addon builds would fall back to whatever node-gyp the environment has.
  • Download path dropped. bin/*.mjs, install.js and native-binary.mjs (the Corepack / install-time path) are not shipped, and neither is dist/node_modules/get-pnpm, the downloader they call. Nothing else in dist/ uses it.
  • Bins. Ships all four bins from package.json#bin: pnpm, pn, pnpx and pnx. The last three are upstream's #!/bin/sh alias scripts, which exec the pnpm beside them (pnpx/pnx add dlx). The binary infers dlx only from current_exe(), and on Linux that resolves symlinks, so a symlink alias cannot work. pn/pnx are new relative to 11.x.
  • Runtime deps.
    • Added glibc and subsetOf gcc ["libgcc"] (ELF DT_NEEDED: libgcc_s, libc, libm, libdl, libpthread, librt; needs GLIBC_2.18 or later).
    • Added bash, for the /bin/sh alias scripts and lifecycle scripts.
    • Kept coreutils, which the alias scripts need for readlink.
    • Kept subsetOf node-lts ["node"] on purpose. pnpm no longer needs node to run itself, but lifecycle scripts, the bundled node-gyp wrapper and pnpm run/exec all spawn node. It stays the interpreter-only subset, so the agent-browser and cf still blend a second npm into sessions with node-lts (follow-up to #665/#670) #751 rule holds: no second npm enters consumer closures.
  • Removed needs (dns/internet). The build no longer touches the network; all sources are declared.
  • New standalone tests.
    • cli: pnpm --version and pn --version print exactly 12.5.1, /usr/bin/pnpm resolves to an ELF, and nothing mentions a download.
    • install: a dependency-free pnpm install --offline works with no download message, and a root postinstall sees /usr/libexec/pnpm/dist/node-gyp-bin/node-gyp and node on PATH.
  • Build-time checks. build.sh asserts that the bundled dist/node-gyp-bin/node-gyp sits beside the binary and that the binary reports $MINIMAL_ARG_VERSION.

packages/agent-browser/build.sh (needed by this bump)

  • pnpm 12 picks its default store differently. When it cannot hardlink into its home store (in the sandbox, /build is a separate mount), it puts the store at <project>/node_modules/.pnpm-store (crates/config/src/store_path.rs). agent-browser does cp -R node_modules into its output, so it would have shipped the whole pnpm store.
    • Observed with 12.5.1: Content-addressable store is at: /build/node_modules/.pnpm-store/v11.
    • pnpm 11 baseline on main: /state/data/pnpm/store/v11.
  • Fix: PNPM_CONFIG_STORE_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/pnpm/store". The store is now back at /state/data/pnpm/store/v11. The build also fails if node_modules/.pnpm-store ever reappears.

Sources and checksums

Each tarball's sha512 was checked against the registry's dist.integrity for 12.5.1 (all match). The sha256 values in build.ncl were computed from the same verified files.

tarball sha512 (= registry integrity) sha256
pnpm-12.5.1.tgz 4/MFvHhKK8ifWtO2E4iJRw+ujSr182thIW7JHCw9ZAiXdfneOKrDMQROpA8kXLDVZmOS399lgk4ZB+9qLGLeXw== 3c1439171c1396d7f30892d2444135c9f11de739175058a1503cdf53788f2099
exe.linux-x64-12.5.1.tgz 3PkUBYo5z4dgtlnTNIFj7QGpcDUAuqXz9WGVigPDCeccEnhGiRkWmA5102TmYJHtwJP3LfmE+ZF9PGeWhn8p9Q== c980bc463e4b1dcd34ab136c738d987dd21a5590f4b4b82dc2c8ad3e605e2f7f
exe.linux-arm64-12.5.1.tgz 6hbMWW2/eQo1b5wvQPe/ndLHVTH88Rav6N+ffD4/h6IuFMjWCgasFYYsFv0GrvpqREAx3SwmZSvli+0NFXqbxA== d6b8b296256372cdbd02be78b7e19b8387de252abcf920017987660b76c429e8

What's in the tarballs:

  • x64: package/pnpm, 52 MB, glibc-dynamic PIE, interpreter /lib64/ld-linux-x86-64.so.2.
  • arm64: 42 MB, interpreter /lib/ld-linux-aarch64.so.1.
  • Both @pnpm/exe.* manifests have no bin, libc: ["glibc"], and MIT license.

Verification

All builds ran in a Linux min session (arm64), each on a fresh min session activate snapshot, with min session exec pnpm12 -- min package build --rebuild --verbose <pkg> followed by min check --packages <pkg>.

  • Negative control. Put exit 97 at the top of build.sh in a fresh activation: the build failed with process(./build.sh) exited with code 97. Restored, re-activated, then built.
  • Test negative control. Changed the cli test to expect 0.0.0-negctl: standalone tests...Fail (test "$out" = '0.0.0-negctl' had exit code 1). Restored, and it passes, so the tests really run against the built tree.
  • pnpm: build finished; min check: all Pass (enumerate bins, output types, missing runtime_deps, standalone tests, import line, fmt, disallowed-patterns).
  • agent-browser: build finished; Done in 3.3s using pnpm v12.5.1; store at /state/data/pnpm/store/v11; min check: all Pass, including the end-to-end open_check standalone test.
  • next: build finished; sharp 0.35.4 vips 8.18.6 addon sharp-linux-arm64-0.35.4.node; min check: all Pass, including standalone tests.
  • pnpm 11 baseline (origin/main, same session setup): agent-browser store at /state/data/pnpm/store/v11, using pnpm v11.21.0; next using pnpm v10.33.0.

Review fixes (6d3ba43)

  • Restored pnpm's needs = { dns, internet }. The first commit dropped it because pnpm's own build is offline, but the block was never for pnpm's build. It is the abstract network dep that packages building with pnpm inherit (71d7239, the same as curl/go/rust/uv/wget).
    • Negative control: a fresh session with the block removed still built agent-browser. The log shows reused 0, downloaded 410 packages. agent-browser reaches the registry today through rust (its toolchain dep carries the same block), not through pnpm.
    • So dropping the block breaks nothing today. But any future pnpm consumer without rust would silently lose registry access, so the convention stays.
  • build.sh no longer uses uname -m. It unpacks the single exe.linux-*-<version>.tgz that build.ncl selected by target, and fails unless there is exactly one. That gives one source of truth for the architecture.
  • Re-verified in a fresh session (arm64):
    • pnpm: build finished, and min check passes all 15 checks, including the standalone tests.
    • agent-browser: build finished (Done in 1.9s using pnpm v12.5.1). min check passes, including the build-dependent checks (enumerate bins, missing runtime_deps, standalone tests).
    • The first attempt was SIGKILLed (exit 137) under shared-pool memory pressure. The retry passed unchanged.
  • Still open: no x64 min build has run yet (see the local x64 smoke test below). CI's checks on this PR are masked by the stale-evaluator node-guard failure until ci(node-runtime-guard): evaluate with the runner's pinned mip, not the stale shim #761 merges.

Local x64 + arm64 smoke test (outside min)

The min sandbox here is arm64-only, so I ran this PR's build.sh verbatim (at 6d3ba43) against the real tarballs in debian:bookworm containers: --arch amd64 through Rosetta, and native arm64. Node 18.20.4 came from Debian. This supplements the min builds; it doesn't replace them.

check x64 arm64
build.sh builds from the single native tarball ✅ ✅
/usr/bin/pnpm is a native ELF for that arch ✅ x86-64 ✅ aarch64
pnpm --version / pn --version print 12.5.1 ✅ ✅
negative control: two native tarballs make the build fail ✅ ✅
pnx cowsay@1.6.0 (dlx alias, from the registry) ✅ ✅
pnpm add microtime@3.1.1 --allow-build, forced to build from source: build/Release/microtime.node compiles and loads ✅ ✅
no "Downloading the pnpm … binary" anywhere ✅ ✅

The image has no node-gyp of its own (command -v node-gyp finds nothing with Debian's nodejs installed). So the addon compiled through the bundled usr/libexec/pnpm/dist/node-gyp, which is the layout this PR preserves beside the binary. next's sharp never exercises that path, because it uses prebuilt binaries.

Reviewer TODOs / unresolved

  • Resolved: next keeps its own pinned pnpm, deliberately. It is not changed here.
    • next's package.json pins "packageManager": "pnpm@10.33.0", so pnpm hands off to (and fetches) 10.33.0 at build time. That happens under 11.21.0 on main and under 12.5.1 here, so this bump doesn't change next's install.
    • I tested the alternative locally (arm64 container, next 16.3.6 source, this PR's pnpm). PNPM_CONFIG_PM_ON_FAIL=ignore and PNPM_CONFIG_MANAGE_PACKAGE_MANAGER_VERSIONS=false both keep 12.5.1 running instead of switching. But pnpm 12 then rejects next's lockfile (lockfileVersion: '9.0', written by pnpm 10): pnpm install --frozen-lockfile fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH ("configuration doesn't match the value found in the lockfile").
    • Forcing next onto pnpm 12 would therefore mean regenerating the lockfile, which gives up the frozen-lockfile reproducibility next relies on. It stays on its pin until upstream next moves to pnpm 12. The build-time fetch of pnpm 10.33.0 is a pre-existing follow-up, not part of this PR.
  • x64: verified by minimal-buildbot on 6d3ba43 (minimal build ✅, run 261b17df).
    • It built agent-browser on amd64 and arm64 (pnpm install reports pnpm 12.5.1, then the Rust CLI compiles) and next on both (sharp … addon sharp-linux-x64-0.35.4.node on amd64), then ran 90 package checks.
    • Note that the GitHub Actions minimal-check builds nothing here: its build-dependent checks all Skip for these packages. buildbot is the real build.
  • The red node-runtime-guard / guard ✗ is stale and non-blocking. That workflow is disabled repo-wide until ci(node-runtime-guard): evaluate with the runner's pinned mip, not the stale shim #761 lands (it fails every PR on CI's stale May evaluator), and it is not a required check.
  • 12.6.0 exists. agent-browser's install printed Update available! 12.5.1 → 12.6.0. This PR pins 12.5.1 as requested. The update notifier makes a harmless registry request during builds.
  • pnpm 12 runs lockfile supply-chain policy checks. agent-browser logged Verifying lockfile against supply-chain policies (473 entries)... ✓, which is new relative to 11.x. It passed here.
  • Conflicts with Redirect pnpm, bun, deno, and gem global installs to ~/.local per the inbox#584 decision #659. Open draft Redirect pnpm, bun, deno, and gem global installs to ~/.local per the inbox#584 decision #659 (redirects pnpm/bun/deno/gem global installs) also edits packages/pnpm/build.ncl and build.sh, and will need a rebase onto this. Redirect pnpm, bun, deno, and gem global installs to ~/.local per the inbox#584 decision #659 is not modified here.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • pnpm 12.5.1 is available with native executables for Linux on x86_64 and ARM64.
    • Added the pn, pnpx, and pnx command aliases.
    • pnpm installations can run offline without downloading the package manager during setup.
  • Bug Fixes
    • Agent Browser builds now keep pnpm’s package store outside the build tree and stop with an error if a store is found inside it.

pnpm 12 is a native binary. The npm `pnpm` tarball is now only a wrapper
whose `pnpm` placeholder hands over to bin/pnpm.mjs, which downloads the
native binary from the registry on first run. Ship the binary from
@pnpm/exe.linux-{x64,arm64} instead, laid out the way upstream's
install.js does (binary over the placeholder, dist/ with the bundled
node-gyp beside it, where the binary looks for it), and drop the
Corepack/download path (bin/*.mjs, install.js, native-binary.mjs,
dist/node_modules/get-pnpm).

agent-browser: pnpm 12 places its default store inside
node_modules/.pnpm-store when /build is a separate mount, which the
build copies into its output. Pin the store dir outside the build tree
and fail the build if it ever lands in node_modules again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

  • Run on-demand review

This review includes 1 billable file and costs up to $0.25.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 38 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 57 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: gominimal/pkgs/.coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: 2079f24a-b83d-4a39-897e-2cabee313414

📥 Commits

Reviewing files that changed from the base of the PR and between 3336bd1 and a98197b.

📒 Files selected for processing (1)
  • packages/next/build.sh

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: gominimal/pkgs/.coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: 3ee77cb1-3041-4e9b-9725-b7661f5e7a6a

📥 Commits

Reviewing files that changed from the base of the PR and between bad002e and 6d3ba43.

📒 Files selected for processing (2)
  • packages/pnpm/build.ncl
  • packages/pnpm/build.sh

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.


📝 Walkthrough

Walkthrough

The pnpm package now uses native Linux executables for Amd64 and Arm64. The agent-browser build sets the pnpm store outside the project tree and stops if a local pnpm store exists.

Changes

agent-browser Store Handling

Layer / File(s) Summary
External store path and local store guard
packages/agent-browser/build.sh
The build sets PNPM_CONFIG_STORE_DIR under XDG_DATA_HOME or $HOME/.local/share. Before copying node_modules, it exits with an error if node_modules/.pnpm-store exists.

Native pnpm Package

Layer / File(s) Summary
Native binary packaging and validation
packages/pnpm/build.ncl, packages/pnpm/build.sh
The package upgrades pnpm to 12.5.1 and packages native Linux binaries for Amd64 and Arm64. It adds pn, pnx, and executable-file support in libexec. The build selects and extracts a matching archive. Tests check the ELF binary, version, download behavior, and an offline install lifecycle script.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Other

Merge Risk: ⚪ Minimal · up to 3336b

The change is mergeable; normal build validation should still cover the unverified environment-specific store path.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: updating pnpm from version 11.21.0 to 12.5.1. It is concise and specific, although it does not mention the related agent-browser store change.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@bryan-minimal
bryan-minimal marked this pull request as ready for review September 25, 2026 00:30
@bryan-minimal
bryan-minimal requested a review from a team as a code owner September 25, 2026 00:30
@bryan-minimal
bryan-minimal marked this pull request as draft September 25, 2026 00:30
…l fetched

Restore `needs = { dns, internet }`. It was never for pnpm's own build: it is
the abstract network dep a package that builds WITH pnpm inherits (71d7239,
as on curl/go/rust/uv/wget). agent-browser declares no `needs` of its own and
today reaches the registry through rust; a pnpm consumer without rust would
lose it.

build.sh no longer re-derives the arch with `uname -m`; it uses the single
exe.linux-*-<version>.tgz that build.ncl selected by `target`, and fails if
there is not exactly one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@bryan-minimal
bryan-minimal marked this pull request as ready for review September 25, 2026 00:45
…its stale result)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@norrietaylor
norrietaylor added this pull request to the merge queue Sep 28, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 28, 2026
next's build.sh ran an unpinned `npm install sharp node-addon-api node-gyp`.
sharp 0.35.5 (published 2026-09-27) raised its floor to libvips >=8.18.7, so
the rebuild triggered by the pnpm 12.5.1 bump (#764) FTBFS on both arches
against our libvips 8.18.6:
  common.h:23: #error "libvips version 8.18.7+ is required"
Pin sharp to 0.35.4 (satisfies next 16.3.6's ^0.35.4 and libvips >=8.18.6),
and node-addon-api/node-gyp to the versions that resolved. Exact pins also make
the build reproducible. Follow-up: libvips 8.18.7, then SHARP_VERSION=0.35.5.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@bryan-minimal

Copy link
Copy Markdown
Member Author

The merge-queue run failed on next, not on pnpm: next's build.sh installed sharp unpinned, and sharp 0.35.5 (published 2026-09-27) requires libvips >=8.18.7 while we ship 8.18.6 (#error "libvips version 8.18.7+ is required", both arches). This PR's rebuild of next was just the first one after that release.

Added a98197b: the same exact-version pin as #773 (sharp@0.35.4, node-addon-api@8.9.2, node-gyp@13.0.2), so the pnpm bump and the fix go through the queue together. #773 will be closed as superseded once this lands. Follow-up: libvips 8.18.7, then sharp 0.35.5.

@bryan-minimal
bryan-minimal added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 2d07baa Sep 28, 2026
11 checks passed
@bryan-minimal
bryan-minimal deleted the pnpm-12.5.1-native branch September 28, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants