fix(installer): clear stale global installs and detect a shadowed upgrade - #169
Merged
Conversation
…rade Preferring npm (#168) fixed which package manager installs, but not what happens on a machine that already had the CLI installed by another one. A prior `pnpm add -g` leaves its own shim on PATH. The installer would put a current build in npm's global root, then report success using whatever `threatcrush --version` resolved to - the old shim. The output reads ✓ ThreatCrush 0.11.3 installed successfully! on a machine that just downloaded 0.11.4, and nothing says why the upgrade did not take. Reported on macOS, reproduced on Linux. Two changes: - remove_stale_global_installs() runs before the install and drops a copy of the package held by any package manager other than the one being used (pnpm, yarn, bun). Every probe is guarded - `set -e` is on, and none of it is worth aborting a working install for. pnpm refusing to run because its global bin dir is not exported is expected and benign here. - warn_if_shadowed() compares the version on PATH against the version actually written to npm's global root, read from the installed package.json so it stays correct offline. On a mismatch it names both versions and the shadowing path, and suggests `hash -r` before `rm`. Verified end to end: seeded a pnpm global install, ran the installer, watched it remove the pnpm copy and land on 0.11.4 via npm. Unrelated pnpm globals on the box were left alone. Both new functions unit-tested for the equal, empty and mismatched cases; shellcheck -s sh is clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3GDps1fD6ccfo93B3ePy1
ThreatCrush Security Scan12 finding(s) HIGH/CRITICAL: 1 | MEDIUM: 6 | LOW: 5
Snippets are redacted; ThreatCrush never prints matched credential material. |
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.
What
Follow-up to #168. That fixed which package manager installs; this fixes what happens on a machine that already had the CLI installed by a different one.
Why
A prior
pnpm add -gleaves its own shim on PATH, and it usually sorts ahead of npm's. The installer would write a current build into npm's global root, then report success using whateverthreatcrush --versionresolved to — the old shim:…on a machine that just downloaded 0.11.4. Nothing told the user why the upgrade didn't take. Reported on macOS, reproduced on Linux.
There's a second flavour of the same trap: the pnpm global
pnpm-lock.yamlpins the resolved version, sopnpm add -greinstalls the locked release and exits 0 while handing back something older thanlatest.Changes
remove_stale_global_installs()runs before installing and drops a copy of the package held by any package manager other than the one in use (pnpm, yarn, bun). Every probe is guarded —set -eis on and none of this is worth aborting a working install for. pnpm refusing to run because its global bin dir isn't exported is expected and benign here.warn_if_shadowed()compares the version on PATH against the version actually written to npm's global root, read from the installedpackage.jsonso it stays correct offline and on a pinned install. On mismatch it names both versions plus the shadowing path, and suggestshash -rbeforerm.Testing
shellcheck -s shclean;sh -nclean.installed_versionreturns0.11.4for the real package and empty (not a crash) for a missing one;warn_if_shadowedstays silent for equal versions and for an empty expected version, and warns on a mismatch.pnpm add -ginstall (which created a secondglobal/5root alongsideglobal/v11), ran the installer, and watched it print→ Removing an older @profullstack/threatcrush installed with pnpm..., install via npm, and land on0.11.4. Confirmed the pnpm copy was gone afterwards and that an unrelated pnpm global on the same box was left untouched.next build.🤖 Generated with Claude Code
https://claude.ai/code/session_01H3GDps1fD6ccfo93B3ePy1