Skip to content

fix(upgrade): stop npm installs self-shadowing on upgrade; verify the resolved version after every upgrade#1245

Merged
colbymchenry merged 1 commit into
mainfrom
fix/upgrade-npm-detection-and-version-verify
Jul 10, 2026
Merged

fix(upgrade): stop npm installs self-shadowing on upgrade; verify the resolved version after every upgrade#1245
colbymchenry merged 1 commit into
mainfrom
fix/upgrade-npm-detection-and-version-verify

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Companion to #1239 / #1238. Together they make three guarantees hold after codegraph upgrade: hooks refreshed, agent instruction files refreshed (#1239), and — this PR — codegraph -v in the same terminal provably serving the new version.

Problem 1 — npm installs self-shadow on upgrade (found while validating #1239)

Reproduced live in a sandboxed $HOME: install 1.3.1 via npm i -g, run codegraph upgrade — and codegraph --version reports 1.3.1 forever, in that terminal and every future one.

Root cause: the npm thin-installer's per-platform package (@colbymchenry/codegraph-<platform>-<arch>) is itself a complete bundle — vendored node + bin/ launcher — living inside node_modules. detectInstallMethod checked the bundle layout before the node_modules path, so every npm install misdetected as a standalone bundle and upgrade curled install.sh into ~/.codegraph: a second install that never wins the PATH race against npm's shim. The #1071 shadow pile-up, manufactured by upgrade itself.

This also silently broke #1239 for npm users (the issue author's own environment): its post-upgrade codegraph install --refresh spawn resolves the stale npm shim, which doesn't know --refresh.

Fix: path-based checks (/_npx/, /node_modules/) now run before the layout sniff — where the file lives is authoritative about how the user installed, whatever the artifact inside looks like. npm installs upgrade through npm install -g …@latest again: same shim path, so the same terminal picks up the new version immediately. The shim's GitHub-download self-heal cache (~/.codegraph, issue #303) is outside node_modules and still detects as a bundle.

Problem 2 — nothing ever verified the upgrade took

The unix-bundle path ended with "✓ Upgrade complete. Open a new terminal if the version looks unchanged (PATH cache)" — an unconditional hedge for a failure mode we can detect. After a successful swap, runUpgrade now probes the PATH-resolved codegraph --version (through cmd.exe on Windows for the .cmd launcher) and reports the real outcome:

  • match✓ codegraph on your PATH now reports v1.4.0 — this terminal is already using it.
  • mismatch → a loud warning that a stale install is shadowing the upgraded one, with which -a codegraph / where codegraph to find it. Warn-only; the upgrade itself still exits 0.
  • inconclusive (no codegraph on PATH, probe fails or output unparsable) → the old soft new-terminal hint, never a scare.

Skipped for npm-local installs, whose binary PATH never serves. New capture dep on UpgradeDeps (piped stdio, 30s timeout) keeps it unit-testable; probe parsing takes the last non-empty stdout line so a stray runtime warning can't spoil it.

Validation

  • 3 detection regression tests (thin-installer platform package → npm global / npm local / npx-cached) — verified to fail against the pre-fix code and pass now.
  • 8 probe orchestration tests: match / mismatch / both inconclusive shapes / last-line parsing / Windows cmd.exe routing / npm-local skip / no probe after a failed upgrade.
  • Full suite: 2290 passed, 4 skipped (platform-gated).
  • Live e2e against real binaries in a sandboxed $HOME: bundle 1.3.1 → upgrade → same-shell -v = 1.4.0 with the green confirmation; simulated shadow prints the warning. (The npm misdetection itself was reproduced live pre-fix: upgrade curled install.sh and left the shim at 1.3.1.)

Interaction with #1239

Independent — either can merge first; whichever lands second has a trivial conflict in runUpgrade's post-success block and the CHANGELOG. Ordering note for the rebase: the version probe should run (and ideally gate) before the install --refresh spawn, so the refresh never executes through a shadowed stale binary.

🤖 Generated with Claude Code

… resolved version after every upgrade (#1238, #1071)

Two fixes to make `codegraph upgrade` trustworthy in the terminal it ran in:

1. detectInstallMethod checked the bundle layout before the node_modules
   path check, but the npm thin-installer's per-platform package IS a
   complete bundle inside node_modules — so every npm install misdetected
   as a standalone bundle, and upgrade curled install.sh into ~/.codegraph:
   a second install that never wins the PATH race against npm's shim,
   leaving `codegraph -v` permanently on the old version. Path-based
   checks (_npx, node_modules) now win over layout sniffing, so npm
   installs upgrade through npm again, in place.

2. After a successful swap, runUpgrade now probes the PATH-resolved
   `codegraph --version` and reports the real outcome: a green
   confirmation that this terminal already serves the new version, a
   loud shadow warning naming the fix (`which -a codegraph`) on
   mismatch, or the old soft new-terminal hint only when the probe is
   inconclusive. Replaces the unconditional "open a new terminal if the
   version looks unchanged" hedge. Skipped for npm-local installs, whose
   binary PATH never serves.

Companion to #1239: the misdetection also broke its post-upgrade
`install --refresh` for npm users (the spawn resolved the stale shim).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@colbymchenry

Copy link
Copy Markdown
Owner Author

Cross-platform validation

Linux (Docker, node:22-bookworm, --rm --init)

  • Targeted suites: 194/194. Full suite: 2290 passed, 4 skipped (platform-gated), 0 failed.
  • Live e2e in the container: real install.sh bundle 1.3.1 → codegraph upgrade → same-shell codegraph --version = 1.4.0.
  • Probe harness with the real defaultCapture/hasCommand against the PATH-resolved binary: match prints the green confirmation; a forced mismatch prints the shadow warning.

Windows (Parallels VM, win32-arm64, Node 24, fresh npm ci at C:\dev\codegraph on b108500)

  • Targeted suites: 194/194 (upgrade 43, installer-targets 151).
  • Live probe against a naturally occurring The version and the “--version” display are inconsistent #1071 shadow found on the VM: a stale 0.9.6 bundle launcher (AppData\Local\codegraph\current\bin\codegraph.cmd) sits earlier on PATH than a fresh 1.4.0 npm install, so codegraph --version genuinely reports 0.9.6.
    • Target v1.4.0 → mismatch: the shadow warning fired on a real-world true positive.
    • Target v0.9.6 → match: green "this terminal is already using it."
    • This exercised the cmd.exe /d /s /c routing, the PATHEXT hasCommand scan, and CRLF stdout parsing against a real .cmd launcher.

🤖 Generated with Claude Code

@colbymchenry colbymchenry merged commit 63eb488 into main Jul 10, 2026
1 check passed
colbymchenry added a commit to xuing/codegraph that referenced this pull request Jul 10, 2026
…he version probe

Conflict resolution after colbymchenry#1245 landed, plus the integration it called for:
runUpgrade now runs the PATH version probe first and skips spawning
`codegraph install --refresh` on a 'mismatch' — a shadowed stale binary
would rewrite the agent surfaces with the very templates the refresh
exists to heal. The skip logs a pointer to run the refresh manually once
the PATH is fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@colbymchenry colbymchenry deleted the fix/upgrade-npm-detection-and-version-verify branch July 10, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant