Commit Graph

10792 Commits

Author SHA1 Message Date
Zoltan Kochan
7f7c581ce2 docs: revise supported versions in SECURITY.md
Updated supported versions for security policy.
2026-05-02 09:45:36 +02:00
Colin Fristoe
6ac06cbed4 feat(audit): add registry signature verification (#11405)
* feat(audit): add registry signature verification

* chore: add registry signature terms to cspell

* chore: sort cspell registry terms

* refactor(audit): use repo concurrency and error helpers

* refactor(audit): use registry fetch helper for signatures

* refactor(audit): share audit command context

* fix(audit): respect scoped registries for signatures

* fix(audit): handle missing signature metadata gracefully

* docs(audit): document signature verification

* test(audit): avoid signature spellcheck false positives

* chore(audit): add scoped registry project reference

* refactor(audit): clarify signature verification fetching

* style(audit): align signature verifier formatting

* fix(audit): validate signature metadata shape and report cleanly

* fix(audit): handle crypto.verify throws on malformed registry keys

A registry returning malformed PEM key material made verifier.verify throw
synchronously, rejecting the Promise.all and crashing the whole audit run.
Treat any verify failure as an invalid signature for that single package.

* refactor(audit): extract parseJsonResponse helper

Both fetchRegistryKeys and fetchPackument repeated the same JSON.parse +
PnpmError wrapping pattern. Collapse into a single helper.

* refactor(audit): split signature verification into its own package

Move verifySignatures from @pnpm/deps.compliance.audit into a new
@pnpm/deps.compliance.signatures package. Vulnerability auditing and
signature verification are conceptually distinct trust subsystems, and
sigstore provenance verification is in scope for a future change — keeping
all signature work in its own package avoids growing the audit module into
two unrelated concerns.

* docs(audit): drop signature verification section

The signature verification implementation moved to
@pnpm/deps.compliance.signatures; that package's README documents the
behavior. The audit package no longer needs to mention it.

* refactor(signatures): move package to deps/security

Place the new signature verification package under deps/security/ rather
than deps/compliance/. Compliance is a fuzzy fit for tamper detection;
security is the right home, and sigstore provenance verification (future
scope) will live alongside it. Existing audit/license/sbom packages stay
where they are — this only changes where the new package lands.

---------

Co-authored-by: Colin Fristoe <47856231+ctfristoe@users.noreply.github.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-05-01 23:18:50 +00:00
Zoltan Kochan
d374e330ad 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-01 21:54:51 +02:00
Zoltan Kochan
4bf61ba1fe chore: update pnpm to v11.0.3 2026-04-30 23:20:40 +02:00
Zoltan Kochan
2c36c4e3e1 Merge branch 'release/11.0' 2026-04-30 23:19:31 +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
76fa8d8942 fix: too many open files error when creating command shims (#11414)
close #11412
2026-04-30 22:58:21 +02:00
Zoltan Kochan
7f490af7a3 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:42:28 +02:00
Zoltan Kochan
76b9e480d3 fix: preserve file: and git-hosted tarball URLs in lockfile (#11410)
Closes #11407
2026-04-30 22:07:47 +02:00
Zoltan Kochan
e6aca55bd8 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:07:33 +02:00
Zoltan Kochan
086c5e91e8 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 18:59:49 +02:00
Charlie Croom
b2c7489a01 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 18:22:29 +02:00
Zoltan Kochan
1ee8de4aea Merge branch 'release/11.0' 2026-04-30 17:23:30 +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
dfa825889e 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:05:36 +02:00
Zoltan Kochan
7ab28284d8 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:05:24 +02:00
Armaan Aggarwal
dbf19076f3 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:04:53 +02:00
Charlie Croom
3b12eb27de 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 12:43:27 +02:00
chaoliang yan
4ac15b2512 fix(publish): report generated manifest in publish summary (#11371)
Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
2026-04-29 23:15:04 +02:00
Zoltan Kochan
d00b4952cd Merge branch 'release/11.0' into main 2026-04-29 23:05:17 +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
Zoltan Kochan
490a97ef34 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:56:33 +02:00
Zoltan Kochan
ca474f1c9c 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 21:07:46 +02:00
Alessio Attilio
601317e7a3 feat: implement native 'pnpm owner' command (#11288)
Implements the native pnpm owner command with ls, add, and rm subcommands, providing a complete replacement for npm owner functionality.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-04-29 16:43:44 +02:00
Allan Kimmer Jensen
4750fd370c 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 13:54: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
Igor Savin
b61e268d57 feat: add support for github prefix and named registries (#11324)
This is consistent with #9358, but implements support for the GitHub Packages npm registry and, more broadly, for vlt-style https://docs.vlt.sh/cli/registries for any registry.

This PR adds a built-in gh: specifier that resolves against the GitHub Packages npm registry, plus a namedRegistries config key so a project can map its own aliases to arbitrary registries. A project can mix public npm packages and private GitHub Packages (or self-hosted) ones without applying a scope-wide registry override to every @scope/* package.

- pnpm add gh:@acme/private writes "@acme/private": "gh:^1.0.0" and resolves from https://npm.pkg.github.com/.
- pnpm add gh:@acme/private@^1.0.0 (with or without an alias) is also supported. Aliased form writes "my-alias": "gh:@acme/private@^1.0.0".
- Auth comes from the existing per-URL .npmrc mechanism, e.g. //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}. No new auth surface.
- @github is intentionally not defaulted to https://npm.pkg.github.com/ - hardcoding that would hijack installs of the public @github/* packages on npmjs.org (e.g. @github/relative-time-element) for users without a scope-wide override. Use gh: to install from GitHub Packages, or configure @github:registry=... yourself if that's really what you want.
- Additional named registries (a self-hosted proxy, GitHub Enterprise Server, etc.) can be configured in pnpm-workspace.yaml:

```yml
namedRegistries:
  gh: https://npm.pkg.github.example.com/   # optional: overrides the built-in `gh` alias for GHES
  work: https://npm.work.example.com/
```

- Then work:@corp/lib@^2.0.0 resolves against https://npm.work.example.com/, and the built-in gh alias can be redirected to a GHES host.
- Env-var substitution (${VAR}) is supported in namedRegistries values, mirroring the .npmrc convention.
- Reserved alias names (npm, jsr, github, workspace, catalog, file, git, http, https, link, patch, and related git host shorthands) cannot be redefined as user-named registries - the resolver throws ERR_PNPM_RESERVED_NAMED_REGISTRY_ALIAS at startup rather than silently shadowing another protocol. Malformed URLs throw ERR_PNPM_INVALID_NAMED_REGISTRY_URL at startup too, instead of failing as a confusing 404 during resolution.
- On publish, createExportableManifest strips any named-registry prefix (both the built-in gh: and any user-configured alias) so npm and yarn consumers can still resolve the dependency via their own scope-registry configuration - mirroring the user-facing requirement when installing such a dep without the prefix.

The prefix is gh: rather than github: because github: is reserved by npm-package-arg / hosted-git-info as a git host shorthand (e.g. github:owner/repo) - reusing it would be a deviation from the specs used by the npm CLI. gh: is  shorter, matches vlt's convention, and cannot collide with any existing npm scheme.

Unlike jsr:, gh: (and any other named-registry alias) does not rewrite the package name - gh:@acme/foo resolves @acme/foo from the GitHub Packages registry as-is. This also means npm/yarn consumers see the original name after the prefix is stripped on publish.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-04-29 12:38:56 +02:00
Zoltan Kochan
3f37d17b23 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 00:36:03 +02:00
Zoltan Kochan
e30c22f0d5 chore: update pnpm to v11.0.0 2026-04-28 21:46:50 +02:00
Zoltan Kochan
1a7c088e4d chore: update pnpm to v11.0.0 2026-04-28 11:51:43 +02:00
Zoltan Kochan
60fe422540 docs: add links to the changelog 2026-04-28 11:51:43 +02:00
Zoltan Kochan
4b822eca85 chore(release): 11.0.0 2026-04-28 11:51:43 +02:00