Commit Graph
65 Commits
Author SHA1 Message Date
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 Kochanandgithub-actions[bot] 91774e72a0 chore(release): 11.28.7, pacquet 12.15.0, pnpr 0.1.0-alpha.16 (#17187)
* chore(release): 11.28.7, pacquet 12.15.0, pnpr 0.1.0-alpha.16

* docs(release): curate 11.28.7, pacquet 12.15.0, and pnpr 0.1.0-alpha.16 release notes

Add lead paragraphs and group the patch entries by what the reader was
doing, with security fixes first on each page.

- v11: lead with the registry metadata name check, pinned pnpm
  trustPolicy check, maxTarballUnpackedSize, and the removal of registry
  revisions; merge overlapping entries for minimumReleaseAge metadata
  revalidation, frozen-lockfile directory dependency checks,
  syncInjectedDepsAfterScripts, verifyDepsBeforeRun, pnpm sbom, and
  unreadable config settings.
- v12: order minor highlights from config includes and
  lockfile.integrityTarget down to interactive update styling; drop the
  pnpr-only distribution note from the CLI changelog; merge overlapping
  entries for workspace and pnpr install speedups, minimumReleaseAge and
  If-Modified-Since revalidation, frozen-lockfile and injected package
  checks, verifyDepsBeforeRun, pnpm prune, pnpm pack, pnpm licenses
  list, pnpm self-update, pinned pnpm flag forwarding, and WebContainer
  fixes.
- pnpr: lead the minor section with the breaking ecosystem URL prefix,
  hosted storage layout, artifacts.orgs, and strict config schema
  changes; fold dist.pnpr tarball metadata into one entry and drop the
  redundant /metrics note; lead the patch section with reserved-username
  and auth security fixes.
- Use one issue-link label style across the release pages.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-10-21 12:15:12 +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
fe4a0c2323 chore(release): 11.28.6, pacquet 12.14.0 (#16952)
* chore(release): 11.28.6, pacquet 12.14.0

* docs(release): curate 11.28.6 and pacquet 12.14.0 release notes

Add lead paragraphs and group the patch entries by what the reader was
doing, with security first on the v11 page.

- v11: lead with the NPM_ID_TOKEN audience check and the invalid file
  name warning as security fixes; say the `pnpm setup` message was
  printed, since v11 reports it as a warning.
- v12: merge the stdout and stderr broken-pipe entries and the two
  optional-peer entries; say the Windows Rust toolchain change undoes
  the MinGW fallback a MinGW-built pnpm used since 12.13.0; correct the
  `browser` packing claim; drop the reference to another release line.
- Use one issue-link label style on both pages.

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

* docs(release): smooth two sentences in the 11.28.6 and 12.14.0 notes

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

* docs(release): say sideEffectsCache.exclude covers the local and remote cache

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

* docs: give sideEffectsCache.exclude an example a cache key cannot cover

An environment variable such as JAVA_HOME could be added to the cache
key, so it does not justify excluding a package. Name the system
libraries a native addon links against instead.

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-15 14:35:42 +02:00
Altay 581a17de66 fix(reporter): restore colored script output performance (#16821)
Avoid per-fragment sanitization when output contains only printable text,
tabs and SGR sequences. Preserve the existing sanitizer for other controls.

Closes pnpm/tasks#119
2026-10-10 18:38:52 +02:00
Zoltan Kochan f79f8638e2 feat(run): keep script colors in streamed output and sanitize it (#16694)
When `pnpm run` or `pnpm exec` prints a script's output under the
project's name (--stream, --parallel, concurrent recursive runs, pipeline
tasks), the child's stdout is piped, so most tools turned their colors
off. pnpm now sets FORCE_COLOR=1 for these children when its own output
is in color through the default or append-only reporter, keeping a
FORCE_COLOR that is already set.

Colored child output exposed rendering bugs in the v12 reporter, fixed
here:

- cut_line counted escape bytes as visible characters and could split a
  color code. It now uses console::truncate_str.
- Lines are split only on \n, so a \r progress bar reached the in-place
  frame with embedded carriage returns. printable_script_line keeps the
  last non-empty \r frame.
- Cursor movement, OSC links and other control characters from a child
  are dropped by a small ECMA-48 escape parser (the locked console
  0.16.3 iterator misses OSC and private-marker CSI). Only SGR sequences
  whose parameters are digits, ';' or ':' count as colors, and they
  are kept only when pnpm renders in color. A line that keeps a color
  ends with a reset so it cannot bleed into the next line or prefix.

run_stage wrote the [ELIFECYCLE] line with eprintln! while the default
reporter redrew its frame in place, so the next redraw moved the cursor
over the wrong rows. A streamed run now emits it as an error-level pnpm
log, which the reporter adds to the frame. An inherited run still writes
it to stderr.

The v11 reporter had the same cursor-code problem (a TODO in
reportLifecycleScripts.ts). It now keeps only SGR sequences, using
node:util stripVTControlCharacters for the rest, and appends the same
reset. v11 already splits \r into separate lines, and FORCE_COLOR is a
v12-only feature.
2026-10-07 15:54:14 +02:00
68112bada4 chore(release): 11.28.5, pacquet 12.10.0 (#16637)
* chore(release): 11.28.5, pacquet 12.10.0

* docs(release): curate the 11.28.5 and 12.10.0 release notes

Add a lead paragraph to each page and group the patch entries under
subject headings, with the security fixes first.

- Merge the unpublish path-boundary fix into the unpublish entry, the
  legacy metadata cache prune into the metadata cache entry, the two
  binary size entries, and the two 64 MiB archive limits on the v11 page.
- Drop the manifest-utils saveType entry from the CLI page: the CLI
  only passes saveType values derived from its own flags, so no CLI user
  can reach the fixed path.
- Rewrite mechanism-only entries (PAX header validation, bundled
  dependency symlinks, custom resolutions under name@version keys, proxy
  setting validation) in terms of what the user sees.
- Use one link style for pnpm/pnpm issues.

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 02:00:03 +02:00
Zoltan Kochan ff295f3904 fix(config): make --global and --location=global read only the global config (#16601)
`pnpm config get --global` and `pnpm config list --global` printed the
settings from the project's pnpm-workspace.yaml when run inside a
project, and `--global` and `--location=global` disagreed on what the
global config is, although the docs call them the same.

pnpm v12: `ConfigFlags::is_global` resolves both flags in one place,
with `--location` winning. A `get`/`list` scoped that way loads config
the way other global commands do, anchored at the pnpm home, so neither
the project's pnpm-workspace.yaml nor its .npmrc applies. The
pre-command pin checks and the `-w` conflict check use the same helper.
A global config read also implies --ignore-workspace, so
PNPM_CONFIG_WORKSPACE_DIR does not bring a workspace back in.

pnpm v11: config commands turn `--global` into `--location=global`
before loading config, so `--global` no longer loads the config of a
global install. That mode required the global bin directory in PATH and
read the global packages' pnpm-workspace.yaml. The CLI parser lets
`--location` win over `--global` when looking for the workspace.

Both now skip the project .npmrc for these reads, as npm does in global
mode. A new `ignoreProjectNpmrc` getConfig option does it in v11; other
v11 global commands are unchanged.

Closes pnpm/pnpm#16598
2026-10-05 16:20:00 +02:00
88d67feb0d fix: forward config flags to install spawned by verifyDepsBeforeRun (#16558)
The install that verifyDepsBeforeRun spawns before `pnpm run` and `pnpm exec`
now receives the parent's `--config.<key>=<value>` options. Settings from
config files and pnpm_config_* environment variables already reached the
child; command-line ones did not, so e.g. `--config.lockfile-dir` was lost and
the install wrote its lockfile into the project.

Both CLIs forward the options as given, at the single place that spawns the
install, so the recheck after waiting for another gate's install gets them too.
The confirmation prompt shown for `verifyDepsBeforeRun: prompt` omits them,
since a `--config.//registry/:_authToken=...` value would otherwise be printed.
pnpm v11 does not forward `--config.dir`: the install already starts in the
resolved directory, where a relative value would resolve a second time.

pnpm v11 carries the options on the config context (`rawCliConfig`) rather than
on cliOptions, which would make them a setting and an explicitly set key.

Closes https://github.com/pnpm/tasks/issues/60

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:49:42 +02:00
5dafb09800 chore(release): 11.28.4, pacquet 12.9.1 (#16567)
* chore(release): 11.28.4, pacquet 12.9.1

* docs(release): curate 11.28.4 and pacquet 12.9.1 release notes

Add a lead paragraph to both pages. Move the two credential-leak fixes
in 11.28.4 to the top and group the remaining 27 entries by what the
reader was doing. Merge entries that described one change: the two
INVALID_SETTING validations, the two metadata revalidation fixes, the
two hoisted filtered-install fixes, and, in pacquet 12.9.1, the two
[<since>] selector fixes. Order pacquet 12.9.1 so the `@pnpm/wasm` move,
which WebContainer users must act on, comes first.

Normalize issue links to the [#N] form and link the ETag fix to
pnpm/pnpm#16506.

Every fix was checked against the code released in 11.28.3 and
pacquet 12.9.0; none fixes a defect that never shipped.

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

* docs(release): describe the frozen-lockfile fixes accurately in the 11.28.4 lead

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 22:13:02 +02:00
Zoltan KochanandClaude Opus 5.5 53428ea2dd fix(self-update): refuse to update a pnpm installed by Homebrew (#16564)
`pnpm self-update` installs the target pnpm into the global packages
directory and links it into PNPM_HOME. It never touches the Homebrew
keg, so a Homebrew user ended up with a second pnpm that the Homebrew
binary on PATH kept shadowing. The update reported success while
`pnpm -v` stayed the same, and later runs declined because the target
was "already installed globally".

Both CLIs now detect a running pnpm that lives inside a Homebrew keg
(`<cellar>/pnpm/<version>/` or `<cellar>/pnpm@<major>/<version>/`) from
its canonical path and fail with ERR_PNPM_CANT_SELF_UPDATE_IN_HOMEBREW,
pointing at `brew upgrade <formula>`. The check sits next to the
existing Corepack refusal, before project config is loaded.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 21:49:08 +02:00
KhảiandClaude Opus 5 1606ba03fb docs: add the documentation and comment principles and apply them (#16516)
* docs(agents): add the documentation and comment principles

Import the principles that transfer from KSXGitHub/perfectionist's
contributor guide, plus four of our own: concise and non-repeating text,
structured text over prose, removal over addition when reviewing or
fixing nitpicks, and a definition of the user-facing text that must not
name implementation details.

The root guide's "Comments" section gains "Register", "Prose that cannot
go stale", "User-facing text", and "Reviewing documentation and
comments". The pacquet style guide adds the Rust specifics (clap and
napi doc comments are user-facing; a default is documented on the
field, not the variant). DOCUMENTATION.md gains the renderer and link
table for each markdown surface.

The guides themselves are brought in line: counts over growable lists
become plain references, a quoted heading becomes an anchor link, and
the size limits are stated once, in the style guide, instead of three
times.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs: keep user-facing text free of implementation names

The `@pnpm/napi` README and type declarations named the Rust engine, the
in-repo package name, and TypeScript internals (`filterPkgsDiff`,
`nameFormatter`) that a user of the addon cannot reach. The pnpmfile
page in both docs trees explained a limitation by the IPC mechanism
behind it. Four changesets named the release line or implementation,
which the package targets already express.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating and stale comments in pack, modules-yaml and nine more crates

Apply the comment principles to pack, versioning, pnpr-client,
package-is-installable, fs-packlist, workspace-task-scheduler,
engine-runtime-node-resolver, exportable-manifest, modules-yaml,
pnpr-registry, and pnpr-auth. Removed: call-site comments that repeat
the callee's doc, module rosters of exports that the `pub use` lines
already list, "not yet implemented" notes for behaviour that exists
(`beforePacking`, `hoistedLocations`), body narration, and history
framing. Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating and stale comments in the small resolver, catalog and pnpr crates

Apply the comment principles to the local, tarball, default, deno and
jsr resolvers, the catalog crates, detect-libc, config-parse-overrides,
env-replace, git-utils, matcher, diagnostics, and the pnpr policy,
cargo, error, osv and fixture crates. Removed: parentheticals that
repeat a `#[diagnostic(code)]` attribute, counts over lists of
variants, callers and entry points, rosters of callers, doc paragraphs
that repeat a sibling's or the module's text, comments narrating the
match arms or condition below them, and history framing. The
`pnpr-prepare --help` text no longer names the test harness.
Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating and stale comments in publish, workspace, registry and graph-hasher

Apply the comment principles to publish, auth-commands, registry,
workspace, lockfile-verification, default-reporter, the git resolver,
deps-inspection, hooks, graph-hasher, package-manifest, and the pnpr
shared-artifacts and route crates. Removed: a module roster of every
export, counts over lists, plan notes for work that landed ("Phase 5",
"Phase 6"), call-site comments repeating the callee's doc, docs
narrating match arms, a default claim on a `#[default]` variant, a
misattached doc, and history framing. Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating comments in napi, reporter and pnpr crates

Apply the comment principles to napi, reporter, resolving-resolver-base,
real-hoist, git-fetcher, workspace-manifest-writer, and the pnpr config
and storage crates. Removed: "Mirrors X in index.d.ts" sentences on
`#[napi]` items and other implementation names in addon-facing docs,
stale "not emitted yet" and "when it lands" notes for behaviour that
exists, step-by-step comments narrating the body, emit-site and caller
rosters, docs duplicated from a sibling or the module, a doc attached to
the wrong item, and history framing. Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs: cut restating and stale comments across the remaining crates and pnpm11

Apply the comment principles to the rest of the Rust workspace and to the
TypeScript CLI: the cli crate and its clap definitions, package-manager,
config, patching, the deps resolver, lockfile, pnpr, the npm resolver,
tarball, network, executor, cmd-shim, the benchmark and fixture tooling,
and the pnpm11 packages.

Removed: comments narrating the body, docs repeating a callee's, a
sibling's or the module's text, counts over growable lists, rosters of
callers and exports, "not yet implemented" notes for behaviour that
exists, history framing, and `@param` lines restating a signature.

One exception to comment-only: in `pnpr/crates/pnpr/src/resolver/resolve.rs`
the `Workspace` struct sat inside the doc block written for `resolve`, so
the struct moved above it and each doc now attaches to its own item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut body narration and duplicated docs in resolver, fs and package-manager

Removed: a numbered "Sequence:" list narrating `ensure_file`'s body and
the paragraph restating its backoff constants, the stress-test module
doc's roster of its own tests, refactor-history paragraphs in the peer
walk's finalize pass, call-site and caller-side copies of a callee's doc
(the `optional` AND-fold stays documented on `register_seeded_package`
and on `ResolvedPackage`), a verbatim quotation of a TypeScript test's
expected output in the pnpr search module doc, and field and digest-input
rosters in the package-manager.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(deps-restorer): cut plan references and re-attach misplaced docs

Removed the "slice 4" plan references and the comments narrating the
bodies they sat above. The `Auto` downgrade-chain doc moved from
`copy_and_log` to `auto_link`, the function it describes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(deps-restorer): cut the remaining body narration in the hoist path

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs: cut the last body narration and a history clause in the cmd-shim test

`build_graph.rs` kept a `patches` parameter doc that re-derived what
`BuildOptions::patches` documents. The PowerShell-arguments test on main
said the arguments survived "before the shim ended its batch context
too", which describes the change rather than the behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cmd-shim): point the PowerShell-shim link at its current module

Main moved `wants_powershell_shim` into `windows_shim_policy`, so the
shim writer's link to it no longer resolved and `cargo doc` failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cli): link the fixture the ignored-build setup installs

The shortened doc named `workspace_with_unapproved_build` in backticks,
which `perfectionist::bare_identifier_reference` rejects for an item that
resolves in scope. It is an intra-doc link now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): restore two contracts and fix four dangling references

A review of this branch's sweep flagged seven places. Six needed a
change:

- `from_ini` documents again that a relative `cafile=` resolves against
  `npmrc_dir`, a precondition its callers have to honour.
- `hash_object` documents again that the private serializer's bytestream
  has to match pnpm 11's, because the digest is persisted and read by
  both.
- The hooked-manifests note no longer says "above" of a gate that lives
  in another module.
- The store-dir race test states its synchronization contract instead of
  labelling it "Post-Option-C".
- `GraphNodeHashOptions.nodeVersion` keeps `undefined` as a literal.
- The pnpr streaming module drops the sentence fragment that introduced
  its list.

The seventh, a `beforePacking` limitation in exportable-manifest, stays
removed: the note said the pnpmfile bridge cannot supply that hook, and
`pnpm_pack::lifecycle::apply_before_packing` has been running it since
before this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cli): say in `pnpm why --help` that `--exclude-peers` is ignored

Demoting the caveat to an ordinary comment took it out of the help,
which then advertised a flag that does nothing: `WhyArgs::run` never
reads `exclude_peers`, and pnpm 11's `why` handler never forwards its
`excludePeers` either. The doc comment states that behavior in the words
a user sees, and the parity reason stays in a comment beside it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cli): drop the doc comment that described the wrong module

The comment described the `pnpm_deps_inspection as deps_tree` re-export
above it, but a doc comment attaches to the item that follows, so rustdoc
showed it as the description of `mod dispatch`. The `use` item already
names the alias, so the comment goes rather than moving.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-02 20:28:21 +02:00
Zoltan Kochan 6d72710fe1 fix: warn when an optional dependency cannot be fetched (#16522)
An optional package whose tarball fetch failed (a 404, an integrity
mismatch) was dropped without a word. With fetch retries off nothing on
stdout or stderr said the package was missing, and no ndjson record
carried the skip. pnpm v12 also counted the package in `Packages: +N`,
and pnpm v11 left a dangling `node_modules/<name>` symlink and listed
the package among the added dependencies.

Both CLIs now emit `pnpm:skipped-optional-dependency` with a new
`fetch_failure` reason, the error code and message in `details`, and
the default reporter renders it as a warning wherever the package sits
in the graph.

In v12 the `pnpm:stats added` event moves from planning to after the
cold downloads and leaves out the failed snapshots. The paired
`removed` event comes from the link phase, so the summary line renders
at the same point as before.

In v11 the isolated layout drops failed packages from the graph and
from the direct dependencies, so they are neither hoisted, built, nor
linked into the project. The current lockfile still lists them, and
their missing directory makes the next install fetch them again. The
v11 `Packages: +N` count is unchanged: that line renders before the
fetches start there.

A parent package's slot links its children while the downloads are
still running, so the link to an optional child whose fetch failed is
removed afterwards: v12 after the cold download batch (except under
the hoisted linker and `frozenStore`), v11 when it drops the failed
packages from the graph.

Both default reporters render a `fetch_failure` skip whatever its
prefix. The skip carries the lockfile directory, so the usual
current-project filter hid it when `pnpm install` ran from a workspace
project.

The v11 integrity error message now redacts the tarball URL with
`redactUrlForDisplay`, matching the v12 tarball errors, so the warning
cannot print credentials or a signed query token. An absolute local
tarball path is kept as is.

Closes pnpm/pnpm#16514
2026-10-02 19:52:01 +02:00
de9611cf28 chore(release): 11.28.3 (#16444)
* chore(release): 11.28.3

* docs(changelog): curate the 11.28.3 release notes

Merge the eleven entries about names such as `constructor` into one,
group the patch changes by what the reader was doing, and add a lead
paragraph.

Drop the zlib-rs entry: that change only touched Cargo.toml, and the
TypeScript CLI does not use the Rust engine. It belongs to the next
pacquet release.

Rewrite the store index entry for CLI users. `ReadOnlyStoreIndex` and
`ImmutableStoreIndex` are library API documented in the
`@pnpm/store.index` changelog.

Say what the store prune mark-phase fix changes for the user.

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-09-30 16:56:44 +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
9ce8c2e734 chore(release): 11.28.1, pacquet 12.8.0, pnpr 0.1.0-alpha.14 (#16312)
* chore(release): 11.28.1, pacquet 12.8.0, pnpr 0.1.0-alpha.14

* docs(release): park Rust changelogs and curate release notes

The release bump ran with pnpm 12.7.0, which since pnpm/pnpm#14934
writes the changelog of every private project to a committed
CHANGELOG.md. pacquet, `@pnpm/napi` and `@pnpm/pnpr` are private
in-repo but published, and release.yml and the publish-time changelog
composer both read their parked section. Move the three sections back
to .changeset/changelogs so the GitHub release bodies and the npm
tarball changelogs are not empty. The tooling follow-up is recorded
on pnpm/tasks#38.

Curate the pnpm 11.28.1, pnpm 12.8.0 and pnpr 0.1.0-alpha.14 pages:
add lead paragraphs, group patch entries by subject, merge entries
describing one change, drop internals no CLI user sees, and fix
"instead of" tails, implementation names and link placement. This
addresses both Qodo findings on the catalog entry.

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-09-28 08:57:31 +02:00
c4875bf52f fix(reporter): preserve install diagnostics at quiet log levels (#16076)
Quiet reporter routing discarded lifecycle events before failures could
render their buffered output. Consume the lifecycle stream at warn/error,
group by package, stage, and working
directory, discard successful blocks, and flush complete
failed blocks. Keep optional failures at warn without changing exit status.

Show ignored-build warnings at warn and failed supply-chain verification
at error, while leaving progress, successful verdicts, and successful
lifecycle output hidden. Preserve info, silent, NDJSON, and direct script-run behavior.

Capture TypeScript root install hook output only for quiet default and
append-only reporters. Separate the CLI reporter name from the installer's
reporter callback options at both forwarding boundaries.

Cover both TypeScript and Rust reporters plus resolved/frozen root and
dependency installs, optional failures, real parallel builds, more than
ten output lines, ignored builds, and failed supply-chain verification routing.

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 00:34:30 +02:00
b341f5ada2 chore(release): 11.28.0, pacquet 12.7.0, pnpr 0.1.0-alpha.13 (#15647)
* chore(release): 11.28.0, pacquet 12.7.0, pnpr 0.1.0-alpha.13

* docs(release): curate the 11.28.0 and 12.7.0 release pages

Group both pages under subject headings with a lead paragraph that
names the headline changes and the security fixes, and move the
security entries to the top of the patch section.

Merge entries that describe one change: the node shim version files,
ranged selectors without a package.json, SemVer build metadata,
completion injection, custom modulesDir command lookup,
list --only-projects, store status, npm_execpath, catalog and npm-alias
workspace edges, the macOS CA fallback, and the prepare/devPreinstall
skips.

Drop entries that describe no change a published version could show:
the test-only --no-optional entry on both pages, the exported
CreateNewStoreControllerOptions type, the publish availability-probe
fix for a flag first shipping in 12.7.0, and the executable-bit check
the Rust CLI never had wrong.

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

* docs(release): describe the bin shim part of the modulesDir entry accurately

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-09-25 12:01:04 +02:00
Altay 363129c613 fix(run): name the signal that killed a script (#15424)
A script killed by a signal has no exit code, so both CLIs reported
only "Command failed." pnpm v12 now reads the signal from the exit
status and prints "Command failed with signal SIGKILL." pnpm v11 keeps
the signal on the lifecycle error and the default reporter prints the
same title. The signal title also replaces the fixed "Test failed."
title of the test stage.

pnpm still re-raises the signal on itself afterwards, so the shell
keeps seeing an interrupted command. With v11, a signal that ends the
Node.js process on delivery (SIGKILL, SIGTERM) still ends pnpm before
the reporter prints.

Closes pnpm/pnpm#9821
2026-09-25 08:15:36 +02:00
Chengwen Zhang cd81e6840b fix(lockfile): show versions in the incompatible lockfile error (#15485)
The "lockfile not compatible with current pnpm" error carried no version
information, and its only hint was to rerun with --force, which can break an
application whose lockfile was generated by a different pnpm version
(Closes pnpm/pnpm#848).

The throw site already knows the file's lockfileVersion and the versions the
current pnpm supports, so pass both into LockfileBreakingChangeError and
include them in the message. The default-reporter hint now warns that
recreating the lockfile may break the application and suggests installing
the pnpm version that generated it as the safe alternative.

pacquet's LockfileVersionError::IncompatibleMajor had the same deficiency; it
now reports the file's lockfileVersion and the supported major. The
derive_more Display was replaced with a hand-written impl because the format
string cannot interpolate the const-generic MAJOR.
2026-09-24 19:04:14 +02:00
Altay 01feae8078 fix(default-reporter): print boxed notices as plain lines in append-only mode (#15421)
The ignored build scripts warning and the update notice were always
wrapped in a boxen box. pnpm already picks the append-only reporter when
stdout is not a TTY or CI is detected, but these two reporters ignored
appendOnly, so CI logs got a box drawn for an 80-column terminal that
broke apart in viewers without line wrapping.

Both now return their text unboxed when appendOnly is set, matching the
Rust reporter, which never boxes these notices.

Closes pnpm/pnpm#9421
2026-09-24 02:23:54 +02:00
Zoltan Kochan 3c217a9deb fix(exec): re-invoke an entry script only when it belongs to the running pnpm (#15408)
`resolvePnpmSelfCommand` decided whether `process.argv[1]` was pnpm from
its basename and the manifest above it, rejecting a script only when
another package claimed it as a bin. A script that no package claims, a
project's own `scripts/pnpm.mjs` among them, still passed.

pnpm's own code knows where it lives. The entry script is now accepted
only when its real path is the running module itself, as when a bundle
is run directly or copied elsewhere, or lies in the same package as that
module, as with `bin/pnpm.mjs` loading `dist/pnpm.mjs`. The nearest
`package.json` marks the package; the published `pnpm` and `@pnpm/exe`
tarballs carry only the one at their root. The basename set stays to keep
out hosts such as Jest, and a `pnpx` entry maps to the `pnpm.mjs` beside
it, since `pnpx` prepends `dlx` to `process.argv`. An entry that cannot
be resolved now
falls back to the pnpm on PATH, which is safe because the bundle-copy
case no longer depends on failing open.

The resolver moves to `@pnpm/cli.meta`, next to
`detectIfCurrentPkgIsExecutable`, so `npm_execpath` can share it without
`@pnpm/exec.npm-lifecycle` depending on the CLI runner. `npm_execpath`
previously took `process.argv[1]` unchecked, so a script run under
`pnpx` got `pnpx.mjs` and `$npm_execpath install` became `dlx install`.
It now gets the running pnpm's entry or executable, or the pnpm on
pnpm's own PATH when there is none, matching the runner's fallback. The `process.pkg` branch it
replaces was dead since `@pnpm/exe` moved to a Node.js SEA.

The lookup is cached for the process, since lifecycle scripts ask once
per script and neither `process.argv[1]` nor the module moves.

On Windows, `@pnpm/exe` installs `pnpx.exe` and `pnx.exe` as hardlinks
of the pnpm binary, which runs as `pnpm dlx` when launched through
either name. Re-invoking the current executable under one of them
prepended `dlx` again. Both versions now re-invoke the `pnpm` executable
beside the alias: v11 in `resolvePnpmSelfCommand` and `npm_execpath`,
and v12 through `pnpm_executor::current_pnpm_exe()` in `npm_execpath`,
`doctor`, the `verifyDepsBeforeRun` install, the pipeline agent and the
git-dependency build.

The `npm_execpath` fallback is resolved to an absolute path before a
script's PATH puts `node_modules/.bin` first, so a dependency's `pnpm`
bin cannot stand in for it.
2026-09-23 21:50:35 +02:00
Altay 5b02bb130f fix(completion): complete bash words that contain a colon (#15368)
Bash splits COMP_WORDS at every COMP_WORDBREAKS character, so
`pnpm run test:u` reaches the completion function as `test`, `:`, `u`,
and readline replaces only the text after the last colon.

pnpm v12 passed the split words to the completion server unless
bash-completion's `_get_comp_words_by_ref` was loaded, so the server saw
`test` as the script argument and returned nothing. The bash script now
rejoins adjacent words from COMP_LINE itself.

pnpm v11 reads the command line from COMP_LINE and returned `test:unit`,
but bash inserted it after `test:` and produced `test:test:unit` unless
bash-completion's compatibility helpers were loaded. Both scripts now strip
the part of the current word up to its last word break from each candidate,
without depending on bash-completion.

Closes pnpm/pnpm#5482.
2026-09-23 21:41:55 +02:00
b21b6269ac fix(store): drop refetch hint from store status output (#15359)
help: "pnpm install --force" reinstalls packages and might fix the modified ones

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 18:19:17 +02:00
AltayandZoltan Kochan cc0494d184 fix(install): skip an unresolvable optional dependency again on a frozen install (#15252)
A failed optional dependency is dropped at resolution time, so the lockfile
importer has no entry for it. The frozen freshness check then diffs manifest
specifiers against importer specifiers and reports it as added, which fails
`pnpm install --frozen-lockfile` and every CI install right after the install
that wrote the lockfile.

Treat such an entry as satisfied only on the explicit frozen path (the
`--frozen-lockfile` flag or the CI default). The auto-frozen and up-to-date
checks stay strict so a plain `pnpm install` still resolves and locks an
optional dependency that was added by hand. The frozen install re-emits the
`pnpm:skipped-optional-dependency` event with reason `resolution_failure`
for each such entry so the reporter prints the same notice the resolving
install printed. Ignored optional dependencies and `link:` entries excluded
from the lockfile are left out of both the leniency and the notice.

Recording the skip in the lockfile was considered and rejected: the v9
importer entry is `{specifier, version}` and has no slot for a declared but
unresolved dependency, so it would need a format change.

The reporter's notice for a resolution failure now names the requested
range and says the dependency could not be resolved instead of "failed
compatibility check", which describes platform skips.

Closes pnpm/pnpm#3960

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-09-22 16:37:16 +02:00
Zoltan Kochan 238a92a351 fix(cli): complete workspace filter values (#15240)
Supply workspace package names for separated --filter and -F completion
values. Clap has no fixed possible values for these options, which made
completion fall through to command suggestions.

Reuse workspace project discovery and extract the directory resolution
already used by script completion. Preserve workspace package patterns
and prefix filtering without loading install configuration or hooks.

The TypeScript CLI already implements these completion forms. Both completion
servers now omit unsafe candidates without rewriting their identities.
This prevents manifest-controlled names from injecting output records or
terminal controls, including script names as well as package names.
Omit backslashes in TypeScript Fish candidates because the tabtab template
decodes them after the completion server emits its output.
Closes pnpm/pnpm#15216.
2026-09-22 00:05:13 +02:00
Zoltan Kochanandgithub-actions[bot] 201f9fc51f chore(release): 11.27.1 (#15185)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-20 23:11:14 +02:00
Zoltan Kochan 94d1e762a6 fix: stop printing deprecation notices (#15099)
A package's deprecation notice is free-form text that any publisher can
rewrite on an already-published version. It is not covered by the tarball
integrity hash and not pinned by the lockfile, so it is the one
registry-mutable field that reached the terminal with no integrity check
behind it, and it reached it unfiltered. That made it a channel for
terminal escape sequences, and, for an agent reading install output, for
prompt injection.

A deprecated direct dependency is now reported as `deprecated
<name>@<version>`, in both the TypeScript v11 CLI and pacquet. The notice
is dropped from the `pnpm:deprecation` payload as well, so it does not
reach an NDJSON consumer either.

The identifier itself is sanitized. It comes from the resolved manifest
rather than the validated dependency alias, so a git or tarball
dependency names itself, and it was printed raw.

The shared text sanitizer also strips U+2028 and U+2029, which end a line
for a JSON or JavaScript consumer without being control characters.

The lockfile keeps recording the notice. Replacing it with a flag changes
a field's type inside an unchanged lockfile version, which breaks
strongly typed consumers and churns the file between pnpm versions. That
belongs in the next lockfile major.

Discussed in https://github.com/orgs/pnpm/discussions/13422.
2026-09-19 13:53:05 +02:00
Zoltan Kochan b1094872fa fix(cli): restore package script completion (#15086)
The completion server previously offered only candidates from clap's command
and option definitions, leaving the run script position empty.

Initialize clap metadata before scanning boolean options and register the
run-script alias. Track positional arguments and directory options in the
completion context.
Reuse the npm project prefix lookup and manifest reader to return sorted script
names. Share workspace-root lookup with command execution, preserve explicit
directories, and respect equals-only options. Escape zsh candidate separators
after prefix filtering. Read manifests only at the run script position, before configuration or
hooks are initialized, and propagate malformed manifest errors.

The missing-script regression affects v12 only. The TypeScript v11 implementation
already reads scripts from the project manifest. A related Bash glob expansion
bug affects both versions and is fixed in both generated scripts. Preserve
candidate lines without splitting or pathname expansion, quote Bash candidates
for insertion, escape PowerShell
candidate syntax, and normalize its quoted prefixes. Reuse the short-option
scanner so combined directory and workspace-root flags select the same project
as command execution.

Closes pnpm/pnpm#15034.
2026-09-19 02:58:18 +02:00
Zoltan Kochanandgithub-actions[bot] b62f5b004f chore(release): 11.27.0 (#14856)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-12 12:01:04 +02:00
Zoltan Kochan f00e7680aa chore(release): 11.26.0 (#14638) 2026-09-07 01:30:44 +02:00
Zoltan Kochan 6d90c71efd chore(release): 11.25.0, pacquet 12.1.0, pnpr 0.1.0-alpha.9 (#14306) 2026-08-29 15:50:36 +02:00
Zoltan Kochan e9ab4fcc10 fix(global): stop update -g from downgrading, and pnpm from rolling back (#14272)
fix(global): stop `update -g` from downgrading, and pnpm from rolling back

`pnpm update -g --latest` resolves the `latest` dist-tag, which points at
an older release than the one installed whenever that came from another
tag (`pnpm add -g <pkg>@next`) or from a major that has not been promoted
to `latest` yet. The group was reinstalled at whatever `latest` named, so
an update moved packages backwards. Both stacks now compare the resolved
versions against the ones already installed and, when any went backwards,
reinstall the group holding those at the version that is there.

The pnpm CLI's own group is exempt from `update -g` regardless: that
install is `self-update`'s, and reinstalling it here would skip the engine
signature check, the broken-release refusal and the "does it run" probe,
then relink the pnpm home's bins to the result. Naming pnpm explicitly
fails with ERR_PNPM_GLOBAL_PNPM_INSTALL, the rule `add -g` already
applied, and an `npm:` alias no longer slips past either. Two engine
groups side by side also stopped dead-ending every later `up -g` on
ERR_PNPM_GLOBAL_BIN_CONFLICT.

The reporter had a second defect the same command exposed: the differ
redraws by moving the cursor up from the end of its frame, so a frame
taller than the terminal walks past the top of the screen and overwrites
the scrollback above it. The overflowed lines are now handed to the
scrollback, and a frame the differ can no longer reach — outgrown,
shrunk under, or reflowed by a resize — is redrawn afresh below rather
than revised. The Rust height probe works on Windows too.

Closes pnpm/pnpm#14270
2026-08-28 15:09:29 +02:00
Zoltan Kochan 4c07abab66 fix: stop pointing users at Corepack for pnpm updates (#14115)
## Summary

The v11 CLI and the Rust engine, matching #14113 (merged) plus its follow-up #14116.

Two places told users to update pnpm with Corepack:

- The **update notification** printed `corepack use pnpm@<version>` when pnpm ran under Corepack. It now prints pnpm's [standalone install script](https://pnpm.io/installation) — `curl -fsSL https://get.pnpm.io/install.sh | sh -`, or the `Invoke-WebRequest` form on Windows.
- **`pnpm self-update`** refused under Corepack with *"You should update pnpm with corepack"*. It now says it cannot update itself under Corepack, and names the standalone install script as the hint.

The notification also stopped naming `pnpm add -g pnpm`, which `add` refuses outright (`ERR_PNPM_GLOBAL_PNPM_INSTALL` in the TypeScript CLI, `GlobalError::GlobalPnpmInstall` in the Rust one). `pnpm self-update` is named only where it can replace the executable in use — an install another package manager owns is resolved from that manager's bin directory, so a self-update would land beside it and report success while the old pnpm keeps announcing the update:

| `PNPM_HOME` set | under Corepack | suggestion |
| --- | --- | --- |
| yes | no | `pnpm self-update` |
| yes | yes | standalone install script |
| no | either | standalone install script |

The command has one definition per stack — `standaloneInstallCommand` in `@pnpm/cli.meta`, `standalone_install_command` in `pnpm-config` (beside `PNPM_VERSION`) — shared by the notification and the self-update refusal so the two cannot drift.
2026-08-24 16:45:42 +02:00
Zoltan Kochanandgithub-actions[bot] e3cb54258c chore(release): 11.24.0, pacquet 12.0.0-rc.10 (#14134)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-24 15:53:03 +02:00
Zoltan Kochanandgithub-actions[bot] 726d6b4a04 chore(release): 11.23.0 (#14111)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-23 15:47:36 +02:00
APZN a6d9ee70f0 fix(workspace): keep settings-only workspaces root-scoped (#14059)
Keep settings-only workspace manifests scoped to the root package when checking dependency status, filtering projects, and completing --filter values.

These call sites previously passed an undefined package pattern to the projects reader, activating its recursive default even though config had already defined settings-only workspaces as root-only. Preserve the projects reader default for other callers and apply the root-only fallback only at the three manifest-aware boundaries.

Fixes pnpm/pnpm#14047.
2026-08-23 01:18:13 +02:00
Zoltan Kochanandgithub-actions[bot] 93fcba4224 chore(release): 11.22.0, pacquet 12.0.0-rc.6 (#13926)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-15 18:50:30 +02:00
Zoltan Kochanandgithub-actions[bot] 8adb97ed05 chore(release): 11.21.0, pacquet 12.0.0-rc.2 (#13742)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-09 16:02:53 +02:00
Zoltan Kochanandgithub-actions[bot] ebc48abdc5 chore(release): 11.20.0, pacquet 12.0.0-beta.4 (#13608)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-03 15:48:54 +02:00
Zoltan Kochan d3556f6ba9 refactor(text): move lexCompare and nerfDart into the monorepo (#13535)
Both utilities lived in the pnpm/components Bit workspace, where their
component names collide with same-named components elsewhere in the Bit
registry. Move the code here and publish it under new names:

  `@pnpm/util.lex-comparator` -> `@pnpm/text.ordinal-comparator`
  `@pnpm/config.nerf-dart`    -> `@pnpm/config.registry-auth-key`

The new names describe what the utilities do: the comparator is ordinal
rather than locale-aware, and the mapped URL is the key that registry
settings are stored under in `.npmrc`. The exported functions keep their
names, so consumers only change their import specifiers.

Implementations and tests are carried over unchanged. The rationale from
the components' docs pages moves into doc comments: why `localeCompare`
cannot be used for values compared across machines, and where `nerfDart`
originates.

No pacquet counterpart is needed. The Rust stack has its own
implementations of both and no user-visible behavior changes.
2026-07-31 23:00:10 +02:00
Zoltan Kochan 536b7a2c8a chore(release): 11.19.0 (#13524) 2026-07-31 10:46:26 +02:00
Zoltan Kochan 7f81da30b8 refactor(default-reporter): drop the runtime dependency on config.reader (#13517)
Every import was type-only, so the declared dependency shipped the
whole config-reader tree to reporter consumers for nothing — Bit's
mirror-constrained installs were pulling config.env-replace@4.x through
it. The reporter now declares ReporterPnpmConfig, the structural slice
of the config it actually reads; the pnpm CLI's full Config satisfies
it unchanged.
2026-07-31 02:03:04 +02:00
Abdullah Alaqeel 9a4f51c6fa fix(install-summary): suppress '(X is available)' when latest is held back by minimumReleaseAge (#13214)
fix(install-summary): suppress '(X is available)' when latest is held back by minimumReleaseAge

When minimumReleaseAge (default: 24h) left the registry's
dist-tags.latest immature, the install summary still printed
'(X is available)' for it — advertising the exact version the policy
had just refused to install.

The hint only ever names the actual latest tag: the resolvers now
surface dist-tags.latest on the resolve result only when the active
policy would allow installing it (latest_allowed_by_policy /
latestAllowedByPolicy — an O(1) check of the tag's publish timestamp
against the cutoff, honoring publishedByExclude full-name and exact-
version entries). An immature latest suppresses the hint instead of
being rewritten to an older mature version, so the hint never names a
non-latest version as latest. Suppression requires positive evidence
of immaturity: a missing or unparsable timestamp keeps the raw tag,
matching the pick itself, which only enforces the policy when the
packument's time map is usable.

Also fixes a pre-existing divergence in the pacquet reporter: it gated
the hint on 'latest != version' rather than 'latest > version', so it
would suggest downgrading when the installed version was newer than
the latest tag. Now uses node-semver comparison, matching the
TypeScript reporter's semver.lt check.

Closes pnpm/pnpm#11698.
2026-07-30 20:00:23 +02:00
Zoltan Kochanandgithub-actions[bot] 925c33d780 chore(release): 11.18.0, pacquet 12.0.0-beta.0 (#13481)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-29 09:29:53 +02:00
Zoltan Kochan 760b2ece2c fix(cli): close the remaining pnpm 12 CLI-surface parity gaps (#13376)
Close the four CLI-surface differences left over from pnpm/pnpm#13315
after pnpm/pnpm#13359 and pnpm/pnpm#13375 landed the other two.

Three land in the Rust engine. The `Scope:` line arrives via a new
`pnpm:scope` channel and a port of `reportScope.ts`; pnpm gates it on the
command being one that reports scope *and* the run being workspace-wide,
and since the engine's recursive-by-default set is narrower than pnpm's,
that conjunction is computed at dispatch and seeded into the reporter.
The event is emitted where the counts already exist — the `--filter`
resolution and the installer's workspace walk — so no install pays for a
second directory walk. A `sharedWorkspaceLockfile: false` plan reports
once for the whole selection rather than once per child install, which
would otherwise overwrite the filtered count with the workspace total.

The second is the `allowBuilds` placeholder an install writes for a build
it blocked, which pnpm/pnpm#13375 taught the engine to read but not yet to
write. The third is the elapsed time on a cache-satisfied lockfile
verdict.

The fourth goes the other way. The store block a first install prints is
unreachable in the TypeScript CLI: `reportContext` needs
`pnpm:package-import-method`, which only `@pnpm/fs.indexed-pkg-importer`
emits, and that runs inside a `@pnpm/worker` thread whose logger never
reaches the reporter. The main process already receives the import method
back from the worker, so it is reported from there instead.

Reporter globals are now seeded before the pre-command checks. They are
`OnceLock`s and the pre-command checks emit, so whatever fired first was
locking in unset values.

Closes pnpm/pnpm#13315
2026-07-26 02:24:03 +02:00
Zoltan Kochanandgithub-actions[bot] 454e7d62b3 chore(release): 11.17.0, pacquet 12.0.0-alpha.19, pnpr 0.1.0-alpha.5 (#13237)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-23 17:07:05 +02:00
Zoltan Kochanandgithub-actions[bot] d1edab423e chore(release): 11.16.0, pacquet 12.0.0-alpha.18 (#13216)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-22 21:58:38 +02:00
Zoltan Kochanandgithub-actions[bot] 331c26aa4b chore(release): 11.15.1, pacquet 12.0.0-alpha.16 (#13162)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-20 00:19:20 +02:00
Zoltan Kochan f4948525df chore: remove repository changelogs (#13119)
Remove the legacy repository changelog files now that release changelog storage defaults to the registry. The publish path composes and injects CHANGELOG.md into release tarballs, so keeping historical copies in source control duplicates generated release data.

Update adm-zip to the patched 0.6 release and override vulnerable transitive versions after the dependency audit began rejecting versions below 0.6.0.
2026-07-18 13:10:25 +02:00