feat(installing): delegate resolution to pacquet >= 0.11.7 when configured#12210
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR extends pnpm's pacquet integration to delegate dependency resolution to pacquet >= 0.11.7 during non-frozen installs. It introduces a PacquetEngine with version-based capability detection, a resolve-mode invocation that omits lockfile-enforcing flags, single-pass delegation with env-lockfile capture/restore, compatibility fallbacks to the legacy two-phase flow, unit and integration tests, and a changeset note. ChangesPacquet delegation with resolution capability
Sequence DiagramsequenceDiagram
participant install as pnpm install
participant willDelegate as willDelegateToPacquet
participant pacquetEngine as PacquetEngine
participant lockfile as Lockfile FS
install->>willDelegate: Check if delegation enabled
willDelegate->>willDelegate: Check supportsResolution, nodeLinker, lockfileCheck
alt Single-pass resolve + materialize (pacquet >= 0.11.7)
install->>lockfile: readEnvLockfile()
install->>pacquetEngine: run({ resolve: true })
pacquetEngine->>lockfile: Write resolved pnpm-lock.yaml
install->>lockfile: writeEnvLockfile(saved config)
else Resolve in pnpm, then delegate materialize
install->>install: _installInContext(lockfileOnly: true)
install->>pacquetEngine: run({ filterResolvedProgress: true })
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
|
/agentic_review |
Code Review by Qodo
1. Branch lockfile reloaded
|
|
Code review by qodo was updated up to the latest commit f637f25 |
When pacquet is declared in configDependencies, pnpm previously always ran it with --frozen-lockfile (pnpm resolved, pacquet materialized). If the installed pacquet is >= 0.11 it ships its own resolver, so a non-frozen plain install on the default isolated linker is now delegated end-to-end: pacquet resolves, writes pnpm-lock.yaml, and materializes in a single pass. Older pacquet keeps the resolve-then-materialize split, and add/update/remove still resolve in pnpm.
Bump the e2e pacquet pin to 0.11.0 (published under both pacquet and @pnpm/pacquet) and add tests for the resolve path, the materialize-only fallback (pinned to 0.2.14), and the scoped alias. Un-skip the add/update tests now that pacquet 0.11 writes a compatible .modules.yaml, and fix the update test (is-positive has no v4; update from 1.0.0 instead). Also preserve the configDependencies env document when pacquet resolves: pacquet rewrites pnpm-lock.yaml without the leading env YAML doc, which dropped configDependencies and broke the next --frozen-lockfile install. Capture it before delegating and restore it after.
…cquet fails On the pacquet resolve-delegation path the configDependencies env document was only restored after a successful pacquet run. A non-zero exit could leave a rewritten pnpm-lock.yaml without it, breaking the next --frozen-lockfile install's config-deps freshness gate. Restore it in a finally block, swallowing (and warning on) any restore error so it cannot mask the original pacquet failure.
|
Code review by qodo was updated up to the latest commit 674f1ec |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pnpm/test/install/pacquet.ts`:
- Around line 80-97: The two "newly-added dependency" tests (in
pnpm/test/install/pacquet.ts at lines 80-97 and 99-115) assert identical
outcomes despite describing different resolver ownership paths. Add a
differentiating assertion to each test that proves which resolver performed the
resolution, not just that pacquet materialized the result. The first test (lines
80-97) should validate the behavior specific to pacquet performing resolution
itself in a non-frozen pass, while the second test (lines 99-115) should
validate the behavior specific to pnpm performing the resolution. This prevents
a regression where both execution paths converge but still pass the same
assertions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 9a53f26f-c81d-4e1d-972f-d5ab9c915012
📒 Files selected for processing (7)
.changeset/pacquet-resolving-install-delegation.mdinstalling/commands/src/recursive.tsinstalling/commands/src/runPacquet.tsinstalling/commands/test/runPacquet.tsinstalling/deps-installer/src/install/extendInstallOptions.tsinstalling/deps-installer/src/install/index.tspnpm/test/install/pacquet.ts
✅ Files skipped from review due to trivial changes (1)
- .changeset/pacquet-resolving-install-delegation.md
🚧 Files skipped from review as they are similar to previous changes (5)
- installing/commands/src/recursive.ts
- installing/commands/test/runPacquet.ts
- installing/deps-installer/src/install/extendInstallOptions.ts
- installing/commands/src/runPacquet.ts
- installing/deps-installer/src/install/index.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use Standard Style with trailing commas, prefer functions over classes, declare functions after they are used relying on hoisting, limit function arguments to two or three with options objects for additional parameters
Follow import order: standard libraries, external dependencies (sorted alphabetically), then relative imports
Use JSDoc for function contracts (preconditions, postconditions, edge cases, why it exists) not for re-narrating the body; do not record past implementation shape or refactor history in comments
Files:
pnpm/test/install/pacquet.ts
🧠 Learnings (4)
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.
Applied to files:
pnpm/test/install/pacquet.ts
📚 Learning: 2026-05-24T08:18:00.622Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11895
File: pnpm/test/deploy.ts:91-95
Timestamp: 2026-05-24T08:18:00.622Z
Learning: In pnpm/pnpm integration tests that intentionally hit the real npm registry (registry.npmjs.org)—for example when the test passes `--config.registry=https://registry.npmjs.org/` to `execPnpm` and simply increases the timeout—do not request adding a runtime environment-variable gate (e.g., `PNPM_RUN_PUBLIC_REGISTRY_TESTS`). This is the established pattern for those tests (see files like `pnpm/test/install/pacquet.ts` and `pnpm/test/deploy.ts`).
Applied to files:
pnpm/test/install/pacquet.ts
📚 Learning: 2026-06-05T13:47:05.929Z
Learnt from: vsumner
Repo: pnpm/pnpm PR: 12190
File: installing/deps-installer/test/install/frozenStore.ts:2-17
Timestamp: 2026-06-05T13:47:05.929Z
Learning: In the pnpm/pnpm repository, the shared Jest preset keeps `injectGlobals` at its default (`true`), so `test` and `expect` are available as Jest globals. Therefore, reviewers should not flag (or treat as TypeScript/compilation errors) missing `import { test, expect } from 'jest/globals'` when a test file uses `test`/`expect` without importing them. Importing from `jest/globals` may still be used for consistency with sibling files, but it is not required for execution in this repo unless a Jest preset is explicitly configured with `injectGlobals: false`.
Applied to files:
pnpm/test/install/pacquet.ts
📚 Learning: 2026-06-05T13:47:26.046Z
Learnt from: vsumner
Repo: pnpm/pnpm PR: 12190
File: installing/deps-installer/src/install/index.ts:2337-2343
Timestamp: 2026-06-05T13:47:26.046Z
Learning: In the pnpm/pnpm codebase, `PnpmError` automatically prefixes `err.code` with `ERR_PNPM_` when you pass a code that does not already start with `ERR_PNPM_` (it normalizes `this.code` via `code.startsWith('ERR_PNPM_') ? code : `ERR_PNPM_${code}``). Therefore, during code review you should NOT flag `new PnpmError(...)` call sites for passing a bare error code (e.g., `new PnpmError('FROZEN_STORE_INCOMPATIBLE_WITH_PNPR', ...)`); the resulting `err.code` will still be `ERR_PNPM_FROZEN_STORE_INCOMPATIBLE_WITH_PNPR`.
Applied to files:
pnpm/test/install/pacquet.ts
🔇 Additional comments (1)
pnpm/test/install/pacquet.ts (1)
13-17: No boundary inconsistency found—implementation, tests, and release notes all consistently use>= 0.11.7.All layers use the same version boundary:
PACQUET_VERSION = '0.11.7'in tests,>= 0.11.7in implementation comments, delegation gating, and release notes. The version check logic inpacquetSupportsResolutioncorrectly handles pre-releases (e.g.,0.11.7-rc.1). No changes required.> Likely an incorrect or invalid review comment.
|
Code review by qodo was updated up to the latest commit 875ef2a |
|
Code review by qodo was updated up to the latest commit ce8df5b |
|
Code review by qodo was updated up to the latest commit cf7fa36 |
|
Code review by qodo was updated up to the latest commit ad49a92 |
|
Code review by qodo was updated up to the latest commit dde125d |
What
When pacquet is declared in
configDependencies, pnpm previously always ran it with--frozen-lockfile: pnpm resolved the dependency graph (in JS, writingpnpm-lock.yaml) and pacquet only fetched / imported / linked. This PR lets pacquet do the resolution too — when the installed pacquet is new enough to support full resolving installs (>= 0.11.7).With a resolution-capable pacquet, a non-frozen plain
pnpm installon the default isolatednodeLinkeris delegated end-to-end in a single non-frozen pass: pacquet resolves the manifests, writespnpm-lock.yaml, and materializesnode_modules. Older pacquet keeps the existing resolve-then-materialize split, andadd/update/removestill resolve in pnpm (it must rewrite the manifests first).How
installing/commands/src/runPacquet.ts—makeRunPacquetnow returns aPacquetEngine{ supportsResolution, run }.supportsResolutionis detected from the pacquet version innode_modules/.pnpm-config/<name>/package.json(gated>= 0.11.7; prereleases like0.11.7-rc.1count; unreadable version →false, degrading to the safe materialize-only path).rungained aresolveoption that omits the injected--frozen-lockfile/--ignore-manifest-check.installing/deps-installer/src/install/index.ts— the isolated-linker non-frozen path now delegates the whole install viarun({ resolve: true })for plain installs when pacquet supports resolution, returning a minimalInstallFunctionResult(mirroring the frozen delegation). The redundantverifyLockfileResolutionspass is skipped when pacquet will re-resolve (it applies the resolver policy during fresh resolution itself).configDependenciesare recorded in a YAML document prepended topnpm-lock.yaml, a pnpm-only concept pacquet doesn't model. Since pacquet rewritespnpm-lock.yamlon the resolve path, pnpm now captures that env document before delegating and restores it afterwards; otherwise it was dropped and the next--frozen-lockfileinstall failed its config-deps freshness gate.opts.runPacquet(...)toopts.runPacquet.run(...); engine type threaded throughextendInstallOptions.tsandrecursive.ts.Tests
installing/commands/test/runPacquet.ts— hermetic unit tests for the version gate.pnpm/test/install/pacquet.ts— e2e pin bumped to the released0.11.7(published under bothpacquetand@pnpm/pacquet). Added coverage for the resolve path, the materialize-only fallback (pinned to0.11.6), and the scoped alias; un-skipped theadd/updatetests (pacquet 0.11.7 now writes a compatible.modules.yaml) and fixed theupdatetest (is-positive has no v4 — it updates from1.0.0). All 7 pass against the live registry.Scope
Resolution delegation is currently scoped to the default isolated linker + plain
install; hoisted-linker andadd/update/removecontinue to resolve in pnpm. This can be widened later.Written by an agent (Claude Code, claude-opus-4-8).
Updated by an agent (Codex, GPT-5).
Summary by CodeRabbit