fix(dashboard): blank agent-spawned terminals, inflated bridge count, Centrifugo reconnect flapping - #98
Merged
Conversation
…ridge count, and Centrifugo reconnect flapping Three user-visible problems, one shared cause in how the bridge and the dashboard model sessions and connections. Blank terminal pane. The bridge served terminal output only for sessions whose PTY was attached in the current process, checked via an in-memory map. A session alive in tmux but not attached in-process — the normal state right after another agent spawns or re-runs one — failed that check, so the browser's watch request was dropped and nothing was published, on every device. The liveness check now also counts live tmux sessions, and the first watcher reattaches to the tmux session (reusing the existing resurrection path, read-only, no init keystroke) so output streams. A missing bridgeId on a session row can no longer blank the pane: the UI preserves the known bridgeId across merges. "N bridges" too high. The bridge list was keyed by Centrifugo connection id, so one bridge that reconnected showed as several. It now tracks all connections per bridgeId and shows one entry per bridge (newest connection wins), and a bridge disappears only when its last connection leaves — no transient "0 bridges" that would disable the + button. Reconnect flapping (the source of the duplicate connections). The bridge subscribed to channels it only publishes to, so Centrifugo echoed its whole output stream back; the application-level ping then queued behind that backlog and the client declared "no ping" and reconnected, roughly once a minute. The publish-only subscriptions are removed (publishing is allowed by allow_publish_for_client, verified), a maxServerPingDelay is set, the reconnect re-sync is throttled and skips finished sessions, the tmux liveness probe is cached, and the Solo hub config carries explicit ping settings. Verified in an isolated Docker container running this branch: an agent-spawned session (created via the local API, not the panel) rendered its terminal and echoed a marker in a real browser, proving both the reattach fix and that terminal output still publishes after the subscriptions were removed; no flapping and no publish errors over the run. 772 bridge tests and the UI hook tests pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…d-bridge-dedupe # Conflicts: # bridge/package-lock.json # bridge/package.json
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 three things the user hit in the cloud dashboard, all verified in a real browser.
1. Blank terminal for agent-spawned / re-run sessions
A session created or re-run by another agent (via the local API / fticket, not the panel) showed a blank pane with no output, on every device, while the session was clearly running.
Cause: the bridge served terminal output only when it considered the session "known", and that check (
index.tsisKnownSession) counted only sessions with a PTY attached in the current process. A session alive in tmux but not attached in-process failed it, so the browser'sterminal_watchwas silently dropped andpublish-router.tspublished nothing.Fix:
isKnownSessionalso counts live tmux sessions (runner.hasTmuxSession), and the first watcher triggers a read-only reattach to the tmux session, reusing the existing resurrection path (no init keystroke, no agent restart), so output streams. Dropped watches are now logged. Defensively, the UI (useSessions.ts) preserves a knownbridgeIdacross row merges so a partial update can never blank the pane.2. "N bridges" too high (user saw 4 for one bridge)
useBridges.tskeyed the list by Centrifugo connection id, so one bridge that reconnected with a lingering old connection counted twice. It now tracks every connection perbridgeIdand exposes one entry per bridge (newest connection wins); a bridge disappears only when its last connection leaves, so there is no transient "0 bridges" that would disable the + button.3. Centrifugo reconnect flapping (the source of the duplicate connections)
The bridge subscribed to channels it only publishes to (
sessions:updates, per-terminalterminal:), so Centrifugo echoed its entire output stream back; the app-level ping then queued behind that backlog and the client declared "no ping" and reconnected about once a minute, each reconnect re-publishing everything and feeding the loop.Fixes: remove the publish-only subscriptions (publishing is permitted by
allow_publish_for_client, verified againstcentrifugo/config.json); setmaxServerPingDelay; throttle the reconnect re-sync and skip finished sessions; cache the tmux liveness probe so it stops spawningtmux has-sessionon every watch heartbeat; add explicit ping settings to the Solo hub config.Verification
~/.ftown): an agent-spawned session created through the local API rendered its terminal and echoed a marker in a real browser — proving both the reattach fix and that terminal output still publishes after the subscriptions were removed. A panel-created session also round-tripped. Zero flapping keywords and zero publish permission errors over the run. Screenshot in the review notes.Follow-ups noted, not in this PR
events:still uses subscribe-before-publish (minor residual echo).~/.ftown/bridge.jsonandloops.jsonare written from$HOMEregardless of--data-dir, so a Solo instance clobbers a co-resident bridge's pointer file. This bit us during testing.🤖 Generated with Claude Code