* fix: resolve relative path params in global add against CWD
When running `pnpm -g add .`, the "." was resolved relative to the
temporary install directory instead of the user's working directory.
This happened because handleGlobalAdd switches opts.dir to a fresh
temp directory before the dependency selectors are resolved.
Now relative path params (., ./foo, ../bar, file:./foo, link:../bar)
are resolved to absolute paths before the directory is switched.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve relative local selectors against opts.dir instead of process.cwd()
This fixes `pnpm -C <dir> -g add .` where the relative selector would
incorrectly resolve against process.cwd() instead of the user's intended
directory. Also adds test coverage for file: and link: prefixed selectors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(config): stop overwriting dir to globalPkgDir for global commands
Previously, `pnpmConfig.dir` was set to `globalPkgDir` when `--global`
was used. This caused `opts.dir` to point to the global packages
directory instead of the user's CWD, breaking `pnpm -g add .` because
relative paths resolved against the wrong directory.
Now `pnpmConfig.dir` is always set to the user's CWD. Global command
handlers already use `opts.globalPkgDir` where they need the global
packages directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use globalPkgDir in pnpm root -g handler
The root command handler was using opts.dir which no longer points to
the global packages directory. Use opts.globalPkgDir instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: allow global install to override bins owned by the new package
When a package name matches the bin name (e.g., `npm` package providing
`npm` bin), the new package gets priority and can override an existing
bin from another global package. The `npx` bin is also treated as owned
by the `npm` package via a hardcoded override map.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: run benchmarks on node.js 25
* feat: skip linking bins owned by existing global packages instead of failing
When installing a package globally (e.g. node) whose bins conflict with
an already-installed package that owns those bins (e.g. npm owns npm/npx),
the install now succeeds and skips linking the conflicting bins rather
than aborting with GLOBAL_BIN_CONFLICT.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: improve global bin conflict checks for aliased packages and multi-provider bins
Track all new bin providers (not just the last one) so ownership is
correctly resolved when multiple new packages provide the same bin.
Use manifest.name instead of the dependency alias when checking
existing package ownership, fixing incorrect decisions for aliased
installs. Use symlink-dir in tests for Windows compatibility and
remove a non-null assertion in link-bins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use Set for conflicting bins lookup and fix error hint to use alias
Convert the conflicting bins collection from an array to a Set for O(1)
lookups. Use the dependency alias in the `pnpm remove -g` hint since
that is what the user originally installed with, showing both alias and
manifest name when they differ.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: remove changeset
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
**TLDR:** Global packages in pnpm v10 are annoying and slow because they all are installed to a single global package. Instead, we will now use a system that is similar to the one used by "pnpm dlx" (aka "pnpx").
Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own `package.json`, `node_modules`, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts or version resolution shifts.
## Changes
- Add `@pnpm/global-packages` shared utilities package for scanning, hashing, and managing isolated global installs
- `pnpm add -g` creates isolated installs in `{pnpmHomeDir}/global/v11/{hash}/`
- `pnpm remove -g` removes the entire installation group containing the package
- `pnpm update -g` re-installs into new isolated directories and swaps symlinks
- `pnpm list -g` scans isolated directories to show installed global packages
- `pnpm outdated -g` checks each isolated installation for outdated dependencies
- `pnpm store prune` cleans up orphaned global installation directories
## Breaking changes
- `pnpm install -g` (no args) is no longer supported — use `pnpm add -g <pkg>`
- `pnpm link <pkg-name>` no longer resolves packages from the global store — only relative or absolute paths are accepted
- `pnpm link --global` is removed — use `pnpm add -g .` to register a local package's bins globally