Commit Graph

10773 Commits

Author SHA1 Message Date
Dami Oyeniyi
3fd440bc7f docs: clarify default catalog protocol behavior (#11381) 2026-05-05 19:37:24 +02:00
Fotis Papadogeorgopoulos
16f5cd302a fix(config): gracefully handle configDependencies errors during config commands (#11362)
Closes #10684. Running `pnpm config set` triggers `resolveAndInstallConfigDeps` before the new config (e.g. auth token) is saved to `.npmrc`, causing a 401 crash when the config dependency is hosted in a private registry.

This patch adds a `tolerateConfigDependenciesErrors` flag to `installConfigDepsAndLoadHooks`. For `cmd === 'config'`, `'set'` and `'get'`, installation failures are now caught and logged at debug level so the command can proceed and actually write / read the auth token.

`pnpm set` and `pnpm get` are separate top-level commands whose handlers delegate to the `config` command internally, so they are explicitly listed alongside `'config'`; users can hit #10684 via any of the three entry points.

Plugin pnpmfile paths from `configDependencies` are resolved by checking each file's existence on disk, so previously-installed hooks survive a transient install failure and `requireHooks` won't throw `PNPMFILE_NOT_FOUND` when nothing has been installed yet.

Covers the fix with:
- Unit tests in `pnpm/test/getConfig.test.ts` exercising the `installConfigDepsAndLoadHooks` contract (success, tolerated error, rethrown error, store creation/close errors propagating) and the on-disk pnpmfile resolution behavior.
- Four e2e tests in `pnpm/test/configurationalDependencies.test.ts` that spawn the pnpm CLI against a bogus `configDependency` and assert each entrypoint (`pnpm config set`, `pnpm config get`, `pnpm set`, `pnpm get`) still works.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-05-05 19:37:14 +02:00
Zoltan Kochan
0219ab2484 fix(self-update): refresh legacy v10 bootstrap shim at PNPM_HOME (#11467)
pnpm v10 setup added PNPM_HOME (not PNPM_HOME/bin) to PATH and wrote
a pnpm bootstrap shim there. After upgrading to v11, that shim still
points into the old .tools/<version> install, so PATH continues to
resolve `pnpm` to the pre-update version even though the new version
was installed under global/v11.

Detect that layout during self-update, refresh the shims at PNPM_HOME
so the upgrade actually takes effect, and warn the user to run
`pnpm setup` for a clean migration to the v11 PATH layout.

Closes #11464.
2026-05-05 19:37:03 +02:00
Maikel van Dort
817b1b4c3e fix: dlx catalogs not found (#11308)
Fixes #10594, catalogs not being read from the workspace when using the `catalog:` protocol with the `pnpm dlx` / `pnpx` command, resulting in a catalog entry not found error.

Added e2e tests to check if the workspace config is actually loaded. Also added that pnpm dlx reads the retry options from the workspace (Could potentially put that in a separate PR)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Fixed catalog resolution when using the `catalog:` protocol with `pnpm dlx` / `pnpx` so catalogs are correctly read from the workspace.

* **New Features**
  * `dlx` now inherits workspace catalog and fetch retry/timeout settings so CLI runs respect those local configs.

* **Tests**
  * Added tests validating catalog inheritance and failure cases for `dlx` catalog resolution.

* **Chores**
  * Updated changeset metadata to mark related packages for patch releases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-05-05 19:36:55 +02:00
palkim
ab6c42d99e fix: refresh ignored builds when allowBuilds changes (#11366)
* fix: refresh ignored builds when allowBuilds changes

* refactor: extract isBuildExplicitlyDisallowed into @pnpm/building.policy

Removes the duplicated ignored-build filter from deps-installer and
deps-restorer and exposes it as `isBuildExplicitlyDisallowed` on
`@pnpm/building.policy`, alongside `createAllowBuildFunction`.

* fix: respect ignoredWorkspaceStateSettings in allowBuilds stale-state check

The fallback that flagged installs when allowBuilds went from unset to
non-empty bypassed the ignoredSettings filter, so callers that explicitly
opted out of allowBuilds tracking (via ignoredWorkspaceStateSettings)
could still be forced into a redundant install.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-05-05 19:36:42 +02:00
Zoltan Kochan
159b4c0fb4 ci: update pnpm/action-setup 2026-05-05 19:36:18 +02:00
Zoltan Kochan
cc373c39f1 chore(release): 11.0.5 v11.0.5 2026-05-04 22:14:24 +02:00
Zoltan Kochan
cd87c16dd5 fix(reporter): make WARN and error labels readable without color (#11460)
The `WARN` and `ERR_PNPM_*` labels in pnpm's output relied entirely on a colored background to stand out from the surrounding text. In terminals without color — `NO_COLOR` set, output piped, dumb terminals — the badge collapsed into bare `WARN` / `ERR_PNPM_FOO` and became hard to spot inside the message.

This PR wraps each label in brackets (`[WARN]`, `[ERR_PNPM_FOO]`, `[ERROR]`). The bracket characters are painted in the same color as the badge background, so in a color-capable terminal they appear as plain padding inside the colored badge — the rendering matches what we had before. When ANSI is stripped the brackets reappear as ordinary text, giving the label a clear delimiter.
2026-05-04 22:11:34 +02:00
Zoltan Kochan
47b100ecf7 fix(exe): drop darwin-x64 artifact (upstream Node SEA bug) (#11455)
## Summary

Closes #11423.

`pnpm-darwin-x64.tar.gz` and `@pnpm/macos-x64` are removed because the binaries they contain segfault at startup on Intel Macs and the underlying bug is upstream and unfixed.

## Why this isn't a fix in code

The crash happens in `__cxx_global_var_init` with `EXC_BAD_ACCESS (code=1, address=0x3)` — the unprocessed-chain-entry tag — in dyld's chained-fixup processing. PR #11415's hypothesis was that `ldid`'s page hashes were the cause, but switching to native `codesign` in #11415 didn't fix it: the upstream minimal repro in [nodejs/node#62893](https://github.com/nodejs/node/issues/62893) is `node --build-sea` + `codesign --sign -` + run, with no pnpm and no `ldid`, and it still crashes. The corruption is in LIEF's Mach-O surgery during `--build-sea` for x64 — chained-fixup chain entries get rewritten incorrectly when the SEA segment is inserted, and re-signing produces a valid signature over the broken bytes.

The Node.js team is not going to fix this:

- [nodejs/node#60250](https://github.com/nodejs/node/pull/60250) (merged) — *"It's unlikely that anyone would invest in fixing them on x64 macOS in the near future, now that x64 macOS is being phased out."* They skipped the SEA tests on x64 macOS rather than chase the bug.
- [nodejs/node#59553](https://github.com/nodejs/node/issues/59553) (open) — long-running test failures on macOS x64 with the same root cause (sometimes surfacing as `unsupported thread-local, larger than 4GB`).

`@yao-pkg/pkg` works around it by appending the JS payload to the file tail and using a custom-patched Node binary that reads from the tail at startup; this avoids Mach-O surgery entirely. We can't reuse pack-app for that because vanilla Node from nodejs.org doesn't read tail-appended payloads — only pkg-fetch's patched binaries do — so adopting that path would mean re-implementing pkg-fetch for one target. For now we're dropping the broken artifact rather than introducing a second build mechanism.

## Changes

- **`pnpm/artifacts/exe/package.json`** — remove `@pnpm/macos-x64` from `optionalDependencies`; remove `darwin-x64` from `pnpm.app.targets`.
- **`.meta-updater/src/index.ts`** — remove `@pnpm/macos-x64` from the enforced `optionalDependencies` list (otherwise `meta-updater` would put it back).
- **`pnpm/artifacts/exe/scripts/build-artifacts.ts`** — drop `darwin-x64` from `narrowTargets` so dev-local builds match the published matrix; comment explains why.
- **`__utils__/scripts/src/copy-artifacts.ts`** — stop creating `pnpm-darwin-x64.tar.gz` so the GitHub release page no longer ships it.
- **`pnpm/artifacts/darwin-x64/`** — deleted (was the workspace source for `@pnpm/macos-x64`).
- **`pnpm/artifacts/exe/setup.js`** — wraps the `import.meta.resolve('${pkgName}/package.json')` lookup in `try`/`catch`. On Intel Mac specifically, prints a clear message pointing at this issue, the upstream Node.js issue, and the two workarounds (`npm install -g pnpm` to use the system Node.js, or stay on pnpm 10.x). Other unsupported hosts get a generic message in the same shape. Exits non-zero so the install fails loudly instead of silently leaving a broken `pnpm`.
- **`pnpm-lock.yaml`** — regenerated.
- **`.changeset/drop-darwin-x64-broken-sea.md`** — patch bumps for `@pnpm/exe` and `pnpm` with user-facing explanation and pointers.

Docs side already lists this limitation under `pack-app` Known limitations: pnpm/pnpm.io@36d962f6 / pnpm/pnpm.io@91f45632.

## Compat

- Intel Mac users on existing `@pnpm/exe` (≤ 11.0.4) keep working with the (broken) old binary they already have.
- `pnpm self-update` from an Intel Mac on an older `@pnpm/exe` will hit the new `setup.js` error path with a clear pointer to the workarounds.
- New Intel Mac installs via `npm install -g @pnpm/exe` will fail loudly with the same pointer.
- Install via `npm install -g pnpm` (the JS-only package, uses system Node) is unaffected and remains the recommended path.
- The `install.sh` from `get.pnpm.io` will fail with a 404 on the missing `pnpm-darwin-x64.tar.gz`. That's a separate repo and a follow-up — happy to do that as a second PR.
2026-05-04 22:11:28 +02:00
Zoltan Kochan
f6bc1db683 fix(dlx): prompt to approve ignored builds (#11452)
`pnpm dlx` (and `pnpx`/`pnx`/`pnpm create`) now mirrors the `pnpm add -g` flow when the launched package's transitive deps have install scripts:

- dlx overrides `strictDepBuilds: false` for its install so the v11 default no longer turns ignored builds into an `ERR_PNPM_IGNORED_BUILDS` error. Without this, `pnpx @google/gemini-cli` (and similar — `node-pty`, `@github/keytar`) failed outright and forced users to retry with `--allow-build=<pkg>` for every offending dependency.
- After install, dlx detects skipped builds via `getAutomaticallyIgnoredBuilds` and runs the same interactive `approve-builds` prompt as `pnpm add -g`. In non-interactive mode the install is committed with builds skipped, matching `pnpm add -g` in CI; users who need those scripts can re-invoke with `--allow-build=<pkg>` to force a fresh cache key.
- If the install errors for unrelated reasons (network, etc.) the partially-populated prepare directory is removed so the next dlx run starts clean.

Closes #11444.

### Plumbing

- Exports `getAutomaticallyIgnoredBuilds` from `@pnpm/building.commands` so dlx can detect skipped builds without re-implementing modules-yaml reading.
- Adds `strictDepBuilds` (optional) to `InstallCommandOptions` — already accepted at runtime via the spread, this just makes it explicit at the type level so callers can override it.
2026-05-04 22:11:22 +02:00
Zoltan Kochan
0b2f86ee86 fix: render peer dependency issues on strict error (#11450)
Fixes #11439.

When `strictPeerDependencies: true` causes `ERR_PNPM_PEER_DEP_ISSUES`, the peer dependency issues are again rendered inline — using the **same format as `pnpm peers check`** — so users (and CI tools like Renovate) can see what failed without running another command.

The non-strict warning path is unchanged: it still emits the short "Run `pnpm peers check`" hint.

### Behavior

`strictPeerDependencies: true`:
```
 ERR_PNPM_PEER_DEP_ISSUES  Unmet peer dependencies

✕ unmet peer react
  Installed: 17.0.2
  Wanted:
    ^18.2.0:
      react-dom@18.2.0
hint: To disable failing on peer dependency issues, add the following to pnpm-workspace.yaml in your project root:

  strictPeerDependencies: false
```

`strictPeerDependencies: false` (unchanged):
```
 WARN  Issues with peer dependencies found. Run "pnpm peers check" to list them.
```

### Implementation

- Added a new `@pnpm/deps.inspection.peers-issues-renderer` package at `deps/inspection/peers-issues-renderer/`, alongside its data producer `@pnpm/deps.inspection.peers-checker`. It exposes a single `renderPeerIssues()` that emits the flat issue list previously inlined in `pnpm peers check`.
- Removed the duplicated formatter from `deps/inspection/commands/src/peers.ts` and made the `pnpm peers check` command consume the new renderer.
- `cli/default-reporter/src/reportError.ts`: `reportPeerDependencyIssuesError` now calls the shared `renderPeerIssues()` and prefixes the hint block with the rendered output. Tests strip ANSI escapes before substring assertions so they stay correct under `FORCE_COLOR=1`.

Result: a single renderer is shared between the install error and the `pnpm peers check` command — output is identical between the two paths.
2026-05-04 22:11:13 +02:00
Zoltan Kochan
72629fc611 fix(list): honor --json and --parseable for pnpm -g ls (#11451)
Restores `--json` / `--parseable` / `--long` support on `pnpm -g ls` and tightens `--depth>0` semantics around isolated global installs. Closes #11440.

- **`--json` / `--parseable` (the regression):** aggregate global packages from all isolated install dirs into a single synthesized `PackageDependencyHierarchy` and dispatch to the existing `renderJson` / `renderParseable` / `renderTree`. Output shape matches pnpm 10 (`result[0].dependencies[name].version`), so tools like `npm-check-updates` work again.
- **`--depth>0`:** the v11 architecture installs each global package into its own isolated dir with its own lockfile, so merging transitive trees across installs would be incoherent. New behavior:
  - One global install dir total → fast-path delegate to the regular `list` flow with `params` unchanged, so `listForPackages` can match top-level *or* transitive packages.
  - Multiple installs, params narrow to one install dir (top-level alias match) → drop the params and render that install dir's full tree.
  - Multiple installs, params don't narrow → throw `ERR_PNPM_GLOBAL_LS_DEPTH_NOT_SUPPORTED` with a message asking the user to filter to a single global package or omit `--depth`.

The regression was introduced by the isolated global packages refactor (#10697), which added a custom `listGlobalPackages` shortcut that always returned plain text and ignored format flags.
2026-05-04 22:11:01 +02:00
Zoltan Kochan
2b8932d8fc fix(publish): respect publishConfig.registry in non-recursive publish (#11449)
The native publish flow introduced in v11 (replacing the `npm publish`
shell-out with `libnpmpublish`) only read the registry from `registries`
config, ignoring `publishConfig.registry` from the package's
`package.json`. Restore the prior behavior by giving
`publishConfig.registry` precedence over the configured registries.

Closes #11419
2026-05-04 22:10:53 +02:00
Zoltan Kochan
017c1ef430 docs(release): correct rationale comment on macos-latest runner (#11446)
The previous comment attributed the darwin SEA crashes to ldid producing
bad page hashes, but the upstream minimal `node --build-sea` + `codesign`
repro (nodejs/node#62893) shows codesign-signed binaries crash too. The
bug is in LIEF's Mach-O surgery during --build-sea, not in signing.

Rewrite the comment to state the actual reasons the job runs on macOS
(native codesign avoids building ldid; macos-latest is Apple Silicon so
verify-binary.mjs can smoke-test the darwin-arm64 SEA) and explicitly
note that this does NOT fix the darwin-x64 crash.

Comment-only change. No behaviour change.
2026-05-04 22:10:44 +02:00
Zoltan Kochan
4f52bef097 ci(release): attest build provenance for release artifacts (#11441)
Generate Sigstore-backed SLSA build provenance for the platform tarballs
and zips produced by `pn copy-artifacts` via actions/attest-build-provenance,
so users can verify with `gh attestation verify` that the binaries attached
to a GitHub release came from this repository's release workflow rather
than from a manual upload.

This complements the release attestation that GitHub auto-generates for
Releases (predicate `https://in-toto.io/attestation/release/v0.2`), which
only proves what files were attached to a tag, not how they were built.
The new attestation uses `https://slsa.dev/provenance/v1` and binds each
artifact's digest to the workflow_ref, commit SHA, and runner identity.

The `pn release` step already publishes npm tarballs with provenance, so
this closes the same gap on the GitHub Release side.
2026-05-04 22:10:33 +02:00
Zoltan Kochan
3a5534d75e chore(release): 11.0.4 v11.0.4 2026-05-03 01:24:22 +02:00
Zoltan Kochan
15c3f614b2 docs: move changesets to correct location 2026-05-03 01:21:55 +02:00
Zoltan Kochan
42a8f29f41 fix(config): default minimumReleaseAgeStrict to true when user sets minimumReleaseAge (#11436)
* fix(config): default minimumReleaseAgeStrict to true when user sets minimumReleaseAge

Without this, a user-set `minimumReleaseAge` would silently fall back to
installing an immature version when no mature version satisfied the
requested range, making the setting look like it had no effect (#11433).

The built-in default of `minimumReleaseAge` (1440) stays non-strict for
backward compatibility, and an explicit `minimumReleaseAgeStrict: false`
is still respected.

* chore(changeset): downgrade to patch

* fix(config): apply minimumReleaseAgeStrict default after env var parsing

Move the strict-default logic to run after `parseEnvVars` so
`pnpm_config_minimum_release_age` is also covered.

* test(config): also assert minimumReleaseAge in the strict=false test
2026-05-03 01:15:03 +02:00
Zoltan Kochan
c1d29d2258 fix(self-update): do not downgrade when latest dist-tag is older (#11435)
* fix(self-update): do not downgrade when latest dist-tag is older

`pnpm self-update` defaults to the `latest` dist-tag, but `latest` on the
registry can lag the installed version when a new major has shipped
without being tagged. Refuse to downgrade in that case. Users can still
run `pnpm self-update latest` (explicit) to force the downgrade.

Closes #11418

* fix(self-update): use lockfile-pinned version for project-pin downgrade check

When a project pins pnpm via a range (e.g. `devEngines.packageManager.version: ">=8.0.0"`)
and the env lockfile pins an exact version above the range's lower bound,
the previous guard compared the resolved `latest` against `semver.minVersion(spec)`
and missed the downgrade. Read `packageManagerDependencies.pnpm.version` from
`pnpm-lock.yaml` and use the max of (lockfile-pinned, spec.minVersion) as the
current version. Also fix the explicit-`latest` test which mocked `latest`
as newer than the current version, defeating its own assertion.

* chore(engine.pm.commands): add lockfile/fs project reference to tsconfig
2026-05-03 01:14:54 +02:00
Zoltan Kochan
b1eccd8f28 fix(ci): reinstall workspace package node_modules (#11434)
`pnpm ci` was missing `recursiveByDefault`, so in a workspace the
composed install handler ran only against the root and never linked
dependencies into workspace packages.

Closes #11427.
2026-05-03 01:14:45 +02:00
Rayan Salhab
654f575776 fix(clean): ignore lockfile setting unless flag is passed (#11431)
Keep pnpm clean from removing pnpm-lock.yaml just because the workspace config sets lockfile: true. The lockfile cleanup now follows the command-line --lockfile option.

Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
2026-05-03 01:14:38 +02:00
Zoltan Kochan
17ec7a699d docs: clarify support end date for version 10.x
Updated support information for version 10.x.
2026-05-03 01:14:25 +02:00
Zoltan Kochan
0415899b19 docs: revise supported versions in SECURITY.md
Updated supported versions for security policy.
2026-05-03 01:14:18 +02:00
Zoltan Kochan
9c7c438a51 ci(release): build artifacts on macos-latest to fix darwin-x64 signing (#11415)
* ci(release): build artifacts on macos-latest to fix darwin-x64 signing

Cross-signing darwin Mach-O binaries on Linux with the saurik fork of
ldid produces an ad-hoc signature whose page hashes don't match the
post-postject layout for Node.js 25's chained fixups, leaving fixups
unapplied at load and crashing the binary in __cxx_global_var_init
(EXC_BAD_ACCESS at 0x3 — the unprocessed chain-entry tag).

Running the release on macos-latest lets pack-app's adHocSignMacBinary
use native codesign, which understands chained fixups. Drops the entire
ldid build step.

* ci(release): document why release runs on macos-latest
2026-05-03 01:14:04 +02:00
Zoltan Kochan
6ef34b7a11 chore(release): 11.0.3 v11.0.3 2026-04-30 23:03:46 +02:00
Zoltan Kochan
e8eb5dbea0 fix: too many open files error when creating command shims (#11414)
close #11412
2026-04-30 22:59:47 +02:00
Zoltan Kochan
5a901e7957 feat(fs.graceful-fs): expose promisified chmod and unlink (#11413)
* feat(fs.graceful-fs): expose promisified chmod and unlink

So callers can perform mode changes and removals through the same
EMFILE/ENFILE-queueing layer as the other operations.

* chore: remove ENFILE word to satisfy cspell
2026-04-30 22:59:42 +02:00
Zoltan Kochan
6b891a552a fix: preserve file: and git-hosted tarball URLs in lockfile (#11410)
Closes #11407
2026-04-30 22:59:32 +02:00
Zoltan Kochan
b6b87b7be9 test: make checkPlatform negation tests platform-independent (#11411)
* test: make checkPlatform negation tests platform-independent

The two multi-valued supportedArchitectures tests added in #11375 used
'current' alongside a value that the negation in the wanted platform
matched on some hosts (e.g. ['linux', 'current'] on Windows expands to
['linux', 'win32'], which is correctly rejected by ['!win32']). Replace
'current' with fixed second values so the multi-value code path is still
exercised without depending on process.platform / process.arch.

* test: mock process.platform / process.arch instead of avoiding 'current'

Restores the more realistic scenario from #11375 where supportedArchitectures
mixes a fixed value with 'current'. Mock process.platform / process.arch
explicitly per test so the result no longer depends on the host CI runner.
2026-04-30 22:59:25 +02:00
Zoltan Kochan
184ce26f3f docs: fix package names in README files (#11409)
* docs: fix package names in README files

* docs: update links to point to npmx.dev
2026-04-30 22:59:17 +02:00
Charlie Croom
a99ffe0893 fix: also preserve relative symlinks in copy-artifacts.ts (release tarballs) (#11408)
#11399 fixed the fs.cpSync call in pnpm/artifacts/exe/scripts/build-artifacts.ts,
which controls the dist/ shipped inside the npm-published @pnpm/exe package.

But the GitHub release tarballs (pnpm-{darwin,linux}-{x64,arm64}.tar.gz) are
produced by a different script — __utils__/scripts/src/copy-artifacts.ts, run
via 'pn copy-artifacts' in the release workflow. That script has the same
fs.cpSync(...) call without verbatimSymlinks: true, so the broken absolute
symlinks under dist/node_modules/.bin/ pointing at /home/runner/work/pnpm/
pnpm/... still made it into the v11.0.2 GitHub release tarballs.

Apply the same one-line fix to that script so the next release ships clean
relative symlinks.

Follow-up to #11398.

🤖 Generated with [Amp](https://ampcode.com)

Amp-Thread-ID: https://ampcode.com/threads/T-019dda79-b947-742f-8711-b6f83bcda9ff

Co-authored-by: Amp <amp@ampcode.com>
2026-04-30 22:59:07 +02:00
Zoltan Kochan
a53f78b111 chore(release): 11.0.2 v11.0.2 2026-04-30 17:16:34 +02:00
Zoltan Kochan
685a3694c3 fix(global): avoid doubled modulesDir in approve-builds during global add (#11404)
* fix(global): avoid doubled modulesDir when approving builds in global add

The global add → approve-builds flow used to forward an absolute
`modulesDir` (`<installDir>/node_modules`) into the install run by
`approve-builds`. The install layer treats `modulesDir` as a path
relative to `lockfileDir` and joins it again — producing a doubled
path on Windows because `path.join` does not collapse an embedded
absolute path. The hoist step then failed with `ENOENT` while trying
to symlink under `<installDir>\<installDir>\node_modules\.pnpm\...`.

Closes #11403.

* test: type test fixtures correctly

* fix(install): tolerate absolute modulesDir in headless install context

Replace the prior unit test (which only checked the call shape) with an
integration test that exercises `install()` with an absolute `modulesDir`
through both the regular and frozen-lockfile paths — the failure mode the
global add → approve-builds chain originally hit on Windows.

`headlessInstall` and `readProjectsContext` now resolve `modulesDir` via
`pathAbsolute` instead of `path.join(lockfileDir, modulesDir)`, so an
absolute value no longer produces a doubled prefix. The
`promptApproveGlobalBuilds` change from the previous commit is retained
as the contract-level fix.

* test: add e2e test driving the pnpm CLI with --modules-dir=<abs>

Replace the programmatic install() regression test with an e2e test in
pnpm/test/install/absoluteModulesDir.ts that runs the bundled pnpm
binary with `pnpm install --modules-dir=<abs>` (regular and frozen).
This is the closest CLI-level reproduction of the doubled-prefix path
bug from #11403 — the bug fired specifically in the headless install
path that --frozen-lockfile triggers.

* test(global): drive add -g + approve-builds chain end-to-end

Add an e2e test that runs the bundled pnpm CLI through the full
`pnpm add -g <pkg-with-build>` → approve-builds → install chain that
produced the doubled-prefix `ENOENT` in #11403.

The chain only fires when `process.stdin.isTTY` is true, which CI
subprocesses don't satisfy. Add a test-only env var
`PNPM_AUTO_APPROVE_BUILDS_FOR_TESTS` that bypasses the TTY guard in
`promptApproveGlobalBuilds` and forwards `all: true` so `approve-builds`
skips its multiselect and confirm prompts. The post-approval install
then runs the same code path a real user hit, and the test asserts the
build artifacts ended up in the global install dir.

Replaces the narrower `--modules-dir=<abs>` regression test, which
only exercised the install layer and not the global-add flow that
originally surfaced the bug.

* test: enable global add -g + approve-builds e2e test on Windows

- Switch to @pnpm.e2e/install-script-example which is cross-platform.
- Use pathAbsolute for modulesDir to prevent doubled path bugs on Windows.
- Add path-absolute dependency to affected packages.
2026-04-30 17:14:44 +02:00
Zoltan Kochan
27faa7290f fix: run packageManager check and lockfile sync under corepack (#11406)
The package-manager handling block in main.ts was guarded by
`!isExecutedByCorepack()`, which skipped the entire block — including
syncEnvLockfile and checkPackageManager — when COREPACK_ROOT was set.
The lockfile's packageManagerDependencies entry would drift stale, and
devEngines.packageManager mismatches were silently ignored.

Move the corepack guard onto switchCliVersion only (corepack owns
version selection), so that checkPackageManager and syncEnvLockfile run
regardless of how pnpm was invoked. syncEnvLockfile self-gates via
shouldPersistLockfile, so projects that only use the legacy
packageManager field still won't have the lockfile rewritten.

When the check fires under corepack, augment the message and hint to
explain that pnpm cannot switch versions under corepack and point to
the two ways out (align packageManager with devEngines.packageManager,
or invoke pnpm directly).

Closes #11397
2026-04-30 17:14:37 +02:00
Armaan Aggarwal
d96a1bf5e6 fix: negated os / cpu skipped under multi-platform supportedArchitectures (#11375)
* fix: bug with checkList fn

* refactor: simplify checkList, add changeset

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-04-30 17:14:30 +02:00
Charlie Croom
d613c81acf fix(@pnpm/exe): preserve relative symlinks when packaging dist/ (#11399)
* fix(@pnpm/exe): preserve relative symlinks when packaging dist/

The standalone executable build copies dist/ via fs.cpSync(...) without
verbatimSymlinks: true, which causes Node to resolve relative symlinks
into absolute paths at the source filesystem location. On the GitHub
Actions runner this rewrites .bin symlinks to /home/runner/work/pnpm/...
targets that ship verbatim in the release tarballs.

Adding verbatimSymlinks: true preserves the relative symlink targets so
the archived links remain valid at any extraction location.

Fixes #11398.

🤖 Generated with [Amp](https://ampcode.com)

Amp-Thread-ID: https://ampcode.com/threads/T-019dda79-b947-742f-8711-b6f83bcda9ff
Co-authored-by: Amp <amp@ampcode.com>

* chore: add 'unextractable' to cspell.json

Per https://github.com/pnpm/pnpm/pull/11399#issuecomment-4348220789

🤖 Generated with [Amp](https://ampcode.com)

Amp-Thread-ID: https://ampcode.com/threads/T-019dda79-b947-742f-8711-b6f83bcda9ff
Co-authored-by: Amp <amp@ampcode.com>

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-30 17:14:23 +02:00
chaoliang yan
8c41c5c5ff fix(publish): report generated manifest in publish summary (#11371)
Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
2026-04-30 17:14:16 +02:00
Zoltan Kochan
38ffda2a18 chore(release): 11.0.1 v11.0.1 2026-04-29 23:00:21 +02:00
btea
5e11362c8a fix: sort the keys of the overrides object (#11309) 2026-04-29 22:59:01 +02:00
Dami Oyeniyi
f543b77006 fix: reject null named catalogs in workspace manifest reader (#11231) 2026-04-29 22:58:54 +02:00
Rayan Salhab
16b347620b fix: validate unknown options before implicit run (#11374)
* fix: validate unknown options before implicit run

* test: ignore intentional misspelling in CLI test

---------

Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: Hermes Agent <hermes@example.invalid>
2026-04-29 22:58:44 +02:00
Zoltan Kochan
2d061b74a6 chore: add tracked .git-wt/pr-hook so wt <pr> launches a Claude review (#11383)
@zkochan/git-wt 0.0.3 looks for an executable .git-wt/pr-hook in the
worktree before falling back to ~/.config/git-wt/pr-hook. Shipping the
hook in-repo gives every contributor with Claude Code installed an
auto-launched PR review via `wt <pr-number>`. The hook silently no-ops
when `claude` isn't on PATH so contributors who don't use it aren't
affected.
2026-04-29 22:58:24 +02:00
Allan Kimmer Jensen
f9afe81eed fix(sbom): populate download location for git-sourced dependencies (#11329)
* fix(sbom): populate download location for git-sourced dependencies

* fix(sbom): avoid double git+ prefix when repo already includes it

Address Copilot review on #11329: gitDownloadUrl() would produce
git+git+ssh://... when GitResolution.repo already starts with git+.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-04-29 22:58:06 +02:00
Zoltan Kochan
0fbcf74aac fix: sync packageManager and devEngines.packageManager on self-update (#11395)
* fix: sync packageManager and devEngines.packageManager on self-update

When `package.json` declares both `packageManager` and
`devEngines.packageManager`, `pnpm self-update` previously bumped only
the latter — leaving Corepack (which reads `packageManager`) pinned to
the old version until a manual edit.

Now, when `packageManager` pins pnpm, both fields are rewritten to the
new exact version on update: `packageManager` to `pnpm@<version>`
(without an integrity hash) and `devEngines.packageManager.version` to
the same exact `<version>` (dropping any range operator). When only
`devEngines.packageManager` is declared, the existing range-preserving
behavior is unchanged.

Closes #11388

* refactor: export and reuse parsePackageManager from @pnpm/config.reader

Drop the inline duplicate in self-updater and use the existing
parser from config.reader. Same parsing rules (strips integrity
hash, rejects URL-style refs).

* refactor: collapse devEngines.packageManager array/object branches

Resolve to the underlying pnpm entry first (whether the field is an
array or an object) and run the version-update logic once, instead of
duplicating it across both branches.
2026-04-29 22:57:38 +02:00
Zoltan Kochan
7b83ecfc98 fix: sync env lockfile when devEngines.packageManager version is stale (#11392)
* fix: sync env lockfile when devEngines.packageManager version is stale

Update the env lockfile's `packageManagerDependencies` entry when
`devEngines.packageManager` declares a pnpm version that the lockfile
no longer satisfies. Previously the stale entry was kept even though
the running pnpm matched the declared version, silently breaking the
integrity record.

Closes #11387

* refactor: drop redundant pm.name guard in main.ts (syncEnvLockfile already checks)

* refactor: hoist pm.onFail !== 'ignore' guard so each clause appears once

* test: assert syncEnvLockfile actually rewrites the lockfile entry on disk
2026-04-29 22:57:29 +02:00
Rayan Salhab
32eae3112f fix: clean pnpm workspace state during ci (#11368)
Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
2026-04-29 12:55:07 +02:00
Zoltan Kochan
bf4214eb55 docs: add links to the changelog 2026-04-28 11:49:30 +02:00
Zoltan Kochan
8aeeff4c46 chore(release): 11.0.0 v11.0.0 2026-04-28 11:27:43 +02:00
Zoltan Kochan
77e913c0b4 feat(self-update): point users at the migration guide across major bumps (#11354)
When `pnpm self-update <version>` crosses a pnpm major (upward) from
the version being upgraded from, print a one-line pointer to the
versioned migration guide on pnpm.io.

The "from" version is the project's `packageManager`/`devEngines.packageManager`
pin when present (so the hint still fires if the running pnpm is already
the new major — e.g. corepack-managed), falling back to the running
binary's version otherwise. No-op updates (target === previous) are
silent.

v11 points at https://pnpm.io/11.x/migration. Future majors register an
entry in the in-file `MAJOR_UPGRADE_HINTS` table.
2026-04-28 02:01:06 +02:00
Yuriy Matskanyuk
390b9d188d feat: add info about update started (#11334) 2026-04-28 02:00:58 +02:00