Commit Graph
560 Commits
Author SHA1 Message Date
Zoltan Kochanandgithub-actions[bot] 901f2438e0 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#17217)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-23 10:35:07 +02: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 78365b06ce chore: require code-owner review for tasks.yaml (#17197)
The pipelines decide what each CI job runs, and `pnpm pipeline`
reports a pipeline whose script does not exist as skipped and exits 0.
The task settings also control ordering and the cache keys of the
remotely cached jobs. An unowned tasks.yaml could therefore turn a CI
check into a no-op without code-owner review.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 15:10:24 +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 Kochanandgithub-actions[bot] 87636f932c chore: update dependencies, Node.js, pnpm, and GitHub Actions (#17191)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-21 14:08:06 +02:00
Zoltan Kochan 890d7c777a test: expand equivalence, convergence, and v11/v12 differential harnesses (#17183)
Complete the test harness requirements of pnpm/tasks#141 (including the
deferred cross-version switch matrix from pnpm/tasks#144 and
injected-freshness convergence/differential checks from pnpm/tasks#148):

1. Equivalence and convergence harnesses:
   - Extract shared `TreeView`, `workspace_lockfiles`, and normalized
     `workspace_modules_manifests` helpers into
     `pnpm/crates/cli/tests/suite/_utils/mod.rs`.
   - Include `.modules.yaml` in `repeat_install_oracle` snapshots and
     assert convergence after every scenario (second install snapshot
     byte-identity, `--frozen-lockfile` acceptance, `dedupe --check`,
     and quiet repeat `exec` under `verifyDepsBeforeRun=install`).
   - Add `check_repeat` (second install byte-identity) and
     `check_run_gate` (`verify-deps-before-run=error` exec gate) to
     `peer_convergence::harness::check_row`.
   - Add repeat-install lockfile byte-identity,
     `verify-deps-before-run=error` run-gate checks, `dedupe --check`,
     and `PNPM_V11_BUNDLE` differential lockfile comparison to
     `injected_freshness_matrix::check`.

2. v11/v12 differential suite (`pnpm_compatibility.rs`):
   - Honor `PNPM_V11_BUNDLE` in `CommandTempCwd::init()` so integration
     tests no longer require a system-installed pnpm v11 on `PATH`.
   - Un-ignore `store_usable_by_pnpm_offline` and
     `same_global_virtual_store_layout_with_approved_postinstall`.
   - Compare wanted lockfiles, current lockfiles, `.modules.yaml`,
     `node_modules` resolution tree, cross-CLI frozen handoffs, and
     registry request logs across shared/dedicated workspace lockfiles,
     isolated/hoisted `nodeLinker`, `injectWorkspacePackages`,
     `autoInstallPeers`, `dedupePeerDependents`, and filtered installs.

3. Upward cross-version switch harness and nightly matrix:
   - Add `switches_up_to_a_newer_pnpm_across_setting_sources_and_unknown_options`
     and `v11_switches_up_to_head_binary_from_local_registry` in
     `version.rs` using a local `pnpr` registry populated with
     synthetic `@pnpm/exe` platform packages.
   - Add `.github/workflows/version-switch-matrix.yml` to run the
     outer-pnpm x pin x setting-source x platform matrix nightly and on
     `workflow_dispatch`.
   - Wire `pnpm_compatibility`, `injected_freshness_matrix`, and upward
     version-switch tests into the `convergence` job of
     `.github/workflows/pacquet-ci.yml`.

Closes pnpm/tasks#141
2026-10-21 07:17:04 +02:00
Zoltan Kochan 7164fc7f27 fix: finish repeat-install and verifyDepsBeforeRun unification across v11 and v12 (#17150)
Unify repeat-install freshness and `verifyDepsBeforeRun` validation across
pnpm v11 and v12 (Closes pnpm/tasks#161, pnpm/tasks#157, pnpm/tasks#148):

1. Centralize v11 workspace state updates in `@pnpm/workspace.state`
   (`preserveCarriedSettings`) and `@pnpm/installing.commands`
   (`workspaceStateUpdate.ts`), preserving carried `dev`/`optional`/`production`
   settings when `ignoredWorkspaceStateSettings` ignores them and preserving
   v12-recorded `autoDedupe`. A filtered install that prunes direct
   dependencies no longer records the workspace root as installed.
2. Hold `{.}...` workspace dependencies for non-recursive `pnpm run`,
   `pnpm exec`, and `pnpm restart` inside a workspace project in v11
   (`selectProjectsToVerify.ts`).
3. Align v11 recorded validation (`checkRecordedWorkspace`) and legacy
   unrecorded validation (`checkModifiedSinceLastValidation`) in
   `@pnpm/deps.status` with v12's `check_freshness`, including empty-project
   handling, `dedupeDirectDeps`, `dedupePeerDependents`, `autoInstallPeers`,
   `excludeLinksFromLockfile`, catalog/override config comparison, and
   `opts.lockfileDir` resolution.
4. Forward effective CLI flags (`--lockfile-dir`, `--modules-dir`,
   `--virtual-store-dir`, `--store-dir`, `--dir`, `--workspace-root`, `--prod`,
   `--dev`, `--no-optional`, `--filter`, `--filter-prod`, `--test-pattern`,
   `--changed-files-ignore-pattern`, and `--config.*`) when
   `verifyDepsBeforeRun: install` spawns `pnpm install` in both v11 and v12.
5. Align `GatePolicy::dedupe_peers` and empty-project predicates in v12
   `pnpm-package-manager`, and run `repeat_install_oracle.rs` across v12, v11,
   and mixed v11/v12 writers in CI, with a longer nextest period for the
   peer convergence harness that shares the job.
6. Parse `--config.<key>=<value>` with the type the command declares for
   `<key>` in v11, so the list and number options forwarded to the spawned
   install arrive as lists and numbers; forward `--npmrc-auth-file` in v11
   and `--test-pattern` / `--changed-files-ignore-pattern` in v12, so both
   forward the same set; and skip the current-lockfile read for a project
   whose manifest changed but whose lockfile did not, as v12 does.
7. Resolve relative v11 store overrides against the workspace or project
   root before forwarding them to the spawned install. Remove the isolated
   linker's duplicate package merge so filtered installs retain unselected
   dependencies and drop obsolete selected dependencies from the current
   lockfile. Cover both cases with CLI regressions. The restore API also
   handles a selected project absent from the previous current lockfile.
8. Record workspace validation from the projects the installers actually
   processed. Ignored projects receive no new proof, and empty or entirely
   ignored selections leave state untouched. Cover both lockfile modes and
   an ignored workspace root.
2026-10-20 20:24:27 +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 4aafdb407c test(cli): run the peer convergence harness through pnpm v11 and v12 in CI (#17103)
With `PNPM_V11_BUNDLE` naming the pnpm v11 bundle, the peer convergence
harness also runs every fixture through v11, apart from the rows that
set the v12-only `autoDedupe`, and each row's fresh v11 lockfile has to
equal the v12 one. v11 gets every check the harness makes, so a
convergence bug no longer has to be confirmed on v11 by hand.

A Rust CI job builds the v11 bundle and runs the harness this way on
changes to the resolution, lockfile, install and deploy code of either
stack. The success gate requires it.

pnpm/pnpm#17094 is tracked as a divergence only v11 shows.

Related to pnpm/tasks#143
2026-10-18 21:18:59 +02:00
573c4d1e8e fix(pnpr): gate server-only error variants behind server feature (#16972)
pnpr-error depended on axum, bcrypt, object_store, reqwest, rusqlite,
serde_json, tokio and tracing on every non-wasm target. pnpm-config depends
on pnpr-registry for Ecosystem and PackagePattern, and pnpr-registry and
pnpr-package-name both depend on pnpr-error, so every consumer of pnpm-config
compiled and linked the registry server's HTTP, storage and auth crates.

- pnpr-error: those dependencies are optional and enabled by a new `server`
  feature. The response module (IntoResponse, public_message, log_kind) and
  the Upstream, Bcrypt, Sqlite, JoinError, ObjectStore and Json variants are
  gated on it, replacing the cfg(not(target_family = "wasm")) gate.
- The pnpr crates that use those variants or the response rendering (auth,
  osv, pipeline-runs, pnpr, search, shared-artifacts, storage, upstream)
  enable `server`. pnpr-config only builds InvalidConfig and does not.
- pnpr-registry drops its unused pnpr-error dependency.
- pnpr-package-name tests compare Display output instead of
  public_message(), so they pass without the server feature.
- Three workflow_run workflows carry their zizmor ignore directive on the
  trigger line. zizmor did not apply the standalone comment, which failed the
  zizmor job on fork PRs.

Closes pnpm/tasks#134.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:45:10 +02:00
Zoltan Kochanandgithub-actions[bot] 8e8ffe85ad chore: update dependencies, Node.js, pnpm, and GitHub Actions (#17076)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-18 10:04:23 +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 Kochanandgithub-actions[bot] 1a4d9bf626 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#17018)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-17 09:46:23 +02:00
Zoltan KochanandClaude Opus 5.5 902b4a8efd fix(ci): update zizmor-action to v0.7.1 (#16995)
zizmor 1.31.0 stopped applying ignore comments to the dangerous-triggers
audit, so the three workflow_run workflows failed the zizmor check on
every fork pull request. zizmor-action v0.7.1 defaults to zizmor 1.31.1,
which fixes the regression.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:56:00 +02:00
Zoltan Kochanandgithub-actions[bot] 3876e3f975 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16965)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-16 11:25:40 +02:00
Zoltan Kochanandgithub-actions[bot] 3a1a9b1797 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16948)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-15 11:15:32 +02:00
Zoltan Kochan 607ed0a0e9 test(cli): give the update notice install a dependency to outlast the check (#16913)
Since the update check no longer holds the command (pnpm/pnpm#16902),
two suite tests that depended on the wait fail.

The notice test installed an empty workspace, which is done in
milliseconds, so the install finished before the registry answered the
check. It now installs a dependency, as the add tests in the same module
do, so the check's request, which is in flight before the install's
first, is answered while the install still has work.

The Rust test runner sets PNPM_CONFIG_CI=false, so a pnpm spawned
without the shared command harness ran the daily check against the
runner's un-isolated state directory. While the command awaited the
check, the first such pnpm recorded it and every later one skipped it.
Now an unanswered check is dropped unrecorded, so every bare pnpm asked
its mock registry for pnpm's latest, and a test whose public mock
forbids any request failed. The runner and the coverage workflow now set
PNPM_CONFIG_UPDATE_NOTIFIER=false as well; the notifier suite turns the
check back on itself.
2026-10-14 00:30:52 +02:00
Zoltan Kochanandgithub-actions[bot] 3c76f7b72e chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16896)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-13 08:53:54 +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
Zoltan Kochanandgithub-actions[bot] 95fc851c75 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16864)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-12 11:25:04 +02:00
Zoltan KochanandClaude Opus 5.5 77186e6172 docs: remove users list page (#16848)
* docs: remove users list page

* ci(docs): build against pnpm.io with the users page redirect

check-urls failed because /users is no longer built. pnpm.io now
redirects it to the home page.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:21:38 +02:00
Zoltan Kochanandgithub-actions[bot] 3994543da9 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16841)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-11 10:51:07 +02:00
Zoltan Kochan 27be1a9a5a ci: share Rust Clippy and Doc results through Vercel Remote Cache (#16837)
The Clippy and Doc tasks declare `outputs: []`, so `pnpm pipeline` caches
their results, keyed on every file in the repository plus `RUSTFLAGS` (and
`RUSTDOCFLAGS` for Doc). Their jobs no longer pass `--no-cache`.

A new `remote-cache` composite action points the pipeline at Vercel Remote
Cache. It runs only in the merge queue and on pushes to main, which also
sign and publish their results, so the Vercel token never reaches pull
request code. The push to main tests the tree the merge queue already
tested, so its Clippy and Doc rows restore the results instead of
recompiling. The action does nothing until the token, team, and public key
are configured.

The credentials live in the remote-cache environment, which only main and
the merge queue branches can use, so a workflow on a pushed branch cannot
read the signing key.

Dylint keeps `--no-cache`: its run on main saves the build cache pull
requests restore, and a cache hit would leave that cache stale.
2026-10-10 23:08:03 +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 Kochanandgithub-actions[bot] a8a47d3c0e chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16819)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-10 13:42:52 +02:00
Zoltan Kochan 52fd8d8a1b ci: run dylint as a pnpm pipeline again (#16798)
pnpm runs scripts with the workspace toolchain first on PATH, the way it
puts a pinned Node.js first. cargo-dylint needs rustup itself: it runs the
`rustup` binary and builds its lint library with the nightly the library
pins, which only rustup's cargo selects. That is a requirement of the one
tool, so the dylint script asks for rustup's proxies instead of pnpm
changing how it runs Rust for every script.

pnpm/scripts/cargo-dylint.mjs runs `cargo dylint` from the first PATH
directory that holds both rustup and cargo, with that directory first on
PATH. The ci:rust-dylint script, the rust-dylint pipeline and its cargo
concurrency group come back, and CI runs the pipeline again, which also
installs the esm-loader bundle the crates embed, so its separate install
step goes. The pre-push hook calls the same helper in place of its own
PATH edit.

CONTRIBUTING.md no longer says pnpm install needs cargo on PATH: pnpm runs
cargo metadata from the toolchain it installs for rust-toolchain.toml.
2026-10-09 17:33:21 +02:00
8778146f56 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16781)
* chore: update dependencies, Node.js, pnpm, and GitHub Actions

* ci: run the wasm nightly through pnx and dylint through rustup

pnpm 12.11 runs scripts with the toolchain from rust-toolchain.toml first
on PATH, so `cargo +nightly-2026-08-27` reached a plain cargo that does not
know the `+toolchain` syntax. The wasm and runtime-probe builds now run
`pnx --package=rust@nightly-2026-08-27 cargo`, which installs the nightly
with the wasm target, so the rustup install and the job-wide
RUSTUP_TOOLCHAIN go.

cargo-dylint builds its lint library through the rustup proxies, which
pick the nightly the library pins and set RUSTUP_TOOLCHAIN for
dylint-link. Under pnpm it got the workspace's stable cargo instead. CI
now runs `cargo dylint` directly, as `just dylint` does, and the unused
pipeline goes. The pre-push hook, which runs as a pnpm script, puts the
directory holding `rustup` first on PATH for its dylint check.

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

* ci: bundle the esm loader before the dylint check

`pnpm-deps-restorer` embeds `cas-loader.mjs.inc`, which the prepare
script of `@pnpm/esm-loader` generates. `pnpm pipeline` installed it
implicitly; the direct `cargo dylint` run needs the install as a step.

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-09 15:09:32 +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
Zoltan Kochan 7e4db25f84 feat(pnpr): serve the web UI at /-/ui/ (#16769)
pnpr now serves its web UI at /-/ui/ from the same origin, so the UI
needs no CORS setup and no server URL. The UI ships as the separate
`@pnpm/pnpr-ui` package, an optional peer dependency of `@pnpm/pnpr`.
pnpr finds it next to its own package (npm and pnpm both link a resolved
peer beside the package that declares it), or reads it from `ui.dir`,
and `ui.enabled: false` turns it off.

- Serving: files from the UI directory, `index.html` for every other
  path outside `assets/`, a 404 for a missing hashed asset. The page
  gets a relative `<base>` so deep routes and path prefixes work without
  an absolute Vite base. Responses carry a CSP that keeps scripts and
  requests on this origin.
- The UI source stays on bit.cloud. `pnpr/ui` is a workspace of its own
  that pins `@pnpm/pnpr.apps.pnpr-web` from bit.cloud's registry and
  builds it into `pnpr/npm/pnpr-ui/dist`.
- Release: a `build-pnpr-ui` job builds the bundle. The verify and
  publish jobs download it. The smoke test installs the UI beside the
  wrapper and checks that pnpr serves it. `@pnpm/pnpr-ui` releases in a
  fixed group with `@pnpm/pnpr`.
2026-10-09 00:56:04 +02:00
Zoltan Kochan 5750517f25 docs: update FUNDING.yml to remove custom links (#16736)
Removed custom funding links from FUNDING.yml
2026-10-08 15:10:42 +02:00
Zoltan Kochanandgithub-actions[bot] 21c234428f chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16722)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-08 09:55:05 +02:00
Zoltan Kochanandgithub-actions[bot] 496217e397 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16671)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-06 19:41:51 +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 Kochanandgithub-actions[bot] 146b66d3a0 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16574)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-05 11:15:30 +02:00
Trevor Burnham fca2d32621 ci(release): build the Linux CLI without forced unwind tables (#16565)
rustc emits unwind tables on Linux even under panic = "abort". The CLI
never unwinds, so pass -C force-unwind-tables=no to its Linux release
builds. The NAPI addon builds with panic = "unwind" and keeps them.

The flag goes in CARGO_TARGET_<TRIPLE>_RUSTFLAGS rather than RUSTFLAGS:
Cargo appends it to the ppc64le rustflags in .cargo/config.toml, while
RUSTFLAGS would replace them and drop the LLD workaround. cross forwards
CARGO_* variables into its container.

Measured on fat-LTO release builds of pnpm-cli:

- aarch64 gnu: 48.48 MB to 47.42 MB, .eh_frame 2.60 MB to 1.53 MB,
  gzip -185 KB.
- aarch64 musl: -0.98 MB.
- x86_64 gnu and musl: unchanged. Fat LTO merges in std's bitcode, and
  LLVM's x86 backend then emits the same frame info for every function.

On aarch64 every FDE remains, but without uwtable LLVM writes only the
prologue's unwind info, so each entry is smaller. Panic messages, exit
codes and RUST_BACKTRACE output are unchanged.
2026-10-05 00:51:11 +02:00
bac8077715 chore: update dependencies, Node.js, pnpm, and GitHub Actions (#16373)
* chore: update dependencies, Node.js, pnpm, and GitHub Actions

* fix(deps): hold `@yarnpkg/core` at 4.9.1

`@yarnpkg/core` 4.9.2 was published with `got` declared as a Yarn
`patch:` specifier. pnpm resolves that to a `link:` into a nonexistent
workspace path, so `got` is missing and the TypeScript compile fails
with TS2307 in `@yarnpkg/core/lib/httpUtils.d.ts`.

Pin the catalog entry back to 4.9.1, override the transitive copy that
`@yarnpkg/nm` pulls in through `^4.9.1`, and add the package to
`update.ignoreDeps` so the daily update-lockfile run stops bumping it.

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-03 23:06:01 +02:00
Zoltan KochanandClaude Opus 5.5 b6cf8497d6 ci(release): unpack each verified tarball once (#16540)
* ci(release): unpack each verified tarball once

The release verify jobs compared every payload file against the packed
tarball with one `tar -xOf` per file, which decompresses the whole
tarball each time. Since the WebContainer runtime added dist/wasm (a
47 MB pnpm.wasm plus about 600 files) to both the pnpm and `@pnpm/exe`
wrappers, that loop runs for more than ten minutes. Unpack each tarball
once and compare files with cmp.

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

* ci(release): reject payload paths outside the package

With the tarball unpacked once, a files entry with enough .. segments
resolves to the same outside file on both sides of cmp and passes.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:22:01 +02:00
Zoltan Kochan ef7d3c5e33 fix: publish the WebContainer runtime as @pnpm/wasm (#16544)
The 12.9.0 release bundled the 47 MB WebAssembly build and its runtime
dependencies into the `pnpm` and `@pnpm/exe` wrappers, so every native
install downloaded about 55 MB to run a binary that never uses it.

The runtime now publishes as its own package, `@pnpm/wasm`, which provides
the `pnpm`, `pn`, `pnpx`, and `pnx` bins. `pnpm/wasm/stage.mjs` writes it to
`pnpm/npm/wasm`, and the release stages it with the native packages. The
wrappers no longer carry `dist/wasm`. In a WebContainer their launchers
exit with an error that names `@pnpm/wasm`, and `install.js` leaves the
Node launchers in place instead of linking a native binary there.

The browser test now covers the `@pnpm/wasm` tarball installed locally and
globally, including the bin aliases and `npx` dispatch. The wrapper and
Corepack modes are removed, since the wrapper no longer runs in
WebContainers.
2026-10-03 17:52:52 +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 658dbc30a6 feat: support pnpm in StackBlitz WebContainers (#16499)
Compile the shared Rust CLI for wasm32-wasip1-threads and supply filesystem,
network, process, terminal and cancellation capabilities through a Node host.
Select host implementations at compile time so native builds retain their
native dependency/features and execution paths.

Bundle the WASM runtime in the regular npm wrappers and select it from the
WebContainer runtime marker. Keep Node launchers usable without installation
scripts. Native installation replaces all four launchers with native bytes.
Regenerate shims after upgrades or dependency builds replace Node targets with
native binaries, including before dependent lifecycle scripts run. Preserve
collision winners and publish replacement shims with executable permissions.
Reject non-descendant permission templates and intermediate symlink escapes, validate before creating directories, and avoid path-based cleanup races.
Restore direct native aliases in both version-management implementations.
Retain process cleanup after failed stdin shutdown. Prevent cross-origin redirects from replaying login credentials in both CLI lines, and strip npm-otp from cross-origin WASM requests. Avoid repeated selected-snapshot and removed-bin scans.

Preserve resolution, lockfile, integrity and build-approval behavior. Use an
isolated WASM store with rollback journals and process leases. Patch WASI path
normalization for multiple parent segments and retain that patch in bundles.

Add pinned tooling, release packaging, real-browser workflow and selection
tests, documentation and a release note. Document host limits, including the
Corepack cold-download failure in WebContainer's streaming hash implementation.
Controlled native CLI cases showed no separated slowdown, and the latest
hoisted rebuild and repeat-install fixture improved. Retain the documented
microbenchmark uncertainty and host limitations.

Related to pnpm/tasks#63.
2026-10-02 10:32:41 +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 KochanandClaude Opus 5.5 f46c6c67c6 fix(release): run the ppc64le smoke test outside the checkout (#16414)
The root package.json pins packageManager to pnpm 12.8.1, so the freshly
built 12.8.2 binary handed off to the pinned x64 pnpm under qemu-ppc64le
and failed with an exec format error, blocking the v12.8.2 release.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:06 +02:00
Zoltan KochanandClaude Opus 5.5 8b906af900 test: run pnpm in a StackBlitz WebContainer on the ecosystem e2e cron (#16260)
* test: run pnpm in a StackBlitz WebContainer on the ecosystem e2e cron

WebContainers run Node.js in the browser, and their fs errors and
node:sqlite differ from Node.js in ways no local test reproduces. Two
such differences broke pnpm install there (pnpm/pnpm#15649).

The new harness boots a WebContainer in headless Chromium through
`@webcontainer/api`, mounts the files the published pnpm package ships,
and runs install without a lockfile, a repeat install, a reinstall from
the store, add, remove, and list, failing on any non-zero exit. It
lives next to the Rust ecosystem-e2e harness, and a webcontainer job in
the same daily workflow runs it against the bundle the build job makes.
It needs StackBlitz's servers, so it stays off the per-PR checks.

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

* test(webcontainer-e2e): open the page on the address the server listens on

The server binds 127.0.0.1, while the page was opened at localhost,
which reached it only through Chromium falling back from ::1.

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

* test(webcontainer-e2e): reinstall offline and check the removal

A reinstall that could reach the registry passed even when the store
index was unreadable, and a remove that left is-odd in place passed too.
The reinstall now runs with --offline, and a new step checks that is-odd
left package.json and no longer resolves. The server helper now rejects
when it cannot listen and documents that.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:04:19 +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