* 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>
* 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>
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.
* 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>
A build-policy change changes global store hashes, including the hashes of
packages depending on the approved build. Rebuild previously fell back to the
old project-linked slot when the new slot did not exist, modifying content
still shared by projects without that approval.
Reuse frozen materialization from the installed lockfile before running the
selected rebuild scripts. Preserve patches, validate their recorded hashes,
reject patches added after install, and derive the global store directory from
the configured virtualStoreDir. Share patch grouping with the installer and
remove the old linked-directory fallback.
The Rust CLI already isolates the same scenario. This fixes the TypeScript
CLI.
Closespnpm/pnpm#12302.
A patched dependency's hash appears in a lockfile twice: in
`patchedDependencies`, and as a `(patch_hash=...)` segment on every dependency
path referring to that package. The freshness gate compared only the first
against the configured patches, which stands in for the second in every
lockfile pnpm writes but not in one a hand edit or mis-resolved merge conflict
left disagreeing with itself. That lockfile read as up to date: resolution was
skipped, the stale paths were never rewritten, the install reused
already-linked content rather than the current patch, and `--frozen-lockfile`
accepted it.
Add `checkPatchedDepPaths` (`check_patched_dep_paths` in pacquet), which
compares every dependency path naming a patched package, and every path
carrying a segment, in the importer entries, snapshot keys and dependency
edges against the patch `patchedDependencies` gives that package. A path
missing the segment its patch calls for disagrees as much as one carrying the
wrong hash:
- a normal install forces a full resolution;
- `--frozen-lockfile` raises ERR_PNPM_INCONSISTENT_PATCH_HASH, or
ERR_PNPM_UNCHECKABLE_PATCH_HASH when it cannot tell;
- `verifyDepsBeforeRun` reports it where it compares the lockfile settings.
It returns three values, not a predicate: judging a path needs the package's
version and the patch set, and this lockfile state can be missing either.
Calling that stale would send the user after the wrong defect and calling it up
to date would hide a real one, so `indeterminate` forces the resolver without
naming a cause. A `patchedDependencies` key that does not resolve leaves only
its own package undecided, and any definite disagreement outranks it. Paths
for unpatched packages are skipped before they are built, and repeated paths
reuse their verdict, so large lockfiles pay little for the walk.
Derive the package identity as every other patch consumer does, so this check
and the install cannot disagree about which patch applies: a git, tarball,
`file:` or registry-qualified path holds its resolution where the version goes,
while patches match the version `packages:` records. In pacquet,
`name_version_from_package_key` moves from `pnpm-deps-restorer` to
`pnpm-lockfile` so the frozen installer, the fast-update path and this check
share one definition.
That move uncovered a pre-existing divergence, fixed here: pacquet rendered a
registry-qualified key's whole `registry:version` slot where pnpm's `parse`
reports the bare semver, so such a patch matched in one stack and missed in the
other. The frozen installer's lookup was affected too.
So a more actionable cause wins, the check runs last in
`check_lockfile_settings`. A non-frozen install skips it for a lockfile with
merge conflicts, which is re-resolved anyway; a frozen install checks an
autofixed lockfile too, since it installs it as is. The fast-update path no
longer treats an agreeing `patchedDependencies` map as sufficient on its own.
A suffix is read from the end, as pnpm's `parse` reads it: the trailing run
of balanced, back-to-back segments, with the package's own hash first. A
marker anywhere else, or in a suffix whose parentheses do not balance, makes
the path uncheckable. Unless peers are deduped, a peer segment is the peer's
whole dependency path, so each peer segment carrying a marker is judged as its
own path, and so is an unmarked one naming a registry version of a patched
package behind a registry parent. Peers are walked level by level, so nesting
depth never reaches the call stack.
`groupPatchedDependencies` now builds its record without a prototype, so a
`patchedDependencies` key named after an `Object.prototype` member gets its
own group.
The importer fast path in pnpm declines a locked version the range admits
when its key is patched: the bare version it would write points at no
snapshot. pacquet already declined it. pacquet's patch fast-update path now
checks the paths before absorbing drift in `patchedDependencies`.
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
* 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>
Resolution never reads a patch. It appends the patch file's hash to an
already-resolved package id, so a `patchedDependencies` change leaves the
set of packages and versions untouched and moves only the affected keys.
Rewrite those keys and the references pointing at them instead of
re-resolving.
`packages:` is keyed without the patch hash, so only `snapshots:`, the
importers' resolved versions, and dependents' dependency references move.
The patched tarball is already in the store, so materialization applies
the patch with no network access, and the new depPath puts the package in
a fresh virtual-store slot so an install script reruns against the
patched sources.
Fall back to the resolver when the patched package is reachable as a peer
(its depPath is embedded in dependents' peer suffixes), when a peer suffix
was shortened into a hash and cannot be inspected, when the new
configuration would leave a patch unused while `allowUnusedPatches` is
off, and when a patch file cannot be read.
Implemented in both the TypeScript CLI and pacquet.
Related to pnpm/pnpm#13474.
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.
The TypeScript pnpm CLI freezes at v11; pnpm 12 will be the Rust pacquet
port. To make that split legible, all TypeScript source, test, and build
directories move under a new top-level pnpm11/ directory. The name states
the version boundary rather than implying a behavioral fork, since the two
stacks are meant to behave identically.
Scope is source-only: the shared workspace root stays at the repo root.
pnpm-workspace.yaml, package.json, pnpm-lock.yaml, .pnpmfile.cjs,
.meta-updater, __patches__, .changeset, .husky, and the lint/spell configs
remain in place, so one pnpm workspace and one Cargo workspace still span
all three products. pnpr/client and pacquet/tasks/registry-mock stay as
cross-product workspace members.
Rewiring the move required:
- pnpm-workspace.yaml globs prefixed with pnpm11/
- root package.json script paths, eslint.config.mjs, tsconfig.lint.json,
.gitignore, and CODEOWNERS updated
- .meta-updater/src/index.ts literals repointed (pnpm11/pnpm/package.json,
pnpm11/__utils__, pnpm11/__typings__, and the main package directory)
- regenerated every moved package's repository/homepage URL via meta-updater
- pnpm11/pnpm/bundle-deps.ts and __utils__/scripts/src/typecheck-only.ts
climb one more level to reach the repo root
.meta-updater stays at the repo root because @pnpm/meta-updater resolves
its config at <cwd>/.meta-updater/main.mjs.
TS CI (.github/workflows/ci.yml) now only runs when pnpm11/-relevant paths
change, via a dorny/paths-filter changes job plus a TS CI / Success
aggregate gate; branch protection should require only that gate.