Repository navigation
feat(cli): update preflight UI while replacing the background service - #36448
Merged
Merged
Conversation
This was referenced Jul 11, 2026
3 of 6 tasks
This was referenced Jul 19, 2026
jinhuang712
pushed a commit
to jinhuang712/opencode
that referenced
this pull request
Sep 26, 2026
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.
What
When a freshly launched
opencodefinds a version-mismatched background service and must replace it before the TUI can attach, the terminal currently shows one raw stderr line and then up to ~5s of silence. This PR replaces that window with an animated split-footer preflight:from → toversions✓ OpenCode updated to <version>) that survives above the TUI after handoffThe footer renders at 60fps via the renderer's own frame loop, tears down completely (back to main screen) before the TUI creates its own renderer, and falls back to the existing stderr messages when stdin/stdout is not a TTY.
How
packages/client:Service.StartOptions.onStartnow receives the registrationInfoof the service being replaced, so the caller knows the old version. Backwards compatible.packages/cli/src/services/update-preflight.tsx: the component + a small handle (begin/finish/fail). Stage labels linger a minimum of 350ms so transitions read as deliberate motion; real work is never delayed.packages/cli/src/commands/handlers/default.ts: mounts the preflight fromonStartonversion-mismatch, finishes it afterServer.resolvesucceeds, writes a failure receipt if resolve fails.Scope
This covers the fresh-launch restart window only. Already-connected TUIs going through the reconnect herd (#36285) need service lifecycle events that don't exist yet; the finer in-restart stages (draining, health polling) are part of that follow-up.
Testing
bun typecheckinpackages/clientandpackages/clibun run testin both packages (25 + 24 pass)0.0.1-old, launched a client as0.0.2-new(runtimeOPENCODE_VERSIONglobals from wrapper entrypoints, isolated XDG dirs). Verified the preflight renders with real versions, the service is replaced (new pid, new version, same URL), the receipt lands in scrollback, and the TUI attaches at the new version.Demo
Real end-to-end run: a service registered as
0.0.1-oldis replaced by a client launched as0.0.2-new. Preflight plays through its stages, the receipt lands in scrollback, and the TUI attaches at the new version.e2e-demo.mp4
Flow
sequenceDiagram participant CLI as opencode (new version) participant Foot as Preflight footer participant Old as Old service participant New as New service participant TUI CLI->>Old: discover + /api/health Note over CLI,Old: version mismatch CLI->>Foot: begin(from: old version) Note over Foot: "Keeping your session safe" CLI->>Old: SIGTERM (drain + suspend sessions) CLI->>New: spawn opencode serve --service Note over Foot: "Starting the new background service" CLI->>New: poll /api/health until ready CLI->>Foot: finish() Note over Foot: "Connecting to OpenCode" Foot-->>CLI: ✓ receipt written to scrollback, renderer destroyed CLI->>TUI: run({ server }) Note over TUI: fresh renderer, receipt survives above