feat: store config deps and package manager integrities in pnpm-lock.env.yaml#10912
feat: store config deps and package manager integrities in pnpm-lock.env.yaml#10912
Conversation
Move integrity hashes from inline `configDependencies` values in pnpm-workspace.yaml to a dedicated pnpm-config-lock.yaml lockfile. The workspace manifest now contains only clean version specifiers, while the config lockfile stores resolved versions, integrity hashes, and tarball URLs using a format similar to pnpm-lock.yaml. Projects using the old inline-hash format are automatically migrated when running pnpm install. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a dedicated pnpm-config-lock.yaml to store resolved config dependency integrity (and tarball when needed), keeping pnpm-workspace.yaml configDependencies as clean specifiers and migrating older inline-integrity entries during install.
Changes:
- Introduces config lockfile read/write utilities and uses them when resolving/installing config dependencies.
- Updates resolve/install flows to write clean specifiers to
pnpm-workspace.yamland integrity data topnpm-config-lock.yaml, with migration support for the legacy inline format. - Updates types/constants and adjusts unit/e2e tests and workspace wiring to cover the new lockfile format.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm/tsconfig.json | Adds project reference so pnpm can consume the updated config deps installer package. |
| pnpm/test/configurationalDependencies.test.ts | Updates e2e coverage for pnpm add --config to assert clean specifiers + lockfile integrity. |
| pnpm/package.json | Adds @pnpm/config.deps-installer devDependency for tests. |
| pnpm-lock.yaml | Updates workspace lock entries to include new deps needed by config lockfile support. |
| packages/types/src/package.ts | Documents old vs new configDependencies formats and introduces ConfigDependencySpecifiers type. |
| packages/constants/src/index.ts | Adds CONFIG_LOCKFILE constant for pnpm-config-lock.yaml. |
| config/deps-installer/tsconfig.json | Adds TS project reference to @pnpm/constants. |
| config/deps-installer/test/resolveConfigDeps.test.ts | Extends unit test to validate lockfile writing + clean workspace manifest. |
| config/deps-installer/test/installConfigDeps.ts | Refactors install tests to install from lockfile, adds migration test scaffolding. |
| config/deps-installer/src/resolveConfigDeps.ts | Writes config deps into pnpm-config-lock.yaml and workspace manifest specifiers, then installs from lockfile. |
| config/deps-installer/src/migrateConfigDeps.ts | New migration helper to convert legacy inline-integrity config deps into the lockfile format. |
| config/deps-installer/src/installConfigDeps.ts | Changes install API to accept either config lockfile or legacy manifest config deps (migration path). |
| config/deps-installer/src/index.ts | Exposes config lockfile utilities/types from the package public API. |
| config/deps-installer/src/configLockfile.ts | New YAML read/write + sorting logic for pnpm-config-lock.yaml. |
| config/deps-installer/package.json | Adds runtime deps needed for YAML lockfile parsing/writing and constants usage. |
| .changeset/config-deps-lockfile.md | Changeset describing the new config lockfile behavior and migration. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Resolved conflicts in: - config/deps-installer/package.json (combined both branch deps) - config/deps-installer/src/installConfigDeps.ts (integrated lockfile approach with calcLeafGlobalVirtualStorePath and symlinkDir from main) - config/deps-installer/tsconfig.json (included both calc-dep-state and constants references) - pnpm-lock.yaml (regenerated) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Validate integrity is a non-empty string in resolveConfigDeps - Detect clean-specifier format without lockfile in migrateConfigDeps and throw a descriptive error instead of misleading "no integrity" hint - Strengthen isConfigLockfile check to verify structural shape - Throw on missing packages entry in normalizeFromLockfile instead of silently skipping - Validate parsed YAML structure in readConfigLockfile - Add lockfile content assertions to migration test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The default import doesn't work with verbatimModuleSyntax since read-yaml-file is a CJS module. Use the named `sync` export consistent with the rest of the codebase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a project has a `packageManager` field in package.json specifying a pnpm version, resolve integrity checksums for both `pnpm` and `@pnpm/exe` (including their transitive dependencies) and store them in the `packageManager` section of pnpm-config-lock.yaml. This runs during both `pnpm self-update` (when updating the packageManager field) and `pnpm install` (when the field is present). Uses `pnpm install --lockfile-only` in a temp directory to resolve the full dependency tree. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-lock.yaml" This reverts commit 977f9c6.
…cess Replace `runPnpmCli` calls with direct `@pnpm/core` API usage in: - `resolvePackageManagerIntegrities`: uses `install()` with `lockfileOnly: true` - `installPnpmToTools`: uses `mutateModulesInSingleProject()` with `ignoreScripts: true` and `nodeLinker: 'hoisted'` - `switchCliVersion`: creates store controller for `installPnpmToTools` When integrities are available in pnpm-config-lock.yaml, self-update writes a pnpm-lock.yaml and performs a frozen install for verification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… in config lockfile - Add packageManagerDependencies to importers section (matching configDependencies pattern) - Store full packages and snapshots data using convertToLockfileFile - Use LockfilePackageInfo and LockfilePackageSnapshot from @pnpm/lockfile.types - Remove custom ConfigLockfilePackageInfo and ConfigLockfileSnapshotInfo types - Call resolvePackageManagerIntegrities in regular self-update path - Fix nock mock URL encoding for @pnpm/exe Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace mutateModulesInSingleProject with direct fetchPackage/importPackage into the global virtual store, making pnpm a regular global package. Add version discovery via findPnpmInGlobalStore for CLI version switching. Use pruneSharedLockfile to remove orphan entries from config lockfile. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use tryReadProjectManifest to detect if package.json exists. When it doesn't, fall back to pnpmHomeDir for config lockfile location and skip writing the packageManager field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the `copyCli` function in `pnpm setup` with `installCliGlobally` which runs `pnpm add -g file:<execDir>` to install the CLI into the standard global directory. This removes the need for the `.tools/pnpm-exe/` directory and aligns setup with the normal global package installation flow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cast the resolution to the expected shape since config dependencies always use tarball resolutions with integrity. Fixes TS2339 errors where LockfileResolution union includes types without these properties. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ading from disk resolvePackageManagerIntegrities now returns the ConfigLockfile it produced, which is then passed directly to installPnpmToTools via a new required configLockfile option. This avoids a redundant disk read of pnpm-config-lock.yaml. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 28 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…g lockfile Replace the manual fetch/import approach in installPnpmToTools with headlessInstall from @pnpm/headless, which properly installs all dependencies including subdeps of @pnpm/exe. Install location changed from $PNPM_HOME/.tools/ to the global directory ($PNPM_HOME/global/v11) using the @pnpm/global.packages utilities for consistency with pnpm add -g. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace manual headlessInstall with handleGlobalAdd from @pnpm/global.commands, which properly handles the global virtual store, hash links, bin linking, and the full installation pipeline. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r version switching - self-update: uses headlessInstall with config lockfile integrity hashes for secure frozen install, falls back to full resolution without lockfile. Installs to globalPkgDir and links bins to pnpmHomeDir. - version switch: uses installPnpmToStore which installs pnpm to the global virtual store ($STORE_DIR/links/) instead of globalPkgDir. Computes GVS hash from lockfile to check if already cached. Version-switched pnpm does not appear in `pnpm ls -g` and does not overwrite global binary. - Restores linkExePlatformBinary for @pnpm/exe support without Node.js. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The version switch now installs pnpm to the global virtual store instead of the tools dir. Update the test to find and corrupt the pnpm binary in the GVS path within the store. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The static imports of @pnpm/store-connection-manager, @pnpm/config.deps-installer, and @pnpm/tools.plugin-commands-self-updater (which now transitively imports @pnpm/headless) were loading on every pnpm CLI startup, causing hangs in unrelated commands. Switch to dynamic import() so these modules are only loaded when version switching is actually needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The resolvePackageManagerIntegrities call in getConfig ran for every command when packageManager was set in package.json, even for non-pnpm package managers like yarn. This caused hangs because it tries to resolve pnpm@VERSION from the registry for versions that may not exist. The resolution is only needed during version switching and is already called in switchCliVersion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move ConfigLockfile interface to @pnpm/lockfile.types, reusing SpecifierAndResolution - Move create/read/writeConfigLockfile to @pnpm/lockfile.fs - Use PnpmError instead of plain Error for validation - Use sortDirectKeys from @pnpm/object.key-sorting - Remove unused deps from @pnpm/config.deps-installer - Update all consumers to import from new locations - Sort imports in touched files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move toLockfileResolution from updateLockfile.ts to @pnpm/lockfile.utils for shared use - Use it in resolveConfigDeps.ts and migrateConfigDeps.ts instead of custom tarball comparison logic - Adds protocol normalization and %2f handling to config deps resolution (was missing before) - Remove get-npm-tarball-url from resolve-dependencies deps Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the install() + temp directory approach in resolvePackageManagerIntegrities with a direct call to resolveDependencies via a new resolveManifestDependencies helper. This eliminates temp dir creation, package.json writing, lockfile read-back, and cleanup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Inline the config lockfile filename string to avoid a tsgo resolution issue after @pnpm/core was removed from dependencies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the separate configLockfileToLockfileObject helper with a direct convertToLockfileObject call in resolvePackageManagerIntegrities. This removes the redundant manual merge/prune logic and reuses the existing lockfile format converters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared lockfileYamlDump and writeFileAtomic from write.ts and reuse them in configLockfile.ts instead of duplicating the YAML format config and write-file-atomic callback wrapper. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split getConfig into two phases: basic config and config deps/hooks installation. This allows switchCliVersion to run before config deps are installed, and ensures packageManagerDependencies are always written to the config lockfile even when the wanted pnpm version matches the current version. Also adds tests for version switching scenarios (v9.3.0, v10.32.0) and verifying packageManagerDependencies are saved when versions match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
write-file-atomic already returns a Promise when called without a callback, so util.promisify wraps it incorrectly (DEP0174) and the returned promise never resolves. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename ConfigLockfile to EnvLockfile, and all related functions (createConfigLockfile, readConfigLockfile, writeConfigLockfile) and variables throughout the codebase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The getToolDirPath function was never imported anywhere. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…update The global install path in self-update should not modify package.json. This matches the v10 behavior where only the managePackageManagerVersions path updates the packageManager field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 50 out of 51 changed files in this pull request and generated 6 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use replaceAll instead of replace for '%2f' in toLockfileResolution to handle multiple encoded slashes in tarball URLs - Strengthen resolvePackageManagerIntegrities early-return check to verify both pnpm and @pnpm/exe match the requested version Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot review feedback — addressedReviewed all 16 comments. Two were valid and fixed in 4a9b0d7. The rest are false positives (Copilot was reviewing outdated file snapshots). Fixed (2)
Already addressed — false positives (14)These were flagged against older file snapshots. The current code already handles all of them:
|
…kfile in switchCliVersion - Extract shared parseIntegrity function and NormalizedConfigDep interface into config/deps-installer/src/parseIntegrity.ts to remove duplication across normalizeConfigDeps.ts, migrateConfigDeps.ts, and installConfigDeps.ts - Fix bug in switchCliVersion.ts where envLockfile was never updated after resolvePackageManagerIntegrities() wrote it, causing first-time version switches to always throw NO_PKG_MANAGER_INTEGRITY - Replace confusing `&& true` with `Boolean()` in installPnpm.ts - Use util.types.isNativeError() instead of type assertion for error checking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
normalizeConfigDeps is no longer called by any code in the codebase. installConfigDeps was refactored to use normalizeForInstall which delegates to normalizeFromLockfile or migrateConfigDepsToLockfile. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Store config dependency and package manager integrity info in a separate
pnpm-lock.env.yamllockfile instead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the new env lockfile.Key changes
pnpm-lock.env.yamllockfile: Uses the standard lockfile format (importers,packages,snapshots) to store resolved config dependencies and package manager dependencies with integrity hashes and tarball URLs.pnpm-workspace.yamlare automatically migrated on install.packageManagerfield, pnpm is installed to the global virtual store ($STORE_DIR/links/) instead ofglobalPkgDir, reusing the content-addressable store for deduplication.pnpm self-updateperforms frozen headless installs using integrity hashes from the env lockfile, then links bins toPNPM_HOME.packageManagerDependencies: The env lockfile also stores resolvedpackageManagerDependenciesduring version switching and self-update.@pnpm/exesupport: Replicates@pnpm/exe's postinstall script (linking platform-specific binaries) since install scripts are disabled.pnpm setuprefactored: Usespnpm add -ginstead of copying the CLI binary directly.toLockfileResolutionto@pnpm/lockfile.utilsand deduplicatediteratePkgMetainto@pnpm/calc-dep-state.@pnpm/tools.pathpackage.Test plan
managePackageManagerVersions