fix(tui): load the catalog without waiting for the event stream - #353
Merged
Conversation
The provider and model lists only synced once the SSE stream reported server.connected. That handshake is bounded by a 2s connectTimeout armed before roughly 2s of blocking startup work, so on a compiled build it almost always aborted spuriously: 7 of 8 cold launches burned the full timeout, then paid reconnect backoff before any catalog request went out. Measured time-to-model was 4.6-4.9s on a static transport and 5.4-12.4s on a managed one, against a server that had published catalog.updated at 450ms. Fetch the catalog on location set, since those reads are plain HTTP and never depended on the stream; server.connected still resyncs, and DataProvider already drops the cached completion whenever the stream is down, so a healthy start costs one fetch. Retry an opening handshake that never established against the endpoint just resolved instead of re-resolving the managed service first, which was the source of the multi-second variance. A stream that established and then dropped still re-resolves, since a restarted server may have moved. Distinguish an unfetched model list from an empty one so the dialog shows 'Loading models…' rather than 'No items available'.
shuv1337
added a commit
that referenced
this pull request
Aug 13, 2026
Merge anomalyco/opencode upstream/v2 (283258e, 187 commits) into integration-v2 (00e7c54), aligning with upstream everywhere except fork-critical features, per PLAN-upstream-v2-merge.md. Preserved fork features: identity/publish/updater/launcher, managed service lifecycle (ServiceLifecycle.ensure everywhere), Anthropic Claude Pro/Max subscription provider, structured output, session tool policy, strict prompt retry identity (durable admitted-event reconciliation), mobile pairing removal, and prior fork fixes (#350/#353/#354). Adopted from upstream: session_v2 rename, skills prompt attachments, plugin hook rename request -> http.request/http.response, new CLI commands (models/export/import/debug config), workspace_domain, legacy-credential import, docs/app/desktop changes. Database bridge (M2): DatabaseMigration.apply now detects a fork-tip session table (fork_boundary column, tool-policy migration present, no session_v2) and renames it to session_v2 in one transaction before upstream migrations run, rebuilding session_v2_* indexes and marking the upstream squash migration as already applied so its destructive SQL never executes. Validated against a real dev DB copy (12 sessions/16 messages/86 events preserved) and via a fork-tip fixture test. Data-safety corrections (M3): V1Migration no longer globally wipes events when V2 sessions already exist (gated on empty session_v2); imported legacy Anthropic OAuth credentials now map to methodID claude-pro-max. CLI/service wiring (M4): new upstream handlers registered without pair; every server-start path (auth login, debug config, server-connection) routes through ServiceLifecycle.ensure. Regeneration & docs (M5): protocol/client/www regenerated; publish.yml gains a github.ref_name == integration-v2 guard; merged docs rebranded to Shuvcode while preserving SDK/API symbols; migrate-v1.mdx documents the DB bridge, scoped event deletion, and the hook rename; AGENTS.md records the session_v2/bridge and hook-name invariants. Upstream-bug follow-ups (M6): symlinked mutation targets now resolve through the nearest existing ancestor's real path before authorization, closing an external-directory approval bypass; desktop background-cli prefers the canonical managed state root over the first running candidate; failed server replacement no longer removes existing tabs. Validated: full per-package typecheck+test pass (schema, protocol, core, server, client, cli, tui, app) plus a live smoke test against an isolated standalone server pointed at a scratch copy of a real dev database, confirming existing sessions/transcripts render and that a live prompt round-trips both structured output and a skill attachment.
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.
Fixes #351.
Summary
The TUI's provider and model lists only synced after the SSE stream reported
server.connected. That handshake is bounded by a 2sconnectTimeoutarmed before ~2s of blocking startup work on the same JS thread, so on a compiled build it almost always aborted a connection that was never unhealthy; the model switcher showedNo items availableand the footerNo provider selecteduntil the retry landed. Measured 4.6–4.9s to first model on a static transport and 5.4–12.4s on a managed one, against a server that had publishedcatalog.updatedat 450ms.Changes
server.connectedstill resyncs, andDataProvideralready drops the cached completion whenever the stream is down, so a healthy start costs exactly one fetch.ServiceLifecycle.ensure()was the source of the multi-second variance). A stream that established and then dropped still re-resolves, since a restarted server may have moved.Loading models…instead ofNo items available.Validation
bun typecheckclean inpackages/tuiloads the catalog before the event stream connects(test/cli/tui/data.test.tsx)retries an unestablished handshake before re-resolving the server(test/cli/tui/use-event.test.tsx)Out of scope (tracked in #351)
The 2s
connectTimeoutstill measures wall-clock across a potentially blocked event loop; arming it after dispatch is a separate repair. Upstreamv2carries the same defects, so expect a conflict at the next sync.