feat(tmux): add floating agent-status popup (prefix + g)#52
Conversation
Add a centered floating panel that lists agents across all sessions and lets you jump to one with Enter, opened via `tmux display-popup` and bound to `prefix + g` (also reachable through the `prefix o → g` table). The key is configurable with `@opensessions-popup-key` and the size with `@opensessions-popup-width` / `@opensessions-popup-height`. Unlike the docked sidebar, the TUI runs in popup mode (set through the OPENSESSIONS_POPUP env var) so it can be toggled freely: - skips IdentifyPane, so the server never resizes the transient pane to sidebar width or believes a docked sidebar is visible - quitting (q / Esc) or selecting an agent closes the popup locally and does not send /quit, keeping the shared server alive - agent-panel scope is kept local: it opens scoped to all sessions and the `a` toggle no longer rewrites the shared server scope - does not pull focus back to the launching pane on startup popup.sh cold-starts the server first via server-common.sh in case a prior popup or sidebar tore it down. Covered by unit tests for popup focus, local scope, local quit, and jump-to-pane-then-close behavior.
There was a problem hiding this comment.
inspect review
Triage: 24 entities analyzed | 0 critical, 0 high, 16 medium, 8 low
Verdict: standard_review
Findings (1)
- [low] Formatting error in queue_focus_agent_pane: closing brace is on the same line as the if statement, causing a syntax error
Reviewed by inspect | Entity-level triage found 0 high-risk changes
The function's closing brace shared a line with the popup-mode if block, which rustfmt flagged. Put it on its own line.
There was a problem hiding this comment.
inspect review
Triage: 24 entities analyzed | 0 critical, 0 high, 16 medium, 8 low
Verdict: standard_review
Findings (2)
- [low] In main.rs, the popup mode check for startup_refocused is incorrect. When popup_mode is true, the code does nothing (empty if branch), then falls through to the else-if that checks identity. This means a popup will still execute do_startup_refocus if identity exists, defeating the purpose of the popup_mode guard.
- [low] In main.rs, the popup mode check for startup_refocused is missing an else-if chain, causing do_startup_refocus to never be called for non-popup mode. The code has 'if popup_mode { ... } else if let Some(identity) = ...' but the else-if will never execute because it's not properly chained.
Reviewed by inspect | Entity-level triage found 0 high-risk changes
Rewrite the empty popup_mode if-branch as an explicit `if !popup_mode` guard around the identity refocus. Behavior is unchanged (popups never refocus the launching pane; docked sidebars with an identity do), but the intent reads clearly without an empty branch that looked like a fall-through.
There was a problem hiding this comment.
inspect review
Triage: 24 entities analyzed | 0 critical, 0 high, 16 medium, 8 low
Verdict: standard_review
Findings (2)
- [low] In main.rs, the popup mode check for startup_refocused is inverted - it checks
!popup_modebut the comment says 'A popup is its own transient client, so skip the startup refocus'. However, the logic is correct (skip when popup_mode is true). The real bug is thatstartup_refocusedis set to true BEFORE the conditional check, so even in popup mode, it prevents any future refocus attempts. This means if the first message isn't a State message, subsequent State messages won't trigger refocus logic. - [low] In main.rs, there are two separate blocks checking
app.should_closeand returning early (lines 265-268 and 307-309 in the new code). The first block at line 265 returns Ok(()) after draining commands, but the second block at line 307 returns Ok(()) WITHOUT draining launches that were just collected. This creates an asymmetry where launches queued between command draining and the second should_close check will be lost.
Reviewed by inspect | Entity-level triage found 0 high-risk changes
|
Thanks for the review. I looked into both of the latest findings and don't think either is a live bug — happy to be corrected:
Let me know if I'm missing a path where a launch and |
Summary
tmux display-popup, bound toprefix + g(also reachable through theprefix o → gtable). It lists agents across all sessions;Enterjumps to the selected agent's pane.ato toggle between all sessions and just the focused one.q/Esccloses the popup.@opensessions-popup-key(key, defaultg) and@opensessions-popup-width/@opensessions-popup-height(default80%/70%).Motivation
The docked sidebar is great while you're working in a session, but there was no quick, transient way to glance at agent status across all sessions and jump to one without permanently rearranging panes. A floating popup gives that at-a-glance overview and disappears as soon as you've picked where to go.
Implementation notes
The TUI runs in a dedicated popup mode (
OPENSESSIONS_POPUP=1) so the transient client behaves differently from a docked sidebar:IdentifyPane, so the server never resizes the popup pane to sidebar width or believes a docked sidebar is visible.q/Esc) or selecting an agent closes the popup locally and does not send/quit, keeping the shared server alive so the popup can be toggled freely.atoggle no longer rewrites the shared server scope.popup.shcold-starts the server first (viaserver-common.sh) in case a prior popup or sidebar tore it down.Verification
cargo test -p opensessions-sidebar-core(34 passed, includes new coverage for popup focus, local scope, local quit, and jump-to-pane-then-close)cargo build -p opensessions-sidebar