get-pnpm moves from pnpm/get.pnpm.io into pnpm/npm/get-pnpm, at 0.0.9
(get.pnpm.io be4e983, where its history stays).
- The pnpm v12 npm package depends on it with `workspace:*`, so a pnpm
release bundles get-pnpm's source as of that release. A wrapper fix no
longer needs a get-pnpm release, a catalog bump, and a
minimumReleaseAge exclusion first. bundle-node-gyp builds it before
the deploy injects its build output.
- It is released on its own: a `get-pnpm` product in bump.ts and
create-release-pr.yml (off by default), `get-pnpm@<version>` tags,
and build-get-pnpm/publish-get-pnpm jobs in release.yml. It is private
in the workspace so the TypeScript release's recursive publish skips
it; the packed manifest drops the flag.
- Its runtime dependencies stay exact, through a `get-pnpm` named
catalog. Its lint is the root ESLint config. Its TLS tests use the
fixture the Rust network tests use.
- The npm-wrapper CI job runs its tests on Node.js 24 and 22, beside
the wrapper's. The forwarding proxy in its download tests forwards
only to the servers the tests start.
npm's registry signing keys were pinned in five places: v11, v12,
get-pnpm, and get.pnpm.io's install.sh and install.ps1. Only v11's copy
was refreshed, by the release PR, and the two repositories handled a
withdrawn key in opposite ways. They now come from
.config/npm-signing-keys.json:
- .github/scripts/update-npm-signing-keys.mjs refreshes it from npm on
every release PR, not only v11 ones. A key npm stops listing stays,
marked withdrawn.
- The meta-updater renders it into the v11, v12, and get-pnpm copies,
so `pnpm lint:meta` fails on a copy edited by hand. pnpm v11 and v12
keep trusting withdrawn keys, so packages signed before a rotation
verify. get-pnpm drops them, as get.pnpm.io's installers do.
- get.pnpm.io's update script is to read this file.
* docs: lint prose with Vale
Add Vale with an in-repo style, .vale/styles/pnpm, that turns the
writing rules in AGENTS.md and the Google developer documentation style
guide into lint rules. The stock Vale packages (Google, Microsoft,
RedHat, write-good) were too noisy to block on, for example 1,300
passive-voice hits in the v12 docs alone, so the rules are written for
this repo, following the GitLab model. Each one links the guideline it
enforces.
Levels:
- error, fails CI: dashes, plain-word substitutions, condescending
words, "please", "note that", hedges, puffery, optional plurals,
exclamation marks, ellipses, curly quotes, generic link text, product
spellings, sentence-case headings, repeated words, double spaces,
implementation history in comments; in changesets, bold or italic
emphasis, internal names and release-line names.
- warning: future tense, sentences over 30 words, "instead of" and
"so that" tails in changesets.
- suggestion: passive voice.
.vale.ini scopes the rules. Docs get every rule. Contributor Markdown
and code comments keep dashes and headings as warnings until their
roughly 8,100 em dashes are rewritten. Released changesets stay in
.changeset/ and are not rewritten, so lint-prose.mjs lints only the
changesets added since PROSE_BASE (the PR base in CI).
The prose workflow installs a pinned, checksum-verified Vale release and
runs `pnpm lint:prose`. The rest of this change rewrites the existing
docs, READMEs, contributor Markdown, and code comments to pass the
error-level rules. Only prose and comment text changed. Renamed
headings keep their anchors.
Spelling stays with cspell, which checks identifiers that Vale does not
see.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: keep prose lint from flattening meaning
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore: move supply-chain settings to a protected config file
Use the `include` setting from pnpm 12.15 to move the settings that
decide what gets installed and what may run into
.config/pnpm/security.yaml: allowBuilds, auditConfig, the
minimumReleaseAge and trustPolicy settings, overrides,
packageExtensions, patchedDependencies, patchesDir, and registries.
pnpm-workspace.yaml delegates exactly that list, so no other file can
define those settings. Patch paths are relative to the included file.
pnpm 12.14 ignores `include` and would drop every moved setting, so
the packageManager pin moves to 12.15.0.
CODEOWNERS now names both workspace files, the pnpmfile, and the
patches explicitly, and the CI path filters watch the new file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: move routine settings to a file without a code owner
The catalog, the update settings, and the task-runner settings
(pipelines, tasks, concurrencyGroups) move to
.config/pnpm/routine.yaml, which CODEOWNERS leaves unowned. Because
pnpm-workspace.yaml delegates only that list to the file, any other
setting defined there fails with ERR_PNPM_SETTING_NOT_DELEGATED, so
the file cannot be used to change the protected settings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: move the catalogs to their own file
.config/pnpm/catalog.yaml owns `catalogs`, which covers the default
catalog and any named catalog added later. Like routine.yaml, it has
no code owner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: name the protected file policies.yaml and give tasks their own file
security.yaml becomes policies.yaml. The task-runner settings
(pipelines, tasks, concurrencyGroups) move to tasks.yaml, and
`update` joins the catalogs in catalog.yaml, since its ignoreDeps list
holds back catalog entries. routine.yaml is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: move catalogMode and catalogPrune to catalog.yaml
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: keep the patch list next to the patches
patchedDependencies and patchesDir move to __patches__/patches.yaml,
so the entries name the patch files without a directory prefix and
patchesDir is `.`. CODEOWNERS already covers __patches__/. The CI path
filters that did not watch __patches__/ now watch patches.yaml, since
they watched the patch list when it lived in pnpm-workspace.yaml.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: move the patches to .config/pnpm/patches
Every pnpm configuration file now lives under .config/pnpm, so each CI
path filter watches `.config/pnpm/**` instead of listing the files.
CODEOWNERS keeps the patches protected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(bench): add Cargo repeat-install scenario to integrated-benchmark
Add the cargo.repeat-install.hot-cache.hot-store scenario to
pnpm-integrated-benchmark and the CI integrated-benchmark workflow
to guard Cargo crate slot reuse (pnpm/pnpm#17105).
* fix(bench): isolate cargo repeat-install benchmark from parent workspace
* fix(bench): connect generated crates in Cargo dependency graph and verify prewarm slots
Adds `<version>-alpine`, `<major>-alpine`, and `alpine` tags built from
docker/Dockerfile.alpine with the musl release tarball. Alpine users can
use the image as a base or copy /opt/pnpm into `node:*-alpine` without
fetching the installer from get.pnpm.io, which was returning 403 to
bursts of concurrent CI jobs.
The download, checksum, and version check move into
docker/install-pnpm.sh, shared by both Dockerfiles. The Alpine image
also installs libstdc++ and libgcc, which the musl Node.js builds
installed by `pnpm runtime` need. The Alpine build runs only for
releases that ship musl tarballs for both x64 and arm64, so v11 and
v10 releases skip it.
Every release used to publish the `latest` and `<major>` tags, so a v11
maintenance release moved `latest` back to v11. The builds now push only
the exact version tags. A final step lists the stable releases and, with
`docker buildx imagetools create`, points `<major>` at the highest
version in that major and `latest` at the highest version overall. The
Alpine tags follow the same rule. Deciding after the builds sees every
release of a burst, since lines are published seconds apart. A
concurrency group was rejected because GitHub cancels a pending run when
a third one queues. The selection lives in
.github/scripts/docker-image-tags.sh with a test run by CI, and fails on
an empty release list.
The v12 CI docs now run the Bitbucket Pipelines and GitLab CI examples
in `ghcr.io/pnpm/pnpm:12` instead of downloading the installer, and
recommend the image for CI that runs jobs in containers. CircleCI keeps
the installer because its checkout step needs git and ssh.
The CI examples that still use the standalone script fall back to the
latest pnpm/get.pnpm.io installer release when get.pnpm.io fails. They
run the script only after a download succeeds.
Related to pnpm/pnpm#16973.
None of the integrated benchmark's scenarios resolved against a lockfile
the walk could mostly reuse, installed store-only (`enableModulesDir:
false`), or read the per-file store index. The install regressions fixed
in pnpm/pnpm#16886, pnpm/pnpm#16888 and pnpm/pnpm#16890 all sat in that shape; the
benchmark would have missed each of them, and would miss their reversal.
The new `store-only.unlocked-direct-deps.cold-cache.hot-store` scenario
seeds the static fixture's lockfile with the direct dependencies whose
locked version carries a peer suffix left out of the importer, while
`packages` and `snapshots` keep the whole graph. That is `pnpm install`
after dependencies were added to `package.json` by hand: the missing
direct dependencies resolve from the registry, land on versions the
graph holds, and the walk reuses their subtrees. The choice of the
peered ones is deliberate: a dependency without peers is taken from the
lockfile's package list without a registry request, and a dependency
whose specifier merely changed is reused as long as the recorded version
satisfies the new range, so neither exercises the fresh pick that the
subtree reuse then follows. The metadata cache is wiped per iteration,
so every package the walk does resolve costs a round trip over the
emulated registry link; with a hot cache on local disk the whole
speculative warm-up costs about 25 ms and sits inside the noise. The
lockfile is trusted (`trustLockfile: true`): its supply-chain
verification reads every entry's packument and left nothing for the
resolution to fetch, hiding the difference entirely. With
`enableModulesDir: false` nothing is linked, so the rest of the timed
work is the check that the store holds every package, read through
`storeIndexFormat: files`.
`--no-frozen-lockfile` is passed explicitly because the runners set
`CI`, where a plain `install` is frozen and would reject the lockfile.
Only `cache-dir` is removed and the lockfile restored between
iterations; `node_modules` is never created and the warm store stays.
The scenario runs direct targets only, like the workspace fixtures: a
pnpr server would take over the resolution being measured. The
comparison script and its matrix-coverage test, the Bencher upload and
the summary list it alongside the others. Every `cleanup` arm now goes
through a `Cleanup` constructor, which keeps the method within the
function-length limit with the new arm.
Measured locally (hyperfine, 5 runs, main vs the commit before pnpm/pnpm#16886):
main 1.008 s +- 0.025 s (0.991 .. 1.052 s), 513 packuments
before pnpm/pnpm#16886 1.148 s +- 0.026 s (1.131 .. 1.194 s), 840 packuments
Avoid replacing an injected directory when its regular files are still
hardlinked to the current source and its entries match. Keep the existing
refresh path for mismatches, links, forced imports and build isolation.
Preserve import reporting and add a frozen-repeat scenario to the existing
integrated benchmark and CI comparison.
Closespnpm/tasks#121.
* chore: update dependencies, Node.js, pnpm, and GitHub Actions
* chore: generate the embedded CAS loader bundle on install
The CAS loader that `deps-restorer` embeds with include_str! was a
minified esbuild bundle committed to the repo. Every enhanced-resolve or
esbuild bump rewrote most of it, and a stale copy failed CI with a
byte-by-byte assertion diff.
`@pnpm/esm-loader` now generates it from a `prepare` script, so every
`pnpm install` that includes the package writes it before cargo builds.
Cargo already depends on that install for `.pnpm/crates`. The package
gets its own esbuild devDependency instead of borrowing pnpm11/pnpm's.
The filtered installs that feed cargo (install-crates and the wasm
release job) now also select `@pnpm/esm-loader`.
Also ignore GHSA-hp3w-g68c-fv3c. sprintf-js has no patched release, and
it is reached only through argparse 1 formatting its own help text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: write the CAS loader bundle atomically and generate it for wasm CI
An interrupted `prepare` could leave a truncated bundle that a later
up-to-date install never rewrites. Write to a temporary file and rename.
The pnpm-wasm workflow builds the CLI after a filtered install, so it now
selects `@pnpm/esm-loader` too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Add an opt-in CAS installer and synchronous Node.js module loader.
Generate package-instance manifests and embed the runtime in the Rust CLI.
Load compatible package files directly from verified store blobs while retaining
ordinary complete GVS installations for explicitly materialized dependency trees.
Reuse the existing fetch, graph hashing, linking, build approval, and command shim
pipelines. Preserve loader references during store pruning and preload the loader
for normal script and command execution. Keep application filesystem APIs intact.
Document the install mode; keep compatibility experiment results in the implementation task.
Related to https://github.com/pnpm/tasks/issues/64. Future linker-specific settings and nested hoisting configuration are tracked separately in https://github.com/pnpm/tasks/issues/72. Only the loaded-linker object form is included here.
A release event runs the workflow file from the tagged commit, and the
sync took the release keys and verification scripts from that commit
too. Anyone able to push a tag and publish its release controlled the
checks that guard the job holding DOCS_SYNC_TOKEN.
The release event now only dispatches Sync documentation from the
default branch with the release tag, using GITHUB_TOKEN with
actions: write. The sync itself runs only on workflow_dispatch, as a
manual retry does, with the workflow, scripts and keys from main. The
docs-sync environment should be restricted to main to close the other
route to the token.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sync documentation ran on the completion of the Release workflow. The
release only stages pnpm on npm, so the publication check always failed
and every sync had to be dispatched by hand after approval.
The maintainer publishes the draft GitHub release after approving the
staged packages, so that event now starts the sync. The tag commit must
match the commit the release event names, and the npm publication check
stays.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sync documentation now carries blog/releases/<version>.md into the
pnpm.io publish commit. pnpm/pnpm.io writes the page from the changelog
section the release PR curated, read at the signed release commit, so
the release page and the GitHub release body share one source and patch
releases get pages too.
Release pages are added without clearing the directory, which keeps the
hand-written pages for earlier releases.
GitHub CLI can print an HTTP error response to stdout before exiting nonzero.
Appending pending inside command substitution retained that response in the
conclusion variable, which the polling loop misread as a terminal build result.
Check the command's exit status and set conclusion to pending on failure.
Preserve terminal build failure handling, polling frequency, and step timeout.
Run the workflow step with stubbed commands in CI to cover API-error recovery
and genuine build failures.
The unsaved constructor dependency test expected the temporary directory's
original spelling, but the dependency tree returns its canonical path.
Resolve the expected path with the native asynchronous API to handle Windows
short names and symlinked temp roots. The production dependency-tree behavior is unchanged.
Add TypeScript ports of the perfectionist rules that the Rust workspace
enforces through dylint.toml to @pnpm/eslint-config, with the same limits,
and fix every finding that needs no refactor.
The size and shape rules (function length, cognitive complexity, nesting,
local bindings, file length) are enforced for packages that already meet
them. The packages that do not are listed in PENDING_SIZE_AND_SHAPE_REFACTOR
in eslint.config.mjs and are refactored in follow-up changes.
The custom rules mirror perfectionist's semantics rather than reusing
sonarjs or max-lines-per-function, so that one limit means the same thing
in both codebases: a closure is a level of the body that contains it, a
nested function declaration is measured on its own, and a test-framework
callback plays the role of a #[test] function.
Bugs found and fixed along the way:
- a registry error body cut at exactly 64 KiB lost its truncation marker
- removing a dependency could leave dangling .bin shims
- constructor/__proto__ names crashed the projects graph, were skipped by
the injected-deps syncer, and were dropped from writeWantedLockfile's
returned lockfile
The CI chunk runner learns to run the node:test suite of the ESLint
config package.
Gate documentation publication on creation of a generated commit.
An unchanged import exits the commit step successfully, but must also skip
credential lookup and pushing. Emit changed=true after a successful commit
and use it as the condition for the push step.
The cross 0.2.5 ppc64le image uses binutils 2.26.1. It mislinks
calls to optional libc functions absent from its sysroot: the
published binary tests the dynamically resolved gettid address,
then branches to an unmapped address instead of calling it.
Let GCC retain its sysroot and library selection, but route its
linker invocation to the LLD bundled with the pinned Rust toolchain.
This fixes the weak-symbol calls without raising the glibc baseline
or adding another linker download. Scope the setting to ppc64le.
Smoke-test the actual release binary against a newer libc, where
gettid is present. Testing only against the build sysroot misses
the bug because Rust takes its syscall fallback there.
Closespnpm/pnpm#16380.
* chore(github): ask issue authors without the fix checkbox about a PR
Issues filed through `gh issue create --body` or the API skip the issue
form, so they never carry the "I am working on a fix" checkbox. When the
"Contributing a fix" section is missing from the body, the triage
workflow now comments asking the author whether they plan to open a
pull request. The regression form gets the same checkbox, so its
reports are not asked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(github): cover the issue fix-intent classifier
The classifier moves from the triage workflow into
.github/scripts/issue-fix-intent.sh, with a test that CI runs next to the
other workflow script tests. The workflow checks out the default branch
before the step so the script is available.
A "Contributing a fix" heading without its checkbox now counts as
missing. A hand-written body containing only the heading was classified
as unchecked and got neither an assignment nor the question.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The published Windows pnpm.exe linked VCRUNTIME140.dll, so it exited
0xC0000135 on a clean Windows install. The Rust release job now passes
-C target-feature=+crt-static when building the CLI for
*-pc-windows-msvc. The NAPI cdylib build is unchanged, including the
musl -crt-static flag.
The release verification job rejects a Windows pnpm.exe that still
imports that DLL.
Closes https://github.com/pnpm/pnpm/issues/15723
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
pnpr/crates/*/*.md was already excluded from the rust filter, while the
matching Markdown under pnpm/crates still ran the whole Rust suite on
three platforms. No build step or test reads those files. The docs
filter gains the same pattern, so the spell check still runs on them.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Link pnpr's integration tests as one binary with the shared helpers
declared once, run Garnet on one TS chunk, keep Markdown out of the Rust
CI and benchmark triggers while still spell-checking it, and build the Linux pnpr fixtures on 16 vCPUs
while the Linux TS chunks start and wait for them.
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Split TypeScript tests into three chunks per Node.js version on Linux and
five on Windows, balanced by recorded Jest durations, and start the
Windows chunks while their pnpr fixtures build. Skip Jest coverage in CI,
which nothing reads. Keep Rust sources from widening the TypeScript test
scope.
Cache Rust compiler output with sccache on Linux and macOS, because
rust-cache prunes every dependency of this workspace, and run Rust
coverage on 8 vCPUs with its own compiler cache. Save at most one cache
entry per scope and day.
Build the pnpr fixtures without fat LTO, at opt-level 1, on every push to
main and on 16 vCPUs for Windows. Avoid obsolete PR work, full-history
benchmark build checkouts and test-only network backoff. Keep all
platforms, Node.js versions, merge-queue validation, production retry
defaults, and the release and benchmark build profiles.
Confirm suspected integrated benchmark regressions once with target order
reversed. Same-run measurements can still be biased by sustained runner drift:
a control run on identical Rust sources produced a 29% apparent pnpr slowdown.
Keep the 5% tolerance with a 2 ms floor and the retained-sample noise guard.
Require the regression to reproduce in the confirmation, preserve both sets
of measurements in the artifact and report, and keep the initial timings for
historical Bencher uploads. Missing required confirmations fail the check.
The wrapper preserves the existing harness arguments and assertions. It does
not retry command failures, and confirmation failures propagate. Main-only
runs and scenarios without suspected regressions execute once.
Related to pnpm/pnpm#15228.
Compare integrated benchmark samples against main measured on the same runner.
Keep absolute minimum timings in Bencher for historical tracking without letting
cross-machine historical alerts overwrite the PR regression check.
Require at least nine successful samples per target. Fail when the median
slowdown and retained sample separation both exceed 5% of main's median or
2 ms, whichever is larger. Trim up to 10% from each tail. Report other median
slowdowns above that tolerance as inconclusive. This conservative noise guard
is not a statistical confidence interval; smaller or noisy regressions can pass,
and sequential measurements remain vulnerable to runner drift.
Run the comparison from trusted default-branch code in the privileged comment
workflow, publish the report before enforcing the result, and preserve the
existing check name on the triggering PR commit. Keep the peer-heavy
Rust-versus-TypeScript assertion unchanged.
Cover regressions, shared machine slowdowns, outliers, invalid data, all scenario
and engine combinations, command names, CLI exit codes, and the duration-dependent tolerance with Node tests.
Keep the explanation in the existing benchmark documentation.
Import cmd-shim source, tests, and snapshots from pnpm/cmd-shim at
83f9b9449c2adeec26e1cc2d03ef0fe82d2e41ca. Maintaining the shim alongside
its consumers removes the need for coordinated changes across repositories.
Publish the package as `@pnpm/bins.cmd-shim` and replace external dependencies
with workspace links. Preserve the original BSD-2-Clause license, including
its copyright notice, and keep the manifest updater from replacing it with MIT.
Reuse `@pnpm/fs.graceful-fs` and integrate the existing Node.js tests with the
workspace test scripts. Retain the existing snapshots and align the version
with the TypeScript workspace's required 1100.x band.
Declare CI pipelines and root task scripts, and invoke them from the
TypeScript, Rust, reusable test, and pnpr build workflows. Let pipelines
perform frozen installs and order TypeScript compilation before linting.
Keep existing test runners responsible for affected-package selection,
file-level sharding, and summary generation. Read shard settings from the
workflow environment, with explicit command-line arguments taking precedence.
Run root tasks with --include-workspace-root --full: the scripts live in the
root manifest only, and the test runners already select their own scope. Pass
--no-cache so a task that later declares outputs cannot skip a check.
Keep the dependency install in its own step in the two jobs whose commands are
timed for Bencher, so the reported duration stays a test duration. Preserve
existing job gates and artifact handoffs.
The v12.3.2 release run died in "Package pnpm-napi darwin-x64" because
Apple clang segfaulted while linking the httparse build script. Nothing
in the tree changed; the same Blacksmith image built v12.3.1 fine the
day before. Every other packaging job was cancelled and the release had
to wait for the run to finish before "re-run failed jobs" was possible.
Route the three release cross builds through a wrapper script that
retries up to three times. Cargo keeps the crates a failed attempt
finished, so a retry only redoes the crate that died.
The Windows legs of build-rust and build-pnpr now run the build step
under bash instead of the default pwsh, as the napi packaging job
already did on both Windows targets. The clang-cl environment for
win32-arm64 is exported through GITHUB_ENV and GITHUB_PATH, so it
reaches bash the same way.
Keep staged publishing above direct OIDC publishing in the trust-policy ranking.
Use the stronger release path instead of lowering the rank.
Stage the TypeScript `@pnpm/exe` and `pnpm` packages in dependency order.
Stage Rust native packages, wrappers, and the `pnpm` gate as separate layers.
Let CI finish after creating every stage without polling for approval.
Maintainers approve the completed stages later with interactive 2FA.
Pin publication traffic to the npm registry and ignore ambient auth configuration.
Sanitize stage output before logging registry-provided content.
Closespnpm/pnpm#13693.
The first pnpm 12 beta release used pnpm 12.0.0-alpha.21 to publish a wrapper whose workspace name is `pacquet`. That version predates `publishConfig.name`, so npm trusted publishing was attempted for `pacquet` instead of `pnpm` and the root package failed after all native packages had already been published.
Use pnpm 11.18.0, the released TypeScript CLI that supports `publishConfig.name`, for release tooling. Update every `pnpm/setup` consumer to the revision that can install v11 from GitHub release archives. Make the Rust publishing loop query each effective published name and skip versions already on npm, while preserving hard failures for registry errors other than 404. This allows a moved beta tag to resume the partial release and reach the dependent GitHub release job.
* chore(release): drop the packing workarounds now that pacquet 12.0.0-alpha.19 is pinned
The pinned pacquet now carries the fs-packlist fix from
https://github.com/pnpm/pnpm/pull/13231, so a files allowlist wins over
workspace-inherited ignore rules and the release workflow no longer
needs to neutralize them: remove the empty pnpm11/pnpm/.npmignore
override, the temporary root .gitignore shadow, and the pre-publish
payload verification step (with its script) that guarded against the
now-fixed empty-tarball packing bug. The payload-verify step was also
what broke the v11.17.0 release: its filtered pn list fired a
verifyDepsBeforeRun auto-install that pruned the excluded pnpm
project's node_modules, so the darwin-arm64 artifact's prepublishOnly
could no longer resolve symlink-dir.
`@pnpm/prepare` and `@pnpm/prepare-temp-dir` were the only
publishable packages without a files allowlist; their lib/ payload
survived packing only through the .gitignore shadow. Give them files
allowlists so their tarballs no longer depend on workspace ignore
state.
* chore: record the pacquet 12.0.0-alpha.19 pin in the lockfile
* chore: drop the changeset - both files-allowlist fixes ship without a new version
The pending `@pnpm/prepare` 1100.0.22 is not on npm yet, so the rerun
of the v11.17.0 release publishes it with the files allowlist already
in place. `@pnpm/prepare-temp-dir` 1100.0.1 is already published with
correct tarball content (packed under the .gitignore shadow), so its
manifest-only change needs no republish. A changeset would only
schedule a patch release whose sole delta is the manifest field.
Pack every publishable workspace package in dry-run mode before the
first immutable npm publish and verify each reported file list against
the manifest-declared payload (files, main, module, types, exports,
browser, bin, publishConfig.executableFiles). A packing regression like
the one that shipped nearly-empty lib tarballs for five releases
(pnpm/pnpm#13164) now fails the release job before anything publishes.
The verification is one pn compile-only (pack does not run
prepublishOnly), four concurrent `pnpm pack --dry-run --json` chunks
(recursive pack packs one project at a time and, unlike recursive
publish, does not skip private packages — so publishable projects are
selected by explicit name filters), and a single node pass over the
reported file lists. No tarballs are written or read.
Also give @pnpm/modules-mounter.daemon the lib/index.js entry point its
manifest declares; the verifier caught that it never existed.
Fixespnpm/pnpm#13179
Run Windows TypeScript test jobs only on Node.js 22 and split them into three parallel chunks.
Windows TS tests are significantly slower than Linux, and running the full suite on three Node versions spends the extra capacity on duplicate runtime coverage instead of reducing wall clock time. The reusable test workflow now accepts chunk inputs, includes chunk identity in concurrency and artifact names, and keeps Bencher uploads with chunk-specific benchmark names.
Add a CI helper that discovers the selected workspace packages for the same full or affected test scope, shards Jest test files into balanced chunks, runs selected package files with the same Jest Node options and package pretest setup, and writes pnpm-style execution summaries so the pnpm CLI e2e duration extraction still works.
## Summary
Adds CI duration tracking for the `pnpm-ci-performance` Bencher project.
Tracked Rust testbeds and benchmarks:
- `pacquet.ubuntu`, `pacquet.windows`, `pacquet.macos` -> `tests.all`
- `pnpr.ubuntu`, `pnpr.windows`, `pnpr.macos` -> `tests.all`
Tracked pnpm testbeds and benchmarks for full test runs:
- `pnpm.ubuntu.node22`, `pnpm.ubuntu.node24`, `pnpm.ubuntu.node26` -> `tests.all`, `tests.cli`
- `pnpm.windows.node22`, `pnpm.windows.node24`, `pnpm.windows.node26` -> `tests.all`, `tests.cli`
The test workflows produce Bencher-compatible JSON artifacts without receiving `BENCHER_API_TOKEN`. A separate `workflow_run` workflow downloads those artifacts only for same-repository runs, validates their metadata, and uploads from trusted workflow code using the existing `BENCHER_API_TOKEN` secret. The pnpm CLI e2e duration is extracted from `pnpm run --report-summary` output during the same full-test execution, so the CLI e2e suite is not run a second time.