feat(session): unified Session Manager — welcome list + searchable modal + live SSE refresh#153
Conversation
Backs the welcome-screen "Resume Conversation" list with the new GET /api/sessions/unified endpoint instead of /api/history/sessions, so it shows the COMPLETE set (live + persisted + non-Claude + closed history) newest-first with richer context, rather than only Claude transcripts. - terminal-ui.js: new _fetchUnifiedSessions(); loadHistorySessions() now uses it. _buildHistoryItem upgraded to the unified shape (kept backward-compatible with the folder-modal's old shape): title = name || firstPrompt || dir; a mode badge + a LIVE badge (sources includes 'live'); timestamp from lastActivityAt (falls back to lastModified); size only when present; detail panel + "View all in this folder" preserved (gated on projectKey). Resume branches: an open live session selects its tab, a closed one resumes. - unified-session-service.ts + endpoint: pass projectKey through the history source so the folder drill-down survives. - styles.css: .history-item-badges / -badge / -badge-live pills. Verified: tsc 0, lint 0, frontend-syntax + public-asset format clean, service tests 13/13 (+projectKey), route tests 4/4. Playwright on an isolated beta: the welcome list renders real items from /api/sessions/unified, and the renderer produces the tab-name title + codex mode badge + visible LIVE badge, omits LIVE on closed items, keeps "View all in folder", and routes resume correctly (open->select tab, closed->resume). Persistent panel + live SSE status are later units.
… A, unit 3) Adds a header-reachable Session Manager so the complete session list is available mid-session, not only on the welcome screen. - index.html: always-on header button (.btn-session-manager) + #sessionManagerModal (mirrors the Away Digest modal) with a search box + results list. - panels-ui.js: openSessionManager()/closeSessionManager()/_loadSessionManagerList() — loads GET /api/sessions/unified (limit 200), renders via the unit-2 _buildHistoryItem (rich items, mode/LIVE badges, open->select / closed->resume), debounced search wired to the endpoint's q= param, empty/error states. A modal-scoped Escape listener closes it even when focus is in the search input; backdrop click and item click also close it. - app.js: closeSessionManager() added to the global Escape chain. - styles.css: modal + list styling (items reuse .history-item). Verified on an isolated beta instance (Playwright): the header button opens the modal, it lists 200 sessions from /api/sessions/unified, a no-match query issues ?q= to the server and yields 0 items, clearing restores the list, clicking an item closes the modal and routes resume/select, and Escape closes it. Gates: tsc 0, lint 0, frontend-syntax + public-asset format clean, 17 tests pass.
The complete session list now updates live as sessions change, instead of only on open/welcome-load. - app.js: extra SSE listeners (session:created/updated/deleted) on the same EventSource (multiple listeners per event; existing handlers untouched; registered via addListener so they tear down on reconnect) call _onSessionListMaybeChanged(). - panels-ui.js: _onSessionListMaybeChanged() debounced-refreshes the Session Manager modal when it's open and the welcome list when its overlay is visible (no work when neither is showing). _loadSessionManagerList stores the active query so refreshes preserve the user's search. Verified on an isolated beta instance (Playwright): dispatching a session event refreshes the modal while open, does NOT while closed (gated), and refreshes the welcome list while visible. Gates: tsc 0, frontend-syntax + public-asset format clean, build clean.
The per-row ⋯ in the session list was a details toggle that did nothing in the Session Manager modal (swallowed by the modal's capture-phase close-on-click). Replace it with a real kebab context menu. - terminal-ui.js: ⋯ now opens _openSessionRowMenu() — a body-anchored popup (fixed-positioned, flips/clamps to viewport, z-index above the modal) with: Resume/Switch-to (live→select tab, closed→resume), Open folder in the file browser (live sessions only — the browser is session-scoped), Copy path (_copyText + toast, when workingDir present), and Show details (the old inline prompt/path panel). Closes on outside-click / Escape / scroll / resize. - panels-ui.js: _loadSessionManagerList scopes its modal-close to the .history-item-main (resume) click, so the ⋯/menu no longer closes the modal. - styles.css: .session-row-menu + .session-row-menu-item. Verified in Chromium on an isolated beta: ⋯ opens the menu with the modal still open; closed rows show Resume/Copy path/Show details, live rows add Switch-to + Open folder; Show details expands inline (modal stays open), Copy path copies the path, Resume closes the modal, Escape closes only the menu. Gates: tsc 0, lint 0, frontend-syntax + public-asset format clean.
Resolve the 4 conflicted files toward master's merged Ark0N#146 work while keeping PR Ark0N#153's genuinely-new additions: - app.js: keep the full Escape chain (closeSessionManager + closeCommandPalette + closeShortcutOverlay). - index.html: keep master's Command Palette modal markup alongside the PR's Session Manager modal + header button. - styles.css: keep master's Command Palette + COD-157 shortcut CSS AND the PR's COD-130 session-row kebab-menu CSS (both inserted at the same spot — reunited each with its own closing brace). - terminal-ui.js: resolve _buildHistoryItem's main-row click handler to master's options.onActivate contract with a liveness + claudeSessionId -aware resume default, preserving the PR's two-shape/badges/kebab body. - panels-ui.js: the PR's pre-Ark0N#146 Session Manager block auto-merged as a duplicate AFTER master's fixed block (last-key-wins regression) — drop it, keep master's implementation plus the PR's new _onSessionListMaybeChanged. Backend projectKey plumbing and the SSE live-refresh listeners in app.js merge additively and are kept as-is.
…implementation (PR Ark0N#153) - Hide the new btn-session-manager header button on phones: add it to the @media (max-width: 430px) display:none block in mobile.css (next to .btn-away-digest) and to KNOWN_PHONE_HIDDEN in the mobile-header policy test, closing the recurring phone-header-leak regression that was PR Ark0N#153's red CI job. - Put the session-manager header button on its own line in index.html (was crammed onto the away-digest line). - app.js: drop session:updated from the unified-list SSE refresh trigger — it is batch-broadcast ~every 500ms per active session and would turn an open modal / visible welcome list into a sustained ~1 Hz full projects rescan loop; created/deleted (structural changes) are sufficient. - terminal-ui.js _fetchUnifiedSessions: check the ApiResponse envelope and throw on failure so a 5xx surfaces via the caller's catch instead of rendering an empty history. - terminal-ui.js _openSessionRowMenu: on re-entry, invoke the previous menu's close fn (stored as _openRowMenuClose) so its document/window listeners are detached rather than leaked; use claudeSessionId || sessionId in the 'Resume session' menu item to match the main-row and Session Manager resume routing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merged — thank you @aakhter! This ties the whole session-management story together: unified welcome list with LIVE/mode badges, per-row kebab menu, and SSE-driven live refresh so the list stays current without manual reload. Because it arrived stacked on the earlier #139/#146 work that had already merged (with review fixes), we rebuilt it onto the current master rather than merging over it — kept your new pieces (the |
Frontend companion to the unified Session Manager backend merged in #139. Where the backend added the aggregated session service + list endpoint, this adds the UI that surfaces it.
What this adds
⋯opens a context menu of per-session actions.Scope
8 files, +502/-19 — frontend (
terminal-ui.js,panels-ui.js,app.js,index.html,styles.css) plus a smallunified-session-servicetouch and one route wire-up, and a unit test.Verification
tsc --noEmit0 · frontend-syntax 22/22 · prettier clean · unit tests 16/16 · build clean.⋯context menu opens with actions; creating a session live-refreshes the open list with no reload; no console errors.Rebased onto current master (the #139 backend commits are now upstream), so this is a clean frontend-only diff.