feat(cli): nudge raven upgrade in the tui status bar when behind - #220
feat(cli): nudge raven upgrade in the tui status bar when behind#220arelchan wants to merge 2 commits into
Conversation
0xKT
left a comment
There was a problem hiding this comment.
Review of ce56583, merged onto main 16719d0: clean merge, full unit suite green locally (4621 passed). Note the green checks on this PR predate #224, which switched CI to the full unit suite, so a rebase and re-run is needed regardless.
Items are ID severity. Each is independent; reply with the ID when addressed.
B1 blocking: unit tests now hit the GitHub API and write the real $HOME
- Where:
raven/cli/tui_commands.py:997-999,tests/test_cli_tui_commands.py:505 - What:
test_tui_announces_log_path_only_on_abnormal_exit(6 cases) mocksfind_node, so control flow reachesmaybe_refresh_async()with nothing stubbing it. Under a throwaway HOME those cases write$HOME/.raven/update_check.jsonwith a real fetchedlatest_version. All failures are swallowed, so the test stays green either way. Since #224 the CI unit job runs the full suite. - Fix: autouse fixture redirecting
update_notice._CACHE_PATHtotmp_path, mirroringtests/conftest.py:30-52formodel_catalog_cache._CACHE_PATH. That also isolatestests/test_tui_rpc_session.py, whosesession_create({})reads the real cache today. - Do not: patch
tui_commands.maybe_refresh_async. The import attui_commands.py:997is function-local, so there is no module attribute to replace.
B2 blocking: a valid-JSON, non-object cache file raises instead of being swallowed
- Where:
raven/cli/update_notice.py:37-40, raising at:77and:93 - What:
_read_cachereturns whateverjson.loadsyields with no dict check. A cache holding"0.2.0",[1]or42reachescache.get(...)and raisesAttributeErrorinsidetui()(raven tuifails to launch) and inside_default_session_info(session.createfails). Both reproduced. Reaching it takes a hand-edited file, which the "To see it locally" snippet invites, and the module contract is that the hint never breaks startup. - Fix:
isinstance(parsed, dict)guard in_read_cache.
S1 should-fix: the nudge points at a command that always fails for editable and pip installs
- Where:
raven/cli/update_notice.py:96-100vsraven/cli/upgrade_commands.py:440-449 - What:
raven upgraderaises for editable installs and non-uv-tool installs and exits 1, butupdate_notice()only compares versions, so those users get a permanent warn-colored nudge to a failing command. - Fix: gate the notice on
upgrade_commands._is_uv_tool_install()(:356), wrapped in try/except since_uv_tool_targetraisesUpgradeErroron a malformed receipt.
S2 should-fix: the failure path never backs off, and its comment says otherwise
- Where:
raven/cli/update_notice.py:56-65 - What:
_refreshwriteschecked_atonly on success, so while offline, rate-limited, or whenever the latest release is a draft or prerelease (_parse_release_payloadraises), every launch spawns a thread and refetches. The comment at:64claims "try again next TTL". - Fix: write
checked_aton failure too, keeping the previouslatest_version.
S3 should-fix: the cache path bypasses the cache-dir helper
- Where:
raven/cli/update_notice.py:24 - What: hardcodes
Path.home() / ".raven", so a non-default instance set viaset_config_path()writes back into the default home. - Fix:
paths.get_cache_dir()(raven/config/paths.py:37), the designated disposable-cache dir, with precedent atraven/token_wise/model_catalog_cache.py:39. It also removes the manualmkdir.
N1 minor: duplicate version parser
update_notice.py:27,30 reimplements upgrade_commands.py:21,178. The looser semantics (prefix match, return None) look deliberate, but the module already imports _fetch_latest_release from that file, so one shared lenient parser keeps a single source of truth.
N2 minor: dead and missing demo fixtures
ui-tui/src/demo/gallery.tsx:102-103 still seeds update_behind: 2 into the SessionPanel demo, dead now that the banner block is gone, while the StatusRule demos and stubGatewayFixtures.ts:32 never exercise the new nudge state.
N3 minor: no opt-out for the launch-time network call
The fetch sends the raven version in the User-Agent (upgrade_commands.py:234-239). An env-var escape hatch is conventional for update checks.
N4 minor: update_behind is a flag in a count-shaped field
Nothing on main ever populated it (stubGatewayFixtures.ts:32 is null), so renaming it to a boolean update_available is free now and not later.
Verified fine, no action: the status bar stays on one line at narrow widths (checked down to cols=44, where Yoga shrinks and truncates both slots), and the RPC server is only constructed inside the raven tui process, so the refresher and the reader always share a process.
The TUI already read update_behind / update_command out of the session init bundle, but nothing ever filled those fields, so the hint never appeared. Add raven/cli/update_notice.py: a cached check against the GitHub releases API. The live call is too slow for the session-create path, so `raven tui` refreshes ~/.raven/update_check.json in a daemon thread at most once a day and the gateway only reads that cache while building the info bundle. Every failure path is swallowed -- an update hint must never break startup. The cost is that a freshly published release surfaces on the next launch. Show it in the status bar's right slot, replacing the cwd/branch label, in the warn color. The old banner block is removed: the banner is the first thing on screen and an upgrade hint does not deserve that weight. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
Review follow-ups on the startup nudge. Tests no longer touch the network or the real home: an autouse fixture redirects the cache path and sets RAVEN_NO_UPDATE_CHECK for the suite. Redirecting the path alone leaves the cache absent, which is exactly the state that spawns the fetch, so six tui cases fetched a release on every run since CI went to the full suite. A cache file holding valid JSON that is not an object no longer raises out of `raven tui` or session.create -- _read_cache rejects non-dicts. The nudge is gated on an upgradable install, so editable and non-uv-tool users stop being pointed at a command that always exits 1. A failed refresh now stamps checked_at too, so offline, rate-limited and draft-release launches back off for a full TTL instead of refetching every time. The cache moves to paths.get_cache_dir(), resolved per call so set_config_path() is honoured, and the duplicate version parser delegates to upgrade_commands. Also adds a RAVEN_NO_UPDATE_CHECK opt-out, renames update_behind to the boolean update_available it always was, and gives the demo gallery a StatusRule nudge state in place of the dead SessionPanel seed. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
ce56583 to
1c581e6
Compare
|
All nine items addressed, rebased onto B1 fixed -- unit tests no longer fetch or write the real home
The redirect alone is not enough. Under a temp path the cache is absent, which is exactly the state that spawns the fetch thread, so the six
B2 fixed -- non-object cache no longer raises
S1 fixed -- no nudge when
|
Summary
The TUI already read
update_behind/update_commandout of the session initbundle, but nothing on the Python side ever filled those fields, so the hint
never appeared. This wires up the missing half and moves where it shows.
The check
raven/cli/update_notice.pycompares the running version against a smallcache in
~/.raven/update_check.json:raven tuicallsmaybe_refresh_async()once per launch. It spawns a daemonthread only when the cache is missing or older than 24h, so a normal launch
touches the network at most once a day and never blocks startup.
(
_default_session_info). Reading is pure and fast; no network on thesession-create path, which is why the check is cached rather than live.
network error, rate limit. An update hint must never break startup.
The tradeoff is staleness by one launch: the first launch after a release
lands refreshes the cache, and the hint shows on the next launch.
Where it shows
The status bar's right slot, in the warn color, replacing the cwd/branch label
while an update is available. No extra line, no layout shift.
The old banner block in
branding.tsxis removed. The banner is the firstthing on screen at startup and an upgrade nudge does not deserve that weight.
update_behindis now a flag rather than a commit count, so the text isversion-agnostic (
Update available - run raven upgrade) instead of the oldN commits behind.Type
Verification
New tests cover the cache read/write and refresh throttle
(
tests/test_cli_update_notice.py), the status-bar slot swap(
ui-tui/src/__tests__/statusRule.test.tsx), and the banner no longerrendering the block (
branding.test.tsx).Also exercised the five edge cases by hand: absent cache, newer cached
release, cache equal to current, unparseable version string, and a corrupt
cache file. Only the second one returns a notice; the rest return
None.The lint warning reported on
appChrome.tsx(react-hooks/exhaustive-deps,line 275) is pre-existing on
mainand untouched by this change.Risk
The GitHub releases fetch reuses
upgrade_commands._fetch_latest_release, sono new network surface or credential handling. The cache file holds a version
string and a timestamp only.
Wire-compatible:
update_behind/update_commandwere already optionalfields in the info bundle, and a client that never receives them behaves as
before. Rollback is reverting this commit; the feature degrades to its current
state, which is showing nothing.
To see it locally:
Related Issues
N/A