feat: expose per-session window list in sidebar#23
feat: expose per-session window list in sidebar#23shunkakinoki wants to merge 4 commits intoAtaraxy-Labs:mainfrom
Conversation
Add window/tab enumeration to the session data model so the sidebar shows individual windows when a session has more than one tab. Changes across all layers: - Contract: add MuxWindowInfo type, optional windowList on MuxSessionInfo - TmuxProvider: batch-fetch all windows and group by session - Runtime: pipe windowList through SessionData and computeState - Server: handle new switch-window client command - TUI: render clickable window rows under sessions with multiple tabs
There was a problem hiding this comment.
inspect review
Triage: 10 entities analyzed | 0 critical, 0 high, 9 medium, 1 low
Verdict: standard_review
Findings (2)
-
[low] Server-side
switch-windowis hard-coded to tmux and ignores the resolved provider abstraction. Inpackages/runtime/src/server/index.tsthe handler resolvesconst p = sessionProviders.get(cmd.sessionName) ?? mux;and callsp.switchSession(...), but then unconditionally runsBun.spawnSync(["tmux", "select-window", "-t",${cmd.sessionName}:${cmd.windowIndex}], ...). This will be incorrect/broken for non-tmux providers and breaks the provider-agnostic command semantics. -
[low] Server
switch-windowswallows/ignores failures but still updates and broadcasts focus/current session state as if the switch succeeded. The code wrapsBun.spawnSync(...)intry { ... } catch {}butspawnSynctypically does not throw on non-zero exit; failures are ignored, yetfocusedSession,cachedCurrentSession, andcachedCurrentSessionTsare updated andbroadcastFocusOnly()is called. This can leave clients believing the window switched when it did not.
Reviewed by inspect | Entity-level triage found 0 high-risk changes
|
hey @shunkakinoki, would you mind sharing a screenshot of how this looks? |
|
Hey @Palanikannan1437! Here's how the window list looks: primary session (4 windows): The active window has a Windows only appear when a session has >1 tab — single-window sessions are unchanged.
|
Map agent paneId to windowId so each window row displays the agent status icon (spinner, checkmark, error, etc.) for agents running in that specific window. Makes it easy to identify which tab has an active agent at a glance. - Build paneId->windowId map in computeState via tmux list-panes - Enrich WindowData with agentStatus and agentName fields - Render agent status icons on window rows in the TUI
There was a problem hiding this comment.
inspect review
Triage: 24 entities analyzed | 0 critical, 0 high, 23 medium, 1 low
Verdict: standard_review
Findings (1)
- [low] Agent-to-window association is hard-coded to tmux for all sessions/providers: server/index.ts unconditionally builds
paneToWindowviashell(["tmux","list-panes", ...])and then uses it for every session when enrichingwindowList(paneToWindow.get(a.paneId) === w.id). For non-tmux providers (or environments without tmux), this mapping will be empty/wrong, soagentStatus/agentNameon windows will be missing/incorrect.
Reviewed by inspect | Entity-level triage found 0 high-risk changes
There was a problem hiding this comment.
inspect review
Triage: 24 entities analyzed | 0 critical, 0 high, 23 medium, 1 low
Verdict: standard_review
Findings (2)
-
[low] Server-side switch-window is tmux-specific and ignores the resolved mux provider for window selection. In packages/runtime/src/server/index.ts, case "switch-window" calls
const p = sessionProviders.get(cmd.sessionName) ?? mux; p.switchSession(cmd.sessionName, tty);but then always runsBun.spawnSync(["tmux", "select-window", "-t",${cmd.sessionName}:${cmd.windowIndex}]). This will fail/no-op or select the wrong window when the session provider is not tmux. -
[low] switch-window resolves a client
ttybut does not use it for the tmuxselect-windowcall, so with multiple tmux clients attached it may select the window in the wrong client. Evidence:const tty = ...is computed, passed top.switchSession(...), butBun.spawnSync(["tmux","select-window",...])does not include any-c/client targeting usingtty.
Reviewed by inspect | Entity-level triage found 0 high-risk changes
The tracker's applyPanePresence overwrites paneId when multiple panes run the same agent, so only the last pane wins. Instead, build the windowId-to-agent mapping directly in computeState by scanning the process tree per-pane and grouping by window.
There was a problem hiding this comment.
inspect review
Triage: 21 entities analyzed | 0 critical, 0 high, 20 medium, 1 low
Verdict: standard_review
Findings (1)
- [low] STATUS_PRIORITY is referenced before it is defined in packages/runtime/src/server/index.ts. The windowAgentMap builder uses
STATUS_PRIORITY[status]inside theorderedMuxSessions.map(...)block added around line ~525, butconst STATUS_PRIORITY: Record<string, number> = { ... }is declared later in the same function around line ~1055. Sinceconstis not hoisted, this will throw a ReferenceError at runtime when that code path executes.
Evidence:
- Use:
if (!existing || STATUS_PRIORITY[status] > STATUS_PRIORITY[existing.status]) { ... }inside the new windowAgentMap scan block. - Definition later:
const STATUS_PRIORITY: Record<string, number> = { ... }added at ~1100.
Reviewed by inspect | Entity-level triage found 0 high-risk changes
|
i'm not sure about this ui, seems up a bit too much for me, i think we could keep this toggleable via some shortcut, show windows, with the default as off...what do you think? |
|
@eduwass is this something you wanted, I remember from one of the issues you opened a long time ago |

Summary
MuxWindowInfotype and optionalwindowListfield onMuxSessionInfoswitch-windowclient command to switch directly to a specific window within a sessionChanges
Contract (
packages/mux/contract):MuxWindowInfointerface (id,index,name,active,paneCount)MuxSessionInfo.windowListoptional fieldTmuxProvider (
packages/mux/providers/tmux):listWindows()and groups by session namewindowListinlistSessions()Runtime (
packages/runtime):SessionData.windowListfield piped throughcomputeState()switch-windowcommand handler in the serverTUI (
apps/tui):SessionCardrenders window rows (with active indicator) whenwindowList.length > 1switch-windowcommandTest plan
bun test- 349 tests passbun run build- builds successfully