Skip to content

feat(desktop): surface update availability and add one-click install#70

Open
ErikChevalier wants to merge 1 commit into
mainfrom
feat/update-notifier
Open

feat(desktop): surface update availability and add one-click install#70
ErikChevalier wants to merge 1 commit into
mainfrom
feat/update-notifier

Conversation

@ErikChevalier
Copy link
Copy Markdown
Contributor

Why

The daily GitHub update check already worked, but it barely notified: a found update only appeared as a CLI line or the Settings "Check now" modal, and the background check ran once at launch. This makes a found update visible and actionable while the app is open.

What

  • Notify while open — a tray system notification and a dismissible banner across the top of the main window. The background check now runs on first show, so a long-running window still learns about new releases.
  • Owner-only served-page banner — the home and results pages show the same notice, but only to the loopback owner. A network/LAN visitor never sees it (they can't install anything and it would leak the owner's version). Verified by test.
  • One-click fetch-and-hand-off — clicking Update downloads the right installer for the OS (.dmg/.msi), verifies its SHA-256 against the release SHA256SUMS, and opens it for the system installer. Linux (multiple package formats) and any failure fall back to the release page. The web banner links straight to the release.
  • Persistence — pending update stored in prefs (pending_update_version/url), set/cleared by a shared reconcile_pending_update, self-clearing after an in-place update.
  • Settings window constrained to 4:3 (opens 800×600, locked on resize).

Honest limitation

While builds are --adhoc-sign, the one-click install still trips Gatekeeper/SmartScreen on macOS/Windows — unavoidable without real code-signing/notarization.

New / changed files

  • update.pyReleaseAsset, asset parsing, asset_for_system, checksums_asset, VersionTag.formatted(), reconcile_pending_update; body cap 16→64 KiB for the assets list.
  • update_download.py (new) — streamed, size-capped download + SHA-256 verify, default_download_dir.
  • prefs.pypending_update_version / pending_update_url.
  • server/{app,templates}.py — owner-only update_banner on home + results.
  • gui/main_window.py — banner, tray notification, background check on show, _on_update_clicked flow.
  • gui/settings_dialog.py — 4:3 lock; "Check now" reconciles pending. gui/theme.py — banner QSS.
  • cli.py — serve-time check persists pending state.

Tests / checks

Added: asset parsing + platform selection + reconcile; the download/verify module (match / mismatch / missing-entry / oversize / transport-error); owner-vs-network web banner; GUI banner + 4:3 lock. ruff + ruff format + mypy --strict (85 files) + full suite green (581 passed, 1 skipped).

Verification

Offscreen renders confirm the banner and the 4:3 Settings window; served-page render confirms owner sees the banner and a network visitor does not.

🤖 Generated with Claude Code

The daily GitHub update check already worked but barely notified: an update
only showed as a CLI line or a Settings "Check now" modal, and the background
check ran once at launch. This makes a found update visible and actionable.

- Notify while open: a tray system notification plus a dismissible banner
  across the top of the main window; the background check now runs on first
  show so a long-running window still learns about new releases.
- Owner-only served-page banner: the home and results pages show the same
  notice, but only to the loopback owner (a network visitor never sees it and
  the owner's version is not leaked).
- One-click fetch-and-hand-off: clicking Update downloads the right installer
  for the OS (.dmg/.msi), verifies its SHA-256 against the release SHA256SUMS,
  and opens it for the system installer. Linux (multiple package formats) and
  any failure fall back to the release page.
- Pending update persisted in prefs (set/cleared by reconcile_pending_update)
  so the banner survives a restart and self-clears after an in-place update.
- Constrain the Settings window to a 4:3 aspect ratio.

Tests: asset parsing + platform selection + reconcile, the download/verify
module (match/mismatch/missing/oversize/transport-error), the owner-vs-network
web banner, and the GUI banner + 4:3 lock. ruff + mypy --strict + full suite
green (581 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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