feat(desktop): show a restored-session separator when a v2 terminal cold-restores

Merged
KI
4mo ago
+158-10

Summary

  • When host-service respawns a lost terminal session (reboot, pty-daemon loss), it now injects a dim ─── Session Contents Restored ─── separator into the replay buffer ahead of the new shell's first output — so users can tell restored scrollback from the fresh session instead of a new prompt silently appearing under dead content.

Why / Context

In v2, a cold restore is host-side: the renderer paints its persisted scrollback, then the WS attach finds an active session row whose PTY the daemon no longer owns, and host-service respawns a fresh shell (packages/host-service/src/terminal/terminal.ts WS route fallback). Previously nothing marked the boundary — users saw their old content with a brand-new prompt below and no hint the session had died. Other terminal apps mark this (VS Code's "History restored", iTerm2's session-restored banner).

How It Works

  • New restoredNotice option on createTerminalSessionInternal, set only by the WS respawn fallback.
  • The separator bytes are appended to the session's replay buffer immediately after session registration — the buffer is empty at that point (daemon subscribe hasn't started), so the notice is guaranteed to precede the new shell's first output on replay.
  • Injecting inside createTerminalSessionInternal (not at the call site) dedupes concurrent attaches racing into the respawn path, and the !isAdopted guard suppresses the notice when the daemon still owns a live shell (host-service restart adoption) — nothing died, so no separator.
  • Host-side injection means any client (desktop renderer, future web) gets it with no renderer changes, and it persists into xterm scrollback/localStorage like ordinary output.

Manual QA Checklist

Verified end-to-end in the dev desktop app over CDP:

  • Cold restore: killed host-service + the terminal's shell, reloaded the renderer → reattach respawned the shell and the dim separator rendered between the restored scrollback (marker output intact) and the fresh prompt
  • Adoption path: reattaching to a still-live daemon session shows no separator
  • Fresh terminals (POST /terminal/sessions) unaffected — no separator

Testing

  • bun run lint (clean)
  • bun run typecheck for @superset/host-service (clean)
  • node --experimental-strip-types --test src/terminal/terminal.adoption.node-test.ts — 17/17 pass, including two new tests: separator is first in the replay buffer on a respawn; absent on adoption. Both were mutation-verified (breaking the guard or removing the injection fails the corresponding test). Note: these run under node ABI; a node_modules currently rebuilt for Electron will ERR_DLOPEN until rebuilt for node.

Open in Stage

Summary by cubic

Add a dim "─── Session Contents Restored ───" separator on v2 terminal cold-restore so users see where restored scrollback ends and the new shell begins. Skipped when adopting a still-live daemon session; survives buffer eviction and closed-socket attaches.

  • New Features

    • Host-service prepends the notice on the first replay, after the mode preamble and before the new shell’s output.
    • Added restoredNotice to createTerminalSessionInternal; set only by the WS respawn path and ignored when isAdopted is true.
    • Injected server-side so all clients get it, and it persists in scrollback.
  • Bug Fixes

    • Kept the separator out of the bounded replay FIFO; replayBuffer now prepends it on first attach so large output bursts can’t evict it.
    • Ensured the separator appears only on the first replay; added tests for flood and adoption, and cleaned up redundant test buffer copies.
    • Avoided losing the notice when an attach socket is already closed; replayBuffer now bails early instead of clearing replay state.

Summary by CodeRabbit

  • New Features
    • Added a “Session Contents Restored” separator to terminal scrollback during cold restores/respawns, inserted before the recreated session’s replayed output.
  • Bug Fixes
    • Ensured the separator appears only once per restore, remains ahead of any flooded output, and is omitted when attaching to an already-active adopted session.
  • Tests
    • Added end-to-end coverage for restored-notice ordering and presence/absence across restore scenarios.