* chore(release): 11.28.7, pacquet 12.15.0, pnpr 0.1.0-alpha.16
* docs(release): curate 11.28.7, pacquet 12.15.0, and pnpr 0.1.0-alpha.16 release notes
Add lead paragraphs and group the patch entries by what the reader was
doing, with security fixes first on each page.
- v11: lead with the registry metadata name check, pinned pnpm
trustPolicy check, maxTarballUnpackedSize, and the removal of registry
revisions; merge overlapping entries for minimumReleaseAge metadata
revalidation, frozen-lockfile directory dependency checks,
syncInjectedDepsAfterScripts, verifyDepsBeforeRun, pnpm sbom, and
unreadable config settings.
- v12: order minor highlights from config includes and
lockfile.integrityTarget down to interactive update styling; drop the
pnpr-only distribution note from the CLI changelog; merge overlapping
entries for workspace and pnpr install speedups, minimumReleaseAge and
If-Modified-Since revalidation, frozen-lockfile and injected package
checks, verifyDepsBeforeRun, pnpm prune, pnpm pack, pnpm licenses
list, pnpm self-update, pinned pnpm flag forwarding, and WebContainer
fixes.
- pnpr: lead the minor section with the breaking ecosystem URL prefix,
hosted storage layout, artifacts.orgs, and strict config schema
changes; fold dist.pnpr tarball metadata into one entry and drop the
redundant /metrics note; lead the patch section with reserved-username
and auth security fixes.
- Use one issue-link label style across the release pages.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Handle registry read and environment-write failures in setup's existing
post-install outcome handler. Keep installation separate from environment
persistence, as the missing-shell-config fallback already does.
Print session-local PowerShell assignments and profile instructions when
registry persistence is unavailable. Preserve the original diagnostic and
leave environment conflicts and other failures fatal. Do not attempt to
replace an unreadable persisted PATH or elevate to another Windows user.
Apply the behavior in both CLI versions, with regression tests for read and
write failures and literal quoting of ASCII and typographic apostrophes.
Closespnpm/pnpm#17167.
`pnpm setup` treated ERR_PNPM_UNKNOWN_SHELL and ERR_PNPM_NO_SHELL_CONFIG
as fatal. In containers SHELL is usually unset, so setup exited non-zero
and the get.pnpm.io installer failed, although the pnpm binary and bins
were already in place.
Both errors now mean only "no shell config file can be updated". Setup
continues with the GitHub Actions env files and legacy shim cleanup,
then prints the reason and the PNPM_HOME/PATH lines to add manually, and
exits 0. Errors that indicate a real conflict or an unsupported shell
still fail the command.
Implemented in the Rust v12 CLI and the TypeScript v11 CLI with the same
message.
Related to pnpm/pnpm#4495, pnpm/pnpm#6217, pnpm/pnpm#16973.
`pnpm self-update` refused to run when Homebrew installed pnpm or
Corepack ran it, even in a project that pins pnpm. The refusal guards the
global switch, which would install a second pnpm shadowed by the one on
PATH. Writing the pin touches nothing Homebrew or Corepack manages.
Both CLIs now skip only the global switch under an external manager and
report it after the pin update. Without a pnpm pin the command still fails
with ERR_PNPM_CANT_SELF_UPDATE_IN_HOMEBREW / _IN_COREPACK.
In pnpm v12 the check stays in the dispatcher before config is loaded. It
now reads package.json from the same directory as the handler to decide
whether a pin exists.
Closespnpm/pnpm#17001
* chore(release): 11.28.6, pacquet 12.14.0
* docs(release): curate 11.28.6 and pacquet 12.14.0 release notes
Add lead paragraphs and group the patch entries by what the reader was
doing, with security first on the v11 page.
- v11: lead with the NPM_ID_TOKEN audience check and the invalid file
name warning as security fixes; say the `pnpm setup` message was
printed, since v11 reports it as a warning.
- v12: merge the stdout and stderr broken-pipe entries and the two
optional-peer entries; say the Windows Rust toolchain change undoes
the MinGW fallback a MinGW-built pnpm used since 12.13.0; correct the
`browser` packing claim; drop the reference to another release line.
- Use one issue-link label style on both pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): smooth two sentences in the 11.28.6 and 12.14.0 notes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): say sideEffectsCache.exclude covers the local and remote cache
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: give sideEffectsCache.exclude an example a cache key cannot cover
An environment variable such as JAVA_HOME could be added to the cache
key, so it does not justify excluding a package. Name the system
libraries a native addon links against instead.
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>
On macOS `current_exe` returns the path pnpm was started through, such as
npm's `<prefix>/bin/pnpm` symlink. `pnpm setup` took its parent as the
package directory, installed `file:<prefix>/bin`, and generated a
`$PNPM_HOME/bin/pnpm` launcher pointing at an executable the installed
package does not contain. Canonicalize the path before installing.
pnpm v11 has the same bug through `process.argv[1]`, which keeps the
symlink path on every OS. Resolving it makes an npm-installed v11 take
the JS-entry-point branch, which skips the global self-install.
Closespnpm/pnpm#16855
pnpm 11 releases older than 11.28.4 linked the bins of a pnpm 12 store
slot without force. The first link, made while the wrapper's bin was
still the `#!/usr/bin/env node` placeholder, wrote a shim that runs
`node`. The second link, after the native binary replaced the
placeholder, kept that shim because its target path had not changed.
installPnpmToStore reused any slot whose bin directory existed, so the
broken shim survived an upgrade to a fixed pnpm 11.
After linking a slot's bins, installPnpmToStore now writes a
`.pnpm-bins-linked` marker holding the running pnpm version. On reuse,
a missing or different marker makes it relink with force, under the
slot's lock and after rechecking the marker. pnpm v12
already does this for its engine store (`linked_bins.rs`), so only v11
needs the fix.
Closespnpm/pnpm#16646
* chore(release): 11.28.5, pacquet 12.10.0
* docs(release): curate the 11.28.5 and 12.10.0 release notes
Add a lead paragraph to each page and group the patch entries under
subject headings, with the security fixes first.
- Merge the unpublish path-boundary fix into the unpublish entry, the
legacy metadata cache prune into the metadata cache entry, the two
binary size entries, and the two 64 MiB archive limits on the v11 page.
- Drop the manifest-utils saveType entry from the CLI page: the CLI
only passes saveType values derived from its own flags, so no CLI user
can reach the fixed path.
- Rewrite mechanism-only entries (PAX header validation, bundled
dependency symlinks, custom resolutions under name@version keys, proxy
setting validation) in terms of what the user sees.
- Use one link style for pnpm/pnpm issues.
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>
On a repeated run, `pnpm setup` returned early with "No changes to the
environment were made" and dropped the "Configuration already up to date
in <file>" line. The get.pnpm.io installer then printed "the lines pnpm
setup added to the shell config file named above" with no file named.
Report the config file before the no-change message in both the v11 and
v12 setup commands.
Closes https://github.com/pnpm/pnpm/issues/16608
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(release): 11.28.4, pacquet 12.9.1
* docs(release): curate 11.28.4 and pacquet 12.9.1 release notes
Add a lead paragraph to both pages. Move the two credential-leak fixes
in 11.28.4 to the top and group the remaining 27 entries by what the
reader was doing. Merge entries that described one change: the two
INVALID_SETTING validations, the two metadata revalidation fixes, the
two hoisted filtered-install fixes, and, in pacquet 12.9.1, the two
[<since>] selector fixes. Order pacquet 12.9.1 so the `@pnpm/wasm` move,
which WebContainer users must act on, comes first.
Normalize issue links to the [#N] form and link the ETag fix to
pnpm/pnpm#16506.
Every fix was checked against the code released in 11.28.3 and
pacquet 12.9.0; none fixes a defect that never shipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): describe the frozen-lockfile fixes accurately in the 11.28.4 lead
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>
`pnpm self-update` installs the target pnpm into the global packages
directory and links it into PNPM_HOME. It never touches the Homebrew
keg, so a Homebrew user ended up with a second pnpm that the Homebrew
binary on PATH kept shadowing. The update reported success while
`pnpm -v` stayed the same, and later runs declined because the target
was "already installed globally".
Both CLIs now detect a running pnpm that lives inside a Homebrew keg
(`<cellar>/pnpm/<version>/` or `<cellar>/pnpm@<major>/<version>/`) from
its canonical path and fail with ERR_PNPM_CANT_SELF_UPDATE_IN_HOMEBREW,
pointing at `brew upgrade <formula>`. The check sits next to the
existing Corepack refusal, before project config is loaded.
Closes https://github.com/pnpm/pnpm/issues/16547
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* docs(agents): add the documentation and comment principles
Import the principles that transfer from KSXGitHub/perfectionist's
contributor guide, plus four of our own: concise and non-repeating text,
structured text over prose, removal over addition when reviewing or
fixing nitpicks, and a definition of the user-facing text that must not
name implementation details.
The root guide's "Comments" section gains "Register", "Prose that cannot
go stale", "User-facing text", and "Reviewing documentation and
comments". The pacquet style guide adds the Rust specifics (clap and
napi doc comments are user-facing; a default is documented on the
field, not the variant). DOCUMENTATION.md gains the renderer and link
table for each markdown surface.
The guides themselves are brought in line: counts over growable lists
become plain references, a quoted heading becomes an anchor link, and
the size limits are stated once, in the style guide, instead of three
times.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs: keep user-facing text free of implementation names
The `@pnpm/napi` README and type declarations named the Rust engine, the
in-repo package name, and TypeScript internals (`filterPkgsDiff`,
`nameFormatter`) that a user of the addon cannot reach. The pnpmfile
page in both docs trees explained a limitation by the IPC mechanism
behind it. Four changesets named the release line or implementation,
which the package targets already express.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating and stale comments in pack, modules-yaml and nine more crates
Apply the comment principles to pack, versioning, pnpr-client,
package-is-installable, fs-packlist, workspace-task-scheduler,
engine-runtime-node-resolver, exportable-manifest, modules-yaml,
pnpr-registry, and pnpr-auth. Removed: call-site comments that repeat
the callee's doc, module rosters of exports that the `pub use` lines
already list, "not yet implemented" notes for behaviour that exists
(`beforePacking`, `hoistedLocations`), body narration, and history
framing. Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating and stale comments in the small resolver, catalog and pnpr crates
Apply the comment principles to the local, tarball, default, deno and
jsr resolvers, the catalog crates, detect-libc, config-parse-overrides,
env-replace, git-utils, matcher, diagnostics, and the pnpr policy,
cargo, error, osv and fixture crates. Removed: parentheticals that
repeat a `#[diagnostic(code)]` attribute, counts over lists of
variants, callers and entry points, rosters of callers, doc paragraphs
that repeat a sibling's or the module's text, comments narrating the
match arms or condition below them, and history framing. The
`pnpr-prepare --help` text no longer names the test harness.
Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating and stale comments in publish, workspace, registry and graph-hasher
Apply the comment principles to publish, auth-commands, registry,
workspace, lockfile-verification, default-reporter, the git resolver,
deps-inspection, hooks, graph-hasher, package-manifest, and the pnpr
shared-artifacts and route crates. Removed: a module roster of every
export, counts over lists, plan notes for work that landed ("Phase 5",
"Phase 6"), call-site comments repeating the callee's doc, docs
narrating match arms, a default claim on a `#[default]` variant, a
misattached doc, and history framing. Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut restating comments in napi, reporter and pnpr crates
Apply the comment principles to napi, reporter, resolving-resolver-base,
real-hoist, git-fetcher, workspace-manifest-writer, and the pnpr config
and storage crates. Removed: "Mirrors X in index.d.ts" sentences on
`#[napi]` items and other implementation names in addon-facing docs,
stale "not emitted yet" and "when it lands" notes for behaviour that
exists, step-by-step comments narrating the body, emit-site and caller
rosters, docs duplicated from a sibling or the module, a doc attached to
the wrong item, and history framing. Comment-only; no code changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs: cut restating and stale comments across the remaining crates and pnpm11
Apply the comment principles to the rest of the Rust workspace and to the
TypeScript CLI: the cli crate and its clap definitions, package-manager,
config, patching, the deps resolver, lockfile, pnpr, the npm resolver,
tarball, network, executor, cmd-shim, the benchmark and fixture tooling,
and the pnpm11 packages.
Removed: comments narrating the body, docs repeating a callee's, a
sibling's or the module's text, counts over growable lists, rosters of
callers and exports, "not yet implemented" notes for behaviour that
exists, history framing, and `@param` lines restating a signature.
One exception to comment-only: in `pnpr/crates/pnpr/src/resolver/resolve.rs`
the `Workspace` struct sat inside the doc block written for `resolve`, so
the struct moved above it and each doc now attaches to its own item.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): cut body narration and duplicated docs in resolver, fs and package-manager
Removed: a numbered "Sequence:" list narrating `ensure_file`'s body and
the paragraph restating its backoff constants, the stress-test module
doc's roster of its own tests, refactor-history paragraphs in the peer
walk's finalize pass, call-site and caller-side copies of a callee's doc
(the `optional` AND-fold stays documented on `register_seeded_package`
and on `ResolvedPackage`), a verbatim quotation of a TypeScript test's
expected output in the pnpr search module doc, and field and digest-input
rosters in the package-manager.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(deps-restorer): cut plan references and re-attach misplaced docs
Removed the "slice 4" plan references and the comments narrating the
bodies they sat above. The `Auto` downgrade-chain doc moved from
`copy_and_log` to `auto_link`, the function it describes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(deps-restorer): cut the remaining body narration in the hoist path
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs: cut the last body narration and a history clause in the cmd-shim test
`build_graph.rs` kept a `patches` parameter doc that re-derived what
`BuildOptions::patches` documents. The PowerShell-arguments test on main
said the arguments survived "before the shim ended its batch context
too", which describes the change rather than the behaviour.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cmd-shim): point the PowerShell-shim link at its current module
Main moved `wants_powershell_shim` into `windows_shim_policy`, so the
shim writer's link to it no longer resolved and `cargo doc` failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cli): link the fixture the ignored-build setup installs
The shortened doc named `workspace_with_unapproved_build` in backticks,
which `perfectionist::bare_identifier_reference` rejects for an item that
resolves in scope. It is an intra-doc link now.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(crates): restore two contracts and fix four dangling references
A review of this branch's sweep flagged seven places. Six needed a
change:
- `from_ini` documents again that a relative `cafile=` resolves against
`npmrc_dir`, a precondition its callers have to honour.
- `hash_object` documents again that the private serializer's bytestream
has to match pnpm 11's, because the digest is persisted and read by
both.
- The hooked-manifests note no longer says "above" of a gate that lives
in another module.
- The store-dir race test states its synchronization contract instead of
labelling it "Post-Option-C".
- `GraphNodeHashOptions.nodeVersion` keeps `undefined` as a literal.
- The pnpr streaming module drops the sentence fragment that introduced
its list.
The seventh, a `beforePacking` limitation in exportable-manifest, stays
removed: the note said the pnpmfile bridge cannot supply that hook, and
`pnpm_pack::lifecycle::apply_before_packing` has been running it since
before this branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cli): say in `pnpm why --help` that `--exclude-peers` is ignored
Demoting the caveat to an ordinary comment took it out of the help,
which then advertised a flag that does nothing: `WhyArgs::run` never
reads `exclude_peers`, and pnpm 11's `why` handler never forwards its
`excludePeers` either. The doc comment states that behavior in the words
a user sees, and the parity reason stays in a comment beside it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
* docs(cli): drop the doc comment that described the wrong module
The comment described the `pnpm_deps_inspection as deps_tree` re-export
above it, but a doc comment attaches to the item that follows, so rustdoc
showed it as the description of `mod dispatch`. The `use` item already
names the alias, so the comment goes rather than moving.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW
---------
Co-authored-by: Claude <noreply@anthropic.com>
Compile the shared Rust CLI for wasm32-wasip1-threads and supply filesystem,
network, process, terminal and cancellation capabilities through a Node host.
Select host implementations at compile time so native builds retain their
native dependency/features and execution paths.
Bundle the WASM runtime in the regular npm wrappers and select it from the
WebContainer runtime marker. Keep Node launchers usable without installation
scripts. Native installation replaces all four launchers with native bytes.
Regenerate shims after upgrades or dependency builds replace Node targets with
native binaries, including before dependent lifecycle scripts run. Preserve
collision winners and publish replacement shims with executable permissions.
Reject non-descendant permission templates and intermediate symlink escapes, validate before creating directories, and avoid path-based cleanup races.
Restore direct native aliases in both version-management implementations.
Retain process cleanup after failed stdin shutdown. Prevent cross-origin redirects from replaying login credentials in both CLI lines, and strip npm-otp from cross-origin WASM requests. Avoid repeated selected-snapshot and removed-bin scans.
Preserve resolution, lockfile, integrity and build-approval behavior. Use an
isolated WASM store with rollback journals and process leases. Patch WASI path
normalization for multiple parent segments and retain that patch in bundles.
Add pinned tooling, release packaging, real-browser workflow and selection
tests, documentation and a release note. Document host limits, including the
Corepack cold-download failure in WebContainer's streaming hash implementation.
Controlled native CLI cases showed no separated slowdown, and the latest
hoisted rebuild and repeat-install fixture improved. Retain the documented
microbenchmark uncertainty and host limitations.
Related to pnpm/tasks#63.
Switching to a pre-v11 packageManager version on linux-x64-musl (Alpine)
failed with ERR_PNPM_PNPM_ENGINE_NO_NATIVE_BINARY. Every pre-v12 version
resolved to `@pnpm/exe` except on arm64 musl. `@pnpm/exe` first shipped an
x64 musl binary in 11.0.0-rc.3, as `@pnpm/exe.linux-x64-musl`, and as
`@pnpm/linuxstatic-x64` from rc.4 on. Earlier releases had nothing to link
on that host.
The musl rule now depends on the version in both stacks. On musl Linux, a
pre-v12 switch uses `@pnpm/exe` only on x64 at 11.0.0-rc.3 or later, and
the JavaScript `pnpm` otherwise. v11 keeps the running wrapper across a
switch, and now applies the rule when that wrapper is `@pnpm/exe`.
pnpm v12's self-update now runs a JavaScript pnpm engine through Node.js
before linking it as the global command, as v11's assertPnpmRuns does, so
a host without Node.js keeps its working pnpm.
Closespnpm/pnpm#16467
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
pnpm v10 put the standalone pnpm.exe straight into PNPM_HOME and that
directory on PATH. An update links pnpm.cmd shims into PNPM_HOME/bin
instead, so self-update reported success while PATH kept running the old
executable. A pnpm.exe copied into PNPM_HOME/bin shadows the new pnpm.cmd
the same way, because Windows prefers .exe, and v11 failed there with
EPERM when it tried to unlink the running executable.
On Windows, self-update now renames such a pnpm.exe out of the way before
linking. Windows lets a running executable be renamed but not deleted,
so the executable is removed only after the shims are linked and put
back if linking fails. One that is still running is removed by the next
self-update. pnpm v12 replaces it under the global bin lock, and pnpm v11
leaves a retired executable alone while the update that retired it runs. When the executable was in PNPM_HOME itself, the updated
pnpm is also linked there and self-update warns to run pnpm setup, as
v11 already does for the v10 shim layout. Later updates keep re-linking
those shims until pnpm setup removes them, which pnpm v12 now does as
pnpm v11 already did. A native pnpm v12 shim named
pnpm has a sidecar and is left alone.
Closespnpm/pnpm#9094
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A devEngines.packageManager range recorded the running pnpm in
packageManagerDependencies whenever it satisfied the range. The running
pnpm is installed without the project's settings, so a contributor with a
fresh global pnpm wrote a version into the lockfile that every other
contributor's switch then refused under the project's minimumReleaseAge.
When the running pnpm is recorded for a range pin, pnpm now checks it
against the project's cutoff, without the exemption the running version
gets elsewhere. An immature running version gives way to the newest mature
version in the range that also passes the configured trustPolicy, since
every other contributor installs it. Only the lookup of the running pnpm,
which is already executing, leaves the trust policy out. If nothing in the
range passes, the running version is kept, since no switch could do better.
A failed lookup (offline, registry error) warns and records nothing, so
an unchecked version never reaches the lockfile; the next command retries. A frozen lockfile skips
the lookup because it records nothing new. The recording command keeps
running on the current pnpm in both stacks.
pnpm v12 also replaced a recorded version that still satisfied the range
whenever the running pnpm differed, because the sync compared the lockfile
against the running version. It now keeps the locked version, as v11
already did, and only rewrites its specifier when the range changed.
The engine resolve-policy helpers move into config_deps/engine_policy.rs to
keep config_deps.rs under the file-length limit.
Closespnpm/pnpm#16431
* chore(release): 11.28.3
* docs(changelog): curate the 11.28.3 release notes
Merge the eleven entries about names such as `constructor` into one,
group the patch changes by what the reader was doing, and add a lead
paragraph.
Drop the zlib-rs entry: that change only touched Cargo.toml, and the
TypeScript CLI does not use the Rust engine. It belongs to the next
pacquet release.
Rewrite the store index entry for CLI users. `ReadOnlyStoreIndex` and
`ImmutableStoreIndex` are library API documented in the
`@pnpm/store.index` changelog.
Say what the store prune mark-phase fix changes for the user.
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 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.
Shims fall back to the filtered PATH when command -p finds no helper, as in a Nix build sandbox.
A helper comes from PATH only when PATH has it, because the bash 3.2 that macOS ships as sh answers command -p -v from PATH.
Closes#16377
* chore(release): 11.28.1, pacquet 12.8.0, pnpr 0.1.0-alpha.14
* docs(release): park Rust changelogs and curate release notes
The release bump ran with pnpm 12.7.0, which since pnpm/pnpm#14934
writes the changelog of every private project to a committed
CHANGELOG.md. pacquet, `@pnpm/napi` and `@pnpm/pnpr` are private
in-repo but published, and release.yml and the publish-time changelog
composer both read their parked section. Move the three sections back
to .changeset/changelogs so the GitHub release bodies and the npm
tarball changelogs are not empty. The tooling follow-up is recorded
on pnpm/tasks#38.
Curate the pnpm 11.28.1, pnpm 12.8.0 and pnpr 0.1.0-alpha.14 pages:
add lead paragraphs, group patch entries by subject, merge entries
describing one change, drop internals no CLI user sees, and fix
"instead of" tails, implementation names and link placement. This
addresses both Qodo findings on the catalog entry.
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>
StackBlitz WebContainers reject asynchronous fs calls with errors that
inherit from Error but were not created by the native constructor, so
util.types.isNativeError() returns false for them. pnpm used that check
to recognize ENOENT and other codes, so a missing pnpm-lock.yaml was
rethrown and pnpm install failed on any project without a lockfile.
Add isError() to @pnpm/error, which accepts a native error or any
instanceof Error, and use it at every non-test call site. The native
check alone is still needed for Jest, where errors from another realm
fail instanceof. Update the AGENTS.md guidance to match.
Closespnpm/pnpm#15649
* fix(path-extender-posix): keep lines between duplicate pnpm sections
`@pnpm/os.env.path-extender-posix` replaced the pnpm section with a greedy
regex, so a shell config holding two `# pnpm` ... `# pnpm end` blocks lost
everything between the first opening marker and the last closing one.
pnpm/pnpm#15321 already fixed this for `pnpm setup`, but it did so in a
copy of the package inside `@pnpm/engine.pm.commands`, because the package
still lived in pnpm/components. Now that the package is in this repository,
move the fixed code and its tests back into it and let `pnpm setup` use the
package again. The copy is deleted.
The regression test for the published API is adapted from
pnpm/components#29 by Zelys, which proposed a non-greedy regex for the
same bug.
Closes https://github.com/pnpm/pnpm/issues/12282
Co-authored-by: Zelys <zelys@dfkhelper.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(path-extender-posix): prefer the block that sets proxyVarName
The duplicate-section selection looked for `<SECTION>_HOME`, which misses
the generated block when a caller's `proxyVarName` differs from its
section name. Pass `proxyVarName` through to `findSection`.
Also declare the section helpers after `updateShellConfig`, document the
`null` result, and reword the changeset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Zelys <zelys@dfkhelper.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(setup): stop writing .ps1 wrappers for the pn, pnpx, and pnx aliases
PowerShell prefers a .ps1 over a .cmd of the same name, so under the
default Restricted execution policy on Windows client `pn` failed with
"not digitally signed" while `pnpm` worked. The wrappers only called
pnpm.cmd, since the bin linker already omits pnpm.ps1, so they added no
behavior. They also dropped a bare `--` from the arguments, the reason
pnpm itself has no .ps1 (pnpm/pnpm#3168).
Both setup implementations and the `@pnpm/exe` prepare script now write
only the .cmd form and delete a .ps1 left by an earlier run.
Closespnpm/pnpm#8444
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(setup): split the changeset sentence and document the .ps1 removal
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The remaining packages of the pnpm/components Bit workspace now live
under pnpm11/ and are published from here, keeping their npm names:
@pnpm/config.env-replace -> pnpm11/config/env-replace
@pnpm/log.group -> pnpm11/log/group
@pnpm/network.agent -> pnpm11/network/agent
@pnpm/network.ca-file -> pnpm11/network/ca-file
@pnpm/network.config -> pnpm11/network/config
@pnpm/network.proxy-agent -> pnpm11/network/proxy-agent
@pnpm/os.env.path-extender -> pnpm11/os/env/path-extender
@pnpm/os.env.path-extender-posix -> pnpm11/os/env/path-extender-posix
@pnpm/os.env.path-extender-windows -> pnpm11/os/env/path-extender-windows
lex-comparator and nerf-dart were already moved under new names, and the
Bit env component is build tooling with no counterpart here.
The sources are carried over from pnpm/components at 42ec0f7, which
includes the Windows fix that rewrites a PNPM_HOME value stored with the
wrong registry type. pnpm v12 got the same fix in pnpm/pnpm#15746, so
its changeset now also covers pnpm v11, which bundles the workspace copy.
Porting to the monorepo's ES module setup:
- relative imports carry .js and type re-exports are marked `type`;
- tests use jest.unstable_mockModule and import through the package;
- string.prototype.matchall and graceful-fs give way to built-ins;
- safe-execa and lru-cache move to the catalog versions (0.3, 11);
- network.config depends on @pnpm/config.registry-auth-key;
- the strict-ssl proxy test uses node:https and proxy v4 instead of
node-fetch and proxy v1.
The packages start at 1100.0.0 to sit in the pnpm11 version band.
`fs.promises.realpath` is the native realpath, which on Windows expands 8.3
short names such as `RUNNER~1`. The install dir of the global node group
then no longer looked like a subdirectory of the configured global dir, so
`removeGlobalGroups` removed the hash link but kept the install dir. Use the
JS realpath (promisified callback `fs.realpath`), as `scanGlobalPackages`
does through `fs.realpathSync`.
`pnpm env use --global` still requires a global bin directory that pnpm owns and that is on PATH. Removing a Node version only deletes copies pnpm already stored under its home (`nodejs/<version>`), and listing versions does not link a binary, so those commands no longer stop when the global bin is missing or not on PATH.
The TypeScript CLI skips the global-bin PATH check for `env remove` and `env list` (and their aliases) before config loading, because that check ran before the env handler and rejected brew and npm installs. The handler still throws `ERR_PNPM_CANNOT_MANAGE_NODE` for `env use` when there is no global bin. The Rust CLI applies the same split: `use` still returns `CannotManageNode` without a global bin, and `remove` still deletes the store when `global_dirs` cannot be resolved.
Removing the active global `node` package no longer spawns `pnpm remove --global node`, because that child process ran the PATH check again and failed. The TypeScript CLI splits `removeGlobalGroups` out of `handleGlobalRemove` and calls it in-process with the group `env remove` detected. The Rust CLI splits `remove_global_groups` out of `handle_global_remove` the same way. Both still unlink the package's bins when a global bin directory exists.
Closespnpm/pnpm#8357
---------
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>
Implicit `pnpm self-update` resolved latest through minimumReleaseAge and
then treated a mature older pick as a lagging dist-tag. Peek the unfiltered
latest first so the message names the cutoff instead of suggesting a
downgrade.
That second resolve runs only when the update is about to be refused, and
only to choose the message. A self-update that moves forward still does one
lookup, and the version it installs is still the mature pick. If the
second lookup fails, both CLIs report the error. They do not fall back to
the downgrade suggestion.
When the unfiltered tag is older than the version in use and still inside
the cutoff, the downgrade line names that tag and the mature version
separately. `self-update latest` still installs the mature one.
Fixed in both the TypeScript CLI and the Rust CLI.
Closespnpm/pnpm#12006
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: key built packages by the root project's runtime Node
The engine part of a global virtual store slot's hash and of the
side-effects cache key came from the first `node@runtime:` entry in the
lockfile. A dependency that declares its own `engines.runtime` adds such
an entry too, so the key could name that dependency's Node while every
other package's build scripts ran the root project's Node. pnpm v12
iterated a randomly ordered map, so the key and the slot paths could
also change from one install to the next.
Take the install-wide Node version from the root importer's `node`
runtime dependency in both CLIs. That is the Node on the PATH of
dependency builds: the root's `node_modules/.bin` in v11 and with a
local virtual store, and the directory pnpm v12 adds under the global
virtual store. A dependency's own pin still keys that dependency's own
hash.
pnpm v12 reuses the root-importer lookup behind
`find_root_runtime_node_version`. pnpm v11 reuses
`findLockedRootNodeRuntime` and drops `findRuntimeNodeVersion`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(graph-builder): pin the root runtime through the GVS path
The lockfile.utils test exercised `findLockedRootNodeRuntime`, which
existed before, so reverting the v11 call sites left it passing. Test
through `iteratePkgsForVirtualStore` instead: a built package's global
virtual store path must change with the root project's pin while a
dependency's own pin sorts first. The old first-key selection fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A signal sent to pnpm while it ran the pnpm version pinned by the project
never reached that pnpm. The TypeScript CLI ran it with spawn.sync, which
blocks the event loop, so the signal sat undelivered until the pinned pnpm
was done. The Rust CLI ran it with Command::status, which installs no signal
handling, so pnpm died from SIGTERM and left the pinned pnpm running as an
orphan.
Both now run the pinned pnpm under the same signal relay that scripts use,
and wait for it to shut down. The TypeScript CLI does the same for
"pnpm with" through a shared spawnPnpm helper, and without a controlling
terminal gives the pinned pnpm a process group of its own so the relay
reaches its scripts. The Rust "pnpm with" shares spawn_pnpm and is covered
by the same change, which now also ends with the child's signal when a
signal killed it.
Closespnpm/pnpm#9948
* chore(release): 11.28.0, pacquet 12.7.0, pnpr 0.1.0-alpha.13
* docs(release): curate the 11.28.0 and 12.7.0 release pages
Group both pages under subject headings with a lead paragraph that
names the headline changes and the security fixes, and move the
security entries to the top of the patch section.
Merge entries that describe one change: the node shim version files,
ranged selectors without a package.json, SemVer build metadata,
completion injection, custom modulesDir command lookup,
list --only-projects, store status, npm_execpath, catalog and npm-alias
workspace edges, the macOS CA fallback, and the prepare/devPreinstall
skips.
Drop entries that describe no change a published version could show:
the test-only --no-optional entry on both pages, the exported
CreateNewStoreControllerOptions type, the publish availability-probe
fix for a flag first shipping in 12.7.0, and the executable-bit check
the Rust CLI never had wrong.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(release): describe the bin shim part of the modulesDir entry accurately
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>
The standalone install script and earlier `pnpm setup` releases installed
the engine globally as `@pnpm/exe`, while `self-update` installs v12 as
`pnpm`. The two aliases hash to different global groups, so the new hash
link never overwrote the old one and `pnpm ls -g` kept listing the stale
`@pnpm/exe` next to the updated `pnpm`.
After linking the switched-to engine, unlink every other global group
that holds nothing but a pnpm engine, in both the Rust and TypeScript
CLIs. The install directories are left to the orphan cleanup because the
running pnpm may still execute from one of them.
Closespnpm/pnpm#14709
With `trustPolicy: no-downgrade`, the resolver checked trust only after
picking a version, so a trust-downgraded release that satisfied the range
failed the install even when an older release passed the check. This hit
transitive dependencies of `pnpm dlx` and `pnpm install` alike
(pnpm/pnpm#14176).
The trust check now narrows the candidates, like `minimumReleaseAge`
does. A candidate that is a trust downgrade is set aside and the picker
runs again until a candidate passes. Every candidate is still judged
against the full publish history. When nothing is left, the first
downgrade is the error, so an exact-version request still fails with
ERR_PNPM_TRUST_DOWNGRADE. A warning names the versions that were skipped.
The TypeScript resolver re-picks from the packument it already fetched,
using a version filter extracted from the `minimumReleaseAge` filter so
dist-tags move the same way. The Rust resolver runs the check inside the
existing guard re-pick loop. The guard and the trust check are grouped as
CandidateChecks, and the trust handling lives on TrustRejections, so the
loop stays within the dylint size limits. The fallback warning is emitted
after the workspace decision, names at most five skipped versions, and is
deduplicated per name and picked version; the Rust warn-once eviction is
shared with the held-back-update warning. The TypeScript walk is capped at
1000 downgrades like the Rust re-pick loop, so a packument with many
consecutive downgrades cannot force quadratic work.
pnpm self-update and the pnpm engine resolution go through the same
resolver, so a range or `latest` there also falls back; an exact version
still fails.
Closespnpm/pnpm#14176
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
On Nix, `command -p` falls back to the caller's PATH, because no default
path is compiled in. A dependency bin named readlink, sed, or uname in
node_modules/.bin could therefore still redirect a POSIX shim or
launcher.
Every POSIX shim header and launcher, in both stacks, now resolves its
helpers with a PATH that drops node_modules segments and relative and
empty entries, then restores the caller's PATH (or unsets it again if it
was unset) before the target runs. The filter walks PATH with parameter
expansion rather than IFS word splitting, so entries holding glob
characters stay literal. When nothing survives the filter, the helpers
get `/` rather than an empty PATH, which bash and zsh treat as the
current directory. The pnpm placeholder now rejects a walk that does not
end at a regular file, as the pn/pnpx/pnx aliases already do.
is_sh_shim_hardened and pnpm 11's isShimHardened pin the filter line, so
a warm reinstall replaces shims written before this change.
The tests rewrite `command -p` to plain `command`, which is how such a
shell behaves, first prove a decoy on PATH wins without the filter, and
then show node_modules, relative, and empty entries are ignored.
Fixespnpm/pnpm#14883
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Node.js publishes native `win-arm64.zip` archives starting with Node.js 20. Prior releases only publish `win-x64.zip` archives and execute under Windows on ARM emulation.
This change updates architecture normalization and target matching for `win32-arm64`:
- Resolves native `node-v${version}-win-arm64.zip` for Node >= 20.
- Falls back to `node-v${version}-win-x64.zip` for Node < 20.
- Implements this behavior in both the TypeScript pnpm 11 engine-runtime-node-resolver and the Rust pnpm 12 engine-runtime-node-resolver.
Closespnpm/pnpm#7123
When `pnpm self-update` is executed inside a project with a pinned `pnpm` version, `selfUpdate` now updates the active global `pnpm` binary in `PNPM_HOME` in addition to updating the project pin in `package.json`.
The global switch runs first and the pin is written last, so a failed global install leaves the project pin unchanged. When the global switch is declined, its reason is printed alongside the pin message.
Resolvespnpm/pnpm#14747.
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Closespnpm/pnpm#7067.
When rewriting shell startup files, pnpm setup could match an earlier `# pnpm` comment (such as a header preceding shell aliases) against the closing `# pnpm end` marker of the pnpm environment block, dropping all configurations in between.
Ensure section parsing finds non-overlapping, strictly bounded `# <section>` to `# <section> end` pairs, ignoring unclosed comment markers and selecting the appropriate environment section when multiple blocks exist. Fixed in both v11 (TypeScript) and v12 (Rust).
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.
When removing a Node.js runtime version via `pnpm env remove` (or `pnpm env rm`),
clean up legacy nodejs directories, active symlinks, and dangling shims/symlinks
in global bin and pnpm home directories.
Closespnpm/pnpm#6122
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.
Only HTTP 404 from unofficial-builds.nodejs.org is ignored when reading the
musl assets of a Node.js release, since that is how the mirror reports a
release it never built. Every other status and every transport error now
aborts the resolve, so a blocked or unreachable mirror can no longer leave
the musl assets out of the lockfile on one machine and not another
pnpm/pnpm#14813.
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
The alias bins looked pnpm up on PATH, so the pnpm that ran was whichever
one PATH named first. That failed where the directory holding them was
not on PATH, even with the native binary sitting next to them, and it let
any other pnpm ahead of that directory silently handle calls meant for
the local install.
Every form now names its sibling. The POSIX script walks `$0` through its
symlinks and execs the pnpm in that directory; the walk matters because
`$0` is the shim or symlink the alias was launched through, and the
sibling to find is the one in the package, not in whichever directory
linked it. Its hop cap matches the `pnpm` placeholder script, which walks
`$0` for the same reason. The `.cmd` calls "%~dp0pnpm.cmd" with `call`, so
control returns and the exit code is the shim's; the `.ps1` calls
"$basedir\pnpm.ps1" and ends in `exit $LastExitCode`, which it dropped
before. The Windows wrappers have one sibling to name because `pnpm
setup` installs via `pnpm add -g` and link_bins writes a bare pnpm.exe
only for the `node` bin name, so every other bin gets the
pnpm/pnpm.cmd/pnpm.ps1 shim trio.
Only the v12 tarball regressed. The v11 `pnpm` package's bins are real
entry points that resolve relative to themselves, and v12 replaced them
with these scripts. The other three writers have always been PATH-based:
`pnpm setup` in both stacks since pnpm/pnpm#8241, and `@pnpm/exe`'s
prepare.js. All four change here, which puts the fix in both stacks as
the version policy requires.
Two asymmetries are deliberate. `@pnpm/exe`'s POSIX aliases also check
that the sibling is executable, because the placeholder its install
script replaces is not, and the EACCES from exec'ing that placeholder
would say nothing about the script having been skipped. Its .cmd and .ps1
stay on PATH, because that same install script hardlinks the binary onto
pn.exe/pnpx.exe/pnx.exe and points `bin` at them, so those wrappers only
run when it did not — and then there is no sibling to resolve.
Closespnpm/pnpm#14803.
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
The engine identity check verified every package the env lockfile pins and the host's platform binary of the native wrapper, whichever build was going to run. Below v12 the lockfile pins the JavaScript `pnpm` and the SEA `@pnpm/exe` side by side, so on a host where `@pnpm/exe` ships no binary the switch failed before installing the JavaScript `pnpm`, which is the only build that runs there and never links a platform binary.
Pass the package selected for installation into the identity check, in both the TypeScript v11 CLI and pacquet. Verify that package at the exact version the install is rooted at, plus the host platform package the install would link over its bin. Report a dedicated no-native-binary error when the selected native engine cannot run on the host.
Fixespnpm/pnpm#13622.
pnpm 11 installs package-manager versions with lifecycle scripts disabled.
Starting with pnpm 12.3.0, the published placeholder has a Node.js shebang.
The bin linker records Node.js in its launcher before replacing the target
with the native executable, then retains that launcher because the target
path is unchanged.
Restore the shebangless placeholder in the pnpm 12 npm wrapper so existing
pnpm 11 releases can install future pnpm 12 versions through their version
store. Keep the npm global Windows postinstall relink, which regenerates npm's
shims against pnpm.exe after lifecycle scripts install the native binary.
Script-blocked wrapper installs must enable lifecycle scripts. Corepack keeps
its separate JavaScript entry point.
Closespnpm/pnpm#14502.
Standalone release archives contain node-gyp beside the executable, but setup
reinstalls that directory as a global package. The temporary manifest did not
declare the standalone distribution's files, and pacquet hardcoded directory
fetches to all-files mode, whose dependency exclusion removed the nested
node-gyp payload.
Declare the executable and dist directory as the standalone package's files.
Make pacquet pass its existing deployAllFiles-derived package-file setting to
the directory fetcher, matching the TypeScript install path. This preserves the
bundled node-gyp payload through the normal local-directory install without an
intermediate archive or tarball-specific behavior.
Cover nested node_modules selected by a files field in both fetchers, and verify
the setup-shaped pacquet global install retains node-gyp while ignoring the
standalone package's lifecycle scripts.
Related to https://github.com/orgs/pnpm/discussions/14219#discussioncomment-18227726.
Restore the pnpm wrapper target without a file extension so pnpm 12.1 and earlier can replace it with the downloaded native executable on POSIX systems.
The cross-platform pnpm.exe target left its placeholder script in place during upgrades from older pnpm releases, breaking automatic package-manager switching. The PowerShell shim issue remains tracked by npm/cmd-shim#51.