✨ feat(status-bar): app version + a quiet update ping - #45
Conversation
Adds the running version to the far-right of the always-visible status bar: dim "smterm 0.1.24" by default, and when a newer release exists it becomes an accented, clickable ping (reusing .dot.pulse) → opens the release page. The check is best-effort and off any hot path: main hits the GitHub releases API on launch + every 6h; any failure (offline / rate-limited / timeout) just leaves the badge silent. Pure semver compare + release parsing are unit-tested; the status-bar states have component tests.
winlp4ever
left a comment
There was a problem hiding this comment.
Ran /code-review (high effort). Well-built feature — verified the substantive parts: version.ts semver compare is correct incl. prerelease ordering (final > rc, numeric < alphanumeric, fewer-fields-lower), leading-v/+build handling, and unparseable → 0 (no false update); the GitHub check degrades gracefully on every failure path (offline / non-200 / bad JSON / 8s timeout → quiet), sets the required User-Agent, and /releases/latest correctly ignores prereleases; off the hot path, IPC wired full-stack, tsc clean, 12 tests pass. Three findings, all low/low-med.
| render(<StatusBar />) | ||
| expect(await screen.findByText("macOS")).toBeInTheDocument() | ||
| expect(screen.getByText("UTF-8")).toBeInTheDocument() | ||
| describe("StatusBar version badge", () => { |
There was a problem hiding this comment.
#1 (test-coverage — top) — the rewrite deleted the existing StatusBar tests. This file's describe("StatusBar") previously covered the platform label + UTF-8, running/waiting session counts, and git-branch shown-in-repo / hidden-out-of-repo. Rewriting it to describe("StatusBar version badge") replaced those rather than adding to them. The component still renders all of that (its code is unchanged), but I checked and no other component test exercises it — so a future regression in the branch/counts/platform rendering would go uncaught. Restore the platform/counts/branch cases alongside the new version-badge ones.
| void ipc.platformInfo().then((info) => setPlatform(info.label)) | ||
| void ipc.appVersion().then(setVersion) | ||
| // Check on launch, then re-check every 6h so a window left open for days still notices. | ||
| const check = () => void ipc.checkUpdate().then(setUpdate) |
There was a problem hiding this comment.
#2 (correctness) — a failed periodic re-check hides a real update. const check = () => void ipc.checkUpdate().then(setUpdate) sets state unconditionally, and a failed check returns the quiet status ({updateAvailable:false, latest:null}). So: the launch check finds an update → badge pings; 6h later the machine is briefly offline → the re-check returns quiet → setUpdate(quiet) → the ping vanishes; another 6h later it reappears. A transient network blip on a re-check silently drops a real, still-valid update notification. Update state only on a successful check (or keep updateAvailable:true sticky until a newer successful result supersedes it).
| // Check on launch, then re-check every 6h so a window left open for days still notices. | ||
| const check = () => void ipc.checkUpdate().then(setUpdate) | ||
| check() | ||
| const t = setInterval(check, 6 * 60 * 60 * 1000) |
There was a problem hiding this comment.
#3 (correctness, low) — the 6h setInterval is unreliable across system sleep. For the stated "a window left open for days still notices" case, a laptop that sleeps between ticks throttles/defers the timer, so it resumes only after wake and the cadence drifts well past 6h — a mostly-sleeping machine may re-check far less than intended. The on-launch check covers the common path, so impact is low; consider also re-checking on powerMonitor resume / window focus rather than relying on a long wall-clock interval for the 'days open' scenario.
- #1: restore the original StatusBar tests (platform/UTF-8, running/waiting counts, git-branch shown/hidden) that the rewrite had replaced; keep them alongside the new version-badge cases. - #2: a failed re-check no longer clears a real update ping. checkUpdate results fold through a pure applyUpdateResult that ignores a failed check (latest null) and only lets a successful result supersede — so a transient offline blip on the 6h re-check can't drop a still-valid notification. - #3: also re-check on window focus (throttled to the 6h refresh), so a laptop that slept through the wall-clock interval still notices on wake/return.
|
All three addressed:
|
First cut of the version/update QoL — deliberately minimal and non-invasive, in the always-visible status bar (bottom-right).
What you get
smterm 0.1.24at the far right of the status bar. Silent..dot.pulse) → clicking opens the release page. Tooltip: "Update available — v0.1.25 (you have v0.1.24)."Placed in the status bar (not the sidebar) because the sidebar is unmounted when collapsed — a ping there would vanish. Status bar is always rendered.
How (off any hot path, no signing)
app:version→app.getVersion().app:check-update→ main hits the GitHub releases API (vcmf/smterm), compares to the running version, returns{ current, latest, updateAvailable, url }. Runs on launch + every 6h (so a window left open for days still notices). Any failure — offline, rate-limited, 8s timeout — returnsupdateAvailable:false, so the badge just stays quiet. Pure network in main; nowhere near the terminal.Tests
make check+typecheckgreen — 435 tests (+12):version.ts: semver compare incl. prerelease ordering (final > rc), leadingv/build suffix, unparseable → no false update.update-check.ts: release-JSON parsing (tag/url/missing).status-bar.tsx: shows dim version when current; shows the pinging, linking badge when an update exists; stays silent when the check fails.Not in scope (the bigger story we discussed)
Auto-download/apply, delta updates (your
.blockmaps are already published), CDN mirror for faster installs, and the code-signing decision that unblocks silent macOS updates — all deferred. This is just the "know your version / know an update exists" seed.