Skip to content

Terminal panel: LRU eviction for inactive-session xterm instances + server-side scrollback #144

Description

@realDuang

Background

Follow-up to the integrated terminal panel work (PR replacing #88). The original review on #88 raised this concern:

All tabs from all sessions stay in �llTabs() permanently — DOM nodes and xterm instances never get cleaned up. If someone uses 20+ sessions over a workday, that's 20+ xterm renderers alive in memory.

Consider some kind of LRU eviction for inactive sessions — e.g., dispose xterm instances after a session has been inactive for a while, and re-attach from the still-running PTY when the user switches back.

The current implementation only enforces server-side limits (maxPerClient=20, maxPerSession=5) which bounds PTY count but not the front-end xterm renderer footprint.

Scope

LRU eviction operates per-session on front-end xterm instances, not on PTY processes:

Layer Behaviour
PTY process count Unchanged — still gated by maxPerClient / maxPerSession
xterm renderer instances New: keep at most N (default 3) most-recently-active sessions mounted
User-facing terminal limit Unchanged — users can still create up to maxPerSession per session

When the active-session cache exceeds N, the least-recently-used session's xterm instances are dispose()-d but their server-side PTYs continue running. When the user switches back, the panel re-creates xterm instances and re-attaches to the live PTYs.

Required protocol additions

  1. Server-side scrollback ring bufferterminal-service.ts keeps the last ~100 KB of output per PTY.
  2. New RPC: terminal.attach(terminalId) — returns the current scrollback as one chunk and resumes terminal.data notifications. Distinct from terminal.create (no spawn) and terminal.list (no scrollback).
  3. Client LRU evictionTerminalPanel tracks a Set of mounted sessions; when props.sessionId changes and the cache is full, evict the LRU and dispose() its xterm instances. Re-attach on next access.

Trade-offs

  • Switching back to an evicted session shows a brief loading state before the scrollback re-renders.
  • Output produced between dispose() and attach() is preserved in the ring buffer up to its size limit; older output is lost.
  • Pseudo-shell prompt state may look inconsistent until the PTY emits a fresh prompt (e.g. after pressing Enter).

Acceptance criteria

  • Server-side ring buffer with configurable size (default 100 KB, max 1 MB).
  • terminal.attach request type added to unified.ts, ws-server.ts, gateway-client.ts, gateway-api.ts.
  • TerminalPanel evicts xterm instances per LRU policy with default N=3 active sessions.
  • Re-attach on session switch restores scrollback and resumes streaming without losing future output.
  • Unit tests cover: ring buffer overflow, attach returns correct scrollback, LRU eviction order, dispose then re-attach round-trip.
  • Manual verification: create 5+ session terminals, switch around, verify memory stays bounded and content survives switches.

Estimated work

~200–250 lines across server (ring buffer + attach handler), gateway client/API, TerminalPanel (LRU bookkeeping + re-attach flow), and tests.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions