Skip to content

feat(dashboard): multi-session discovery — sessions.list endpoint + SessionList sidebar #445

Description

@xinhuagu

Parent Epic

Part of #430 — Tier 1 Real-Time Execution Tree

Problem

After #444 the dashboard is single-session per tab: the hook filters envelopes by `?session=` and the WS bridge broadcasts every session's events to every connected client, so cross-session leakage is impossible. Good for correctness — bad for discoverability.

The user has to know the sessionId out-of-band:

# Currently the only way to find a sessionId
./aceclaw-cli/build/install/aceclaw-cli/bin/aceclaw-cli daemon status
# … manually copy …
# … paste into …
http://localhost:5173/?session=2af4b82d-ae5a-…

There's no list of active sessions visible in the dashboard, and no way to switch sessions without editing the URL.

Goal

Two coordinated pieces so a dashboard user can:

  1. See which sessions are alive on the daemon
  2. Pick one to watch (and switch later) without leaving the dashboard

Deliverables

Daemon side — `sessions.list` over WebSocket

Two-message handshake, layered on top of the existing #431 bridge. No new transport.

Inbound from client (browser → daemon, new in #433-territory but minimal):

{ "method": "sessions.list" }

Outbound from daemon (one-shot reply, NOT envelope-wrapped — different semantics from event broadcasts):

{
  "method": "sessions.list.result",
  "sessions": [
    {
      "sessionId": "2af4b82d-…",
      "projectPath": "/Users/.../my-repo",
      "model": "claude-opus",
      "createdAt": "2026-04-29T08:30:00.000Z",
      "active": true
    },
    
  ]
}
\`\`\`

\`SessionManager\` already tracks active sessions; the bridge's existing inbound handler hook (\`setInboundHandler\` from #431) is the natural mounting point.

**Live updates**: the dashboard already receives \`stream.session_started\` envelopes; this issue should additionally make sure \`stream.session_ended\` (or a \`session.destroyed\` envelope) is emitted on \`SessionManager.destroySession\` so the sidebar can prune stale entries without polling.

### Dashboard side — \`SessionList\` sidebar

- New left sidebar (~240px wide) listing sessions: project path tail, model, "started Xm ago", and a status dot (running / paused / closed)
- On mount, send \`{ method: "sessions.list" }\` over the WS, populate from the result
- On every \`stream.session_started\` envelope, prepend a new entry
- On every \`session.destroyed\` envelope (this issue's new emission), mark the entry closed
- Click a session → updates \`?session=<id>\` and the hook re-mounts (the existing \`useEffect\` on \`sessionId\` change in \`useExecutionTree\` already resets the tree, so this is one prop change away)
- Visual highlight on the currently-selected session
- Keep the empty-state \`SessionPrompt\` as a fallback when zero sessions are active

## Out of scope

- Snapshot replay on session switch (covered by #432)
- Editing/cancelling a session from the sidebar (separate issue if ever)
- Persisting "last viewed session" across reloads (cookies / localStorage — minor follow-up)

## Acceptance criteria

- [ ] \`SessionManager.destroySession\` publishes a \`SessionEvent.Closed\` (already exists) AND the \`EventMultiplexer\` translates it to a \`session.destroyed\` envelope on the WS
- [ ] Bridge inbound handler routes \`sessions.list\` to a daemon-side \`SessionsListHandler\` and replies once with the active set
- [ ] Dashboard sidebar renders the active session list, highlights the selection, and updates live on \`stream.session_started\` / \`session.destroyed\`
- [ ] Switching sessions resets the tree (already does, via the \`useEffect\` in \`useExecutionTree\`)
- [ ] Two new daemon integration tests (multi-session bridge fan-out + \`sessions.list\` reply)
- [ ] One new dashboard test for the sidebar's add/remove logic

## Estimated effort

- daemon (\`sessions.list\` + \`session.destroyed\` emission): ~2h
- dashboard sidebar: ~3h
- tests: ~1h

Total ~6h.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfrontendFrontend visualization and dashboardp2Low prioritytier1-visualizationTier 1: ReAct real-time execution tree

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions