feat: surface update info via status and daemon startup#23
Merged
Conversation
Adds a best-effort PyPI update check that's deliberately script-friendly: the network call only fires from `stackvox status` and `stackvox serve` startup. Hooks, CI, `say`, `speak`, `stackvox-say` — every script path stays silent unless the user opts in explicitly. - stackvox/updates.py: cache-backed PyPI fetch - 24h cache at ~/.cache/stackvox/update-check.json - 2s timeout, fails silently on network/parse errors - Auto-skipped when CI/GITHUB_ACTIONS/etc. are set - STACKVOX_NO_UPDATE_CHECK=1 disables entirely - cli._cmd_status: synchronous fetch (acceptable here — `status` is the canonical "is everything OK?" query and the user is at a terminal). Always prints `version: X.Y.Z` plus the upgrade notice if applicable. - daemon.serve: spawns a background thread to do the check at startup and log the notice via the daemon's stderr — high-leverage moment to surface "you should upgrade" because the user's at the terminal. Doesn't block daemon startup. - cli.main: STACKVOX_UPDATE_NOTICE=1 turns on a per-invocation stderr notice for users who want the gh-style behaviour. Off by default. Reads cache only — never fetches on this path. - tests/test_updates.py (new): 24 cases covering version comparison, disable env vars, cache I/O round-trip + corruption, fetch happy/error/disabled paths, cached_update + check_for_update freshness, fallback-to-stale-cache, and format_notice. - tests/test_cli.py: autouse fixture mocks `updates.check_for_update` and `cached_update` so existing tests don't hit PyPI. New cases for status's update line and the opt-in stderr notice. - README: daemon section explains the policy and the two env vars. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b3c7fb1 to
10f7e9e
Compare
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.
Summary
Best-effort PyPI update check that's script-friendly by default: the network call only fires from `stackvox status` and at daemon startup. Hooks, CI runs, `say`, `speak`, `stackvox-say` — every script path stays silent. Users see the notice when they're already looking at the terminal.
How it surfaces
Default behaviour
```
$ stackvox status
running (pid 12345) on /Users/.../daemon.sock
version: 0.3.1 (update available: 0.3.1 → 0.4.0 (run `pipx upgrade stackvox`))
$ stackvox serve
[stackvox] daemon listening on … (pid 12345)
[stackvox] update available: 0.3.1 → 0.4.0 (run `pipx upgrade stackvox`)
```
Disable / opt-in env vars
Mechanics
Tests
24 new cases in `tests/test_updates.py`: version comparison (parametrized), disable env vars, cache I/O round-trip + corruption + missing-keys, fetch happy / error / malformed-JSON / disabled paths, `cached_update` and `check_for_update` freshness + stale-fallback, `format_notice`.
`tests/test_cli.py` adds a global fixture mocking `updates.check_for_update` / `cached_update` so the existing suite never hits PyPI, plus dedicated cases for status's update line and the opt-in notice.
108 tests, all green. ruff + mypy clean. Coverage of the new module is at 100% from the new tests.
Test plan