fix(#598,#519): use process.argv[1] + NVM env vars to resolve Pi CLI - #599
Merged
Conversation
When Taskplane runs as a Pi extension, process.argv[1] IS the absolute path to Pi's cli.js \u2014 set by Node from the parent process invocation. Trusting it directly is the single most reliable Pi-resolution strategy: it works for npm-global, mise, asdf, NVM (Windows + Unix), Nix, Bun-installed Pi, and any future install method we can't enumerate. resolvePiCliPath previously ignored argv[1] entirely and relied on 'npm root -g' plus a small static fallback list. That stranded: * #598 (itguy327 + galiling): NVM-on-Windows users whose child processes inherit a stripped PATH \u2014 npm root -g returns empty and the fallback list doesn't include NVM-versioned dirs. * #519 (chenxin-yan): Nix users whose Pi lives at /nix/store/..., not under any npm prefix the resolver knew about. The fix adds process.argv[1] as candidate 0, with two sanity guards: endsWith('cli.js') (matches Pi's bin entrypoint per its package.json's "bin": { "pi": "dist/cli.js" }) AND existsSync() (handles stale state in tests or wrappers). Both guards must pass or the resolver falls through to the existing base-directory search. Defense in depth: two new env-var-driven bases for NVM environments where argv[1] is unavailable (e.g., test harnesses, indirect spawn): * NVM_SYMLINK\node_modules (NVM-for-Windows, points at active version) * dirname(NVM_BIN)/../lib/node_modules (NVM-for-Unix, same property) Both env vars are set by NVM and inherited by child processes even when PATH is stripped, so they survive the failure mode that defeated npm root -g for galiling. Tests (extensions/tests/path-resolver-pi-scope.test.ts): 8.8 \u2014 argv[1] -> real cli.js resolves directly without any npm root 8.9 \u2014 argv[1] takes precedence over npm-root-installed Pi (priority) 8.10 \u2014 falls through when argv[1] doesn't end in cli.js (false-positive guard against wrappers/test runners) 8.11 \u2014 falls through when argv[1] ends in cli.js but file is missing 8.12 \u2014 resolves under $NVM_SYMLINK/node_modules (Windows NVM) 8.13 \u2014 resolves under dirname($NVM_BIN)/../lib/node_modules (Unix NVM) The existing #560 regression tests (8.4\u20138.7) still pass unchanged, verifying back-compat for both @earendil-works and @mariozechner scopes and the both-scopes-named error message. Validation npm run typecheck pass npm run lint 286 warnings / 671 infos (identical to main) npm run format:check pass (1 biome format applied to new tests) path-resolver tests 10/10 pass (6 new for #598) Full test suite 3714/3715 pass, 1 skipped, zero new failures taskplane help / doctor pass Closes #598 Closes #519 Apologies to @chenxin-yan: PR #520 was closed on 2026-05-25 with the claim that the fix was already in main, but I had misread path-resolver.ts \u2014 the process.argv[1] usage at line 235 was in the sibling resolveTaskplanePackageFile function, NOT in resolvePiCliPath. The fix the contributor actually proposed (which is also what this commit lands) was never applied to the function it was meant for. Reopening #519.
HenryLach
enabled auto-merge
June 17, 2026 19:41
This was referenced Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #598. Closes #519.
When Taskplane runs as a Pi extension,
process.argv[1]IS the absolute path to Pi'scli.js— set by Node from the parent process invocation. Trusting it directly is the single most reliable Pi-resolution strategy: it works for npm-global, mise, asdf, NVM (Windows + Unix), Nix, Bun-installed Pi, and any future install method we can't enumerate.The bug
resolvePiCliPathpreviously ignoredargv[1]entirely and relied onnpm root -gplus a small static fallback list. That stranded:npm root -greturns empty and the fallback list doesn't include NVM-versioned dirs./nix/store/..., not under any npm prefix the resolver knew about.The sibling resolver
resolveTaskplanePackageFilealready used theprocess.argv[1]trick (candidate 8, since #560 remediation). The same fix was somehow never applied toresolvePiCliPath, which is the function with the actual job of finding Pi.The fix
Adds
process.argv[1]as candidate 0, with two sanity guards:endsWith('cli.js')— matches Pi's bin entrypoint per itspackage.json's"bin": { "pi": "dist/cli.js" }existsSync()— handles stale state in test mocks or wrapper invocationsBoth guards must pass or the resolver falls through to the existing base-directory search.
Defense in depth — two new env-var-driven bases
For environments where
argv[1]is unavailable (test harnesses, indirect spawn through a wrapper, etc.):NVM_SYMLINK$NVM_SYMLINK\node_modulesNVM_BIN$NVM_BIN= active bin dir)dirname($NVM_BIN)/../lib/node_modulesBoth env vars are set by NVM and inherited by child processes even when PATH is stripped, so they survive the exact failure mode that defeated
npm root -gfor galiling.Tests
extensions/tests/path-resolver-pi-scope.test.ts— 6 new tests:argv[1]→ realcli.jsresolves directly without any npm rootargv[1]takes precedence over npm-root-installed Pi (priority test)argv[1]doesn't end incli.js(false-positive guard against test runners / wrappers)argv[1]ends incli.jsbut file is missing (stale-state guard)$NVM_SYMLINK/node_modules(Windows NVM)dirname($NVM_BIN)/../lib/node_modules(Unix NVM)The existing #560 regression tests (8.4–8.7) still pass unchanged, verifying back-compat for both
@earendil-worksand@mariozechnerscopes and the both-scopes-named error message.Validation
npm run typechecknpm run lintmainnpm run format:checkpath-resolver-pi-scope.test.tstaskplane help/doctorApology to @chenxin-yan
PR #520 was closed on 2026-05-25 with the claim that the fix was already in
main. I had misreadpath-resolver.ts— theprocess.argv[1]usage at line 235 was in the siblingresolveTaskplanePackageFilefunction, not inresolvePiCliPath. The fix the contributor actually proposed (which is also what this PR lands) was never applied to the function it was meant for. Reopening #519 with an apology comment after this merges.Release plan
This is a blocker for fresh installs across NVM + non-canonical install layouts (which are common). Recommend shipping as a patch release
v0.30.2immediately after merge.