feat(system): flag stale native deps, not just missing ones (v0.298.0) - #545
Open
vikasprogrammer wants to merge 1 commit into
Open
feat(system): flag stale native deps, not just missing ones (v0.298.0)#545vikasprogrammer wants to merge 1 commit into
vikasprogrammer wants to merge 1 commit into
Conversation
Settings → System only ever asked "is it installed?". A tenant's box sat on claude 2.1.216 for weeks — /model couldn't list Opus 5 and the `opus` family alias resolved to 4.8 — while the panel showed a green "All required dependencies are installed" the whole time. Deps may now name an `npmPkg`. `checkDepUpdates()` asks the npm registry for `latest` (abbreviated /latest endpoint via global fetch — no `npm` shell-out, no new dep), caches for an hour, and flags a behind-version install. `checkDeps()` stays sync and network-free so freshness is a layer on top, not a slower probe. A stale row goes amber with the published version, an owner-only Update button, and a note that live sessions keep their binary until they restart. POST /api/deps/update runs `npm install -g <pkg>@latest` — owner-gated, audited, never via sudo, and it prefers the npm beside the resolved binary so an nvm box can't install into a different prefix than the one it runs from. Also fixes a latent bug in the same file: deps.ts resolved binaries with a bare `command -v` while claude-cli.ts walks $CLAUDE_BIN → PATH → ~/.local/bin/claude, so a box whose unit ships a minimal PATH reported the runtime MISSING while sessions launched fine. Both now share claudeBinCandidates() and honour the same order — resolving PATH first would report the version of a binary sessions never run. scripts/deps-freshness-test.cjs (38 assertions) wired into test:governance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Why
Two issues on the instawp tenant today —
/modelcouldn't list Opus 5, and theopusalias resolved to Opus 4.8 — had one root cause: the box was on claude-code 2.1.216, whose baked model registry tops out atclaude-opus-4-8. The stringclaude-opus-5doesn't exist in that binary.The config was fine. What's notable is that Settings → System showed a green "All required dependencies are installed." the entire time.
checkDeps()only ever asked is it present? —okisdeps.every(d => !d.required || d.installed), so a months-old runtime is fully "ok" by that definition. And theclaudedep deliberately carries no package-managerpkg, so it sat outside the install path entirely.Both boxes are already upgraded by hand (instawp + expresstech → 2.1.220). This closes the gap that let it go unnoticed.
What changed
Freshness — a
Depmay now name annpmPkg.checkDepUpdates()(src/edge/deps.ts) asks the npm registry forlatestvia the abbreviated/latestendpoint using the globalfetch— nonpmshell-out (it may not be on a systemd unit's PATH), no new dependency — caches for an hour, and flags a behind-version install.checkDeps()stays sync and network-free, so freshness is a layer on top rather than a slower probe; an offline box still gets its full presence report with a per-depupdateError.GET /api/depsannotates the report (?force=1re-asks). A stale row goes amber with the published version and, for the owner, an Update button.Update —
POST /api/deps/updaterunsnpm install -g <pkg>@latest. Owner-gated, auditedsystem.deps.updated, and never via sudo (sudo npm -gleaves root-owned files in the prefix; a permissions failure surfaces the manual command instead). It prefers thenpmsitting beside the resolved binary, so an nvm box can't install into a different node prefix than the one it actually runs from. CLI parity:agent-os depsshows↑ … → v2.1.220 available,agent-os deps update <bin>applies it.Fixed — off-PATH resolution.
deps.tsresolved binaries with a barecommand -v, butclaude-cli.tswalks$CLAUDE_BIN→ PATH →~/.local/bin/claudeprecisely because a launchd/systemd parent ships a minimal PATH. On such a box the panel would report the runtime missing while sessions launched fine. Both now shareclaudeBinCandidates()and honour the same order — the test caught me resolving PATH first, which would report the version of a binary sessions never run. A dep found only via a fallback is version-probed at its resolved path and badgedoff PATH.Verification
npm run typecheck,npm run build,cd web && npm run build— clean.npm run test:governance— 159 + 18 + 18 + 29 + 29 + 38 passed, exit 0.scripts/deps-freshness-test.cjs(38 assertions, isolated home): version comparison, resolution order, the off-PATH case, stale detection, route authz (member/admin 403 on update, owner-only; non-npm and unknown deps refused before any shell-out), and a full update round-trip against a stubbednpm— which also pins the sibling-npm preference.CLAUDE_BINpointed at a fake reporting2.1.100, reproducing the instawp condition exactly:ok: true,outdated: ['claude'],latest: 2.1.220.Panel in that state: amber "1 dependency is out of date — Claude Code", the row reading
2.1.100 (Claude Code)/v2.1.220 available · npm install -g @anthropic-ai/claude-code@latest, an Update button and anoutdatedbadge, plus the note that running sessions keep their binary until they restart.🤖 Generated with Claude Code