Skip to content

fix: install each global package in its own isolated directory by default#11588

Merged
zkochan merged 7 commits into
mainfrom
fix/11587
May 11, 2026
Merged

fix: install each global package in its own isolated directory by default#11588
zkochan merged 7 commits into
mainfrom
fix/11587

Conversation

@zkochan

@zkochan zkochan commented May 11, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #11587.

In v11, pnpm add -g foo bar bundled foo and bar into a single isolated install group, so pnpm remove -g foo also removed bar. This change reverts the default to per-package isolation while preserving a way to opt into grouped installs:

  • pnpm add -g foo barfoo and bar are installed as two independent globals; removing one does not affect the other.
  • pnpm add -g foo,bar qarfoo and bar share a single isolated install dir (and are removed together); qar is its own.

Test plan

  • New e2e test: each space-separated package lands in its own install dir, and removing one leaves the other intact.
  • New e2e test: comma-separated packages share an install dir while a third space-separated arg gets its own.
  • Updated the existing global remove deletes install group and bin shims test to use the comma syntax (since that is the new way to express bundling).
  • Full pnpm/test/install/global.ts suite passes (20 passed, 2 pre-existing skips).

Written by an agent (Claude Code, claude-opus-4-7).

Summary by CodeRabbit

  • Bug Fixes

    • Global installs now default to isolating each space-separated package into its own global install.
    • Bundle multiple packages into a single global install by using comma-separated package selectors.
  • Tests

    • Added tests verifying comma-separated bundling, space-separated isolation, and commas inside local path selectors.
  • Logging / Reporting

    • Per-install summary logs suppressed during grouped installs; a single summary is emitted at the end.
    • Progress output shows per-prefix progress when installing multiple isolated global groups.

Review Change Stack

…ault (#11587)

`pnpm add -g foo bar` now installs `foo` and `bar` as separate isolated
globals — removing one no longer wipes out the other. Packages can still
be bundled into a single isolated install with a comma-separated list:
`pnpm add -g foo,bar qar` keeps foo+bar together and qar separate.
@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 13c73611-8dd1-4b09-87b7-7976d8cc05b4

📥 Commits

Reviewing files that changed from the base of the PR and between b1ed974 and 9bc6ecc.

📒 Files selected for processing (1)
  • .changeset/fix-11587-global-isolated-per-arg.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/fix-11587-global-isolated-per-arg.md
📜 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). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Compile & Lint

📝 Walkthrough

Walkthrough

This PR changes global install behavior: CLI params are split into install groups (space-separated selectors become separate isolated global installs; comma-separated selectors bundle packages into a single install). Implemented in global/commands/src/globalAdd.ts, tests updated, changelog amended, reporter and install options adjusted.

Changes

Global Install Grouping Behavior

Layer / File(s) Summary
User-facing specification
.changeset/fix-11587-global-isolated-per-arg.md
Release notes document space-separated packages installing into isolated groups and comma-separated syntax bundling packages into a single group.
CLI parameter grouping
global/commands/src/globalAdd.ts
handleGlobalAdd now builds groups by applying splitCommaSeparated to each CLI param, resolves selectors, and iterates groups for per-group installation.
Comma-splitting utility
global/commands/src/globalAdd.ts
Introduces splitCommaSeparated and refersToExistingLocalPath to avoid splitting comma-containing local path selectors or URL-like specs.
Per-group install logic
global/commands/src/globalAdd.ts
Adds InstallGroupContext and installGroup that create a fresh install directory per group, build install options (including omitSummaryLog:true), call installGlobalPackages, then run post-install steps (approve builds, read aliases, check bin conflicts, remove prior installs, create cache symlink, link bins).
Install API & options
global/commands/src/installGlobalPackages.ts, installing/deps-installer/src/install/extendInstallOptions.ts, installing/deps-installer/src/install/index.ts, global/commands/package.json, global/commands/tsconfig.json
Introduces omitSummaryLog option on InstallGlobalPackagesOptions and StrictInstallOptions (default false), guards in _installInContext, and adds @pnpm/core-loggers dependency + tsconfig reference.
Reporter initialization
pnpm/src/main.ts, pnpm/src/reporter/index.ts
Reporter init now accepts hideProgressPrefix and main sets it for multi-arg pnpm add -g so progress prefixes are shown per prefix during multiple group installs.
Test discovery helper
pnpm/test/install/global.ts
Adds findGlobalPkgInstall returning installDir and pkgPath; findGlobalPkg delegates to it.
Test cases
pnpm/test/install/global.ts
Updates one test to bundle packages via comma syntax; adds tests for space-separated isolation, comma-separated bundling, and commas inside local path selectors.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (pnpm add -g)
  participant GroupBuilder as splitCommaSeparated / resolveLocalParam
  participant GroupInstaller as installGroup
  participant Resolver as installGlobalPackages
  participant GlobalBin as Global bin/linking steps
  CLI->>GroupBuilder: split param into groups (safe comma-splitting)
  GroupBuilder->>GroupInstaller: create fresh install dir for group
  GroupInstaller->>Resolver: install group (omitSummaryLog:true)
  Resolver-->>GroupInstaller: resolved aliases & package info
  GroupInstaller->>GlobalBin: approve builds, remove prior installs, create cache symlink, link bins
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • pnpm/pnpm#11451: Related coordinated work for isolated-global-installs and pnpm -g ls handling multiple global install dirs.

Poem

I’m a rabbit who sorts the args with care,
Spaces make islands, commas pair.
Each group gets its own little home,
Bins find places where they roam.
Hooray — global installs now share (or not)! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main change: making each space-separated global package installation isolated by default.
Linked Issues check ✅ Passed All coding requirements from issue #11587 are met: packages installed via space-separated arguments are now isolated by default, comma-separated lists enable grouped installs, and removing one package no longer removes all packages installed together.
Out of Scope Changes check ✅ Passed All changes directly support the objective of per-package isolation: refactored handleGlobalAdd for per-group logic, added tests for isolated and grouped installs, updated reporter configuration for visibility, and added necessary dependencies.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/11587

Comment @coderabbitai help to get the list of available commands and usage tips.

@zkochan zkochan marked this pull request as ready for review May 11, 2026 15:51
Copilot AI review requested due to automatic review settings May 11, 2026 15:51

Copilot AI 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.

Pull request overview

This PR changes the default behavior of pnpm add -g to install each space-separated package into its own isolated global install directory (so removing one global package doesn’t remove others installed in the same invocation). It also introduces an opt-in grouping syntax using comma-separated selectors to intentionally bundle multiple globals into one isolated install group.

Changes:

  • Update global add implementation to install one “group” per CLI arg by default, with comma-separated selectors forming a single group.
  • Update/add e2e tests to cover per-arg isolation and comma-based bundling, and adjust the existing global-remove group test to use the new comma syntax.
  • Add a changeset documenting the new default behavior and the comma grouping mechanism.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
global/commands/src/globalAdd.ts Implements per-arg global install grouping, plus comma-based bundling within a single arg.
pnpm/test/install/global.ts Updates and adds tests to validate per-arg isolation and comma-bundled grouping semantics.
.changeset/fix-11587-global-isolated-per-arg.md Documents the behavior change and the new comma grouping syntax.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread global/commands/src/globalAdd.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 @.changeset/fix-11587-global-isolated-per-arg.md:
- Line 9: The example sentence is missing the noun after the issue link; update
the second bullet that contains "`pnpm add -g foo,bar qar`" so it reads
something like "`pnpm add -g foo,bar qar` bundles `foo` and `bar` into a single
isolated install while `qar` lives in its own isolated install (see `#11587`)`" —
ensure the phrase "isolated install" (or equivalent noun) is present and keep
the issue link as a reference.

In `@global/commands/src/globalAdd.ts`:
- Around line 65-68: The loop calling installGroup({ opts, globalDir,
globalBinDir, allowBuilds, params: group }, commands) must be made atomic: first
install and validate every group into isolated temporary dirs (or capture their
planned changes) without touching global state, and only if all installs succeed
perform the destructive steps (call removeExistingGlobalInstalls, create
symlinks, and link bins) to update globalDir/globalBinDir; update or add a new
staging function (e.g., installGroupStaged or a staging phase around
installGroup) to return success artifacts/paths for the commit phase, then run
the commit phase that performs the existing global mutations only once all
groups validated.
- Around line 163-165: The splitCommaSeparated function currently splits every
comma and breaks path/URL/package selectors that legitimately contain commas;
update it to detect path/protocol selectors and skip splitting in those cases:
if the param starts with './', '../', '/', 'file:' or contains '://', or
otherwise looks like a filesystem/path or URL (e.g., contains a slash and a
comma), return [param] unchanged; only perform the comma split/trim/filter for
true grouped package argument strings. Reference the splitCommaSeparated helper
and where resolveLocalParam consumes its output to ensure selector strings that
look like local paths or URLs are not split.
🪄 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: f1d6a9be-2603-4a01-bd8a-79e5dd9ccc05

📥 Commits

Reviewing files that changed from the base of the PR and between 20e7aff and 48d2c51.

📒 Files selected for processing (3)
  • .changeset/fix-11587-global-isolated-per-arg.md
  • global/commands/src/globalAdd.ts
  • pnpm/test/install/global.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). (2)
  • GitHub Check: Agent
  • GitHub Check: ubuntu-latest / Node.js 24 / Test
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,tsx,jsx}: Use trailing commas in code following Standard Style with modifications
Prefer functions over classes
Declare functions after they are used, relying on hoisting
Functions should have no more than two or three arguments; use a single options object for functions needing more parameters
Organize imports in order: standard libraries, external dependencies (sorted alphabetically), then relative imports

Files:

  • global/commands/src/globalAdd.ts
  • pnpm/test/install/global.ts

Comment thread .changeset/fix-11587-global-isolated-per-arg.md Outdated
Comment thread global/commands/src/globalAdd.ts
Comment thread global/commands/src/globalAdd.ts Outdated
`splitCommaSeparated` now detects path-like params (`./`, `/`, `~`,
`file:`, `link:`, Windows drive paths) and URLs (anything containing
`://`), and skips splitting when the param as a whole resolves to an
existing local path. Plain package specs like `foo,bar` are still
split as before. Adds an e2e regression test using a local package
whose directory contains commas.

Also reword the changeset bullet so the example sentence doesn't end
abruptly at the issue link.
zkochan added 2 commits May 11, 2026 18:28
`pnpm add -g foo bar` runs each space-separated arg as its own isolated
install, but the default-reporter's summary pipeline takes the first
`summary` log event and unsubscribes — so only the first group's
"global: + X" block was printed and later groups disappeared from the
summary even though they had been installed correctly.

Adds an `omitSummaryLog` install option that suppresses the per-install
summary log inside `mutateModules`. `handleGlobalAdd` enables it for
each group and emits a single consolidated summary log at the very end,
so the reporter prints one "global:" block listing every package that
was added across all groups.
Copilot AI review requested due to automatic review settings May 11, 2026 16:30
…iple groups

When `pnpm add -g` is given more than one CLI param (and so installs
several isolated groups), force the reporter to use its prefixed
progress/stats output. Without that, the single-prefix stats pipeline
limits emissions to one install via `take(2)`, so only the first
group's "Packages: +N" line is printed and later groups' stats are
silently dropped. Each group now shows its own progress and stats line
labelled with the install dir, and the consolidated "global:" summary
still prints once at the end.

Single-package `pnpm add -g foo` output is unchanged.

Copilot AI 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.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread .changeset/fix-11587-global-isolated-per-arg.md
The new omitSummaryLog install option is consumed by global.commands,
so deps-installer needs a version bump alongside it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm v11: Removing a global package removes any other package installed with the same original command

2 participants