fix: show contextual warning for dev installs with stale hooks (#2162)

When a user manually installs a dev branch where VERSION > npm latest,
gsd-check-update detects hooks as "stale" and the statusline showed
the red "⚠ stale hooks — run /gsd-update" message. Running /gsd-update
would incorrectly downgrade the dev install to the npm release.

Fix: detect dev install (cache.installed > cache.latest) in the
statusline and show an amber "⚠ dev install — re-run installer to sync
hooks" message instead, with /gsd-update reserved for normal upgrades.

Also expand the update.md workflow's installed > latest branch to
explain the situation and give the correct remediation command
(node bin/install.js --global --claude, not /gsd-update).

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-12 11:52:21 -04:00
committed by GitHub
parent f0a20e4dd7
commit c5801e1613
2 changed files with 24 additions and 2 deletions

View File

@@ -289,7 +289,16 @@ Exit.
**Installed:** X.Y.Z
**Latest:** A.B.C
You're ahead of the latest release (development version?).
You're ahead of the latest release — this looks like a dev install.
If you see a "⚠ dev install — re-run installer to sync hooks" warning in
your statusline, your hook files are older than your VERSION file. Fix it
by re-running the local installer from your dev branch:
node bin/install.js --global --claude
Running /gsd-update would install the npm release (A.B.C) and downgrade
your dev version — do NOT use it to resolve this warning.
```
Exit.

View File

@@ -211,7 +211,20 @@ function runStatusline() {
gsdUpdate = '\x1b[33m⬆ /gsd-update\x1b[0m │ ';
}
if (cache.stale_hooks && cache.stale_hooks.length > 0) {
gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd-update\x1b[0m │ ';
// If installed version is ahead of npm latest, this is a dev install.
// Running /gsd-update would downgrade — show a contextual warning instead.
const isDevInstall = (() => {
if (!cache.installed || !cache.latest || cache.latest === 'unknown') return false;
const parseV = v => v.replace(/^v/, '').split('.').map(Number);
const [ai, bi, ci] = parseV(cache.installed);
const [an, bn, cn] = parseV(cache.latest);
return ai > an || (ai === an && bi > bn) || (ai === an && bi === bn && ci > cn);
})();
if (isDevInstall) {
gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
} else {
gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd-update\x1b[0m │ ';
}
}
} catch (e) {}
}