#18961: fix: detect pnpm package manager in openclaw update
size: XS
Cluster:
Update Handling Fixes
## Problem
When running `openclaw update` on a pnpm global installation, it fails with:
> Skipped: this OpenClaw install isn't a git checkout, and the package manager couldn't be detected.
## Root Cause
pnpm uses a content-addressable store (`.pnpm/` directory) where packages are stored with their hash, and symlinks are created in `node_modules/`.
The `detectGlobalInstallManagerForRoot` function only checked if the resolved package path directly matches `{globalRoot}/openclaw`, but with pnpm:
- `pnpm root -g` returns: `/home/user/.local/share/pnpm/global/5/node_modules`
- Actual package is at: `/home/user/.local/share/pnpm/global/5/.pnpm/openclaw@.../node_modules/openclaw`
- The symlink `{globalRoot}/openclaw` points to the actual location
## Solution
Also check if the expected path is a symlink that resolves to the actual package path.
## Testing
- [x] Tested locally with pnpm global installation
- [x] `openclaw update` now correctly detects pnpm instead of showing "Skipped" error
## AI-Assisted
This fix was identified and implemented with AI assistance (Claude). The code was reviewed and tested manually.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes pnpm global installation detection in the `openclaw update` command. pnpm uses a content-addressable store (`.pnpm/` directory) with symlinks in `node_modules/`, so the resolved package path doesn't directly match the global root + package name. The fix adds a symlink target resolution check after the existing direct path comparison.
- Adds `tryRealpath(expected)` call to resolve the symlink at `{globalRoot}/openclaw` before comparing with the actual package path
- Change is narrowly scoped to the pnpm detection path in `detectGlobalInstallManagerForRoot`
- No test coverage added for this specific symlink scenario (existing test file `update-runner.test.ts` does not cover `detectGlobalInstallManagerForRoot` directly)
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — it adds a fallback symlink check that only activates when the existing direct-path match fails.
- The change is minimal, well-scoped, and correct. It adds a secondary symlink resolution check that won't affect existing npm/bun detection paths. The only minor concern is the lack of a unit test for this specific scenario, but the logic is straightforward and the author confirmed manual testing.
- No files require special attention.
<sub>Last reviewed commit: 5d66e06</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#22406: Fix update detection for Companion App npm-prefix installs
by graysurf · 2026-02-21
82.9%
#12804: fix(daemon): use wrapper script for pnpm global installs in service...
by odinho · 2026-02-09
82.3%
#17237: fix(update): guard post-install imports after npm global update
by tdjackey · 2026-02-15
81.8%
#17815: fix: use $HOME as cwd for global update to prevent path-dedot panic
by frankekn · 2026-02-16
80.3%
#17912: fix: configure git to use HTTPS instead of SSH for GitHub URLs
by MisterGuy420 · 2026-02-16
79.1%
#20585: fix: pre-flight ownership check before global update
by mwfj · 2026-02-19
79.0%
#8600: fix(update): add --ignore-scripts to prevent supply chain attacks
by yubrew · 2026-02-04
78.2%
#15475: fix(update): Handle Homebrew+Node Cellar path mismatch
by brandonwise · 2026-02-13
77.9%
#12844: fix(llm-task): use correct import path for built/npm installs
by scout-wolfe · 2026-02-09
77.4%
#13176: fix: resolve llm-task module import for global installs
by striking · 2026-02-10
77.4%