35 Commits
Author SHA1 Message Date
Zoltan Kochan 1860c1c75e chore: move get-pnpm into the workspace and pin npm's signing keys once (#17341)
get-pnpm moves from pnpm/get.pnpm.io into pnpm/npm/get-pnpm, at 0.0.9
(get.pnpm.io be4e983, where its history stays).

- The pnpm v12 npm package depends on it with `workspace:*`, so a pnpm
  release bundles get-pnpm's source as of that release. A wrapper fix no
  longer needs a get-pnpm release, a catalog bump, and a
  minimumReleaseAge exclusion first. bundle-node-gyp builds it before
  the deploy injects its build output.
- It is released on its own: a `get-pnpm` product in bump.ts and
  create-release-pr.yml (off by default), `get-pnpm@<version>` tags,
  and build-get-pnpm/publish-get-pnpm jobs in release.yml. It is private
  in the workspace so the TypeScript release's recursive publish skips
  it; the packed manifest drops the flag.
- Its runtime dependencies stay exact, through a `get-pnpm` named
  catalog. Its lint is the root ESLint config. Its TLS tests use the
  fixture the Rust network tests use.
- The npm-wrapper CI job runs its tests on Node.js 24 and 22, beside
  the wrapper's. The forwarding proxy in its download tests forwards
  only to the servers the tests start.

npm's registry signing keys were pinned in five places: v11, v12,
get-pnpm, and get.pnpm.io's install.sh and install.ps1. Only v11's copy
was refreshed, by the release PR, and the two repositories handled a
withdrawn key in opposite ways. They now come from
.config/npm-signing-keys.json:

- .github/scripts/update-npm-signing-keys.mjs refreshes it from npm on
  every release PR, not only v11 ones. A key npm stops listing stays,
  marked withdrawn.
- The meta-updater renders it into the v11, v12, and get-pnpm copies,
  so `pnpm lint:meta` fails on a copy edited by hand. pnpm v11 and v12
  keep trusting withdrawn keys, so packages signed before a rotation
  verify. get-pnpm drops them, as get.pnpm.io's installers do.
- get.pnpm.io's update script is to read this file.
2026-10-25 17:38:04 +01:00
Zoltan KochanandClaude Opus 5.5 6f95957063 docs: lint prose with Vale (#17238)
* docs: lint prose with Vale

Add Vale with an in-repo style, .vale/styles/pnpm, that turns the
writing rules in AGENTS.md and the Google developer documentation style
guide into lint rules. The stock Vale packages (Google, Microsoft,
RedHat, write-good) were too noisy to block on, for example 1,300
passive-voice hits in the v12 docs alone, so the rules are written for
this repo, following the GitLab model. Each one links the guideline it
enforces.

Levels:
- error, fails CI: dashes, plain-word substitutions, condescending
  words, "please", "note that", hedges, puffery, optional plurals,
  exclamation marks, ellipses, curly quotes, generic link text, product
  spellings, sentence-case headings, repeated words, double spaces,
  implementation history in comments; in changesets, bold or italic
  emphasis, internal names and release-line names.
- warning: future tense, sentences over 30 words, "instead of" and
  "so that" tails in changesets.
- suggestion: passive voice.

.vale.ini scopes the rules. Docs get every rule. Contributor Markdown
and code comments keep dashes and headings as warnings until their
roughly 8,100 em dashes are rewritten. Released changesets stay in
.changeset/ and are not rewritten, so lint-prose.mjs lints only the
changesets added since PROSE_BASE (the PR base in CI).

The prose workflow installs a pinned, checksum-verified Vale release and
runs `pnpm lint:prose`. The rest of this change rewrites the existing
docs, READMEs, contributor Markdown, and code comments to pass the
error-level rules. Only prose and comment text changed. Renamed
headings keep their anchors.

Spelling stays with cspell, which checks identifiers that Vale does not
see.

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

* docs: keep prose lint from flattening meaning

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:48:09 +02:00
Zoltan KochanandClaude Opus 5.5 82e235bacf chore: split workspace settings into policy, catalog, and task files (#17192)
* chore: move supply-chain settings to a protected config file

Use the `include` setting from pnpm 12.15 to move the settings that
decide what gets installed and what may run into
.config/pnpm/security.yaml: allowBuilds, auditConfig, the
minimumReleaseAge and trustPolicy settings, overrides,
packageExtensions, patchedDependencies, patchesDir, and registries.
pnpm-workspace.yaml delegates exactly that list, so no other file can
define those settings. Patch paths are relative to the included file.

pnpm 12.14 ignores `include` and would drop every moved setting, so
the packageManager pin moves to 12.15.0.

CODEOWNERS now names both workspace files, the pnpmfile, and the
patches explicitly, and the CI path filters watch the new file.

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

* chore: move routine settings to a file without a code owner

The catalog, the update settings, and the task-runner settings
(pipelines, tasks, concurrencyGroups) move to
.config/pnpm/routine.yaml, which CODEOWNERS leaves unowned. Because
pnpm-workspace.yaml delegates only that list to the file, any other
setting defined there fails with ERR_PNPM_SETTING_NOT_DELEGATED, so
the file cannot be used to change the protected settings.

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

* chore: move the catalogs to their own file

.config/pnpm/catalog.yaml owns `catalogs`, which covers the default
catalog and any named catalog added later. Like routine.yaml, it has
no code owner.

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

* chore: name the protected file policies.yaml and give tasks their own file

security.yaml becomes policies.yaml. The task-runner settings
(pipelines, tasks, concurrencyGroups) move to tasks.yaml, and
`update` joins the catalogs in catalog.yaml, since its ignoreDeps list
holds back catalog entries. routine.yaml is gone.

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

* chore: move catalogMode and catalogPrune to catalog.yaml

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

* chore: keep the patch list next to the patches

patchedDependencies and patchesDir move to __patches__/patches.yaml,
so the entries name the patch files without a directory prefix and
patchesDir is `.`. CODEOWNERS already covers __patches__/. The CI path
filters that did not watch __patches__/ now watch patches.yaml, since
they watched the patch list when it lived in pnpm-workspace.yaml.

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

* chore: move the patches to .config/pnpm/patches

Every pnpm configuration file now lives under .config/pnpm, so each CI
path filter watches `.config/pnpm/**` instead of listing the files.
CODEOWNERS keeps the patches protected.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:33:59 +02:00
Zoltan Kochan ccd3e217e4 chore(bench): add Cargo repeat-install scenario to integrated-benchmark (#17132)
* chore(bench): add Cargo repeat-install scenario to integrated-benchmark

Add the cargo.repeat-install.hot-cache.hot-store scenario to
pnpm-integrated-benchmark and the CI integrated-benchmark workflow
to guard Cargo crate slot reuse (pnpm/pnpm#17105).

* fix(bench): isolate cargo repeat-install benchmark from parent workspace

* fix(bench): connect generated crates in Cargo dependency graph and verify prewarm slots
2026-10-20 11:53:52 +02:00
Zoltan Kochan 9d3b6c58ae feat(docker): publish an Alpine variant of the pnpm image (#17069)
Adds `<version>-alpine`, `<major>-alpine`, and `alpine` tags built from
docker/Dockerfile.alpine with the musl release tarball. Alpine users can
use the image as a base or copy /opt/pnpm into `node:*-alpine` without
fetching the installer from get.pnpm.io, which was returning 403 to
bursts of concurrent CI jobs.

The download, checksum, and version check move into
docker/install-pnpm.sh, shared by both Dockerfiles. The Alpine image
also installs libstdc++ and libgcc, which the musl Node.js builds
installed by `pnpm runtime` need. The Alpine build runs only for
releases that ship musl tarballs for both x64 and arm64, so v11 and
v10 releases skip it.

Every release used to publish the `latest` and `<major>` tags, so a v11
maintenance release moved `latest` back to v11. The builds now push only
the exact version tags. A final step lists the stable releases and, with
`docker buildx imagetools create`, points `<major>` at the highest
version in that major and `latest` at the highest version overall. The
Alpine tags follow the same rule. Deciding after the builds sees every
release of a burst, since lines are published seconds apart. A
concurrency group was rejected because GitHub cancels a pending run when
a third one queues. The selection lives in
.github/scripts/docker-image-tags.sh with a test run by CI, and fails on
an empty release list.

The v12 CI docs now run the Bitbucket Pipelines and GitLab CI examples
in `ghcr.io/pnpm/pnpm:12` instead of downloading the installer, and
recommend the image for CI that runs jobs in containers. CircleCI keeps
the installer because its checkout step needs git and ssh.

The CI examples that still use the standalone script fall back to the
latest pnpm/get.pnpm.io installer release when get.pnpm.io fails. They
run the script only after a download succeeds.

Related to pnpm/pnpm#16973.
2026-10-18 01:22:12 +02:00
Zoltan Kochan adb6411d85 ci(benchmark): add the store-only install against a mostly reusable lockfile (#16895)
None of the integrated benchmark's scenarios resolved against a lockfile
the walk could mostly reuse, installed store-only (`enableModulesDir:
false`), or read the per-file store index. The install regressions fixed
in pnpm/pnpm#16886, pnpm/pnpm#16888 and pnpm/pnpm#16890 all sat in that shape; the
benchmark would have missed each of them, and would miss their reversal.

The new `store-only.unlocked-direct-deps.cold-cache.hot-store` scenario
seeds the static fixture's lockfile with the direct dependencies whose
locked version carries a peer suffix left out of the importer, while
`packages` and `snapshots` keep the whole graph. That is `pnpm install`
after dependencies were added to `package.json` by hand: the missing
direct dependencies resolve from the registry, land on versions the
graph holds, and the walk reuses their subtrees. The choice of the
peered ones is deliberate: a dependency without peers is taken from the
lockfile's package list without a registry request, and a dependency
whose specifier merely changed is reused as long as the recorded version
satisfies the new range, so neither exercises the fresh pick that the
subtree reuse then follows. The metadata cache is wiped per iteration,
so every package the walk does resolve costs a round trip over the
emulated registry link; with a hot cache on local disk the whole
speculative warm-up costs about 25 ms and sits inside the noise. The
lockfile is trusted (`trustLockfile: true`): its supply-chain
verification reads every entry's packument and left nothing for the
resolution to fetch, hiding the difference entirely. With
`enableModulesDir: false` nothing is linked, so the rest of the timed
work is the check that the store holds every package, read through
`storeIndexFormat: files`.
`--no-frozen-lockfile` is passed explicitly because the runners set
`CI`, where a plain `install` is frozen and would reject the lockfile.
Only `cache-dir` is removed and the lockfile restored between
iterations; `node_modules` is never created and the warm store stays.

The scenario runs direct targets only, like the workspace fixtures: a
pnpr server would take over the resolution being measured. The
comparison script and its matrix-coverage test, the Bencher upload and
the summary list it alongside the others. Every `cleanup` arm now goes
through a `Cleanup` constructor, which keeps the method within the
function-length limit with the new arm.

Measured locally (hyperfine, 5 runs, main vs the commit before pnpm/pnpm#16886):
    main                     1.008 s +- 0.025 s   (0.991 .. 1.052 s), 513 packuments
    before pnpm/pnpm#16886            1.148 s +- 0.026 s   (1.131 .. 1.194 s), 840 packuments
2026-10-13 08:53:08 +02:00
Altay c60133d86c perf(install): speed up frozen injected workspace installs (#16824)
Avoid replacing an injected directory when its regular files are still
hardlinked to the current source and its entries match. Keep the existing
refresh path for mismatches, links, forced imports and build isolation.
Preserve import reporting and add a frozen-repeat scenario to the existing
integrated benchmark and CI comparison.

Closes pnpm/tasks#121.
2026-10-10 19:16:11 +02:00
Zoltan Kochan fdcf882dd1 chore(ci): expose staged publication diagnostics (#16776)
* chore(ci): expose staged publication diagnostics

* chore(ci): route staging diagnostics to stderr
2026-10-09 07:20:44 +02:00
2515828983 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16640)
* chore: update dependencies, Node.js, pnpm, and GitHub Actions

* chore: generate the embedded CAS loader bundle on install

The CAS loader that `deps-restorer` embeds with include_str! was a
minified esbuild bundle committed to the repo. Every enhanced-resolve or
esbuild bump rewrote most of it, and a stale copy failed CI with a
byte-by-byte assertion diff.

`@pnpm/esm-loader` now generates it from a `prepare` script, so every
`pnpm install` that includes the package writes it before cargo builds.
Cargo already depends on that install for `.pnpm/crates`. The package
gets its own esbuild devDependency instead of borrowing pnpm11/pnpm's.
The filtered installs that feed cargo (install-crates and the wasm
release job) now also select `@pnpm/esm-loader`.

Also ignore GHSA-hp3w-g68c-fv3c. sprintf-js has no patched release, and
it is reached only through argparse 1 formatting its own help text.

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

* chore: write the CAS loader bundle atomically and generate it for wasm CI

An interrupted `prepare` could leave a truncated bundle that a later
up-to-date install never rewrites. Write to a temporary file and rename.

The pnpm-wasm workflow builds the CLI after a filtered install, so it now
selects `@pnpm/esm-loader` too.

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

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 06:57:03 +00:00
Zoltan Kochan 8aec5067cc feat(install): add loaded linker with GVS exclusions (#16482)
Add an opt-in CAS installer and synchronous Node.js module loader.
Generate package-instance manifests and embed the runtime in the Rust CLI.
Load compatible package files directly from verified store blobs while retaining
ordinary complete GVS installations for explicitly materialized dependency trees.

Reuse the existing fetch, graph hashing, linking, build approval, and command shim
pipelines. Preserve loader references during store pruning and preload the loader
for normal script and command execution. Keep application filesystem APIs intact.

Document the install mode; keep compatibility experiment results in the implementation task.
Related to https://github.com/pnpm/tasks/issues/64. Future linker-specific settings and nested hoisting configuration are tracked separately in https://github.com/pnpm/tasks/issues/72. Only the loaded-linker object form is included here.
2026-10-05 13:22:21 +02:00
Zoltan KochanandClaude Opus 5.5 d4db285097 ci(docs): run the release-triggered sync from the default branch (#16534)
A release event runs the workflow file from the tagged commit, and the
sync took the release keys and verification scripts from that commit
too. Anyone able to push a tag and publish its release controlled the
checks that guard the job holding DOCS_SYNC_TOKEN.

The release event now only dispatches Sync documentation from the
default branch with the release tag, using GITHUB_TOKEN with
actions: write. The sync itself runs only on workflow_dispatch, as a
manual retry does, with the workflow, scripts and keys from main. The
docs-sync environment should be restricted to main to close the other
route to the token.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:24:24 +02:00
Zoltan KochanandClaude Opus 5.5 5567c623d5 ci(docs): sync documentation when a GitHub release is published (#16530)
Sync documentation ran on the completion of the Release workflow. The
release only stages pnpm on npm, so the publication check always failed
and every sync had to be dispatched by hand after approval.

The maintainer publishes the draft GitHub release after approving the
staged packages, so that event now starts the sync. The tag commit must
match the commit the release event names, and the npm publication check
stays.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:54:52 +02:00
Zoltan Kochan 48cea86d71 feat: publish release pages to pnpm.io from the composed changelog (#16529)
Sync documentation now carries blog/releases/<version>.md into the
pnpm.io publish commit. pnpm/pnpm.io writes the page from the changelog
section the release PR curated, read at the signed release commit, so
the release page and the GitHub release body share one source and patch
releases get pages too.

Release pages are added without clearing the directory, which keeps the
hand-written pages for earlier releases.
2026-10-02 22:01:28 +02:00
Zoltan Kochan b316d1ca15 fix(ci): handle API polling errors and canonical temp paths (#16434)
GitHub CLI can print an HTTP error response to stdout before exiting nonzero.
Appending pending inside command substitution retained that response in the
conclusion variable, which the polling loop misread as a terminal build result.
Check the command's exit status and set conclusion to pending on failure.
Preserve terminal build failure handling, polling frequency, and step timeout.
Run the workflow step with stubbed commands in CI to cover API-error recovery
and genuine build failures.

The unsaved constructor dependency test expected the temporary directory's
original spelling, but the dependency tree returns its canonical path.
Resolve the expected path with the native asynchronous API to handle Windows
short names and symlinked temp roots. The production dependency-tree behavior is unchanged.
2026-09-30 16:45:08 +02:00
Zoltan Kochan 4edeef9176 style(ts): port the perfectionist lint rules to ESLint (#16415)
Add TypeScript ports of the perfectionist rules that the Rust workspace
enforces through dylint.toml to @pnpm/eslint-config, with the same limits,
and fix every finding that needs no refactor.

The size and shape rules (function length, cognitive complexity, nesting,
local bindings, file length) are enforced for packages that already meet
them. The packages that do not are listed in PENDING_SIZE_AND_SHAPE_REFACTOR
in eslint.config.mjs and are refactored in follow-up changes.

The custom rules mirror perfectionist's semantics rather than reusing
sonarjs or max-lines-per-function, so that one limit means the same thing
in both codebases: a closure is a level of the body that contains it, a
nested function declaration is measured on its own, and a test-framework
callback plays the role of a #[test] function.

Bugs found and fixed along the way:
- a registry error body cut at exactly 64 KiB lost its truncation marker
- removing a dependency could leave dangling .bin shims
- constructor/__proto__ names crashed the projects graph, were skipped by
  the injected-deps syncer, and were dropped from writeWantedLockfile's
  returned lockfile

The CI chunk runner learns to run the node:test suite of the ESLint
config package.
2026-09-30 15:10:08 +02:00
Zoltan Kochan 15441b1e75 fix: skip documentation push when content is unchanged (#16389)
Gate documentation publication on creation of a generated commit.

An unchanged import exits the commit step successfully, but must also skip
credential lookup and pushing. Emit changed=true after a successful commit
and use it as the condition for the push step.
2026-09-29 16:36:47 +02:00
Zoltan Kochan 07839df5c3 docs: move product documentation beside its implementation (#16385)
* docs: move website documentation into the pnpm repository

* docs: keep v11 and v12 documentation beside their implementations

* docs(pnpr): keep registry documentation beside its implementation

* ci: classify product documentation as documentation changes

* test: cover product documentation in Rust CI exclusions

* ci: isolate documentation publishing and support manual sync

* test: make dependency status fixture timestamps deterministic
2026-09-29 15:56:43 +02:00
Zoltan Kochan 09bbe5baf7 fix(release): prevent ppc64le startup crashes (#16384)
The cross 0.2.5 ppc64le image uses binutils 2.26.1. It mislinks
calls to optional libc functions absent from its sysroot: the
published binary tests the dynamically resolved gettid address,
then branches to an unmapped address instead of calling it.

Let GCC retain its sysroot and library selection, but route its
linker invocation to the LLD bundled with the pinned Rust toolchain.
This fixes the weak-symbol calls without raising the glibc baseline
or adding another linker download. Scope the setting to ppc64le.

Smoke-test the actual release binary against a newer libc, where
gettid is present. Testing only against the build sysroot misses
the bug because Rust takes its syscall fallback there.

Closes pnpm/pnpm#16380.
2026-09-29 14:18:07 +02:00
Zoltan KochanandClaude Opus 5.5 c4ecac2da2 chore(github): ask issue authors without the fix checkbox about a PR (#16271)
* chore(github): ask issue authors without the fix checkbox about a PR

Issues filed through `gh issue create --body` or the API skip the issue
form, so they never carry the "I am working on a fix" checkbox. When the
"Contributing a fix" section is missing from the body, the triage
workflow now comments asking the author whether they plan to open a
pull request. The regression form gets the same checkbox, so its
reports are not asked.

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

* test(github): cover the issue fix-intent classifier

The classifier moves from the triage workflow into
.github/scripts/issue-fix-intent.sh, with a test that CI runs next to the
other workflow script tests. The workflow checks out the default branch
before the step so the script is available.

A "Contributing a fix" heading without its checkbox now counts as
missing. A hand-written body containing only the heading was classified
as unchecked and got neither an assignment nor the question.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:24:16 +02:00
3172a576b7 fix: statically link CRT for windows-msvc pnpm binaries (#15853)
The published Windows pnpm.exe linked VCRUNTIME140.dll, so it exited
0xC0000135 on a clean Windows install. The Rust release job now passes
-C target-feature=+crt-static when building the CLI for
*-pc-windows-msvc. The NAPI cdylib build is unchanged, including the
musl -crt-static flag.

The release verification job rejects a Windows pnpm.exe that still
imports that DLL.

Closes https://github.com/pnpm/pnpm/issues/15723

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 12:16:54 +02:00
Zoltan KochanandClaude Opus 5.5 50364eee27 ci: keep pnpm crate READMEs out of the Rust CI trigger (#15402)
pnpr/crates/*/*.md was already excluded from the rust filter, while the
matching Markdown under pnpm/crates still ran the whole Rust suite on
three platforms. No build step or test reads those files. The docs
filter gains the same pattern, so the spell check still runs on them.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 20:14:45 +02:00
15da9f3786 perf(ci): link pnpr tests once, run Garnet once, and trim CI triggers (#15361)
Link pnpr's integration tests as one binary with the shared helpers
declared once, run Garnet on one TS chunk, keep Markdown out of the Rust
CI and benchmark triggers while still spell-checking it, and build the Linux pnpr fixtures on 16 vCPUs
while the Linux TS chunks start and wait for them.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 18:49:41 +02:00
Efe Baran Durmaz b04c656cc2 perf(ci): split, balance and cache CI work (#15300)
Split TypeScript tests into three chunks per Node.js version on Linux and
five on Windows, balanced by recorded Jest durations, and start the
Windows chunks while their pnpr fixtures build. Skip Jest coverage in CI,
which nothing reads. Keep Rust sources from widening the TypeScript test
scope.

Cache Rust compiler output with sccache on Linux and macOS, because
rust-cache prunes every dependency of this workspace, and run Rust
coverage on 8 vCPUs with its own compiler cache. Save at most one cache
entry per scope and day.

Build the pnpr fixtures without fat LTO, at opt-level 1, on every push to
main and on 16 vCPUs for Windows. Avoid obsolete PR work, full-history
benchmark build checkouts and test-only network backoff. Keep all
platforms, Node.js versions, merge-queue validation, production retry
defaults, and the release and benchmark build profiles.
2026-09-23 12:15:08 +02:00
Zoltan Kochan 3450bb8fa7 fix(ci): confirm benchmark regressions with reversed target order (#15231)
Confirm suspected integrated benchmark regressions once with target order
reversed. Same-run measurements can still be biased by sustained runner drift:
a control run on identical Rust sources produced a 29% apparent pnpr slowdown.

Keep the 5% tolerance with a 2 ms floor and the retained-sample noise guard.
Require the regression to reproduce in the confirmation, preserve both sets
of measurements in the artifact and report, and keep the initial timings for
historical Bencher uploads. Missing required confirmations fail the check.

The wrapper preserves the existing harness arguments and assertions. It does
not retry command failures, and confirmation failures propagate. Main-only
runs and scenarios without suspected regressions execute once.

Related to pnpm/pnpm#15228.
2026-09-21 21:35:41 +02:00
Zoltan Kochan bd4d526530 fix(ci): compare integrated benchmarks on the same runner (#15228)
Compare integrated benchmark samples against main measured on the same runner.
Keep absolute minimum timings in Bencher for historical tracking without letting
cross-machine historical alerts overwrite the PR regression check.

Require at least nine successful samples per target. Fail when the median
slowdown and retained sample separation both exceed 5% of main's median or
2 ms, whichever is larger. Trim up to 10% from each tail. Report other median
slowdowns above that tolerance as inconclusive. This conservative noise guard
is not a statistical confidence interval; smaller or noisy regressions can pass,
and sequential measurements remain vulnerable to runner drift.

Run the comparison from trusted default-branch code in the privileged comment
workflow, publish the report before enforcing the result, and preserve the
existing check name on the triggering PR commit. Keep the peer-heavy
Rust-versus-TypeScript assertion unchanged.

Cover regressions, shared machine slowdowns, outliers, invalid data, all scenario
and engine combinations, command names, CLI exit codes, and the duration-dependent tolerance with Node tests.
Keep the explanation in the existing benchmark documentation.
2026-09-21 20:54:20 +02:00
Zoltan Kochan 224aed744b refactor: move cmd-shim into the pnpm monorepo (#14893)
Import cmd-shim source, tests, and snapshots from pnpm/cmd-shim at
83f9b9449c2adeec26e1cc2d03ef0fe82d2e41ca. Maintaining the shim alongside
its consumers removes the need for coordinated changes across repositories.

Publish the package as `@pnpm/bins.cmd-shim` and replace external dependencies
with workspace links. Preserve the original BSD-2-Clause license, including
its copyright notice, and keep the manifest updater from replacing it with MIT.
Reuse `@pnpm/fs.graceful-fs` and integrate the existing Node.js tests with the
workspace test scripts. Retain the existing snapshots and align the version
with the TypeScript workspace's required 1100.x band.
2026-09-14 21:30:59 +02:00
Zoltan Kochan d2c5ecbb63 chore(ci): run checks through pnpm pipelines (#14690)
Declare CI pipelines and root task scripts, and invoke them from the
TypeScript, Rust, reusable test, and pnpr build workflows. Let pipelines
perform frozen installs and order TypeScript compilation before linting.

Keep existing test runners responsible for affected-package selection,
file-level sharding, and summary generation. Read shard settings from the
workflow environment, with explicit command-line arguments taking precedence.

Run root tasks with --include-workspace-root --full: the scripts live in the
root manifest only, and the test runners already select their own scope. Pass
--no-cache so a task that later declares outputs cannot skip a check.

Keep the dependency install in its own step in the two jobs whose commands are
timed for Bencher, so the reported duration stays a test duration. Preserve
existing job gates and artifact handoffs.
2026-09-10 21:05:01 +02:00
Zoltan Kochan 949c8d3b62 ci(release): retry cross builds on transient failures (#14522)
The v12.3.2 release run died in "Package pnpm-napi darwin-x64" because
Apple clang segfaulted while linking the httparse build script. Nothing
in the tree changed; the same Blacksmith image built v12.3.1 fine the
day before. Every other packaging job was cancelled and the release had
to wait for the run to finish before "re-run failed jobs" was possible.

Route the three release cross builds through a wrapper script that
retries up to three times. Cargo keeps the crates a failed attempt
finished, so a retry only redoes the crate that died.

The Windows legs of build-rust and build-pnpr now run the build step
under bash instead of the default pwsh, as the napi packaging job
already did on both Windows targets. The clang-cl environment for
win32-arm64 is exported through GITHUB_ENV and GITHUB_PATH, so it
reaches bash the same way.
2026-09-04 03:12:51 +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 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 Kochan 5819fc671e chore(release): drop the packing workarounds and pin pacquet 12.0.0-alpha.19 (#13241)
* chore(release): drop the packing workarounds now that pacquet 12.0.0-alpha.19 is pinned

The pinned pacquet now carries the fs-packlist fix from
https://github.com/pnpm/pnpm/pull/13231, so a files allowlist wins over
workspace-inherited ignore rules and the release workflow no longer
needs to neutralize them: remove the empty pnpm11/pnpm/.npmignore
override, the temporary root .gitignore shadow, and the pre-publish
payload verification step (with its script) that guarded against the
now-fixed empty-tarball packing bug. The payload-verify step was also
what broke the v11.17.0 release: its filtered pn list fired a
verifyDepsBeforeRun auto-install that pruned the excluded pnpm
project's node_modules, so the darwin-arm64 artifact's prepublishOnly
could no longer resolve symlink-dir.

`@pnpm/prepare` and `@pnpm/prepare-temp-dir` were the only
publishable packages without a files allowlist; their lib/ payload
survived packing only through the .gitignore shadow. Give them files
allowlists so their tarballs no longer depend on workspace ignore
state.

* chore: record the pacquet 12.0.0-alpha.19 pin in the lockfile

* chore: drop the changeset - both files-allowlist fixes ship without a new version

The pending `@pnpm/prepare` 1100.0.22 is not on npm yet, so the rerun
of the v11.17.0 release publishes it with the files allowlist already
in place. `@pnpm/prepare-temp-dir` 1100.0.1 is already published with
correct tarball content (packed under the .gitignore shadow), so its
manifest-only change needs no republish. A changeset would only
schedule a patch release whose sole delta is the manifest field.
2026-07-23 18:13:15 +02:00
Mark Xian a1ae5b85f1 fix(release): verify internal package payloads before publish (#13185)
Pack every publishable workspace package in dry-run mode before the
first immutable npm publish and verify each reported file list against
the manifest-declared payload (files, main, module, types, exports,
browser, bin, publishConfig.executableFiles). A packing regression like
the one that shipped nearly-empty lib tarballs for five releases
(pnpm/pnpm#13164) now fails the release job before anything publishes.

The verification is one pn compile-only (pack does not run
prepublishOnly), four concurrent `pnpm pack --dry-run --json` chunks
(recursive pack packs one project at a time and, unlike recursive
publish, does not skip private packages — so publishable projects are
selected by explicit name filters), and a single node pass over the
reported file lists. No tarballs are written or read.

Also give @pnpm/modules-mounter.daemon the lib/index.js entry point its
manifest declares; the verifier caught that it never existed.

Fixes pnpm/pnpm#13179
2026-07-23 15:32:12 +02:00
Zoltan Kochan 25da8c8cde chore: update package manager to pnpm v12 (#12811) 2026-07-10 00:49:52 +02:00
Zoltan Kochan e42c2f23cb ci: shard Windows TS tests (#12612)
Run Windows TypeScript test jobs only on Node.js 22 and split them into three parallel chunks.

Windows TS tests are significantly slower than Linux, and running the full suite on three Node versions spends the extra capacity on duplicate runtime coverage instead of reducing wall clock time. The reusable test workflow now accepts chunk inputs, includes chunk identity in concurrency and artifact names, and keeps Bencher uploads with chunk-specific benchmark names.

Add a CI helper that discovers the selected workspace packages for the same full or affected test scope, shards Jest test files into balanced chunks, runs selected package files with the same Jest Node options and package pretest setup, and writes pnpm-style execution summaries so the pnpm CLI e2e duration extraction still works.
2026-06-24 02:08:56 +02:00
Zoltan Kochan 9ddc86b635 ci: track test suite durations in bencher (#12404)
## Summary

Adds CI duration tracking for the `pnpm-ci-performance` Bencher project.

Tracked Rust testbeds and benchmarks:

- `pacquet.ubuntu`, `pacquet.windows`, `pacquet.macos` -> `tests.all`
- `pnpr.ubuntu`, `pnpr.windows`, `pnpr.macos` -> `tests.all`

Tracked pnpm testbeds and benchmarks for full test runs:

- `pnpm.ubuntu.node22`, `pnpm.ubuntu.node24`, `pnpm.ubuntu.node26` -> `tests.all`, `tests.cli`
- `pnpm.windows.node22`, `pnpm.windows.node24`, `pnpm.windows.node26` -> `tests.all`, `tests.cli`

The test workflows produce Bencher-compatible JSON artifacts without receiving `BENCHER_API_TOKEN`. A separate `workflow_run` workflow downloads those artifacts only for same-repository runs, validates their metadata, and uploads from trusted workflow code using the existing `BENCHER_API_TOKEN` secret. The pnpm CLI e2e duration is extracted from `pnpm run --report-summary` output during the same full-test execution, so the CLI e2e suite is not run a second time.
2026-06-14 18:44:17 +02:00