Skip to content

feat: ask about updates at startup, in the app and the terminal - #305

Merged
quickbeard merged 2 commits into
mainfrom
feat/startup-update-prompt
Aug 23, 2026
Merged

quickbeard merged 2 commits into
mainfrom
feat/startup-update-prompt

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

What

Both apps already checked for updates at launch. Neither told the user.

Desktop

updater.start() has always run a check at launch, but on the new layout the only thing that surfaced it was a small arrow in the titlebar — and only once the download had finished. (The legacy layout's UpdateAvailableToast is unreachable: newLayoutDesigns is always true.)

New fork-only packages/app/src/components/dialog-update.tsx:

  • <UpdatePrompt /> renders nothing, watches the updater, and opens the dialog the first time the state becomes available or ready — once per app run, not once per mount.
  • <DialogUpdate /> names the version and offers Not yet plus the state-appropriate action, reusing useUpdaterAction(): Download when automatic downloading is off, Install and restart once it is downloaded, a loader while either runs. Existing toast.update.* / settings.updates.action.* keys, so no new strings.

Mounted from pages/layout-new.tsx (one import, one element).

Terminal

The TUI has had a confirm dialog for installation.update-available all along, and it could never appear. cmd/tui.ts fired checkUpgrade on a one-second timer; the TUI registers its event.on(...) handlers while it renders, a few hundred milliseconds later; and Rpc.emit is a bare postMessage — an event with no subscribers is dropped, not queued. Traced end to end: worker forwards the event at T, the App's handlers register at T+800ms, event gone.

Fix: TuiInput gains onReady?: () => void, called once the App has registered its handlers; cmd/tui.ts passes checkUpgrade as onReady and drops the timer. Ordering rather than a longer timeout, so it cannot race.

Also in cli/upgrade.ts: a newer version now asks unless the user opted into automatic patch installs. const silent = config.autoupdate === true && getReleaseType(...) === "patch". autoupdate: false and CODEV_DISABLE_AUTOUPDATE still skip the check; "notify" and CODEV_ALWAYS_NOTIFY_UPDATE are unchanged.

Test plan

  • Desktop, seen working: ran bun run dev with the updater backend temporarily stubbed to report version 9.9.9, and confirmed the dialog over the renderer via CDP — "Update available / A new version of CoDev (9.9.9) is now available to install." with Not yet and Install and restart. Stub reverted.
  • Terminal, seen working: ran the TUI from source with Installation.latest() temporarily stubbed, and the dialog appears at startup — "Update Available / A new release v9.9.9 is available. Would you like to update now?" with Skip / Confirm. Before the fix the same stub produced nothing; traces showed the event forwarded by the worker and delivered into an empty handler set. Stub reverted.
  • bun typecheck in packages/app, packages/tui, packages/opencode.
  • bun run test:unit in packages/app (695 pass); bun test in packages/tui (266 pass); bun test test/cli in packages/opencode (375 pass).

DIVERGENCES.md gains two rows (the three upstream CLI/TUI files, and the layout-new.tsx mount); CHANGELOG.md gains two Unreleased entries under Updates.

🤖 Generated with Claude Code

quickbeard and others added 2 commits August 23, 2026 09:53
The desktop app has always checked at launch, but the only sign of an
update was a titlebar arrow, and only once the download had finished.
A fork-only UpdatePrompt now opens a dialog the first time a check
reports an available or ready update: Install and restart, or Not yet.

The terminal app had the same feature and none of the effect. Its check
ran on a one-second timer and announced itself with
installation.update-available, which the TUI has a confirm dialog for —
but Rpc.emit is a bare postMessage and the TUI registers its handlers
while it renders, a few hundred milliseconds after the check resolved.
The event was delivered into an empty handler set every launch. The
check now starts from a new TuiInput.onReady, called once those
handlers exist.

While there: only an explicit `autoupdate: true` installs a patch
release by itself. The default asks, like every other release type.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@quickbeard
quickbeard merged commit cc8b551 into main Aug 23, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the feat/startup-update-prompt branch August 23, 2026 03:05
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