v4.18.0 — keep the runner reachable after a plugin upgrade
Fixed
-
A plugin upgrade no longer silently disables the deterministic runner (issue #150).
Upgrading refreshes the versioned plugin cache dir and nothing else — it never re-runs
install.sh— so~/.local/binkeeps whatever the last/cli-dispatch:setupinstalled.
Any binary introduced by a newer version is therefore simply absent from PATH. That is how
cli-dispatch-run,cli-dispatch-waitandcli-dispatch-gaincame to be missing on a box
running plugin 4.16.0 while the file sat right there in the cache, and/cli-dispatch:run
died withcommand not foundfor a reason nothing on screen explained. Three changes:- The SessionStart hook now compares
~/.config/cli-dispatch/.installed-versionagainst the
newest version in the plugin cache and injects a one-paragraph notice when the install is
behind. It is deliberately not gated onpolicy.json: a stale install is a broken
install, not a preference, and someone who never wrote a policy file is the likeliest
person to hit it.cli-dispatch-status.shandversion-check.shalready detected this,
but only for people who ran a command that happened to check. /cli-dispatch:runfalls back to the plugin's ownscripts/cli-dispatch-runwhen the
wrapper is missing from PATH, so the documented zero-token flow still runs. Both the
fallback and the hard-failure path now name the cause (an upgrade does not reinstall
wrappers) alongside the fix, instead of only suggesting the per-backend commands./cli-dispatch:setupresolves the plugin root at runtime through the new
resolve-plugin-root.sh(+.ps1twin) rather than invoking
${CLAUDE_PLUGIN_ROOT}/scripts/install.shdirectly.CLAUDE_PLUGIN_ROOTis whichever
version the running session loaded, which an upgrade does not change — so the old form
could run an installer several versions old, and printed a stale version number while
doing it. The reporter saw3.30.1in that step with 4.16.0 active and concluded that
3.30.1 was what they had. The resolver picks the newest of (session root, newest cache dir
carrying an installer) and keeps the session root on ties, on unparseable versions, and
when the session root has no manifest — so a local dev checkout is never swapped out.
The runner itself was never broken by any of this; it was only made unreachable, which is
worse, because the fallback is the LLM-babysitter path this plugin exists to avoid. - The SessionStart hook now compares