334 Commits

Author SHA1 Message Date
Zoltan Kochan
732312f49e chore(release): 11.1.0 2026-05-11 19:56:10 +02:00
Zoltan Kochan
f2b28f85ff chore(release): 11.0.9 2026-05-09 02:06:35 +02:00
Zoltan Kochan
0c3ef0ec94 chore(release): 11.0.7 2026-05-07 00:21:03 +02:00
Zoltan Kochan
306fefbb1d fix(scripts): move released-changesets ledger out of .changeset/
@changesets/read treats every directory inside .changeset/ as a legacy
v1 changeset and tries to read changes.md from it, which made
`changeset version` fail with ENOENT on .changeset/.released/changes.md.
Move the per-branch ledger to .changeset-released/ at the repo root.
2026-05-07 00:20:56 +02:00
Zoltan Kochan
76083acd54 chore(release): track consumed changesets per branch to prevent re-application after cherry-pick (#11479)
* chore(release): wrap changeset version with cross-branch consumed-id ledger

When a fix is cherry-picked from main to a release branch (or vice
versa), the changeset file ends up on both branches. The release
branch's release consumes and deletes its copy, but the cherry-picked
copy on main survives the merge back and would be re-applied on the
next main release.

Introduce a small wrapper around `changeset version` that maintains a
per-branch ledger at .changeset/.released/<branch>.txt. Each entry is a
consumed changeset id; the file is written only by the branch it is
named after, so the records merge across branches without conflicts.

Before running `changeset version` the wrapper reads the union of every
ledger file, hides matching .changeset/<id>.md files (rename to
.md.released), then runs `changeset version` against the remaining set.
Newly consumed ids are appended to the current branch's ledger; hidden
files are removed afterward (their consumption is already on record
elsewhere). On failure the hidden files are restored to keep the
working tree clean.

* docs: move release-ledger explanation out of AGENTS.md

AGENTS.md is for instructions to AI agents working on the codebase, but
the cross-branch ledger is release machinery that the maintainer running
`pnpm bump` interacts with — agents authoring changesets do not need to
know about it. Move the explanation to where someone runs into it:

- .changeset/.released/README.md — discovered by anyone exploring the
  directory.
- A short doc-comment header at the top of __utils__/scripts/src/bump.ts
  pointing readers there.

* fix(scripts): harden bump wrapper edge cases from PR review

- Use url.pathToFileURL(realpathSync(...)) to compare against
  import.meta.url so the direct-invocation guard works on Windows
  paths and through symlinks (Copilot review).
- hideReleased() now iterates the changeset directory and filters by
  the released set instead of iterating the (potentially long) ledger
  and probing existsSync per entry (Copilot review).
- hideReleased() restores already-renamed files if a later rename
  throws, so a partial failure leaves the .changeset directory in its
  original state (CodeRabbit review).
- Move deleteHidden() into a finally so the .md.released files are
  cleaned up even if appendReleased() throws after a successful
  changeset version run (CodeRabbit review).
- Add a unit test that forces hideReleased() to fail mid-loop and
  asserts the rollback.
2026-05-06 01:34:52 +02:00
Zoltan Kochan
f79f0540ac chore: update Node.js to 26.0.0 (#11472)
* chore: update Node.js to 26.0.0

* fix(jest-config): use amaro for type stripping on Node.js 26

Node.js v26 removed the `transform` mode and `sourceMap` option from
`module.stripTypeScriptTypes`. Switch the Jest transform to call
`amaro.transformSync` directly (the same wasm transformer Node.js wraps)
so we keep inline source maps for tests.
2026-05-05 22:18:12 +02:00
Zoltan Kochan
548208ac09 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 21:23:10 +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 2026-04-30 23:03:46 +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
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 2026-04-30 17:16:34 +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 2026-04-29 23:00:21 +02:00
Zoltan Kochan
890efaf472 chore: use @zkochan/git-wt package for worktree creation (#11359)
* chore: use @zkochan/git-wt package for worktree creation

Replace the in-repo `worktree:new` script and `shell/wt.*` helpers with
the published `@zkochan/git-wt` package. Contributors now install it
globally (`pnpm add -g @zkochan/git-wt`) and enable the `wt` shell
function via `git-wt init <shell>`, which also makes `git wt <branch>`
available as a native git subcommand.

* chore: remove shell/cleanup-worktrees.sh

Its functionality is now available as `git-wt cleanup` in the
@zkochan/git-wt package, which contributors are already being directed
to install in CONTRIBUTING.md.

* docs: give copy-paste install commands for the wt shell function

Previously CONTRIBUTING.md said "add this line to your config" and showed
the snippet, making contributors open the rc file themselves. Replace with
a one-liner per shell that appends to the rc file and activates `wt` in the
current session in one go.
2026-04-24 09:09:18 +02:00
Zoltan Kochan
4d7cd56ccc chore: upgrade @typescript/native-preview to 7.0.0-dev.20260421.2 (#11332)
* chore: upgrade @typescript/native-preview to 7.0.0-dev.20260421.2

- Add explicit `types: ["node"]` to the shared tsconfig because tsgo
  20260421 no longer auto-acquires `@types/*` from `node_modules`.
- Refactor test files to explicitly import jest globals (`describe`,
  `it`, `test`, `expect`, `beforeEach`, etc.) from `@jest/globals`
  instead of relying on `@types/jest` ambient declarations. Under the
  new tsgo build, `import { jest } from '@jest/globals'` shadows the
  ambient `jest` namespace, breaking `@types/jest`'s `declare var
  describe: jest.Describe;` globals.
- Add `@jest/globals` to each package's devDependencies where tests
  now import from it, and add `@types/node` to packages that need it
  but were relying on hoisted resolution.
- Replace `fail()` calls with `throw new Error(...)` since `fail` is
  no longer globally available.

* chore: fix remaining tsgo type-strictness errors

- Strip `as <PnpmType>` casts on objects passed to toMatchObject /
  toStrictEqual / toEqual; @jest/globals rejects the typed objects
  (which include AsymmetricMatchers) vs. the repo-specific type.
- Type `jest.fn<...>()` explicitly where the mock's signature matters
  for toHaveBeenCalledWith.
- Replace `beforeEach(() => X)` with `beforeEach(() => { X })` so the
  return value is void, as the stricter jest typing requires.
- Use `expect.objectContaining({...})` in one place where the full
  expected object triggered stricter type resolution.
- Cast `prompt.mock.calls` arg through `as unknown as Record<...>[]`
  for patch.test.ts's nested-array matchers.
- Fix off-by-one `<reference path>` in pnpm/test/getConfig.test.ts
  that only surfaced now.
- Move `@jest/globals` from devDependencies to dependencies in the
  two `__utils__` packages that import it from `src/`.
- Clean up unused imports from the @jest/globals migration.

* chore: address Copilot review on #11332

- Move misplaced `@jest/globals` imports to the top import block in
  checkEngine, run.ts, and workspace/root-finder tests where the
  script dropped them below executable code.
- Replace `try { await x(); throw new Error('should have thrown') } catch`
  in bins/linker, lockfile/fs, and resolving/local-resolver tests with
  `await expect(x()).rejects.toMatchObject({...})`. The old pattern
  swallowed an unrelated `throw` if the under-test call silently
  succeeded, which would fail on the catch-block assertion with a
  misleading message.
2026-04-21 23:21:52 +02:00
Zoltan Kochan
187049055f chore: upgrade @typescript/native-preview to 7.0.0-dev.20260421.2 (#11332)
* chore: upgrade @typescript/native-preview to 7.0.0-dev.20260421.2

- Add explicit `types: ["node"]` to the shared tsconfig because tsgo
  20260421 no longer auto-acquires `@types/*` from `node_modules`.
- Refactor test files to explicitly import jest globals (`describe`,
  `it`, `test`, `expect`, `beforeEach`, etc.) from `@jest/globals`
  instead of relying on `@types/jest` ambient declarations. Under the
  new tsgo build, `import { jest } from '@jest/globals'` shadows the
  ambient `jest` namespace, breaking `@types/jest`'s `declare var
  describe: jest.Describe;` globals.
- Add `@jest/globals` to each package's devDependencies where tests
  now import from it, and add `@types/node` to packages that need it
  but were relying on hoisted resolution.
- Replace `fail()` calls with `throw new Error(...)` since `fail` is
  no longer globally available.

* chore: fix remaining tsgo type-strictness errors

- Strip `as <PnpmType>` casts on objects passed to toMatchObject /
  toStrictEqual / toEqual; @jest/globals rejects the typed objects
  (which include AsymmetricMatchers) vs. the repo-specific type.
- Type `jest.fn<...>()` explicitly where the mock's signature matters
  for toHaveBeenCalledWith.
- Replace `beforeEach(() => X)` with `beforeEach(() => { X })` so the
  return value is void, as the stricter jest typing requires.
- Use `expect.objectContaining({...})` in one place where the full
  expected object triggered stricter type resolution.
- Cast `prompt.mock.calls` arg through `as unknown as Record<...>[]`
  for patch.test.ts's nested-array matchers.
- Fix off-by-one `<reference path>` in pnpm/test/getConfig.test.ts
  that only surfaced now.
- Move `@jest/globals` from devDependencies to dependencies in the
  two `__utils__` packages that import it from `src/`.
- Clean up unused imports from the @jest/globals migration.

* chore: address Copilot review on #11332

- Move misplaced `@jest/globals` imports to the top import block in
  checkEngine, run.ts, and workspace/root-finder tests where the
  script dropped them below executable code.
- Replace `try { await x(); throw new Error('should have thrown') } catch`
  in bins/linker, lockfile/fs, and resolving/local-resolver tests with
  `await expect(x()).rejects.toMatchObject({...})`. The old pattern
  swallowed an unrelated `throw` if the under-test call silently
  succeeded, which would fail on the catch-block assertion with a
  misleading message.
2026-04-21 22:50:40 +02:00
Zoltan Kochan
fd437ded13 chore(release): 11.0.0-rc.4 2026-04-21 15:03:02 +02:00
Zoltan Kochan
21fa098e36 chore(release): always build artifacts 2026-04-21 00:57:19 +02:00
Zoltan Kochan
fcdd50aaa7 chore(release): 11.0.0-rc.3 2026-04-21 00:17:38 +02:00
Zoltan Kochan
5a293d250c refactor: rename @pnpm/exe platform packages to @pnpm/exe.<platform>-<arch>[-musl] (#11316)
* refactor: rename @pnpm/exe platform packages to @pnpm/exe.<platform>-<arch>[-musl]

Aligns pnpm's own published platform artifacts with the one naming
convention the rest of the codebase already uses (`process.platform`
values plus an explicit `-musl` libc suffix), matching what `pnpm
pack-app`, `pnpm add --os/--cpu/--libc`, `supportedArchitectures.os`,
and Node.js tarball names all already settled on.

Package renames:
- @pnpm/linux-x64          -> @pnpm/exe.linux-x64
- @pnpm/linux-arm64        -> @pnpm/exe.linux-arm64
- @pnpm/linuxstatic-x64    -> @pnpm/exe.linux-x64-musl   (new dir)
- @pnpm/linuxstatic-arm64  -> @pnpm/exe.linux-arm64-musl
- @pnpm/macos-x64          -> @pnpm/exe.darwin-x64
- @pnpm/macos-arm64        -> @pnpm/exe.darwin-arm64
- @pnpm/win-x64            -> @pnpm/exe.win32-x64
- @pnpm/win-arm64          -> @pnpm/exe.win32-arm64

GitHub release asset names follow suit (`pnpm-linuxstatic-x64.tar.gz`
-> `pnpm-linux-x64-musl.tar.gz`, `pnpm-macos-*` -> `pnpm-darwin-*`,
`pnpm-win-*` -> `pnpm-win32-*`). Internal artifact directories under
`pnpm/artifacts/` renamed to match, which drops the awkward mixed
naming between target and directory.

The umbrella package `@pnpm/exe` keeps its name so that `pnpm
self-update` from v10 and any `npm i -g @pnpm/exe` scripts continue to
resolve. Platform children can be renamed freely because npm/pnpm
filter optional deps by each child's `os`/`cpu`/`libc` manifest
fields, not by package names.

Also updates:
- `@pnpm/exe`'s `setup.js` (preinstall) and the self-updater's
  `linkExePlatformBinary` to look up the platform package by the new
  scheme, using `detect-libc` to append `-musl` on musl Linux hosts.
- `.meta-updater` optional-dependency list for @pnpm/exe.
- `copy-artifacts.ts` target list and Windows detection prefix.
- cspell wordlist (drops `linuxstatic`; it's no longer used anywhere).

Final transition publishes of the old package names (pointing at the
new ones so direct pins keep resolving) are a release-engineering step
handled separately.

Refs #11314.

* chore: keep "linuxstatic" in cspell wordlist for changeset references

* test(pack-app rename): cover the musl branch of platform-package-name lookup

Copilot flagged that the musl -> -musl suffix logic in setup.js's preinstall
and self-updater's linkExePlatformBinary had no regression coverage. Extract
the name-computation from both into small pure helpers and unit-test all
four matrix cases (linux+musl, linux+glibc, darwin, win32) plus the
win32 ia32->x86 arch normalization:

- pnpm/artifacts/exe/platform-pkg-name.js exposes `exePlatformPkgName`
  (returns `@pnpm/exe.<platform>-<arch>[-musl]`). setup.js imports it
  instead of inlining the logic; the new setup.test.ts block covers the
  four-case matrix without having to mock detect-libc or patch
  process.platform.
- engine/pm/commands/src/self-updater/installPnpm.ts exports a new
  `exePlatformPkgDirName` returning `exe.<platform>-<arch>[-musl]` (the
  scope-local dir). linkExePlatformBinary calls it; the new
  selfUpdate.test.ts block covers the same matrix.

Both helpers are deliberately pure so the non-musl CI host can still
exercise the musl code path.
2026-04-20 15:42:04 +02:00
Zoltan Kochan
96ece9d736 chore(release): 11.0.0-rc.2 2026-04-17 18:21:35 +02:00
Zoltan Kochan
f7c23231a9 chore(release): 11.0.0-rc.1 2026-04-16 01:18:55 +02:00
Zoltan Kochan
06d6c2d405 chore(release): 11.0.0-rc.0 2026-04-10 18:30:33 +02:00
Zoltan Kochan
fb58648b00 test: update registry-mock to v6 and fix test fixtures (#11223)
- Update `@pnpm/registry-mock` from 5.2.4 to 6.0.0-6
- Fix auth tests to use bearer token from `globalSetup` instead of hardcoding credentials
- Replace hardcoded integrity checksums with `getIntegrity()` from registry-mock in `customResolvers` tests
- Add `prepareFixtureWithIntegrity()` helper in deps-restorer tests to dynamically patch `@pnpm.e2e` integrity values in fixture lockfiles at runtime, so they don't go stale when registry-mock is updated
- Fix `workspace-external-depends-deep` fixture's current lockfile (was missing `packages/f` and `packages/g` importers)
- Remove unnecessary credentials from `gitChecks` tests (they reject before any registry interaction)
2026-04-08 11:45:38 +02:00
Zoltan Kochan
d6b8e281b6 chore: use pn instead of pnpm (#11124) 2026-03-28 11:55:51 +01:00
Zoltan Kochan
421ceac0b3 chore: compile pnpm CLI bundle before tests that use it (#11059)
Packages whose tests spawn the local pnpm CLI (pnpm/bin/pnpm.mjs) need
the bundle (pnpm/dist/pnpm.mjs) to exist. Add `pnpm --filter pnpm run
compile` to their test scripts so the bundle is built before tests run.
2026-03-22 10:56:36 +01:00
Khải
2e9101d724 chore(typescript): make typecheck threading configurable (#11057)
* feat: make tsgo --singleThreaded configurable via env var

Set PNPM_TYPECHECK_SINGLE_THREADED=false to allow tsgo to use multiple
threads during typechecking. Defaults to true (preserving current
behavior) for environments where memory is constrained.

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* feat: replace binary PNPM_TYPECHECK_SINGLE_THREADED with configurable PNPM_TYPECHECK_THREADING

Replace the binary on/off env var with PNPM_TYPECHECK_THREADING that
accepts three modes: auto, single-threaded, multi-threaded.

Resolution order:
1. PNPM_TYPECHECK_THREADING env var
2. .pnpm-typecheck.json config file (git-ignored, per-developer)
3. Default: "auto"

Auto mode checks system memory: <8GB uses single-threaded, >=8GB uses
multi-threaded.

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* refactor: simplify threading mode resolution

Move validation into the default branch of the switch, removing the
ThreadingMode type and VALID_THREADING_MODES set. readThreadingMode now
returns { mode: string, source: string } so error messages indicate
where the invalid value came from.

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* refactor: error on invalid threading mode instead of warning

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* refactor: remove auto-detect log message

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* refactor: use string literal union type for threading source

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* revert: revert source type back to string

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* refactor: remove try-catch, let parse errors propagate to user

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* refactor: simplify auto case to return directly

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* fix: normalize and validate threading mode input

Trim whitespace and lowercase env var and config file values so that
empty/whitespace-only strings fall through to the default, and
case-insensitive values like "Auto" or "SINGLE-THREADED" are accepted.

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* style: use single quotes for string without interpolation

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

* feat: support .local-settings dir for typecheck config shared across worktrees

Read pnpm-typecheck.json from .local-settings/ directory (with fallback
to the old .pnpm-typecheck.json location). The worktree-new script now
symlinks .local-settings alongside .claude so the config is shared
across all worktrees without manual copying.

https://claude.ai/code/session_01MRhydwHLce7vwZDkf1yvzE

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-22 00:14:40 +01:00
Brandon Cheng
659bb13793 test: wait for Verdaccio to come online before running tests (#11037) 2026-03-21 11:56:09 +01:00
Zoltan Kochan
0d88df854f chore: update all dependencies to latest versions (#11032)
* chore: update all dependencies to latest versions

Update all outdated dependencies across the monorepo catalog and fix
breaking changes from major version bumps.

Notable updates:
- ESLint 9 → 10 (fix custom rule API, disable new no-useless-assignment)
- @stylistic/eslint-plugin 4 → 5 (auto-fixed indent changes)
- @cyclonedx/cyclonedx-library 9 → 10 (adapt to removed SPDX API)
- esbuild 0.25 → 0.27
- TypeScript 5.9.2 → 5.9.3
- Various @types packages, test utilities, and build tools

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

* fix: update unified/remark/mdast imports for v11/v4 API changes

Update imports in get-release-text for the new ESM named exports:
- mdast-util-to-string: default → { toString }
- unified: default → { unified }

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

* fix: resolve typecheck errors from dependency updates

- isexe v4: use named import { sync } instead of default export
- remark-parse/remark-stringify v11: add vfile as packageExtension
  dependency so TypeScript can resolve type declarations
- get-release-text: remove unused @ts-expect-error directives

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

* fix: revert runtime dependency major version bumps

Revert major version bumps for runtime dependencies that are bundled
into pnpm to fix test failures where pnpm add silently fails:
- bin-links: keep ^5.0.0 (was ^6.0.0)
- cli-truncate: keep ^4.0.0 (was ^5.2.0)
- delay: keep ^6.0.0 (was ^7.0.0)
- filenamify: keep ^6.0.0 (was ^7.0.1)
- find-up: keep ^7.0.0 (was ^8.0.0)
- isexe: keep 2.0.0 (was 4.0.0)
- normalize-newline: keep 4.1.0 (was 5.0.0)
- p-queue: keep ^8.1.0 (was ^9.1.0)
- ps-list: keep ^8.1.1 (was ^9.0.0)
- string-length: keep ^6.0.0 (was ^7.0.1)
- symlink-dir: keep ^7.0.0 (was ^9.0.0)
- terminal-link: keep ^4.0.0 (was ^5.0.0)

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

* fix: restore runtime dependency major version bumps

Re-apply all runtime dependency major version bumps that were
previously reverted. All packages maintain their default exports
except isexe v4 which needs named imports.

Updated runtime deps:
- bin-links: ^5.0.0 → ^6.0.0
- cli-truncate: ^4.0.0 → ^5.2.0
- delay: ^6.0.0 → ^7.0.0
- filenamify: ^6.0.0 → ^7.0.1
- find-up: ^7.0.0 → ^8.0.0
- isexe: 2.0.0 → 4.0.0 (fix: use named import { sync })
- normalize-newline: 4.1.0 → 5.0.0
- p-queue: ^8.1.0 → ^9.1.0
- ps-list: ^8.1.1 → ^9.0.0
- string-length: ^6.0.0 → ^7.0.1
- symlink-dir: ^7.0.0 → ^9.0.0
- terminal-link: ^4.0.0 → ^5.0.0

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

* fix: revert tempy to 3.0.0 to fix bundle hang

tempy 3.2.0 pulls in temp-dir 3.0.0 which uses async fs.realpath()
inside its module init. When bundled by esbuild into the __esm lazy
init pattern, this causes a deadlock during module initialization,
making the pnpm binary hang silently on startup.

Keeping tempy at 3.0.0 which uses temp-dir 2.x (sync fs.realpathSync).

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

* docs: add comment explaining why tempy cannot be upgraded

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

* fix: revert nock to 13.3.4 for node-fetch compatibility

nock 14 changed its HTTP interception mechanism in a way that doesn't
properly intercept node-fetch requests, causing audit tests to hang
waiting for responses that are never intercepted.

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

* docs: add comment explaining why nock cannot be upgraded

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

* fix: update symlink-dir imports for v10 ESM named exports

symlink-dir v10 removed the default export and switched to named
exports: { symlinkDir, symlinkDirSync }.

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

* fix: revert @typescript/native-preview to working version

Newer tsgo dev builds (>= 20260318) have a regression where
@types/node cannot be resolved, breaking all node built-in types.

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

* fix: vulnerabilities

* fix: align comment indentation in runLifecycleHook

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

* fix: pin msgpackr to 1.11.8 for TypeScript 5.9 compatibility

msgpackr 1.11.9 has broken type definitions that use Iterable/Iterator
without required type arguments, causing compile errors with TS 5.9.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:28:53 +01:00
Zoltan Kochan
812cae93d6 test(releasing): fix 2026-03-19 19:02:17 +01:00
Brandon Cheng
b3c2b6c1ff build: use stripTypeScriptTypes transform mode for source map support (#11024) 2026-03-19 10:45:50 +01:00
Zoltan Kochan
07304b9282 fix: set worktree upstream via git-config to avoid missing remote-tracking ref
The targeted fetch refspec doesn't create a remote-tracking branch,
causing `git branch --set-upstream-to` to fail. Use `git config` to
set branch.remote and branch.merge directly instead.
2026-03-18 12:04:09 +01:00
Zoltan Kochan
d0ae78821a refactor: rename workspace functions from packages to projects (#11002)
Align function, type, and file names with the packages-to-projects
rename in workspace packages (projects-filter, projects-reader,
projects-sorter).
2026-03-18 11:38:02 +01:00
Zoltan Kochan
dba4153767 refactor: rename packages and consolidate runtime resolvers (#10999)
* refactor: rename workspace.sort-packages and workspace.pkgs-graph

- workspace.sort-packages -> workspace.projects-sorter
- workspace.pkgs-graph -> workspace.projects-graph

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rename packages/ to core/ and pkg-manifest.read-package-json to reader

- Rename packages/ directory to core/ for clarity
- Rename pkg-manifest/read-package-json to pkg-manifest/reader (@pnpm/pkg-manifest.reader)
- Update all tsconfig, package.json, and lockfile references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: consolidate runtime resolvers under engine/runtime domain

- Remove unused @pnpm/engine.runtime.node.fetcher package
- Rename engine/runtime/node.resolver to node-resolver (dash convention)
- Move resolving/bun-resolver to engine/runtime/bun-resolver
- Move resolving/deno-resolver to engine/runtime/deno-resolver
- Update all package names, tsconfig paths, and lockfile references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update lockfile after removing node.fetcher

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: sort tsconfig references and package.json deps alphabetically

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: auto-fix import sorting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update __typings__ paths in tsconfig.lint.json for moved resolvers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove deno-resolver from deps of bun-resolver

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 00:19:58 +01:00
Zoltan Kochan
4a36b9a110 refactor: rename internal packages to @pnpm/<domain>.<leaf> convention (#10997)
## Summary

Rename all internal packages so their npm names follow the `@pnpm/<domain>.<leaf>` convention, matching their directory structure. Also rename directories to remove redundancy and improve clarity.

### Bulk rename (94 packages)

All `@pnpm/` packages now derive their name from their directory path using dot-separated segments. Exceptions: `packages/`, `__utils__/`, and `pnpm/artifacts/` keep leaf names only.

### Directory renames (removing redundant prefixes)

- `cli/cli-meta` → `cli/meta`, `cli/cli-utils` → `cli/utils`
- `config/config` → `config/reader`, `config/config-writer` → `config/writer`
- `fetching/fetching-types` → `fetching/types`
- `lockfile/lockfile-to-pnp` → `lockfile/to-pnp`
- `store/store-connection-manager` → `store/connection-manager`
- `store/store-controller-types` → `store/controller-types`
- `store/store-path` → `store/path`

### Targeted renames (clarity improvements)

- `deps/dependency-path` → `deps/path` (`@pnpm/deps.path`)
- `deps/calc-dep-state` → `deps/graph-hasher` (`@pnpm/deps.graph-hasher`)
- `deps/inspection/dependencies-hierarchy` → `deps/inspection/tree-builder` (`@pnpm/deps.inspection.tree-builder`)
- `bins/link-bins` → `bins/linker`, `bins/remove-bins` → `bins/remover`, `bins/package-bins` → `bins/resolver`
- `installing/get-context` → `installing/context`
- `store/package-store` → `store/controller`
- `pkg-manifest/manifest-utils` → `pkg-manifest/utils`

### Manifest reader/writer renames

- `workspace/read-project-manifest` → `workspace/project-manifest-reader` (`@pnpm/workspace.project-manifest-reader`)
- `workspace/write-project-manifest` → `workspace/project-manifest-writer` (`@pnpm/workspace.project-manifest-writer`)
- `workspace/read-manifest` → `workspace/workspace-manifest-reader` (`@pnpm/workspace.workspace-manifest-reader`)
- `workspace/manifest-writer` → `workspace/workspace-manifest-writer` (`@pnpm/workspace.workspace-manifest-writer`)

### Workspace package renames

- `workspace/find-packages` → `workspace/projects-reader`
- `workspace/find-workspace-dir` → `workspace/root-finder`
- `workspace/resolve-workspace-range` → `workspace/range-resolver`
- `workspace/filter-packages-from-dir` merged into `workspace/filter-workspace-packages` → `workspace/projects-filter`

### Domain moves

- `pkg-manifest/read-project-manifest` → `workspace/project-manifest-reader`
- `pkg-manifest/write-project-manifest` → `workspace/project-manifest-writer`
- `pkg-manifest/exportable-manifest` → `releasing/exportable-manifest`

### Scope

- 1206 files changed
- Updated: package.json names/deps, TypeScript imports, tsconfig references, changeset files, renovate.json, test fixtures, import ordering
2026-03-17 21:50:40 +01:00
Zoltan Kochan
7a304b17c4 refactor: rename directories and unify command packages per domain (#10993)
- Rename `installing/core` → `installing/deps-installer` and `installing/headless` → `installing/deps-restorer` for clearer naming
- Rename all `plugin-commands-*` directories to use `-commands` suffix convention
- Merge multiple command packages per domain into a single `commands/` directory (one commands package per domain rule):
  - `building/{build-commands,policy-commands}` → `building/commands`
  - `deps/compliance/{audit-commands,licenses-commands,sbom-commands}` → `deps/compliance/commands`
  - `deps/inspection/{listing-commands,outdated-commands}` → `deps/inspection/commands`
  - `store/{store-commands,inspecting-commands}` → `store/commands`
  - `releasing/{publish-commands,deploy-commands}` → `releasing/commands`
  - `cli/{completion-commands,doctor-commands}` → `cli/commands`
  - `engine/pm/{self-updater-commands,setup-commands}` → `engine/pm/commands`
  - `engine/runtime/{runtime-commands,env-commands}` → `engine/runtime/commands`
  - `cache/cache-commands` → `cache/commands`
- Fix relative paths in merged test files (pnpmBin, __typings__ references)
- Update jest config to ignore `utils/` dirs at any nesting depth under `test/`
- Fix stale package names in changeset files
2026-03-17 17:42:20 +01:00
Zoltan Kochan
f47ef4b125 refactor: reorganize monorepo domain structure (#10987)
Reorganize the monorepo's top-level domain directories for clarity:

- pkg-manager/ split into:
  - installing/ (core, headless, client, resolve-dependencies, etc.)
  - installing/linking/ (hoist, direct-dep-linker, modules-cleaner, etc.)
  - bins/ (link-bins, package-bins, remove-bins)
- completion/ merged into cli/
- dedupe/ moved to installing/dedupe/
- env/ renamed to engine/ with subdomains:
  - engine/runtime/ (node.fetcher, node.resolver, plugin-commands-env, etc.)
  - engine/pm/ (plugin-commands-setup, plugin-commands-self-updater)
- env.path moved to shell/
- tools/ and runtime/ dissolved
- reviewing/ and lockfile audit packages moved to deps/:
  - deps/inspection/ (list, outdated, dependencies-hierarchy)
  - deps/compliance/ (audit, licenses, sbom)
- registry/ moved to resolving/registry/
- semver/peer-range moved to deps/
- network/fetching-types moved to fetching/
- packages/ slimmed down, moving packages to proper domains:
  - calc-dep-state, dependency-path -> deps/
  - parse-wanted-dependency -> resolving/
  - git-utils -> network/
  - naming-cases -> text/
  - make-dedicated-lockfile -> lockfile/
  - render-peer-issues -> installing/
  - plugin-commands-doctor -> cli/
  - plugin-commands-init -> workspace/

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:45:54 +01:00
Zoltan Kochan
31858c544b refactor: merge env lockfile into pnpm-lock.yaml (#10964)
Instead of a separate pnpm-lock.env.yaml file, the env lockfile
(configDependencies and packageManagerDependencies) is now stored as
the first YAML document in pnpm-lock.yaml, separated by `---`.

The combined file starts with `---\n` when an env document is present,
allowing pnpm to check just the first 4 bytes to know whether
the file contains an env document. Reading uses streaming I/O that
stops as soon as the document separator is found, avoiding parsing
of the full lockfile.

Writing preserves both documents: when the env lockfile is updated
the main lockfile portion is kept, and vice versa.
2026-03-15 01:44:20 +01:00
Zoltan Kochan
251f8a3cfc chore: set up remote tracking for fork PRs in worktree helper (#10952)
When creating a worktree from a PR number, use `gh pr view` to get the
fork owner/repo and branch name, add the fork as a remote, and set the
upstream tracking branch. This makes `git push` work out of the box for
PRs from forks, matching the behavior of `gh pr checkout`.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 13:13:35 +01:00
Zoltan Kochan
5d5818e44f style: enforce node: protocol for builtin imports (#10951)
Add n/prefer-node-protocol rule and autofix all bare builtin imports
to use the node: prefix. Simplify the simple-import-sort builtins
pattern to just ^node: since all imports now use the prefix.
2026-03-13 07:59:51 +01:00
Zoltan Kochan
1c8c4e49f5 style: add eslint-plugin-simple-import-sort (#10947)
Add eslint-plugin-simple-import-sort to enforce consistent import ordering:
- Node.js builtins first
- External packages second
- Relative imports last
- Named imports sorted alphabetically within each statement
2026-03-13 02:02:38 +01:00
Zoltan Kochan
39afb24ce6 chore: add worktree helper script and shell functions (#10938)
Adds a `pnpm worktree:new <branch>` script that creates a git worktree
as a sibling directory of the repo root, with branch slashes replaced by
dashes (e.g. `feat/foo` → `../feat-foo`). Shell helpers in `shell/wt.fish`
and `shell/wt.sh` wrap the script to also `cd` into the new worktree.
Documents setup and usage in CONTRIBUTING.md.
2026-03-11 22:59:42 +01:00
Zoltan Kochan
178f2210e3 fix: don't run pnpm install in the fixture dir, use a temp copy instead (#10936) 2026-03-11 20:09:57 +01:00
Zoltan Kochan
0fda5eaf0b fix: skip entries that disappear between readdirSync and lstatSync on Windows CI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 19:41:40 +01:00
Zoltan Kochan
3a5bfaa94f chore: update zkochan packages to latest versions (#10930)
Update all packages from zkochan/packages to their latest major versions
and exclude them from minimumReleaseAge requirement. This includes
updating catalog entries, adapting to breaking API changes (default
exports replaced with named exports, sync functions renamed with Sync
suffix), and updating type declarations.
2026-03-11 13:47:46 +01:00
Brandon Cheng
01914345d5 build: enable @typescript-eslint/no-import-type-side-effects (#10630)
* build: enable `@typescript-eslint/no-import-type-side-effects`

* build: disable `@typescript-eslint/consistent-type-imports`

* chore: apply fixes for `no-import-type-side-effects`

pnpm exec eslint "**/src/**/*.ts" "**/test/**/*.ts" --fix
2026-03-08 00:02:48 +01:00
Zoltan Kochan
b7f0f21582 feat: use SQLite for storing package index in the content-addressable store (#10827)
## Summary

Replace individual `.mpk` (MessagePack) files under `$STORE/index/` with a single SQLite database at `$STORE/index.db` using Node.js 22's built-in `node:sqlite` module. This reduces filesystem syscall overhead and improves space efficiency for small metadata entries.

Closes #10826

## Design

### New package: `@pnpm/store.index`

A new `StoreIndex` class wraps a SQLite database with a simple key-value API (`get`, `set`, `delete`, `has`, `entries`). Data is serialized with msgpackr and stored as BLOBs. The table uses `WITHOUT ROWID` for compact storage.

Key design decisions:

- **WAL mode** enables concurrent reads from workers while the main process writes.
- **`busy_timeout=5000`** plus a retry loop with `Atomics.wait`-based `sleepSync` handles `SQLITE_BUSY` errors from concurrent access.
- **Performance PRAGMAs**: `synchronous=NORMAL`, `mmap_size=512MB`, `cache_size=32MB`, `temp_store=MEMORY`, `wal_autocheckpoint=10000`.
- **Write batching**: `queueWrites()` batches pre-packed entries from tarball extraction and flushes them in a single transaction on `process.nextTick`. `setRawMany()` writes immediate batches (e.g. from `addFilesFromDir`).
- **Lifecycle**: `close()` auto-flushes pending writes, runs `PRAGMA optimize`, and closes the DB. A `process.on('exit')` handler ensures cleanup even on unexpected exits.
- **`VACUUM` after `deleteMany`** (used by `pnpm store prune`) to reclaim disk space.

### Key format

Keys are `integrity\tpkgId` (tab-separated). Git-hosted packages use `pkgId\tbuilt` or `pkgId\tnot-built`.

### Shared StoreIndex instance

A single `StoreIndex` instance is threaded through the entire install lifecycle — from `createNewStoreController` through the fetcher chain, package requester, license scanner, SBOM collector, and dependencies hierarchy. This replaces the previous pattern of each component creating its own file-based index access.

### Worker architecture

Index writes are performed in the main process, not in worker threads. Workers send pre-packed `{ key, buffer }` pairs back to the main process via `postMessage`, where they are batched and flushed to SQLite. This avoids SQLite write contention between threads.

### SQLite ExperimentalWarning suppression

`node:sqlite` emits an `ExperimentalWarning` on first load. This is suppressed via a `process.emitWarning` override injected through esbuild's `banner` option, which runs on line 1 of both `dist/pnpm.mjs` and `dist/worker.js` — before any module that loads `node:sqlite`.

### No migration from `.mpk` files

Old `.mpk` index files are not migrated. Packages missing from the new SQLite index are re-fetched on demand (the same behavior as a fresh store).

## Changed packages

121 files changed across these areas:

- **`store/index/`** — New `@pnpm/store.index` package
- **`worker/`** — Write batching moved from worker module into `StoreIndex` class; workers send pre-packed buffers to main process
- **`store/package-store/`** — StoreIndex creation and lifecycle management
- **`store/cafs/`** — Removed `getFilePathInCafs` index-file utilities (no longer needed)
- **`store/pkg-finder/`** — Reads from StoreIndex instead of `.mpk` files
- **`store/plugin-commands-store/`** — `store status` uses StoreIndex
- **`store/plugin-commands-store-inspecting/`** — `cat-index` and `find-hash` use StoreIndex
- **`fetching/tarball-fetcher/`** — Threads StoreIndex through fetchers; git-hosted fetcher flushes before reading
- **`fetching/git-fetcher/`, `binary-fetcher/`, `pick-fetcher/`** — Accept StoreIndex parameter
- **`pkg-manager/`** — `client`, `core`, `headless`, `package-requester` thread StoreIndex
- **`reviewing/`** — `license-scanner`, `sbom`, `dependencies-hierarchy` accept StoreIndex
- **`cache/api/`** — Cache view uses StoreIndex
- **`pnpm/bundle.ts`** — esbuild banner for ExperimentalWarning suppression

## Test plan

- [x] `pnpm --filter @pnpm/store.index test` — Unit tests for StoreIndex CRUD and batching
- [x] `pnpm --filter @pnpm/package-store test` — Store controller lifecycle
- [x] `pnpm --filter @pnpm/package-requester test` — Package requester reads from SQLite index
- [x] `pnpm --filter @pnpm/tarball-fetcher test` — Tarball and git-hosted fetcher writes
- [x] `pnpm --filter @pnpm/headless test` — Headless install
- [x] `pnpm --filter @pnpm/core test` — Core install, side effects, patching
- [x] `pnpm --filter @pnpm/plugin-commands-rebuild test` — Rebuild reads from index
- [x] `pnpm --filter @pnpm/license-scanner test` — License scanning
- [x] e2e tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-06 12:59:04 +01:00
Brandon Cheng
0bf7051fb3 build: enable TypeScript verbatimModuleSyntax compiler option (#10628)
* build: enable TypeScript `verbatimModuleSyntax`

* fix: use `import type` to elide import errors during bundling

```
> pnpm dlx node@runtime:24.6.0 bundle.ts

Error: R] Could not resolve "@npm/types"

    ../pkg-manifest/exportable-manifest/lib/transform/index.js:1:15:
      1 │ import {} from '@npm/types';
        ╵                ~~~~~~~~~~~~

  You can mark the path "@npm/types" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.

Error: Build failed with 1 error:
../pkg-manifest/exportable-manifest/lib/transform/index.js:1:15: ERROR: Could not resolve "@npm/types"
    at failureErrorWithLog (/home/runner/work/pnpm/pnpm/node_modules/.pnpm/esbuild@0.25.12/node_modules/esbuild/lib/main.js:1467:15)
```

* fix: use `import type` to elide import errors in tests
2026-03-05 12:07:28 +01:00