Skip to content

TUI: persistent top-right update banner (+ --fake-update testing ground) - #317

Merged
plombeer31 merged 2 commits into
mainfrom
valeryb/update-banner
Sep 3, 2026
Merged

TUI: persistent top-right update banner (+ --fake-update testing ground)#317
plombeer31 merged 2 commits into
mainfrom
valeryb/update-banner

Conversation

@plombeer31

@plombeer31 plombeer31 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

What

A persistent update strip in the top-right corner of the status bar, shown whenever a newer release exists, that also narrates the install once accepted:

   R U N                                                      new version v9.9.9 available   Update
   R U N                                                          updating to v9.9.9 — do not close
   R U N                                                       updated to v9.9.9 — restart to apply

The existing startup modal (y = update now · n / Esc = skip) is untouched. What changes is what happens around it: skipping no longer erases all trace of the update, and accepting no longer leaves the corner silent while the installer works.

Design

  • Inverse-video (SGR 7), not a hand-picked color: the strip is by construction the opposite of whatever background the palette/terminal uses, so it is distinguishable on every theme without ever blinking or animating. Update is additionally accent-tinted + bold so the actionable cell reads as the button.
  • Non-intrusive: static, claims no keys, sits in the corner the eye only visits deliberately. The modal remains the keyboard route.
  • Clicking Update just works — including while the startup modal is still open. The modal raises the mouse floor to the modal rung, so the button registers on that rung too; a click there is exactly the modal's y (same onUpdateConfirmedrunUpdate() path, including its refusal while a turn is in flight), so answering the offer from the corner is the same decision, not a bypass.
  • Lifecycle: raised by update_available; survives update_dismissed; shows updating to vX — do not close while the installer runs; updated to vX — restart to apply once it lands; returns to the offer — the retry path — after a failed install.
  • Degrades instead of wrapping the one-row bar (Ink wraps rather than clips), per phase: new version v9.9.9 available [Update]v9.9.9 [Update][Update] → nothing; updating to v9.9.9 — do not closeupdating — do not closeupdating…. Verified live at 100/70/52/46/42 columns.

Testing ground

atomic-agent tui --fake-update 9.9.9

(from a checkout: npm run build && node dist/cli/index.js tui --fake-update 9.9.9)

The flag pretends that version is on GitHub Releases: the real check is bypassed (a dev build fails canSelfUpdate anyway), and accepting — via the modal's y or the banner's Update — walks the same event sequence the real installer emits (started → feed lines → finished ok) on a watchable timeline, without ever running install.sh. The whole arc is on show: offer, click-through-the-modal, do-not-close strip, restart prompt; the post-update restart re-execs the same dev command, so nothing on the machine is ever replaced. --fake-update v9.9.9 also works; a missing/flag-shaped value is a usage error. Advertised in tui --help.

Tests

  • update-banner.test.tsx — offer/running/done phase texts, per-phase degradation ladders, disappearance below the minimum, plan-never-exceeds-budget sweep across all phases.
  • status-bar-update.test.tsx — banner shown on offer, survives modal dismissal, "do not close" while running (button gone), restart hint when done, retry offer after failure, absent with no offer, right-edge pinning, bar stays one row.
  • Reducer: update_available raises modal+banner, update_dismissed clears only the modal, repeat offers during a run stay ignored.
  • tui-args: --fake-update parsing (default null, v-prefix tolerated, missing value refused, in --help).

Full src/tui suite: 246 files / 2658 tests green (plus this machine's known pre-existing llama-server spawn-EACCES artifact, unrelated). Also verified in a real PTY: inverse attribute present on the whole strip, SGR mouse click on Update fires with the startup modal still on screen, the running and done strips render at the right moments, and the banner survives n.

The startup update modal is skippable, and skipping it left no trace on
screen — an operator who pressed n once stayed on the old version with
nothing reminding them a newer one exists.

The offer now also raises a banner pinned to the right edge of the
status bar: 'new version vX.Y.Z available [ Update ]'. It renders
inverse-video, so it is the opposite of whatever ground the palette and
terminal use — distinguishable by construction, and static, so it never
pulls the eye away from the work. Clicking Update runs the same path as
the modal's y (including the refusal while a turn is in flight); the
modal itself is untouched and remains the keyboard route.

The banner survives update_dismissed (the modal is the question, the
banner is the memory), yields while an update runs or has finished, and
returns on a failed install so there is still a way to retry. On narrow
rows it degrades — full sentence, bare version, button alone, nothing —
instead of wrapping the one-row bar.

Testing ground: 'atomic-agent tui --fake-update 9.9.9' pretends that
version is released — the real check and the real installer are both
bypassed, so the modal, the banner and its degradations can be
eyeballed on a dev build.
Two field reports from the first demo round:

The obvious first click a fresh launch invites is the banner's Update
button — while the startup offer modal is still on screen. The modal
raises the mouse floor to the modal rung, so that click was silently
swallowed. The button now registers on the modal rung itself: a click
there is exactly the modal's y, so answering the offer from the corner
is the same decision, not a bypass.

And once an update is accepted, the corner went quiet at the very
moment it had something worth saying. The strip now narrates the
lifecycle instead of hiding: 'updating to vX — do not close' while the
installer runs (degrading to 'updating — do not close', then
'updating…'), 'updated to vX — restart to apply' once it lands, and
back to the offer — the retry path — after a failure.

--fake-update's accept now walks the same event sequence the real
installer emits (update_started, feed lines, update_finished ok) on a
watchable timeline instead of a one-line notice, so the whole arc —
modal, click-through, do-not-close strip, restart prompt — is on show;
the restart re-execs the same dev command, so nothing is ever
installed.
@plombeer31
plombeer31 merged commit aeda7dc into main Sep 3, 2026
2 checks passed
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