Skip to content

Adds support for generating package maps#311

Merged
arcanis merged 8 commits into
mainfrom
mael/package-maps
Jun 22, 2026
Merged

Adds support for generating package maps#311
arcanis merged 8 commits into
mainfrom
mael/package-maps

Conversation

@arcanis

@arcanis arcanis commented Jun 15, 2026

Copy link
Copy Markdown
Member

Counterpart of yarnpkg/berry#7184 for the Rust implementation.


Note

Medium Risk
Touches install linking, generated artifacts, and NODE_OPTIONS for all scripts; behavior changes module resolution when package maps are enabled, though defaults keep the feature off.

Overview
Adds Node.js experimental package map support for nodeLinker: node-modules and nodeLinker: pnpm (Rust zpm counterpart to Berry #7184).

New settings nodeExperimentalPackageMap (inject --experimental-package-map=… into NODE_OPTIONS when enabled) and nodePackageMapType (standard vs loose dependency edges). During link, the node-modules and pnpm linkers build and write node_modules/.package-map.json (per-workspace for node-modules islands), tracking installed layout and declared vs hoisted dependencies. script environments refresh/strip package-map flags alongside PnP loaders, using island-aware map paths when cwd is in a node-modules island.

Supporting changes: new linker/package_map module, Project::package_map_path, PnP linker cleanup removes stale maps, Path::without_trailing_separators, and acceptance tests for maps, loose mode, and island injection.

Reviewed by Cursor Bugbot for commit 889778e. Bugbot is set up for automated code reviews on this repo. Configure here.

@netlify

netlify Bot commented Jun 15, 2026

Copy link
Copy Markdown

Deploy Preview for yarn-v6 ready!

Name Link
🔨 Latest commit 889778e
🔍 Latest deploy log https://app.netlify.com/projects/yarn-v6/deploys/6a398a48eb750f0009858777
😎 Deploy Preview https://deploy-preview-311--yarn-v6.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@arcanis

arcanis commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

@cursor review

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

⏱️ Benchmark Results

gatsby install-full-cold

Metric Base Head Difference
Mean 4.472s 4.477s +0.11% ⚠️
Median 4.464s 4.473s +0.19% ⚠️
Min 4.396s 4.276s
Max 4.570s 4.567s
Std Dev 0.052s 0.060s
📊 Raw benchmark data (gatsby install-full-cold)

Base times: 4.464s, 4.465s, 4.411s, 4.533s, 4.398s, 4.459s, 4.461s, 4.434s, 4.536s, 4.411s, 4.441s, 4.425s, 4.441s, 4.520s, 4.542s, 4.540s, 4.510s, 4.406s, 4.420s, 4.505s, 4.505s, 4.515s, 4.447s, 4.396s, 4.492s, 4.570s, 4.498s, 4.513s, 4.400s, 4.514s

Head times: 4.506s, 4.501s, 4.567s, 4.544s, 4.463s, 4.465s, 4.449s, 4.533s, 4.541s, 4.460s, 4.470s, 4.537s, 4.451s, 4.453s, 4.501s, 4.497s, 4.420s, 4.528s, 4.492s, 4.555s, 4.475s, 4.509s, 4.467s, 4.436s, 4.470s, 4.536s, 4.440s, 4.276s, 4.363s, 4.418s


gatsby install-cache-only

Metric Base Head Difference
Mean 1.311s 1.317s +0.47% ⚠️
Median 1.297s 1.304s +0.54% ⚠️
Min 1.276s 1.272s
Max 1.614s 1.756s
Std Dev 0.059s 0.084s
📊 Raw benchmark data (gatsby install-cache-only)

Base times: 1.311s, 1.304s, 1.281s, 1.313s, 1.293s, 1.312s, 1.286s, 1.303s, 1.319s, 1.276s, 1.295s, 1.290s, 1.341s, 1.285s, 1.291s, 1.283s, 1.296s, 1.289s, 1.614s, 1.313s, 1.304s, 1.301s, 1.304s, 1.296s, 1.348s, 1.304s, 1.285s, 1.297s, 1.297s, 1.289s

Head times: 1.320s, 1.308s, 1.272s, 1.287s, 1.310s, 1.310s, 1.322s, 1.304s, 1.296s, 1.272s, 1.297s, 1.299s, 1.302s, 1.287s, 1.305s, 1.311s, 1.293s, 1.319s, 1.313s, 1.756s, 1.304s, 1.303s, 1.285s, 1.324s, 1.283s, 1.305s, 1.329s, 1.312s, 1.283s, 1.294s


gatsby install-cache-and-lock (warm, with lockfile)

Metric Base Head Difference
Mean 0.355s 0.369s +3.92% ⚠️
Median 0.355s 0.353s -0.66% ✅
Min 0.349s 0.350s
Max 0.362s 0.831s
Std Dev 0.004s 0.087s
📊 Raw benchmark data (gatsby install-cache-and-lock (warm, with lockfile))

Base times: 0.350s, 0.356s, 0.351s, 0.351s, 0.353s, 0.352s, 0.350s, 0.349s, 0.359s, 0.356s, 0.356s, 0.356s, 0.355s, 0.360s, 0.356s, 0.359s, 0.359s, 0.356s, 0.355s, 0.354s, 0.351s, 0.361s, 0.354s, 0.355s, 0.356s, 0.351s, 0.351s, 0.362s, 0.359s, 0.358s

Head times: 0.356s, 0.354s, 0.352s, 0.350s, 0.353s, 0.351s, 0.353s, 0.831s, 0.352s, 0.350s, 0.354s, 0.353s, 0.352s, 0.351s, 0.356s, 0.355s, 0.355s, 0.356s, 0.354s, 0.354s, 0.352s, 0.352s, 0.350s, 0.352s, 0.354s, 0.352s, 0.351s, 0.354s, 0.351s, 0.359s

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Nm map lacks self dependencies
    • Added implicit self-dependency to node-modules package map builder to mirror pnpm linker behavior, ensuring packages can resolve their own name when using nodeExperimentalPackageMap.

Create PR

Or push these changes by commenting:

@cursor push ba99b5b726
Preview (ba99b5b726)
diff --git a/packages/zpm/src/linker/package_map.rs b/packages/zpm/src/linker/package_map.rs
--- a/packages/zpm/src/linker/package_map.rs
+++ b/packages/zpm/src/linker/package_map.rs
@@ -267,9 +267,16 @@
     let tree
         = &install.install_state.resolution_tree;
 
-    resolution_dependency_names(tree, locator)
+    let mut dependency_names = resolution_dependency_names(tree, locator)
         .or_else(|| workspace_link_dependency_names(project, tree, locator))
-        .unwrap_or_default()
+        .unwrap_or_default();
+
+    // Add implicit self-dependency for non-workspace packages when there's no explicit self-dependency
+    if !locator.reference.is_workspace_reference() && !dependency_names.contains(locator.ident.as_str()) {
+        dependency_names.insert(locator.ident.as_str().to_string());
+    }
+
+    dependency_names
 }
 
 fn resolution_dependency_names(tree: &ResolutionTree, locator: &Locator) -> Option<BTreeSet<String>> {

You can send follow-ups to the cloud agent here.

Comment thread packages/zpm/src/linker/package_map.rs
@arcanis

arcanis commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

@cursor push ba99b5b

When nodeExperimentalPackageMap is enabled, packages that rely on a self
symlink can now correctly resolve their own name under standard enforcement.

The node-modules package map builder now adds an implicit self-dependency
for non-workspace packages when there's no explicit self-dependency,
mirroring the behavior of the pnpm linker. This ensures parity between
both linkers' package map generation within the same PR.

Applied via @cursor push command

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Map saved before island linking
    • Moved package map persistence to after island linking and added logic to rebuild the map including island packages when islands are present.
  • ✅ Fixed: Stale map after build failure
    • Added removal of old package map file at the start of node-modules linking to prevent stale maps from persisting after build failures.

Create PR

Or push these changes by commenting:

@cursor push e6a5becc1a
Preview (e6a5becc1a)
diff --git a/packages/zpm/src/linker/mod.rs b/packages/zpm/src/linker/mod.rs
--- a/packages/zpm/src/linker/mod.rs
+++ b/packages/zpm/src/linker/mod.rs
@@ -22,6 +22,7 @@
 pub struct LinkResult {
     pub packages_by_location: BTreeMap<Path, Locator>,
     pub build_requests: BuildRequests,
+    pub package_map: Option<package_map::PackageMap>,
 }
 
 pub async fn link_project<'a>(project: &'a Project, install: &'a Install) -> Result<LinkResult, Error> {
@@ -38,6 +39,8 @@
             => pnpm::link_project_pnpm(project, install).await?,
     };
 
+    let has_islands = !install.resolved_islands.is_empty();
+
     // Per-island link steps
     for island in &install.resolved_islands {
         match island.linker {
@@ -55,9 +58,88 @@
         }
     }
 
+    // Persist package map after all islands have been linked
+    // If islands were present, rebuild the package map to include island packages
+    if let Some(package_map) = &result.package_map {
+        if has_islands && matches!(project.config.settings.node_linker.value, NodeLinker::NodeModules | NodeLinker::Pnpm) {
+            // Rebuild the package map to include island-added packages
+            let rebuilt_package_map = rebuild_package_map_with_islands(project, install, &result.packages_by_location)?;
+            package_map::persist_package_map(project, &rebuilt_package_map)?;
+        } else {
+            package_map::persist_package_map(project, package_map)?;
+        }
+    }
+
     Ok(result)
 }
 
+fn rebuild_package_map_with_islands(
+    project: &Project,
+    install: &Install,
+    packages_by_location: &BTreeMap<Path, Locator>,
+) -> Result<package_map::PackageMap, Error> {
+    match project.config.settings.node_linker.value {
+        NodeLinker::NodeModules => {
+            let mut builder = package_map::NodeModulesPackageMapBuilder::new(project, install);
+            
+            // Register all packages from the final packages_by_location map
+            for (rel_path, locator) in packages_by_location {
+                let location_abs = project.project_cwd.with_join(rel_path);
+                
+                // Determine the package_path (where the actual package files are)
+                let package_path = match install.package_data.get(&locator.physical_locator()) {
+                    Some(crate::fetchers::PackageData::Local { package_directory, .. }) => {
+                        package_directory.clone()
+                    },
+                    _ => location_abs.clone(),
+                };
+                
+                builder.register_package(location_abs, package_path, locator);
+            }
+            
+            builder.build()
+        },
+        NodeLinker::Pnpm => {
+            let mut builder = package_map::PnpmPackageMapBuilder::new(project);
+            let tree = &install.install_state.resolution_tree;
+            
+            // Register all packages
+            for locator in packages_by_location.values() {
+                let package_location = packages_by_location
+                    .iter()
+                    .find(|(_, l)| *l == locator)
+                    .map(|(path, _)| project.project_cwd.with_join(path))
+                    .unwrap();
+                
+                builder.register_package(locator, package_location);
+            }
+            
+            // Register dependencies
+            for (locator, resolution) in &tree.locator_resolutions {
+                for (dep_name, descriptor) in &resolution.dependencies {
+                    if let Some(dep_locator) = tree.descriptor_to_locator.get(descriptor) {
+                        builder.register_dependency(locator, dep_name, dep_locator)?;
+                    }
+                }
+                
+                // Add implicit self-dependency for non-workspace packages
+                if !locator.reference.is_workspace_reference() {
+                    let has_explicit_self = resolution.dependencies.contains_key(&locator.ident);
+                    if !has_explicit_self {
+                        builder.register_dependency(locator, &locator.ident, locator)?;
+                    }
+                }
+            }
+            
+            builder.build()
+        },
+        _ => {
+            // Other linkers don't use package maps
+            Err(Error::Unsupported)
+        },
+    }
+}
+
 fn cleanup_inactive_linker_artifacts(project: &Project) -> Result<(), Error> {
     let active = project.config.settings.node_linker.value;
 

diff --git a/packages/zpm/src/linker/nm/mod.rs b/packages/zpm/src/linker/nm/mod.rs
--- a/packages/zpm/src/linker/nm/mod.rs
+++ b/packages/zpm/src/linker/nm/mod.rs
@@ -5,7 +5,7 @@
 use zpm_utils::{FromFileString, IoResultExt, Path, ToHumanString};
 
 use crate::{
-    build::{self, BuildRequest, BuildRequests}, content_flags, error::Error, fetchers::PackageData, install::Install, linker::{self, LinkResult, helpers::PackageMeta, nm::hoist::{Hoister, WorkTree}, package_map::{NodeModulesPackageMapBuilder, persist_package_map}}, project::Project
+    build::{self, BuildRequest, BuildRequests}, content_flags, error::Error, fetchers::PackageData, install::Install, linker::{self, LinkResult, helpers::PackageMeta, nm::hoist::{Hoister, WorkTree}, package_map::NodeModulesPackageMapBuilder}, project::Project
 };
 
 pub mod hoist;
@@ -573,6 +573,7 @@
     Ok(LinkResult {
         packages_by_location,
         build_requests,
+        package_map: None,
     })
 }
 
@@ -789,6 +790,11 @@
 pub async fn link_project_nm(project: &Project, install: &Install) -> Result<LinkResult, Error> {
     warn_about_portals_if_any(install);
 
+    // Remove stale package map to prevent it from persisting after a build failure
+    project.package_map_path()
+        .fs_rm()
+        .ok_missing()?;
+
     let mut work_tree
         = WorkTree::new(project, &install.install_state);
 
@@ -833,7 +839,7 @@
 
     run_cas_extractions(project, install, &cas_extractions)?;
 
-    persist_package_map(project, &package_map_builder.build()?)?;
+    let package_map = package_map_builder.build()?;
 
     let dependencies_meta
         = linker::helpers::TopLevelConfiguration::from_project(project);
@@ -849,5 +855,6 @@
     Ok(LinkResult {
         packages_by_location,
         build_requests,
+        package_map: Some(package_map),
     })
 }

diff --git a/packages/zpm/src/linker/pnp.rs b/packages/zpm/src/linker/pnp.rs
--- a/packages/zpm/src/linker/pnp.rs
+++ b/packages/zpm/src/linker/pnp.rs
@@ -593,5 +593,6 @@
     Ok(LinkResult {
         packages_by_location,
         build_requests,
+        package_map: None,
     })
 }

diff --git a/packages/zpm/src/linker/pnpm.rs b/packages/zpm/src/linker/pnpm.rs
--- a/packages/zpm/src/linker/pnpm.rs
+++ b/packages/zpm/src/linker/pnpm.rs
@@ -8,7 +8,7 @@
     error::Error,
     fetchers::PackageData,
     install::Install,
-    linker::{self, LinkResult, package_map::{PnpmPackageMapBuilder, persist_package_map}},
+    linker::{self, LinkResult, package_map::PnpmPackageMapBuilder},
     project::Project,
     tree_resolver::ResolutionTree,
 };
@@ -329,7 +329,7 @@
         }
     }
 
-    persist_package_map(project, &package_map_builder.build()?)?;
+    let package_map = package_map_builder.build()?;
 
     let package_build_dependencies = linker::helpers::populate_build_entry_dependencies(
         &package_build_entries,
@@ -345,5 +345,6 @@
     Ok(LinkResult {
         packages_by_location,
         build_requests,
+        package_map: Some(package_map),
     })
 }

diff --git a/packages/zpm/src/linker/venv.rs b/packages/zpm/src/linker/venv.rs
--- a/packages/zpm/src/linker/venv.rs
+++ b/packages/zpm/src/linker/venv.rs
@@ -180,5 +180,6 @@
             entries: vec![],
             dependencies: BTreeMap::new(),
         },
+        package_map: None,
     })
 }

You can send follow-ups to the cloud agent here.

Comment thread packages/zpm/src/linker/nm/mod.rs

run_cas_extractions(project, install, &cas_extractions)?;

persist_package_map(project, &package_map_builder.build()?)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale map after build failure

Medium Severity

The node-modules linker updates node_modules while generating workspaces, but writes .package-map.json only after package_map_builder.build() succeeds. Unlike pnpm, it does not remove the old map at link start, so a failed build leaves a previous map on disk that may not match the new layout.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6eadee7. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Island maps skip NODE_OPTIONS injection
    • Modified ScriptEnvironment::with_package to detect island workspaces with node-modules linker and inject the workspace-local package map path instead of the root package map.

Create PR

Or push these changes by commenting:

@cursor push 4869fa7c37
Preview (4869fa7c37)
diff --git a/packages/zpm/src/script.rs b/packages/zpm/src/script.rs
--- a/packages/zpm/src/script.rs
+++ b/packages/zpm/src/script.rs
@@ -749,6 +749,40 @@
         self.binaries = self.binaries
             .with_package(&binaries, &project.project_cwd)?;
 
+        // If this package is a workspace in an island with node-modules linker,
+        // update NODE_OPTIONS to use the workspace-local package map instead of
+        // the root package map.
+        if project.config.settings.node_experimental_package_map.value {
+            if let Ok(workspace) = project.workspace_by_ident(&locator.ident) {
+                let in_nm_island = project.config.settings.unstable_islands
+                    .values()
+                    .any(|island| {
+                        island.linker.value == zpm_config::IslandLinker::NodeModules
+                            && island.workspaces.iter().any(|glob| glob.value.check(&workspace.name))
+                    });
+
+                if in_nm_island {
+                    let workspace_package_map_path = workspace.path
+                        .with_join_str("node_modules")
+                        .with_join_str(crate::project::PACKAGE_MAP_NAME);
+                    
+                    if workspace_package_map_path.if_exists().is_some() {
+                        // Remove any existing package-map option from NODE_OPTIONS
+                        if let Some(Some(node_options)) = self.env.get_mut("NODE_OPTIONS") {
+                            let updated = PACKAGE_MAP_MATCHER.replace_all(node_options, "").to_string();
+                            *node_options = updated;
+                        }
+                        
+                        // Add the workspace-local package map
+                        self.append_env("NODE_OPTIONS", ' ', &format!(
+                            "--experimental-package-map={}",
+                            quote_path_if_needed(&workspace_package_map_path.to_file_string())
+                        ));
+                    }
+                }
+            }
+        }
+
         Ok(self)
     }

You can send follow-ups to the cloud agent here.

Comment thread packages/zpm/src/script.rs Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Loose maps miss self-reference symlinks
    • Added package_map_builder.register_package() calls in register_workspace_symlinks_at to ensure workspace self-reference symlinks are indexed in package_locations_by_node_modules_path for loose mode resolution.

Create PR

Or push these changes by commenting:

@cursor push aeec360c22
Preview (aeec360c22)
diff --git a/packages/zpm/src/linker/nm/mod.rs b/packages/zpm/src/linker/nm/mod.rs
--- a/packages/zpm/src/linker/nm/mod.rs
+++ b/packages/zpm/src/linker/nm/mod.rs
@@ -89,6 +89,7 @@
     host_node: &hoist::WorkNode,
     host_abs_path: &Path,
     candidate_workspaces: impl IntoIterator<Item = (Ident, Path)>,
+    mut package_map_builder: Option<&mut NodeModulesPackageMapBuilder>,
 ) -> Result<(), Error> {
     let global_default = project.config.settings.nm_self_references.value;
     let host_children = host_node.children.as_ref();
@@ -147,9 +148,20 @@
             = workspace_dir
                 .relative_to(&host_abs_path.with_join(&symlink_path).dirname().unwrap_or_default());
 
+        let abs_path
+            = host_abs_path.with_join(&symlink_path);
+
         workspace_nm_tree.register_entry(symlink_path, SyncItem::Symlink {
             target_path,
         })?;
+
+        if let Some(package_map_builder) = package_map_builder.as_deref_mut() {
+            package_map_builder.register_package(
+                abs_path,
+                workspace_dir.clone(),
+                &target_locator,
+            );
+        }
     }
 
     Ok(())
@@ -270,6 +282,7 @@
             &work_tree.nodes[workspace_node_idx],
             &workspace_abs_path,
             candidate_workspaces,
+            package_map_builder.as_deref_mut(),
         )?;
     }

You can send follow-ups to the cloud agent here.

Comment thread packages/zpm/src/linker/nm/mod.rs

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Exec cwd skips map refresh
    • Added with_cwd_and_refresh method to refresh the package map after the final cwd change in yarn exec, ensuring NODE_OPTIONS contains the correct --experimental-package-map flag for the actual working directory.
  • ✅ Fixed: Link path workspace lookup fails
    • Normalized link paths to absolute before comparing with workspace.path, allowing relative link: targets to correctly match workspace packages in standard package maps.

Create PR

Or push these changes by commenting:

@cursor push 9ab153219b
Preview (9ab153219b)
diff --git a/packages/zpm/src/commands/exec.rs b/packages/zpm/src/commands/exec.rs
--- a/packages/zpm/src/commands/exec.rs
+++ b/packages/zpm/src/commands/exec.rs
@@ -33,7 +33,7 @@
         Ok(ScriptEnvironment::new()?
             .with_project(&project)
             .with_package(&project, &project.active_package()?)?
-            .with_cwd(Path::current_dir()?)
+            .with_cwd_and_refresh(&project, Path::current_dir()?)
             .enable_shell_forwarding()
             .enable_signal_delegation()
             .run_script(&self.script, &self.args)

diff --git a/packages/zpm/src/linker/package_map.rs b/packages/zpm/src/linker/package_map.rs
--- a/packages/zpm/src/linker/package_map.rs
+++ b/packages/zpm/src/linker/package_map.rs
@@ -303,9 +303,15 @@
     let link_path
         = Path::from_str(&params.path).ok()?;
 
+    let link_path_abs = if link_path.is_absolute() {
+        link_path
+    } else {
+        project.project_cwd.with_join(&link_path)
+    };
+
     let workspace = project.workspaces
         .iter()
-        .find(|workspace| workspace.path == link_path)?;
+        .find(|workspace| workspace.path == link_path_abs)?;
 
     resolution_dependency_names(tree, &workspace.locator())
 }

diff --git a/packages/zpm/src/script.rs b/packages/zpm/src/script.rs
--- a/packages/zpm/src/script.rs
+++ b/packages/zpm/src/script.rs
@@ -801,6 +801,12 @@
         self
     }
 
+    pub fn with_cwd_and_refresh(mut self, project: &Project, cwd: Path) -> Self {
+        self.cwd = cwd;
+        self.refresh_package_map(project);
+        self
+    }
+
     fn install_binaries(&mut self) -> Result<Path, Error> {
         let hash
             = Hash64::from_string(&JsonDocument::to_string(&self.binaries)?);

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 578c179. Configure here.

.with_join(package_cwd_rel);

self.attach_package_variables(project, locator)?;
self.refresh_package_map(project);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exec cwd skips map refresh

Medium Severity

yarn exec calls with_package (which sets NODE_OPTIONS from refresh_package_map using that step’s cwd) and then with_cwd to the shell directory without refreshing the package map again, so the injected --experimental-package-map can reflect the wrong working directory when those paths differ.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 578c179. Configure here.

Comment thread packages/zpm/src/linker/package_map.rs Outdated
@arcanis arcanis merged commit 0670932 into main Jun 22, 2026
24 checks passed
@arcanis arcanis deleted the mael/package-maps branch June 22, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants