You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When an installer keeps dedupeInjectedDeps: false and the workspace has an injected dep — e.g. dependenciesMeta: { b: { injected: true } } on packages/a consuming packages/b via workspace:* — pacquet:
Never copies packages/b's contents into <virtual_store>/b@file+packages+b/.
So the symlink in step 3 points at a directory that doesn't exist on disk.
How it surfaces
Linux / macOS:pacquet install exits 0. The dangling symlink silently breaks anything that tries to read through it; pnpm itself can no longer load that importer's deps from pacquet-written output.
Windows: the bin-link pass that walks each importer's node_modules reading package.json for bin manifests trips ERROR_INVALID_NAME (os error 123) reading through the broken link with a mixed-separator path (packages/a\\node_modules\\b\\package.json). Install fails.
#12023 ships an e2e regression test for the lockfile-writer's File arm (pacquet/crates/cli/tests/dedupe_injected_deps.rs::injected_workspace_dep_with_dedupe_off_writes_file_arm) marked #[cfg_attr(target_os = \"windows\", ignore = \"…\")] because of this gap. The test should be re-enabled on Windows once this is fixed.
Expected behavior
Pacquet's create_virtual_store pass should treat a file:<workspace> snapshot the same way pnpm does: copy (or hardlink, depending on packageImportMethod) the source workspace project's contents into <virtual_store>/<name>@file+<path>/node_modules/<name>/ so the per-importer symlink resolves to a real directory.
Problem
When an installer keeps
dedupeInjectedDeps: falseand the workspace has an injected dep — e.g.dependenciesMeta: { b: { injected: true } }onpackages/aconsumingpackages/bviaworkspace:*— pacquet:btofile:packages/b(correct).pnpm-lock.yamlunderfile:packages/b(correct, after feat(pacquet): port dedupeInjectedDeps #12023'sImporterDepVersion::Filearm).packages/a/node_modules/b→<virtual_store>/b@file+packages+b/node_modules/b.packages/b's contents into<virtual_store>/b@file+packages+b/.So the symlink in step 3 points at a directory that doesn't exist on disk.
How it surfaces
pacquet installexits 0. The dangling symlink silently breaks anything that tries to read through it; pnpm itself can no longer load that importer's deps from pacquet-written output.node_modulesreadingpackage.jsonfor bin manifests tripsERROR_INVALID_NAME(os error 123) reading through the broken link with a mixed-separator path (packages/a\\node_modules\\b\\package.json). Install fails.#12023 ships an e2e regression test for the lockfile-writer's
Filearm (pacquet/crates/cli/tests/dedupe_injected_deps.rs::injected_workspace_dep_with_dedupe_off_writes_file_arm) marked#[cfg_attr(target_os = \"windows\", ignore = \"…\")]because of this gap. The test should be re-enabled on Windows once this is fixed.Expected behavior
Pacquet's
create_virtual_storepass should treat afile:<workspace>snapshot the same way pnpm does: copy (or hardlink, depending onpackageImportMethod) the source workspace project's contents into<virtual_store>/<name>@file+<path>/node_modules/<name>/so the per-importer symlink resolves to a real directory.Upstream's
runLifecycleHooksConcurrently+storeController.importPackageflow for injected dirs is the closest pnpm equivalent; pacquet'sinstall_package_by_snapshot.rsalready has a TODO comment at thedependenciesMeta[*].injected = truebranch on the matter.Scope
file:<rel-path-to-lockfile-dir>snapshot keys duringcreate_virtual_store.packageImportMethod(clone / hardlink / copy).excludeLinksFromLockfileinteractions still work — the materialised path must agree with the symlink target the linker computes.#[cfg_attr(target_os = \"windows\", ignore)]on the e2e test above.Related
injectWorkspacePackagesline).Filearm and surfaced the missing materialise step.Written by an agent (Claude Code, claude-opus-4-7).