refactor: replace the experimental pnpm-agent server with pnpr#12151
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (38)
💤 Files with no reviewable changes (22)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (13)
📜 Recent 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). (6)
🧰 Additional context used📓 Path-based instructions (1)pnpr/**/pnpr/**/*.rs📄 CodeRabbit inference engine (pnpr/AGENTS.md)
Files:
🧠 Learnings (28)📓 Common learnings📚 Learning: 2026-05-25T14:58:11.105ZApplied to files:
📚 Learning: 2026-05-23T09:14:43.635ZApplied to files:
📚 Learning: 2026-05-24T21:11:04.272ZApplied to files:
📚 Learning: 2026-05-23T09:14:43.635ZApplied to files:
📚 Learning: 2026-05-20T21:18:55.266ZApplied to files:
📚 Learning: 2026-05-20T23:07:40.413ZApplied to files:
📚 Learning: 2026-05-21T00:33:05.035ZApplied to files:
📚 Learning: 2026-05-21T00:33:05.035ZApplied to files:
📚 Learning: 2026-05-24T21:11:04.272ZApplied to files:
📚 Learning: 2026-05-20T21:18:56.391ZApplied to files:
📚 Learning: 2026-05-20T22:49:17.652ZApplied to files:
📚 Learning: 2026-05-19T19:23:00.981ZApplied to files:
📚 Learning: 2026-06-02T14:39:46.617ZApplied to files:
📚 Learning: 2026-05-20T23:24:24.022ZApplied to files:
📚 Learning: 2026-05-19T00:19:52.808ZApplied to files:
📚 Learning: 2026-06-02T14:39:19.809ZApplied to files:
📚 Learning: 2026-05-23T17:30:06.849ZApplied to files:
📚 Learning: 2026-05-20T20:41:50.322ZApplied to files:
📚 Learning: 2026-05-28T16:19:30.483ZApplied to files:
📚 Learning: 2026-05-18T20:35:22.917ZApplied to files:
📚 Learning: 2026-05-20T10:06:55.749ZApplied to files:
📚 Learning: 2026-05-29T18:03:15.354ZApplied to files:
📚 Learning: 2026-05-07T20:38:01.796ZApplied to files:
📚 Learning: 2026-05-14T07:57:23.823ZApplied to files:
📚 Learning: 2026-05-29T18:03:15.354ZApplied to files:
📚 Learning: 2026-05-20T23:07:43.668ZApplied to files:
📚 Learning: 2026-05-20T01:42:44.958ZApplied to files:
🔇 Additional comments (8)
📝 WalkthroughWalkthroughThis PR moves the agent lockfile wire to on-disk LockfileFile, updates the agent client and install path to use that format, implements pnpr multi-project importer normalization and temp-workspace reconstruction, and updates tests/CI and repo wiring to target pnpr while removing server-side agent artifacts. ChangesAgent migration to pnpr with lockfile and workspace updates
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #12151 +/- ##
==========================================
+ Coverage 87.56% 87.57% +0.01%
==========================================
Files 267 267
Lines 30649 30710 +61
==========================================
+ Hits 26837 26894 +57
- Misses 3812 3816 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Integrated-Benchmark Report (Linux)Scenario: Isolated linker: fresh restore, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.84146457696,
"stddev": 0.11546319578162129,
"median": 1.83398734886,
"user": 2.8256139399999998,
"system": 2.22499222,
"min": 1.69999182736,
"max": 2.08871451536,
"times": [
1.96108029136,
1.75695415536,
1.8584042203600002,
1.83675816636,
1.73827639336,
1.76899599936,
1.87425366936,
1.83121653136,
1.69999182736,
2.08871451536
]
},
{
"command": "pacquet@main",
"mean": 1.82623376396,
"stddev": 0.050159105814385305,
"median": 1.8309992483600002,
"user": 2.7895607399999998,
"system": 2.25749502,
"min": 1.75440231736,
"max": 1.93454062736,
"times": [
1.75440231736,
1.85275939336,
1.84531259036,
1.8370814913600002,
1.79529454436,
1.79707966436,
1.8249170053600001,
1.93454062736,
1.84410830536,
1.7768417003599999
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.5601436452599999,
"stddev": 0.015508849208250597,
"median": 0.55462221286,
"user": 0.40976973999999994,
"system": 0.8882183600000001,
"min": 0.54132907086,
"max": 0.5954423948600001,
"times": [
0.5954423948600001,
0.55179974286,
0.5628258688600001,
0.5746557668600001,
0.54861304786,
0.55527966886,
0.56503639986,
0.55396475686,
0.5524897348600001,
0.54132907086
]
},
{
"command": "pacquet@main",
"mean": 0.54282169906,
"stddev": 0.02746739030790533,
"median": 0.53440828486,
"user": 0.39042694,
"system": 0.8757921599999999,
"min": 0.52380020886,
"max": 0.61793769086,
"times": [
0.61793769086,
0.5393872468600001,
0.52902304986,
0.5492576598600001,
0.53303400186,
0.52380020886,
0.5258981888600001,
0.54173050786,
0.53578256786,
0.5323658678600001
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.3500621144,
"stddev": 0.04100243045715337,
"median": 2.3547028715,
"user": 4.3350221399999995,
"system": 2.19584242,
"min": 2.2916353634999997,
"max": 2.4044917115,
"times": [
2.4044917115,
2.3947882915,
2.3981878045,
2.3552189045,
2.3231394405,
2.3541868385,
2.3607685215,
2.3190899055,
2.2991143624999997,
2.2916353634999997
]
},
{
"command": "pacquet@main",
"mean": 2.3159471673,
"stddev": 0.05568266499372405,
"median": 2.3031269415,
"user": 4.25996144,
"system": 2.19718362,
"min": 2.2305551484999997,
"max": 2.3937561735,
"times": [
2.2612207255,
2.2305551484999997,
2.2883707995,
2.3661568655,
2.2749817365,
2.2987452155,
2.3937561735,
2.3862539305,
2.3075086675,
2.3519224105
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.51675569952,
"stddev": 0.022693026034219164,
"median": 1.52020203682,
"user": 1.9360488,
"system": 1.2369958,
"min": 1.48281644432,
"max": 1.55246308732,
"times": [
1.52187795932,
1.53234785532,
1.48884597432,
1.48281644432,
1.50266166532,
1.49927185832,
1.51852611432,
1.53041297132,
1.53833306532,
1.55246308732
]
},
{
"command": "pacquet@main",
"mean": 1.5876469764199999,
"stddev": 0.08391295576892865,
"median": 1.58704422282,
"user": 1.9828265000000003,
"system": 1.2849792,
"min": 1.48695008432,
"max": 1.7890921803200002,
"times": [
1.52970950532,
1.58574493932,
1.50004764232,
1.48695008432,
1.7890921803200002,
1.5736942663200002,
1.58834350632,
1.61908893932,
1.59813167232,
1.60566702832
]
}
]
} |
|
| Branch | pr/12151 |
| Testbed | pacquet |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 2,350.06 ms(+0.30%)Baseline: 2,342.99 ms | 2,811.59 ms (83.58%) |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 1,516.76 ms(-0.12%)Baseline: 1,518.65 ms | 1,822.38 ms (83.23%) |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 1,841.46 ms(-10.27%)Baseline: 2,052.16 ms | 2,462.59 ms (74.78%) |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 560.14 ms(-13.77%)Baseline: 649.59 ms | 779.51 ms (71.86%) |
Review Summary by QodoReplace pnpm-agent server with pnpr and add multi-project workspace support
WalkthroughsDescription• Replace experimental pnpm-agent TypeScript server with pnpr Rust server • Add multi-project workspace support to pnpr's install resolution • Bridge on-disk/in-memory lockfile format mismatch between client and server • Add path-traversal validation for importer directories in pnpr • Update pnpm client to read and forward on-disk lockfile format Diagramflowchart LR
A["pnpm Client"] -->|"on-disk lockfile format"| B["pnpr Server"]
B -->|"resolve workspace"| C["Reconstruct temp workspace"]
C -->|"root + members"| D["pacquet install"]
D -->|"resolved lockfile"| E["Convert to in-memory"]
E -->|"LockfileObject"| A
F["readWantedLockfileFile"] -->|"skip conversion"| B
G["sanitized_importer_dir"] -->|"path validation"| C
File Changes1. pnpr/crates/pnpr/src/install_accelerator/resolve.rs
|
There was a problem hiding this comment.
Pull request overview
This PR removes the experimental TypeScript pnpm-agent server from the monorepo and switches the pnpm e2e “agent” coverage to exercise the Rust pnpr server implementing the same /v1/install + /v1/files protocol. It also bridges the lockfile wire-format mismatch by introducing a “raw/on-disk” wanted-lockfile reader and converting server responses into pnpm’s in-memory lockfile object.
Changes:
- Remove
agent/server(pnpm-agent) and scrub references (workspace deps, tsconfig project refs, meta-updater behavior). - Update
@pnpm/agent.client+ deps-installer to send/receive the on-disk lockfile format over the wire, converting only at the client boundary. - Extend
pnprinstall-accelerator to support multi-project workspace requests by reconstructing a workspace on disk, including path traversal protection + tests.
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| worker/src/start.ts | Updates agent URL example comment to reference pnpr. |
| pnpr/crates/pnpr/src/install_accelerator/resolve/tests.rs | Adds unit tests for importer-dir sanitization + manifest name uniqueness. |
| pnpr/crates/pnpr/src/install_accelerator/resolve.rs | Reconstructs workspace installs in a temp dir; adds importer dir sanitization and synthetic manifest naming. |
| pnpr/crates/pnpr/src/install_accelerator/protocol.rs | Adds dir to project requests and normalizes legacy vs multi-project request shapes. |
| pnpr/crates/pnpr/src/install_accelerator/diff.rs | Updates module docs to remove pnpm-agent wording. |
| pnpr/crates/pnpr/src/install_accelerator.rs | Removes hard rejection for multi-project requests and updates docs to reflect workspace support. |
| pnpm/tsconfig.json | Drops tsconfig project reference to removed agent/server. |
| pnpm/test/install/pnpmRegistry.ts | Routes agent e2e tests through the pnpr server and adds an incremental-resolution case (forward existing lockfile). |
| pnpm/package.json | Removes pnpm-agent workspace dependency. |
| pnpm-lock.yaml | Removes agent/server importer; adds @pnpm/lockfile.fs dependency for agent/client. |
| lockfile/fs/src/read.ts | Introduces readWantedLockfileFile() and plumbs raw on-disk lockfile shape through the internal read path. |
| installing/deps-installer/src/install/index.ts | Reads and forwards the raw lockfile shape to the agent instead of the in-memory lockfile object. |
| installing/deps-installer/src/install/extendInstallOptions.ts | Updates agent option docs to be server-agnostic and mention pnpr. |
| agent/server/tsconfig.lint.json | Deletes pnpm-agent server config (package removed). |
| agent/server/tsconfig.json | Deletes pnpm-agent server config (package removed). |
| agent/server/test/tsconfig.json | Deletes pnpm-agent server tests config (package removed). |
| agent/server/test/integration.ts | Deletes pnpm-agent integration tests (package removed). |
| agent/server/test/diff.ts | Deletes pnpm-agent diff unit tests (package removed). |
| agent/server/src/protocol.ts | Deletes pnpm-agent server protocol types (package removed). |
| agent/server/src/metadataStore.ts | Deletes pnpm-agent server metadata store (package removed). |
| agent/server/src/index.ts | Deletes pnpm-agent server exports (package removed). |
| agent/server/src/fileStore.ts | Deletes pnpm-agent server file store (package removed). |
| agent/server/src/diff.ts | Deletes pnpm-agent server diff logic (package removed). |
| agent/server/src/createRegistryServer.ts | Deletes pnpm-agent server implementation (package removed). |
| agent/server/src/bin.ts | Deletes pnpm-agent server CLI (package removed). |
| agent/server/README.md | Deletes pnpm-agent documentation (package removed). |
| agent/server/package.json | Deletes pnpm-agent package manifest (package removed). |
| agent/server/LICENSE.md | Deletes pnpm-agent license file (package removed). |
| agent/server/Dockerfile | Deletes pnpm-agent Dockerfile (package removed). |
| agent/server/CONTRIBUTING.md | Deletes pnpm-agent contributing terms (package removed). |
| agent/server/CHANGELOG.md | Deletes pnpm-agent changelog (package removed). |
| agent/client/tsconfig.json | Adds project reference to lockfile/fs (needed for lockfile conversion import). |
| agent/client/src/fetchFromPnpmRegistry.ts | Converts server-returned lockfile from on-disk to in-memory format; updates lockfile option type to on-disk. |
| agent/client/package.json | Adds @pnpm/lockfile.fs dependency for lockfile conversion. |
| .meta-updater/src/index.ts | Removes pnpm-agent special-casing (experimental + license handling) and normalizes license handling. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1147b13 to
333bf9c
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 38 out of 39 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
pnpr/crates/pnpr/src/install_accelerator/resolve.rs:343
sanitized_importer_dircurrently normalizes a string of only slashes (e.g. "/" or "////") to "." becausetrim_end_matches('/')runs before the absolute-path check. That can silently accept an absolute path and also collide with the real root importer (".") in the same request.
The experimental TypeScript `pnpm-agent` install-accelerator server is superseded by the `pnpr` server, which implements the same protocol. Remove `agent/server` and route the agent e2e test through pnpr. The pnpm TypeScript client (`@pnpm/agent.client`) is kept and made compatible with pnpr. The wire protocol carries the on-disk lockfile format, while pnpm keeps an in-memory `LockfileObject` in process: - Incoming: the agent's response lockfile is converted to the in-memory shape via `convertToLockfileObject`. - Outgoing: the existing lockfile is read in its on-disk shape with the new `readWantedLockfileFile` and forwarded as-is — no in-memory round-trip. pnpr now resolves multi-project workspaces by reconstructing the workspace on disk (root manifest + `pnpm-workspace.yaml` + member manifests) and letting pacquet's install path discover every importer. Member dirs are written as quoted YAML scalars; importer dirs are validated against path traversal (rejecting absolute, `..`, backslash, and slashes-only inputs) and de-duplicated; synthetic manifest names map injectively from dirs. The CI test job builds the `pnpr` server from source (cached on the Rust sources) so the agent e2e tests run against the current server. The published `@pnpm/pnpr` is dropped as a test dependency: running the suite already requires building `pnpr-prepare` from source (no npm fallback), so the toolchain to build `pnpr` is always present, and the published binary can predate the server protocol the tests exercise.
What
The experimental TypeScript
pnpm-agentinstall-accelerator server (agent/server) is superseded by the pnpr server, which implements the same/v1/install+/v1/filesprotocol. This PR removespnpm-agentand routes its e2e test through pnpr.The pnpm-side client
@pnpm/agent.client(which powers--config.agent) is kept — it is server-agnostic and now works against pnpr.Why it needed more than a swap
The pnpm TypeScript client and pnpr had never been exercised together (pnpr's
/v1/installwas only tested against the pacquet Rust client), and two real parity gaps surfaced when pointing the e2e test at pnpr:packages/snapshots,{specifier, version}importer deps), while pnpm keeps an in-memoryLockfileObjectin process. Without bridging, linking failed withref.startsWith is not a function. Handled in@pnpm/agent.client, reusing pnpm's own converters:convertToLockfileObject.readWantedLockfileFileand forwarded as-is — no in-memory→on-disk round-trip./v1/installhard-rejectedprojects.length > 1with a400. It now reconstructs the workspace on disk (root manifest +pnpm-workspace.yaml+ member manifests) and lets pacquet's install path discover and resolve every importer. Importer dirs are validated against path traversal (sanitized_importer_dir).Changes
agent/server/(thepnpm-agentpackage) and scrubbed all references (pnpm/package.json,.meta-updater, tsconfig project reference, docs/comments).pnpm/test/install/pnpmRegistry.tsto drive the pnpr server the test harness already starts; kept the counting proxy so the "agent was used" assertions stay meaningful. Added a case that forwards an existing lockfile to the agent on a second resolution.@pnpm/lockfile.fs: addedreadWantedLockfileFile, returning the raw on-diskLockfileFile(the_readpath now exposes the pre-conversion file).@pnpm/agent.client: incoming on-disk → in-memory conversion; outgoing now sends the raw on-disk lockfile.diradded to the install-request protocol; multi-project workspace resolution; path-traversal guard with unit tests.Verification
pnpm/test/install/pnpmRegistry.ts: 10/10 pass against pnpr (single-project, workspace, and incremental-with-existing-lockfile cases).@pnpm/lockfile.fs: 46/46 unit tests pass.cargo fmt,cargo doc,cargo dylint,taploall clean.pnpm --filter pnpm run compile(tsc + bundle) andpnpm run lint:metapass; ESLint clean on changed files.No changeset (removal of an experimental published package; the pnpm CLI's
--config.agentbehavior is unchanged).Written by an agent (Claude Code, claude-opus-4-8).
Summary by CodeRabbit
New Features
Refactor
Chores