Commit Graph
443 Commits
Author SHA1 Message Date
Zoltan Kochan 03436d6880 fix: repair TS CI compile and lint after the dependency and Node.js update (#14206)
The dependency update (pnpm/pnpm#14205) broke TS CI / Compile & Lint in
two independent ways.

streamx 2.28.1 declares the 'data' event payload as unknown, so the five
tar-stream data handlers in the releasing commands that annotated the
chunk as Buffer no longer typechecked. They now take the chunk as
unknown and cast at the use site; tar-stream emits Buffers at runtime,
so the emitted JavaScript is unchanged.

The Node.js v26.8.0 binaries on nodejs.org were built with a bogus
version string and self-report as 26.8.0-alpha.0.0.0 (Node.js shipped
26.8.1 the next day to correct it). That prerelease-looking version made
cspell's engine guard reject the runtime during lint and made node-gyp
request a nonexistent v26.8.0-alpha.0.0.0 headers tarball for native
builds. The pinned runtime is bumped to 26.8.1 in the root devEngines,
the compile-only script, the CI test matrix, and the benchmark and
release workflows.
2026-08-27 00:49:41 +02:00
Zoltan Kochanandgithub-actions[bot] 2bd58ac4d4 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#14205)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-27 00:16:37 +02:00
Zoltan Kochanandgithub-actions[bot] 07527caf1c chore: update dependencies, Node.js, pnpm, and GitHub Actions (#14122)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-25 14:06:01 +02:00
Zoltan Kochan b4d19c87a1 fix(release): count only installer processes this step started (#14145)
The check that separates a rejected modify command line from an install
that ran and skipped a component watched for any Visual Studio installer
process by name. One already running for an unrelated reason would pass
for the one this step launches, putting the run back on the generic
"clang-cl was not installed" error it is meant to sharpen.

Snapshot the matching process ids before the launch and count only ones
that appear afterwards.
2026-08-25 02:23:09 +02:00
Zoltan Kochan 6098ce7a74 fix(release): drop the unsupported --wait from the Visual Studio installer call (#14144)
The 12.0.0-rc.11 release failed on both win32-arm64 legs with "clang-cl
was not installed under ...\VC\Tools\Llvm", five minutes after the
Visual Studio installer was asked to add the LLVM and ARM64 components.

`--wait` had been added to that `setup.exe modify` call. Microsoft
documents it as bootstrapper-only: "The --wait parameter can only be
passed into the bootstrapper; the installer (setup.exe) doesn't support
it." We invoke the installer at
`C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe`, so
it rejected the command line and installed nothing. The logs show the
call returning in under a second and no installer process alive for the
whole polling window.

The exit-code check could not catch that. `setup.exe` is a
GUI-subsystem binary, so PowerShell's call operator does not wait for it
and never sets $LASTEXITCODE from it — the value tested was still
vswhere's. Check vswhere's own result instead, where the variable
actually means something, and leave the poll loop as the sole
confirmation that the components landed, which is what it was written
for.

Regressed in pnpm/pnpm#14138; the split into separate CLI and NAPI
matrices is unaffected, it only doubled the number of legs running the
step.
2026-08-25 00:46:28 +02:00
Zoltan Kochan 05129e1fd2 perf(release): build the NAPI addon on its own runners (#14138)
The Rust release built the CLI binary and the NAPI addon back to back in
one matrix leg per target. The two are compiled under different Cargo
profiles — `release` for the CLI, `napi-release` for the addon, which
must keep `panic = "unwind"` so a panic reaching the FFI boundary becomes
a JS exception instead of aborting the host node process. Different
profile means a different target directory, so the two builds shared not
one compiled dependency: every leg paid for the whole graph twice, in
series.

Split the addon into its own `build-rust-napi` matrix over the same eight
targets. Measured on the 12.0.0-rc.9 release run, per-leg build time was:

  target             CLI     addon    leg
  win32-arm64        508s    369s     17m09s
  win32-x64          495s    363s     15m06s
  darwin-arm64       477s    241s     12m30s
  darwin-x64         461s    235s     12m10s
  linux-*        322-351s  217-238s   ~10m

The stage is bounded by its slowest leg, so dropping the addon out of
win32-arm64 takes the critical path from ~17 to ~11 minutes and the whole
release run from ~25m30s to roughly 19 minutes. The addon legs run
alongside and gate nothing.

Downstream needs no changes: the new job uploads to
`binaries-rust-napi-<code-target>`, which the `binaries-rust-*` download
pattern the verify, publish and draft-release jobs already use picks up
and merges into the same directory. It is also free of the node-gyp
payload dependency, since only the CLI archives ship `dist/`.

The toolchain prelude the two jobs share — installing cross, the
clang-cl/ARM64 Visual Studio components, the rustup target, and the guard
that the committed PNPM_VERSION matches the tag — moves into a
`rust-release-target` composite action rather than being duplicated.
zizmor flags that action's writes to GITHUB_ENV/GITHUB_PATH because a
composite action cannot see who calls it; the values come from the
Visual Studio install and `vcvarsall`, and the only caller is a release
job running on a maintainer-signed tag, so the audit is suppressed on
that step with that justification.
2026-08-24 21:16:43 +02:00
Zoltan Kochan 9798c9f611 revert: "chore(release): stop publishing @pnpm/exe from v12 (#14121)" (#14133)
This reverts commit afb4071811.
2026-08-24 15:35:45 +02:00
Zoltan Kochan afb4071811 chore(release): stop publishing @pnpm/exe from v12 (#14121)
Up to v11, `@pnpm/exe` was the build of pnpm that bundled a Node.js
runtime, so it ran where the JavaScript `pnpm` package could not. From
v12 the `pnpm` package is itself the native executable and needs no
Node.js, which left `@pnpm/exe` an equal-content copy of it, published
and dist-tagged for nothing.

generate-packages.mjs no longer emits the `pnpm-exe` wrapper dir, and
release.yml no longer packs or stages it. The per-platform
`@pnpm/exe.<target>` native packages are unchanged: they carry the
binaries the `pnpm` wrapper resolves.

update-latest.yml would have failed on the first v12 promotion, since it
unconditionally installs and dist-tags `@pnpm/exe` at the promoted
version. Both sites now pick the wrapper by major. The upgrade check
gates on the *starting* version so upgrading a v11 `@pnpm/exe` onto a
v12 release is still covered, and it gained `--allow-build=pnpm` because
from v12 the preinstall that swaps the placeholder bin for the native
one lives on the `pnpm` package -- without it that check would have
validated a placeholder.

No runtime code changes: both stacks' package-to-install selection
already converges on `pnpm` for major >= 12, the update notifier already
prints `pnpm`, and `@pnpm/exe` stays in the bin-resolver and global-alias
lists so v11-and-earlier installs keep working. Only the comments that
justified those behaviors with "published under both names" needed
correcting.
2026-08-24 02:39:51 +02:00
Zoltan KochanandClaude Opus 5 a390e363b8 fix: include sponsors in v12 release descriptions (#14118)
* fix: include sponsors in v12 release descriptions

The v11 release description comes from `pn make-release-description`, which
appends the sponsors table. v12 builds its description in the workflow by
dumping the pending changelog, so its release pages never showed sponsors.

Adds .github/release-sponsors.md — a checked-in fragment carrying the same
platinum and gold tables with release_notes attribution — and cats it onto
RELEASE.md in the Rust release job. A missing fragment warns rather than
fails; the sponsors table is not worth losing a release over.

The fragment is regenerated from pnpm.io's sponsors.json alongside the
READMEs and the v11 release text.

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

* refactor: read the sponsors table from the shared fragment in v11 too

make-release-description inlined its own copy of the sponsors tables — 109
lines of HTML that had to be regenerated in lockstep with the READMEs. Now
that v12 reads a fragment, v11 can read the same one.

getChangelogEntry goes back to returning just the changelog section, and
writeReleaseText appends the fragment. A missing fragment warns and writes
the description without the table, matching the v12 job: the workflow falls
back to a diagnostic description when this script fails, so throwing here
would trade a missing sponsors table for missing release notes.

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

* test: assert the sponsors fragment is appended exactly once

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 00:42:22 +02:00
Zoltan Kochanandgithub-actions[bot] de2cbefa9d chore: update dependencies, Node.js, pnpm, and GitHub Actions (#14052)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-23 15:46:09 +02:00
Zoltan Kochanandgithub-actions[bot] c233e72abe chore: update dependencies, Node.js, pnpm, and GitHub Actions (#14006)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-20 23:27:00 +02:00
Zoltan Kochanandgithub-actions[bot] 0c5af94e08 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13978)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-18 22:02:17 +02:00
Zoltan Kochan fe8ec8fbec refactor(pacquet): rename the Rust crates from pacquet- to pnpm- (#13948)
The Rust CLI ships as `pnpm`; `pacquet` survives only as the in-repo
package identifier that keeps the npm wrapper from colliding with the
TypeScript CLI's name. Carrying that identifier into all 75 Cargo crate
names made every `use` statement and every `cargo nextest run -p ...`
spell a name users never see. This renames the crates to the product
they belong to.

Mechanical, name-only: package/lib/bin names, the root
`[workspace.dependencies]` keys, every dependency entry, and every Rust
path reference. All the crates are `publish = false`, so nothing about
the released artifacts changes and no changeset is needed.

Also updated the tooling and docs that spell crate names: the `codecov`
cargo alias, the `registry-mock` just recipe, the release workflow's
`-p` targets and `libpnpm_napi.*` artifact paths, the `libpacquet` ->
`libpnpm` cspell dictionary entry, and the crate names quoted across
`AGENTS.md`, `CONTRIBUTING.md`, `CODE_STYLE_GUIDE.md`, and the plans.

Two spots needed more than a token swap. The five insta snapshot files
carry the crate name in their filename, since insta derives it from the
module path, so they are renamed too — otherwise the tests fail with
"snapshot not found" rather than a diff. And the private module in
`pnpm-lockfile-verification` that mirrors the npm verifier's violation
codes is named after the crate it shadows, so it moved with it.

Two knock-on fixes: the shorter names let rustfmt fit three macro
invocations onto one line, where `perfectionist::macro_trailing_comma`
rejects the trailing comma that was legal while they were wrapped; and
the `libpacquet` cspell entry became `libpnpm` for the NAPI addon's
shared library.

Left alone deliberately, none of which are crate names: the product name
in prose and in the changeset package identifier, the `--pacquet`
benchmark flag and testbed IDs, test helpers and temp-dir prefixes
(`pacquet-test-*`, `../pacquet-store`), the released changesets that
quote error codes shipped versions actually emitted, the
`.github/workflows/pacquet-*.yml` filenames, and the
`@pnpm-private/pacquet-registry-mock-launcher` npm package.
2026-08-16 23:18:23 +02:00
Zoltan Kochan a6e8159eef ci(benchmark): measure the shared virtual store (#13944)
Adds `gvs-linker.fresh-restore.hot-cache.hot-store` to the integrated
benchmark job, feeding both Bencher testbeds.

The harness has carried this scenario for a while, but nothing invoked
it: every scenario the workflow ran pins `enableGlobalVirtualStore:
false` in its fixture. Since pnpm/pnpm#13940 that pin is the opposite
of what users get, so the layout pnpm 12 installs into by default had
no continuous measurement at all — a regression in slot reuse could
land without any gate noticing.

It pairs with the isolated fresh-restore hot/hot scenario: same frozen
install, same warm cache and store, and the per-iteration wipe takes
`node_modules` either way, so the difference is what the layout is
worth. Measured locally over 5 runs: 187.8 ms ± 5.6 shared versus
1.047 s ± 0.119 project-local, because the materialized package
directories survive the wipe under the shared store and only the
symlinks have to be rebuilt.

Both testbeds get the scenario. `pnpr@HEAD` under the shared store had
never been exercised — the pre-warm site notes it as hypothetical — so
it was run end to end first: the server starts, both targets pre-warm,
and both installs measure clean.
2026-08-16 14:03:16 +02:00
Zoltan Kochan e97b44f6b1 feat(pacquet): let Corepack run pnpm 12 (#13922)
Corepack installs no dependencies and runs no lifecycle scripts, so the
`@pnpm/exe.<target>` package that carries the native binary is never
installed and the preinstall that links it over the placeholder bins never
runs. `corepack use pnpm@next-12` therefore died with MODULE_NOT_FOUND
(Closes pnpm/pnpm#13018).

Corepack hardcodes `./bin/pnpm.mjs` and `./bin/pnpx.mjs` as the entry
points of every pnpm >=11, so ship them. They resolve the native binary —
from the platform package when a package manager installed one, otherwise
by downloading the pinned `@pnpm/exe.<target>` tarball from the registry
and verifying it against the checksum the registry published — and hand
over to it. The binary is cached next to the wrapper, where it also finds
the `dist/` payload node-gyp ships in, so only the first run downloads.

`package.json#bin` is untouched: an ordinary install still points at the
native binary and pays no Node.js startup. This is the compatibility
wrapper Yarn 6 ships for the same reason, adapted to how pnpm distributes
its binary (https://github.com/nodejs/corepack/pull/887#issuecomment-5292891262).

Registry access mirrors Corepack's own environment (COREPACK_NPM_REGISTRY,
COREPACK_NPM_TOKEN, COREPACK_NPM_USERNAME/PASSWORD, COREPACK_ENABLE_NETWORK),
and the download has no dependencies of its own, since Corepack would not
install those either.
2026-08-15 18:47:40 +02:00
Zoltan Kochan f361560ab4 perf(pnpr): skip the server exchange when there is nothing to resolve (#13905)
With a configured pnprServer, every install paid a full server exchange
even when the answer was already on disk, making pnpr strictly slower
than a direct install on up-to-date projects. Close that gap in three
layers, each deciding locally that the server has nothing to add:

- Let the pre-runtime "Already up to date" fast path run with a pnpr
  server configured. The check decides purely locally that nothing
  changed since the last install; asking the server cannot change that
  answer. The trust/policy settings guard pnpm already records in the
  workspace state (trustPolicy, trustPolicyExclude,
  trustPolicyIgnoreAfter, minimumReleaseAgeStrict,
  minimumReleaseAgeExclude) is now recorded and compared by pacquet
  too, so a policy change still defeats the fast path.

- Gate the resolve exchange on a local satisfaction check: an
  unfiltered install whose on-disk lockfile still satisfies every
  manifest goes straight to the frozen materialization, exactly like
  the non-pnpr preferFrozenLockfile dispatch.

- Consult the local lockfile-verified.jsonl cache before delegating
  input-lockfile verification to the server, and record server-verified
  and server-resolved lockfiles into that cache (pnpm's
  writeWantedLockfileAndRecordVerified), so repeat verifications of an
  unchanged lockfile stay local.

Add repeat-install scenarios (populated node_modules, hot and cold
cache) to the integrated benchmark, pre-warmed before hyperfine runs
and wired into the pnpr-not-slower-than-direct gate with an absolute
slack for tens-of-milliseconds runs.

Closes pnpm/pnpm#13904
2026-08-14 15:25:16 +02:00
Zoltan Kochanandgithub-actions[bot] 5d33ac39b0 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13871)
* chore: update dependencies, Node.js, pnpm, and GitHub Actions

* fix: update undici

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-13 18:53:42 +02:00
Langning Zhang 7e5783681a fix(cli): restore CI frozen lockfile default (#13782)
## Summary

- Restore the Rust CLI default that freezes an existing non-empty `pnpm-lock.yaml` in CI, so an outdated lockfile fails without being rewritten.
- Preserve explicit `frozenLockfile` and `preferFrozenLockfile` choices from CLI flags, trusted configuration, environment variables, and `.pnpmfile.cjs` hooks.
- Recognize `CI=1`, `CI=true`, and GitHub Actions; let explicit `CI=false` opt out, and prevent repository-controlled `pnpm-workspace.yaml` from overriding CI detection.
- Keep missing, byte-empty, and semantically empty lockfiles writable, and isolate CI-sensitive spawned commands in the Rust test workflow.

The TypeScript CLI already has this behavior; this brings the Rust `pnpm/` port back into parity.

Fixes pnpm/pnpm#13760.
2026-08-11 13:58:11 +02:00
Zoltan Kochanandgithub-actions[bot] 54e9c96eac chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13753)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-11 11:47:49 +02:00
Zoltan Kochan 478aee6ab2 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13675) 2026-08-10 00:06:01 +02:00
Zoltan Kochan 9b205980e0 fix: make the Ecosystem E2E workflow pass (#13727)
The Ecosystem E2E workflow failed on every run since it was added, for
two stacked reasons.

The matrix jobs relied on the runner image's system Node (v20), while
the built pnpm bundle needs at least v22.13 for node:sqlite, so every
scaffold died with ERR_UNKNOWN_BUILTIN_MODULE before any cell ran. The
jobs now install the devEngines.runtime pin via pnpm/setup, the same
way the workflow's build job already did.

With scaffolding unblocked, the angular and nuxt global-virtual-store
cells failed in both binaries: "@angular/build" requires tslib and
"@nuxt/vite-builder" (since v4) imports unplugin without declaring
them, and the global virtual store only exposes declared dependencies.
Since neither entry is in the "@yarnpkg/extensions" compatibility DB
yet, carry them as pnpm-specific compatibility packageExtensions in
both stacks, merged after the upstream DB and gated by the same
ignoreCompatibilityDb setting. Drop an entry once the upstream DB or
the package itself declares the dependency.
2026-08-08 13:16:35 +02:00
YES!HYUNGSEOKandZoltan Kochan 97f20b05f7 fix(ci): resume partial pnpr npm publishes (#13635)
Make pnpr npm publication resumable after a partially successful run. Check each native package's publication state, skip immutable versions that already exist, and publish only missing packages.

Treat lookup failures as fatal rather than as missing versions, and continue publishing the wrapper only after every native package is confirmed available.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-08-07 15:54:39 +02:00
Zoltan Kochan 9c50782610 ci(release): stage pnpm packages before publishing (#13702)
Keep staged publishing above direct OIDC publishing in the trust-policy ranking.
Use the stronger release path instead of lowering the rank.

Stage the TypeScript `@pnpm/exe` and `pnpm` packages in dependency order.
Stage Rust native packages, wrappers, and the `pnpm` gate as separate layers.
Let CI finish after creating every stage without polling for approval.
Maintainers approve the completed stages later with interactive 2FA.

Pin publication traffic to the npm registry and ignore ambient auth configuration.
Sanitize stage output before logging registry-provided content.

Closes pnpm/pnpm#13693.
2026-08-07 14:25:35 +02:00
Zoltan Kochanandgithub-actions[bot] b0e819458a chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13668)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-05 23:57:22 +02:00
Zoltan Kochanandgithub-actions[bot] feaf9e1ba9 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13654)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-05 14:07:19 +02:00
Zoltan Kochanandgithub-actions[bot] e3638c1b02 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13631)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-04 12:07:01 +02:00
Zoltan Kochanandgithub-actions[bot] a93748005a chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13577)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-03 16:45:01 +02:00
Zoltan Kochan 290bb5bd38 ci: create release tags by hand, signed (#13607)
Version tags were created in CI with `git tag "$tag" "$SHA"` — a lightweight tag,
which has no tag object to carry a signature. Since v11.18.0 that made
`git verify-tag` fail with "cannot verify a non-tag object of type commit",
breaking downstream packagers who verify the tag before building.

Signing those tags in CI would restore verify-tag but not the property that makes
it worth verifying: the key would live in Actions secrets, inside the same trust
boundary the signature is meant to attest independently of. Cut tags from a
maintainer machine instead, and have release.yml verify the tag before any
publish job runs.

verify-release-tag imports the public keys committed under .github/release-keys
into a throwaway GNUPGHOME and runs `git verify-tag` on the pushed tag. Every
publish path descends from `plan` and `plan` descends from that job, so one edge
gates all three products. Verified against a signed tag, a lightweight tag, an
annotated unsigned tag, and a tag signed by a key outside the directory: only the
first proceeds.

The keyring is isolated so verification cannot succeed against a key already on
the runner, and checkout sets fetch-tags because a tag push checks out the commit
while the signature lives on the tag object. The non-tag verify_ts_release
dispatch exits from inside the step rather than a job-level `if`, since a skipped
job skips everything that needs it.

This guards against unsigned tags, not against an actor who can push arbitrary
ones: a tag push runs the workflow file and checks out the tree from the pushed
tag. Restricting creation of v* and pnpr@* tags is a repository ruleset concern.

RELEASING.md documents the manual procedure: tag an explicit commit, verify every
tag before pushing, and retag at the fixed commit to retry a failed release.

Related to pnpm/pnpm#13578
2026-08-03 15:43:58 +02:00
Zoltan Kochan dbe2dad610 feat(pacquet): ship node-gyp beside the native binary (#13586)
pnpm v12 shipped no node-gyp, so any package that shells out to it during
an install script died with `spawn node-gyp ENOENT`: `node-gyp-build` with
no matching prebuild, `node-pre-gyp`, a plain `"install": "node-gyp
rebuild"`, and the `node-gyp rebuild` script pnpm synthesizes for a package
that ships a `binding.gyp` without one. Embedders worked around it by
putting their own node-gyp on the lifecycle PATH.

pnpm 11 solves this without a JS bundle: node-gyp is declared `external`,
and `pnpm deploy` resolves its whole tree from this repo's lockfile at
release time into a `dist/node_modules/node-gyp` directory that sits beside
the entry point, with `dist/node-gyp-bin` holding the wrappers that go on a
lifecycle script's PATH. Those are ordinary files next to the executable,
so the native binary can ship them the same way — nothing about the
mechanism depended on there being a bundle to hide node-gyp inside.

Resolving the tree at release time rather than at install time is the point,
not an implementation detail: the dependency tree is frozen and reviewed per
pnpm release instead of being fetched from the registry at the moment an
install script is about to execute arbitrary code.

scripts/bundle-node-gyp.mjs builds the payload, reusing the TypeScript CLI's
wrapper scripts so the two stacks cannot drift on how a script's node-gyp is
dispatched, and refusing to produce a partial dist/ — a PATH entry that
resolves nothing is worse than shipping none at all. Both wrappers ship it,
since each places the binary next to itself.

node-gyp moves to a catalog entry so both stacks pin one version; the
Node.js-floor hold-back note moves with it.

At runtime bundled_node_gyp_bin finds the wrapper dir relative to the
executable and returns None when nothing was shipped, which is what a
checkout build sees — lifecycle scripts then fall back to whatever node-gyp
the environment provides, exactly as before. The wrapper itself honors
npm_config_node_gyp and only falls back to the shipped copy when it is
unset, so a user-supplied node-gyp, a workspace one, and a package's own
dependency all keep winning.

Refs https://github.com/pnpm/pnpm/issues/13580
2026-08-02 15:37:41 +02:00
Zoltan Kochan fa8d383cca test(pacquet): stabilize the peer-heavy benchmark and stop its gate dropping data (#13559)
The peer-heavy resolver fixture has a wide run-to-run spread — a local 15-run
pass measured a ~15% coefficient of variation on an idle machine, with the slow
samples scattered through the sequence rather than clustered at the start, so
the noise is runner contention rather than a cold cache. Three CI runs against
that spread produced a 2.83s outlier on pnpm/pnpm#13551 that lifted the pacquet
mean to 2.15s while its fastest run sat at 1.54s, inside main's range.

Compare the cross-engine gate on each target's fastest run instead of its mean.
Contention only ever adds time, so the minimum is the sample least perturbed by
a noisy neighbour; this is already the statistic the workflow reports to
Bencher, for the same reason. Raise the scenario to nine runs so that minimum
has a good chance of landing on an uncontended run, and surface both mean and
min in the diagnostics table.

The gate is a correctness check, not a measurement, and it was costing us the
measurement: asserting mid-job aborted before the Bencher upload and dropped
every scenario's data point for the whole run. That is why this benchmark has
almost no history on bencher.dev — the two main pushes after it was added both
failed on the since-recalibrated 10x floor, so only one point was ever
published. Record the verdict, let the upload proceed, and re-raise the failure
afterwards.

Pacquet-only benchmark-harness and CI change; no user-visible surface, no
TypeScript counterpart, and no changeset.
2026-08-01 16:48:55 +02:00
Zoltan Kochan e2f439ba4e perf(pacquet): bound memory in peer-heavy hoisted installs (#13545)
Stream lazy child resolution through caches and share ancestry, missing-peer summaries, package
data, and dependency paths across repeated peer contexts. Retain only discovery nodes needed as
peer providers instead of occurrence state for every cache-served visit.

Index peer-provider children once per evolving workspace graph so cached peer lookup and lazy
provider previews avoid repeatedly scanning every dependency edge.

Recursively hoist nested conflict roots so the hoisted linker does not expand a small dependency
graph into deeply repeated node_modules paths.

Add a deterministic integrated benchmark that compares the peer-heavy resolver against main and
TypeScript pnpm while enforcing byte-identical lockfiles.

Closes pnpm/pnpm#13540.
2026-08-01 14:29:24 +02:00
Zoltan Kochanandgithub-actions[bot] e706bbf43b chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13520)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-01 12:58:38 +02:00
Zoltan KochanandClaude Fable 5 2e91fa470f ci: bump pnpm/update to run self-update before the dependency update (#13516)
Picks up pnpm/update#4: the pin bump now happens first, so the
dependency update and the refreshed lockfile are produced by the pnpm
version the update PR moves the repository onto.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 01:27:17 +02:00
Zoltan Kochanandgithub-actions[bot] 4c85370bf7 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13515)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-31 01:24:21 +02:00
Zoltan Kochanandgithub-actions[bot] 13f5820de9 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13480)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-30 21:27:43 +02:00
Zoltan KochanandClaude Fable 5 078d4be193 ci: let update-lockfile self-update pnpm to same-day releases (#13509)
Bump pnpm/update to the release that adds the
update-pnpm-minimum-release-age input, and set it to 0. pnpm 12
defaults minimumReleaseAge to 24 hours and self-update deliberately
ignores the repo's minimumReleaseAgeExclude, so the job could never
bump the pin to a pnpm release published the same day: the next-12
dist-tag silently resolved to the newest mature version instead.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 21:20:35 +02:00
Zoltan Kochan 5b063b9e32 docs(contributing): address duplicate and unvetted AI-assisted PRs (#13499)
Strengthen the duplicate-PR guidance to point at the issue's
automatically linked PRs, add an AI-assisted contributions section
(agents are welcome, but contributors own the output — check linked
PRs, understand the change, run the tests, keep the diff focused,
disclose agent authorship with the standard footer), and document that
human review starts only after CodeRabbit approves and CI is green.
CodeRabbit is the single required AI approval — Qodo ignores
Dependabot/Renovate PRs, so a two-reviewer gate could never be
satisfied for dependency updates; the PR template is aligned
accordingly.
2026-07-30 13:48:58 +02:00
Zoltan Kochan b9603f69b4 docs(github): ask PR authors to confirm no linked PR solves the issue (#13498)
Multiple contributors keep submitting parallel PRs for the same issue
(e.g. pnpm/pnpm#13114 was superseded by pnpm/pnpm#13124 for issue
pnpm/pnpm#13108). GitHub already cross-links every PR that references
an issue on the issue's timeline, so add a checklist item prompting
authors to check those links before submitting.
2026-07-30 13:38:12 +02:00
Zoltan KochanandClaude Fable 5 2b23eebb85 ci: run all TS test jobs in parallel without a smoke gate (#13496)
The ubuntu Node 24 smoke job previously gated the Node 22/26 test runs,
delaying them by a full test cycle. Fold the Node 24 (garnet) leg into
the test matrix and gate every test job only on compile-and-lint plus
its platform's pnpr build, so all Node.js versions and all Windows
chunks start in parallel. The trade-off is that a broken build now
surfaces on all test jobs at once instead of costing a single smoke run.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 12:09:05 +02:00
John-David Dalton b9e7b8d88d feat(login): support web login without an interactive terminal (#13479)
pnpm login refused to run whenever stdin or stdout was not a TTY, even
though the registry web-auth flow only prints an authentication URL and
polls the done endpoint until the browser approval completes - neither
needs a terminal. Agent- and CI-adjacent tooling had to wrap pnpm in a
pseudo-terminal (script -q /dev/null pnpm login) to use the web flow.

Move the non-interactive guard from the top of the login command into
the classic username/password fallback, the only path that prompts on
the terminal. Without a TTY the web flow now prints the authentication
URL and polls as before; the URL is printed without the QR code (a
piped stdout cannot render the block art), and the press-ENTER browser
prompt was already skipped for a non-TTY stdin. A registry without web
login support still fails with ERR_PNPM_LOGIN_NON_INTERACTIVE.

Harden the TypeScript web-login path to match pacquet while touching
it: narrow the attacker-controlled response body at runtime (a missing,
empty, or non-string loginUrl/doneUrl is an invalid response), and
reject URLs containing Unicode control characters with pacquet's
ERR_PNPM_AUTH_COMMANDS_LOGIN_UNSAFE_URL before anything is printed or
polled. The shared error message now says "authentication URL" in both
stacks, since the check covers loginUrl and doneUrl alike.

Implemented in both stacks: the TypeScript CLI moves the guard into
classicLogin and prints a URL-only message via the new
formatAuthUrlOnlyMessage export of the web-auth package; pacquet moves
the same guard into classic_login and selects AuthUrlMessage::UrlOnly
when stdout is not a TTY. The pacquet CLI adapter unit test and the
CLI-tier integration tests now drive the guard through a 404 web-login
probe so it exercises the classic fallback, and a new integration test
covers the headless web flow end-to-end against a mock registry.

Also acknowledge a pre-existing zizmor ref-version-mismatch finding on
the winget-releaser pin in update-latest.yml with the repository's
usual inline ignore: the pinned commit is no longer reachable from any
named ref upstream, so no version comment can describe it accurately.
2026-07-29 12:12:10 +02:00
Zoltan Kochan 02f8807f56 fix(release): resume pacquet beta publish (#13483)
The first pnpm 12 beta release used pnpm 12.0.0-alpha.21 to publish a wrapper whose workspace name is `pacquet`. That version predates `publishConfig.name`, so npm trusted publishing was attempted for `pacquet` instead of `pnpm` and the root package failed after all native packages had already been published.

Use pnpm 11.18.0, the released TypeScript CLI that supports `publishConfig.name`, for release tooling. Update every `pnpm/setup` consumer to the revision that can install v11 from GitHub release archives. Make the Rust publishing loop query each effective published name and skip versions already on npm, while preserving hard failures for registry errors other than 404. This allows a moved beta tag to resume the partial release and reach the dependent GitHub release job.
2026-07-29 10:54:15 +02:00
Zoltan Kochanandgithub-actions[bot] e7ec77654a chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13413)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-28 14:07:17 +02:00
Zoltan Kochanandgithub-actions[bot] b726d9f7aa chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13400)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-26 09:25:23 +02:00
Zoltan Kochan 076f6cc97e ci(codecov): free runner disk before the coverage build (#13396)
The Pacquet Code Coverage job has been failing on main and on every PR
with `System.IO.IOException: No space left on device`, thrown while the
runner worker writes its own diagnostic log — so the run reports a
failure with no step output at all.

The job compiles the whole workspace with coverage instrumentation and
`--all-targets`, keeps a profraw file per test process for all 7167
tests, and then merges them, but it never dropped the preinstalled
toolchains the way `Rust CI / Test`, `Test` and `build-pnpr` do. Reclaim
the same ~25 GB before anything is compiled, and build the instrumented
artifacts with line-tables-only debug info: llvm-cov reads its regions
from the binary's `__llvm_covmap`/`__llvm_covfun` sections, so the DWARF
that dominates the debug build buys the report nothing.

Also report the free disk after the run and cap the job at 60 minutes,
so the next disk regression shows up as a number instead of a silent
worker death.
2026-07-26 03:05:00 +02:00
Zoltan Kochanandgithub-actions[bot] 8363615639 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#13292)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-25 11:22:16 +02:00
baca5d63a5 chore: update lockfile, Node.js, and pnpm versions (#13224)
* chore: update dependencies, Node.js, pnpm, and GitHub Actions

* chore: hold typescript on 6.x for typescript-eslint compatibility

The update-lockfile job bumped the `typescript` catalog entry to 7.0.2,
which typescript-eslint refuses to load against — it hard-errors at load
with "typescript-eslint does not support TS 7.0" — failing the
Compile & Lint job.

The 7.x compiler is already used for the build via
`@typescript/native-preview` (tsgo); the `typescript` npm package only
serves the JS-API tooling (eslint, jest), which needs 6.x until
typescript-eslint adds TS >=7.1 support
(https://github.com/typescript-eslint/typescript-eslint/issues/10940).

Revert the catalog entry to 6.0.3 and add `typescript` to
`update.ignoreDeps` so the update-lockfile workflow stops re-bumping it.

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

* chore: drop the stray typescript@7.0.2 from the lockfile

openpgp declares an optional `typescript` peer (>=4.7). After the catalog
was reverted to 6.0.3, pnpm's incremental resolution kept openpgp latched
onto the leftover typescript@7.0.2 node, leaving it (and its native
platform packages) in the lockfile and tripping peer-mismatch review bots.

Re-point openpgp's optional peer to 6.0.3 so typescript@7.0.2 is gone
entirely; the openpgp subtree is now identical to the base branch.

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

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 16:39:43 +02:00
Zoltan KochanandClaude Opus 4.8 8c3bbab46c ci(release): choose which products to release per run (#13267)
pnpm bump ran `pnpm version -r` unfiltered, consuming the entire changeset
ledger, so every release flushed the TypeScript CLI's pending intents alongside
the Rust products' alpha prereleases. A rapid v12 alpha cadence therefore forced
an equally rapid v11 release cadence — and with it a v11 "Update available!"
notification almost every day.

Give create-release-pr.yml three checkboxes — pnpm11 (the TypeScript CLI),
pnpm (the Rust CLI, v12 alpha), and pnpr — in any combination. bump.ts
translates the selected products into `pnpm version -r --filter` arguments,
consuming only their intents and leaving the rest in the ledger. The default
lane (pnpm11) has no single positive selector, so it is expressed as the
complement of the unselected alpha products (an exclude-only filter selects
every project minus those); selecting all three yields no filter — a full
release. The embedded trust-root refresh steps run only when pnpm11 is selected,
since those keys ship in the TypeScript CLI.

Argument parsing fails closed: an unrecognized token (e.g. a `--releases` typo)
throws instead of leaving the selection empty and releasing every product; a
bare `pnpm bump` with no arguments still cuts a full release. The version
command is built as an argv array (execFileSync, no shell) so a filter value is
never interpreted by a shell.

Related to pnpm/pnpm#13264.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 15:06:39 +02:00
Ben HolmesandOz fd9e53498a ci(triage): time out hung Oz triage runs instead of waiting 6h (#13249)
* ci(triage): time out hung Oz triage runs instead of waiting 6h

Triage runs occasionally wedge inside the `Triage with Oz agent` step
before the agent's first turn. The job then sits until GitHub's 6h
ceiling cancels it, so the issue is never labelled and never gets a
comment explaining why. Eight runs have hit this.

Successful triage runs complete in ~3 min (13 min worst case observed),
so a 20 min step timeout leaves ample headroom while turning a silent 6h
stall into a red run you can see and re-run.

Co-Authored-By: Oz <oz-agent@warp.dev>

* remove timeout comment block 1

* remove timeout comment block 2

---------

Co-authored-by: Oz <oz-agent@warp.dev>
2026-07-23 20:31:47 +02:00
Zoltan Kochan 6fb109543c fix(release): restore modules after payload verify and drop target_commitish (#13240)
* fix(pnpm): stop stripping the manifest on disk when bundling deps

bundle-deps.ts deleted dependencies and devDependencies from
pnpm11/pnpm/package.json on disk, a workaround kept from when the
release-pinned pnpm did not honor the beforePacking hook
(pnpm/pnpm#12955). The hook handles it now, and the on-disk strip is
what killed the v11.17.0 release: after build-artifacts ran it, the
payload-verification step tripped the verifyDepsBeforeRun gate, whose
spawned install synced node_modules to the stripped manifest and
removed the pnpm package deps that the artifact packages
prepublishOnly (verify-binary.mjs) needs during publish. The packed
manifest stays dependency-free via the hook, asserted by the release
workflow before the first publish.

* fix(release): drop target_commitish from the Rust draft release

Creating the Rust draft release fails with 403 "Resource not
accessible by integration": with immutable releases enabled, passing
target_commitish makes release creation fail for the workflow token
(the v12.0.0-alpha.19 draft failure, reproduced on rerun). The input
never did anything - GitHub ignores it when the tag exists, and the
assert step already pins the commit.
2026-07-23 18:18:23 +02:00
Zoltan Kochan ae9f10f63f ci: update pnpm/setup to the v12 standalone-executable revision (#13239)
* ci: update pnpm/setup to the v12 standalone-executable revision

Since pnpm/setup#11 the action downloads the standalone pnpm v12
executable directly from the registry — no npm bootstrap, no system
Node.js dependency. Every workflow moves to the new revision except
update-latest.yml: its RELEASE_TOOL_PNPM_VERSION deliberately pins a
proven pnpm 11, which only the pre-v12 action revision can install, so
it keeps the old pin until that version moves to v12.

* ci: operate the Tag workflow with pnpm v12

RELEASE_TOOL_PNPM_VERSION moves to 12.0.0-alpha.19 and the pnpm/setup
pins to the v12 revision. The commands the workflow runs are rewritten
to forms both CLIs accept, since the Rust CLI does not (yet) expose
--registry, --allow-build on add, or a post-subcommand --dir:

- --registry becomes --config.registry (read by both stacks)
- the add build-script approval moves from `--allow-build=@pnpm/exe` to
  an allowBuilds entry in the scratch dir pnpm-workspace.yaml
- --dir moves ahead of the subcommand

Each rewritten command was verified against the 12.0.0-alpha.19 binary,
including the verify-upgrade sequence end to end (add of
`@pnpm/exe@11.16.0` with the build approval, bin shim run) and the
config set/get/delete round trip for the auth token.

* revert: operate the Tag workflow with pnpm v11 again

Moving the operator to v12 required rewriting commands around three
CLI surfaces pacquet is missing (--registry, --allow-build on add,
post-subcommand --dir). The Rust CLI must gain those for parity instead
of the workflow papering over them — tracked in
https://github.com/pnpm/pnpm/issues/13242. The workflow keeps the
pre-v12 pnpm/setup pin and pnpm 11.13.1 until that lands.
2026-07-23 18:14:12 +02:00