A plain install that selected only some workspace projects purged the
shared root modules directory when a layout setting changed, but relinked
only the selected projects. The projects it skipped lost their
dependencies: under the hoisted linker they live in the root modules
directory, and under the isolated linker their links point into the
purged virtual store.
Both CLIs now recreate the modules directory only for an install of every
project. A filtered install fails with the drift's error instead. This
covers nodeLinker, hoistPattern, publicHoistPattern,
virtualStoreDirMaxLength, the store, the virtual store, and the layout
version. In v11 a project installed with other dependency groups still
purges as before.
In v12 the unsafe-target error for a filtered install is unreachable now
and is removed. The refusal accepts some drift that the layout check
flags, such as a tree linked from the sibling v3 store. For that case the
install clears is_inconsistent, so it merges into the recorded current
lockfile and .modules.yaml.
Closespnpm/tasks#217.
* fix(install): refuse nodeLinker changes on v11 mutations
* fix(install): keep node_modules on a filtered install after a nodeLinker change
A plain install that selected the workspace root purged the root modules
directory on a nodeLinker mismatch even when other workspace projects were
not selected. Under the hoisted linker those projects keep their
dependencies in the root modules directory, and the filtered install does
not relink them, so they lost their dependencies.
The purge for a nodeLinker mismatch now runs only when the install covers
every workspace project. Otherwise it fails with ERR_PNPM_NODE_LINKER_DIFF.
Adds tests for the whole-workspace purge and the root-only refusal, and
documents the error in the v11 docs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The v12 command reference (pnpm/docs/cli) had drifted from the clap
definitions, and the error codes the docs name had drifted from the ones
the source emits. Nothing caught either.
Two unit tests in pnpm-cli now compare the docs with the code, following
the settings test from pnpm/pnpm#17269. docs_command_pages maps every
visible clap command to its page and checks both directions: a flag
without a heading, and a heading for a flag the command rejects. Pages
may delegate to another page, import .mdx partials, and document a
--[no-] pair with either side; a flag that spells a setting is claimed
by ConfigOverrides::extract before clap sees it, so the test asks that
entry point, and the -s shorthand is accepted everywhere too.
docs_error_codes checks that every ERR_PNPM_* code the docs name is
emitted by a source file under pnpm/, with the migration guides exempt,
and keeps errors.md in alphabetical order. Each test keeps a list of
today's gaps, and fixing a gap means deleting its entry.
The gaps the tests found are fixed: add documents its include, lockfile,
dedupe, and script flags; deploy names the install options it accepts; remove
documents --[no-]trust-lockfile; import documents --pnpr-server; recursive.md no longer
presents --link-workspace-packages as a recursive option; the
frozenStore section drops the v11-only ERR_PNPM_FROZEN_STORE_INCOMPLETE.
errors.md in both docs trees opens with what a code is for, lists its
codes in alphabetical order, and adds the codes users meet most. The
doctor page stops describing v11 (no skipped store check, no @pnpm/exe
install method), and the exec page states that pnpm parses its own
options up to the command name on either side of `exec`.
DOCUMENTATION.md gets the reference-page templates and the rules the
three drift tests parse.
Part of https://github.com/pnpm/tasks/issues/191.
Correct the v12 guides from agent-skills.md through lockfile.md against
pnpm/crates, and fix the same wrong text on the v11 twins where pnpm11
confirms it. Part of pnpm/tasks#191.
Wrong claims (both versions):
- configuring: the global auth file is auth.ini, not rc; list the
npm_config_* exceptions (workspace dir, userconfig, URL-scoped auth).
- config-dependencies: the hook import used an invalid ESM specifier.
- docker: Example 3 ran fetch --prod and built without an offline install
or pnpm-workspace.yaml.
- errors: drop MISMATCHED_RELEASE_CHANNEL, describe INVALID_NODE_VERSION
through nodeVersion, PEER_DEP_ISSUES needs strictPeerDependencies.
- faq: no lockfile deletion after a readPackage hook, default store order,
junctions depend on symlink privilege.
- filtering: `!./lib` matches one project; use `!./lib/**`.
- git branch lockfiles: every non [A-Za-z0-9_.-] character becomes `!`,
the name is lowercased, merging deletes branch lockfiles, "or" patterns.
- git-worktrees: remove the nonexistent worktree:new and shell/wt.sh.
- global-packages: orphaned dirs are cleaned by add -g (and update -g in
v12), not store prune; document that add -g replaces every group that
contains the package.
- how-peers-are-resolved: current peer directory names.
- completion: built-in completion already covers --filter and scripts.
- feature-comparison: broken JSR anchor.
Wrong claims (v12 only):
- cargo: cargo.indexUrl fails the parse, overrides apply to adding only,
merge the duplicated Cargo index section into Registries.
- global-virtual-store: pnx keeps its own virtual store (dlx part only;
the global-install claims are left for a separate decision).
- installation: the npm package installs on Node.js 18, only get-pnpm
needs 22.13; trim unverified compatibility rows.
Missing facts (v12): agent-skills group filtering and naming, catalogs
(catalogs.default, pnx, --save-catalog, error codes), cargo recursive
add, build-std, resolution keys, completion zsh/pwsh setup, config
dependency location and error codes, include error codes, CI opt-outs and
pnpm ci, finders on list, filtering settings and --no-fail-if-no-match,
global install refusals, trust for npm-registry package managers, Rust
shims, overrides link from aliases.
Stale history (v12): drop v11/v10 version markers and "since v11"
narration in continuous-integration, filtering, finders, git-worktrees,
global-packages, global-virtual-store, how-peers-are-resolved, lockfile,
completion, configuring.
Review follow-up: the Node.js compatibility table keeps the pnpm 10
column; Docker Example 3 builds with all dependencies in a build stage
and ships only production dependencies, with the pnpm-workspace.yaml
caveat (both versions); catalogs keep the bare-path form; v11 global
packages name `pnpm update -g` as cleaning orphans too; the cargo
build-std note says when rust-src must be listed.
Second review: build-std needs a non-empty list; the Docker fetch layer
also depends on the project settings; branch lockfile names keep only
ASCII characters; the conflict merge needs both sides to parse; Rust
shims and package managers are default globalShims participants;
pnpm self-update also cleans orphaned global groups; v12 pnpm login
writes tokens to config.yaml; legacyDirFiltering keeps the subtree
wording (the v12 mismatch is pnpm/tasks#196); the v12 Docker
example copies the files that `include` names before pnpm fetch.
* 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>
The npm resolver copied the packument's top-level `name` into the picked
manifest without checking it against the requested package. That copy
exists for the GitHub Packages quirk (a package published as
`@owner/foo` whose manifest says `foo`), but it also let a registry
answer a request for `@scope/a` as `b`. The resolved identity then
became `b@x`, so `allowBuilds` rules for `@scope/a` no longer matched
and rules for `b` did.
Both stacks now fail with ERR_PNPM_REGISTRY_NAME_MISMATCH when the
packument's `name` differs from the requested name, and always pin the
per-version manifest name to the requested name. A packument without a
top-level `name` still resolves, under the requested name.
Code blocks that hold only shell commands now use the `sh` language,
and blocks showing a file's contents carry a `title` naming the file,
across the pnpm v12, pnpm v11, and pnpr docs. Bold file-name labels
above code blocks are folded into the titles.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>