I released the fix. My terminal ran the version from three releases ago.
I spent an hour debugging two fixes that were correct all along. The terminal I tested them in was running a version from three releases earlier:
$ pwt --version
pwt version 0.2.8
Update available: 0.2.9
Run: npm i -g @jonasporto/pwt@latest
The repository checkout on that same machine carried 0.2.11, freshly
released, symlinked into ~/.local/bin/pwt exactly so the shell would
always run it. The shell had other plans.
“Global” installs are not global
which pwt pointed here:
~/.nvm/versions/node/v22.17.0/bin/pwt
That path says everything. npm i -g does not install globally: it
installs into the bin directory of whichever node version is active.
Under nvm, that directory sits at the front of PATH, ahead of
~/.local/bin, ahead of Homebrew, ahead of your intentions.
Two consequences, both measured on this machine:
Each node version has its own set of “global” CLIs. Listing the two
node versions installed here: v22 had pwt (the stale 0.2.8); v18 has
gemini and task-master and no pwt at all. nvm use 18 and the
command changes identity or vanishes, with no output telling you so.
The full inventory was worse than one stale copy. Asking the tool itself:
$ pwt self
pwt installations:
→ npm v0.2.8 ~/.nvm/versions/node/v22.17.0/bin/pwt
local v0.2.11 ~/code/pwt/bin/pwt (the dev symlink, shadowed)
brew v0.2.0 /opt/homebrew/Cellar/pwt/0.2.0/bin/pwt
Three copies, three versions, spanning six months. The arrow marks the one the shell answers with, and it was the one I had forgotten installing.
The probes, ranked by what they can lie about
$ which -a pwt # every match on PATH, in order (zsh: whence -a)
$ type -a pwt # same, plus functions and aliases -- use this one
type -a matters because a shell function outranks every PATH entry,
and tools like pwt, zoxide and direnv install one. What happens when the
function itself goes stale is its own
post,
and it is the sequel to this one: I removed the npm copy, and the
function that had it baked in took the shell down with it.
And the one probe that nothing local can shadow:
$ npx -y @jonasporto/pwt@latest doctor
npx is a different command name, so no pwt function intercepts it,
and it resolves @latest against the registry, so no PATH entry
matters. Measured while writing this: it picked up a version published
four minutes earlier. One honest caveat: run it during a publish and
you get the previous latest; the registry tag moves when the release
workflow finishes, not when the tag is pushed.
What the tool now does about it
Two changes shipped in 0.2.12, both born from that hour:
$ pwt doctor
⚠ Installation: the pwt on PATH is not the one running
running: ~/code/pwt/bin/pwt (v0.2.12)
on PATH: ~/.nvm/versions/node/v22.17.0/bin/pwt (v0.2.8)
Your shell answers with the PATH one. List all: pwt self
The check is one comparison: resolve the binary that is executing,
resolve the first pwt on PATH, and refuse to stay quiet when they
differ. It costs nothing and it is the setup problem that hides every
other one: fixes that are correct in one install do nothing while the
shell runs another.
The second change is the pointer above: the update notice (which is what
cracked the case, a 0.2.8 announcing that 0.2.9 existed), the doctor
warning, and the stale-wrapper error all now name the npx rescue,
because it is the only diagnosis that works no matter how tangled the
local installs are.
The actual fix: one owner per command name
Diagnosis is not the fix. The fix is deciding which install owns the command and deleting the rest:
$ npm rm -g @jonasporto/pwt # the stale global
$ brew uninstall pwt # the fossil from February
$ pwt self # confirm one entry remains, marked active
If you develop the tool, the owner is the dev symlink and everything else is a trap waiting for a debugging session. If you only use it, pick one package manager and never install the same CLI with two: the second install does not replace the first, it enters a precedence contest you will lose track of.
The rule underneath is the same one this blog keeps arriving at from
different directions: “which one answers” is state, state drifts, and
state that drifts needs an inventory command and a doctor that checks
it. pwt self is the inventory; pwt doctor
(reference) is the
check; npx @jonasporto/pwt@latest doctor is the version of the check
you can run from a machine where everything else lies.
You do not have to memorize any of this.
pwt skillprints the agent-facing guide to pwt; tell your agent the outcome you want and point it there, and it works out the mechanism and verifies it in a throwaway worktree.Before debugging pwt behavior, confirm which install answers:
pwt doctorwarns when the pwt on PATH is not the binary running, andpwt selflists every installation with versions. Reference: pwt doctor.