Repository navigation
Closed
pnpm/pnpm
#17133Labels
area: lockfilearea: monorepoEverything related to the pnpm workspace featureEverything related to the pnpm workspace featuretype: refactor
Description
Found by the defect-hotspots skill on 2026-10-19 over 90 days of main (c43ba554b7), following up on #145 and #147.
Loop: Injected workspace dependencies & pnpm deploy workspace-to-file: synthesis (23 fixes, 4 regressions)
Property. Every consumer of a directory-resolved (file:) workspace package—the resolver, --frozen-lockfile freshness verification, the repeat-install fast path, pnpm deploy lockfile synthesis, and the four injected-copy sync paths—derives the same manifest, child/peer set, and packed file tree.
Recent members.
- Freshness & repeat-install: fix: update injected workspace dependencies when lockfile is not shared pnpm#15356 → fix(install): accept an injected dependency's peer resolved to a workspace link pnpm#16346 (
pnpm install --frozen-lockfilerejects a freshly generated lockfile when an injected workspace package has peer dependencies pnpm#16332), fix(install): keep the repeat-install fast path for injected workspace deps pnpm#16404, fix(package-manager): accept injected optional peers in frozen installs pnpm#16429 (pnpm install --frozen-lockfilestill rejects a fresh lockfile when an injected package's peer is optional and satisfied by a sibling importer pnpm#16428), fix(lockfile): accept injected catalog peers in frozen installs pnpm#16559 (--frozen-lockfile fails with "local dependency is outdated" when an injected workspace package has a catalog: peer dependency pnpm#16557), fix(package-manager): reuse the lockfile when injected projects come from memory pnpm#16815, fix(package-manager): read injected dependencies from the lockfile in the repeat-install check pnpm#17025 (injectWorkspacePackages: true skips changed injected dependency manifests during optimistic install (12.14.0) pnpm#17007), fix(package-manager): check an injected publish directory against its project's manifest pnpm#17042, fix: run the workspace root's pnpmfile for projects with their own lockfiles pnpm#17047, fix(package-manager): read an injected package's children the way the resolver does pnpm#17053, fix(deps-resolver): record every declared peer in the lockfile pnpm#17067 (A later install never binds an optional peer that the package also lists in dependencies pnpm#17056), fix(lockfile): check an injected package's dependencies on a frozen install pnpm#17065 (11.x: --frozen-lockfile accepts stale injected workspace dependencies with separate lockfiles pnpm#17008). - Copy materialization & sync: fix: build an injected workspace dependency's publish directory before relying on it pnpm#15702, fix: publish injected dependency edits while scripts run pnpm#15881, fix(install): sync only the package files into injected copies with dedicated lockfiles pnpm#16684 (Injected workspace package copy includes files outside "files" when the package itself is installed in the same run pnpm#16683), fix(injected-deps-syncer): diff injected copies without parsing their manifests pnpm#16749, fix: sync only the package files into injected copies after scripts pnpm#17033, fix: sync injected copies after listed scripts without a shared lockfile or with a publish directory pnpm#17083, fix: keep a package's links to its own files in synced injected copies pnpm#17088.
pnpm deployworkspacelink:→file:synthesis: fix(deploy): bind the peer of a deduped injected workspace package pnpm#16381 (pnpm deploy ignores injectWorkspacePackages: true, hardcodes false in deploy manifest pnpm#16375), fix(deploy): don't copy the workspace root's package manager pin into the deployed manifest pnpm#16405 (npm refuses to run scripts whenpnpm deploycopiesdevEngines.packageManagerinto the deployed package.json pnpm#16403), fix(deploy): resolve deploy paths from the real target directory pnpm#16473 (pnpm deploy fails with ERR_PNPM_PATCH_NOT_FOUND when the target has a symlinked ancestor (macOS) pnpm#16470), fix(deploy): resolve local dependencies from the project on legacy deploy pnpm#16476 (pnpm deploy --legacy resolves relative file: dependencies from the deploy directory pnpm#16475), fix(deploy): bind a linked workspace package's peer to what its parent provides pnpm#16809 (pnpm deploy fails with ERR_PNPM_DEPLOY_AMBIGUOUS_PEER for aworkspace:peer when registry copies of the peer are in the graph pnpm#16807, pnpm deploy --legacy fails when a workspace dependency has aworkspace:peer pnpm#16806), fix(deploy): deploy file: dependencies outside the lockfile directory pnpm#16998 (pnpm 12 modern deploy rejects declared file:../../ dependencies outside the workspace/lockfile directory pnpm#16983), fix(deploy): record the peers of the workspace packages a deploy copies pnpm#17098 (A deployed lockfile omits the peers of a workspace package, so pnpm v11 rejects it with --frozen-lockfile pnpm#17093), fix(deploy): stop writing a second copy of every package on macOS pnpm#17118 (pnpm deploy writes a second, unlinked copy of every package (regression in 12) pnpm#17116).
Remaining Flaws after #145 & #147
- Manifest resolution & hooking is still duplicated in v12.
unhooked_manifest,manifest_of_project_publishing_from, andread_and_override_manifestinpnpm/crates/package-manager/src/install/lockfile_freshness/directory_deps.rsandhooked_injected_manifestsinpnpm/crates/package-manager/src/install/lockfile_freshness/injected_manifests.rsre-implement how a local directory'spackage.jsonis located (in-memory vs.publishConfig.directoryproject manifest vs.<dir>/package.jsonon disk vs.{ name: dirname }fallback) and hooked (packageExtensions→readPackage→VersionsOverrider), separately frompnpm-resolving-local-resolverandpnpm-resolving-deps-resolver. - Duplicate local/workspace/
npm:specifier satisfaction parsers.pnpm/crates/package-manager/src/install/lockfile_freshness/directory_deps/spec.rs(file_or_link_spec_satisfies,workspace_spec_satisfies,parse_workspace_range,parse_npm_spec) andpnpm/crates/package-manager/src/optimistic_repeat_install/manifest_agreement.rs(linked_dep_is_up_to_date,version_range_of_spec,semver_satisfies_loosely) each implement their ownworkspace:andnpm:specifier parsers. - Dedicated-lockfile repeat-install bail-out.
injected_deps_block_fast_pathinpnpm/crates/package-manager/src/optimistic_repeat_install/local_file_deps.rsunconditionally skips the repeat-install fast path whenever!config.shared_workspace_lockfileandlockfile.injected_dependencies(...)is non-empty, instead of recording injected directory manifest digests in.pnpm-workspace-state-v1.json. pnpm deploysynthesizesfile:lockfile entries and binds peers by hand.pnpm/crates/cli/src/cli_args/deploy/lockfile.rs+deploy/peers.rs(v12) andpnpm11/releasing/commands/src/deploy/createDeployFiles.ts+deployPackageGraph.ts(v11) convert linked workspace importers intofile:snapshots with a custom graph/peer binder, without verifying that the resulting deployed lockfile passes--frozen-lockfile.
Design Change
- Extract directory manifest lookup +
packageExtensions/readPackage/VersionsOverriderhooking andworkspace:/file:/link:/npm:specifier satisfaction into shared helpers used by the resolver,directory_deps.rs, andmanifest_agreement.rs. - Record
lockfile.injected_dependencies(...)target manifest digests inValidation(pnpm/crates/package-manager/src/optimistic_repeat_install/validation.rs) whensharedWorkspaceLockfile: falseand deleteinjected_deps_block_fast_path. - Add a post-deploy
--frozen-lockfileverification assertion topnpm deploytests across both stacks.
Tests
- Extend
pnpm/crates/cli/tests/suite/injected_freshness_matrix.rswith:publishConfig.directorywherepreparewrites a trimmedpackage.jsoninto the publish directory (fix: build an injected workspace dependency's publish directory before relying on it pnpm#15702 → fix(package-manager): check an injected publish directory against its project's manifest pnpm#17042);- dual-declared
dependencies+peerDependenciesshadowing (fix(package-manager): reuse the lockfile when injected projects come from memory pnpm#16815 → fix(deps-resolver): record every declared peer in the lockfile pnpm#17067); - workspace root
.pnpmfile.cjsreadPackagehooks undersharedWorkspaceLockfile: false(fix: run the workspace root's pnpmfile for projects with their own lockfiles pnpm#17047).
- Extend
pnpm/crates/cli/tests/suite/deploy/peers.rsandpnpm11/pnpm/test/deploy.tsto runpnpm install --frozen-lockfileinside the deployed target directory.
Written by an agent (Antigravity, Gemini 4 Argon).
Metadata
Metadata
Assignees
Labels
area: lockfilearea: monorepoEverything related to the pnpm workspace featureEverything related to the pnpm workspace featuretype: refactor
Activity
zkochan commentedon Oct 19, 2026
Opened pnpm/pnpm#17133 to address this:
pnpm_package_manifest::publishes_from_directorysoresolving-local-resolver::find_parent_publish_manifestandlockfile_freshness::directory_deps::manifest_of_project_publishing_fromshare the samepublishConfig.directory/root.package.jsoncheck, and allowedfile:directory dependencies (declared_as_file) outsideworkspace_rootto walk ancestor manifests during lockfile freshness verification.is_declared_local_directoryandspec_target_and_rangeacrosslockfile_freshness::directory_depsandoptimistic_repeat_install::manifest_agreement, fixing aliased workspace specifiers (workspace:<pkg>@<range>) inlinked_dep_is_up_to_dateand normalizing empty trailing@ranges inparse_npm_spec.mark_importers_of_unproven_directory_depsinoptimistic_repeat_install::freshness::driftsoProvenimporters that have aVersionPart::Filedependency on an edited workspace project are markedManifestChangedand re-verified on repeat install.install,install --frozen-lockfile, and optimistic repeatinstall.Written by an agent (Antigravity, Gemini 4 Argon).
fix(install): unify directory manifest lookup and local spec agreement (