feat(desktop): auto-create panes for background terminal sessions on workspace open
Summary
- When a v2 workspace is created or opened, running terminal daemon sessions that have no pane get their panes created automatically, instead of requiring the user to adopt them one by one from the background-terminals dropdown.
- One idempotent adoption pass per workspace open; the dropdown remains for sessions deliberately sent to the background mid-session.
Why / Context
Sessions can exist on the host with no pane in the workspace UI (created by automations, host-side launches, or left over from a previous app run). Today they only surface in the BackgroundTerminalsButton dropdown and users have to adopt each manually. Opening a workspace should just show its running sessions.
How It Works
New useAutoAdoptBackgroundSessions hook (75 lines), mounted in the workspace page next to the automation deep-link consumer. It composes existing, already-tested primitives rather than introducing new derivations:
- Waits for the persisted pane layout to hydrate —
useV2WorkspacePaneLayoutnow exposes the live query'sisReadyasisLayoutReady. Adopting earlier would double-create panes the layout already has, or get clobbered byreplaceState(per the TanStack DB strict-readiness-before-writes rule). - Fetches
terminal.listSessionsonce (no polling), derives paneless sessions with the dropdown's owngetBackgroundTerminalSessions+getAttachedTerminalIdsKey, so auto-adopt and the dropdown can never disagree. - Skips sessions with a background marker (deliberately backgrounded in this app run).
- Adopts each via the idempotent
focusOrAddTerminalPane, oldest→newest so tabs read chronologically, then restores the previously active tab so adoption never steals focus. A one-shot ref guarantees exactly one pass per workspace open — no re-adoption loop when the user backgrounds a session afterwards.
Manual QA Checklist
Validated live over CDP against the dev app (create daemon session via host-service tRPC with no pane, then drive the router):
- Open workspace with a paneless running session → terminal pane auto-created (~500ms after mount), background-terminals button disappears
- Reopen the same workspace → still exactly one pane for that session (no duplicates)
- Background a session (marker set) and reopen → stays in the dropdown, not re-adopted, marker intact
- Focus: adoption into a workspace with existing tabs keeps the previously active tab focused
Testing
bun run typecheckbun run lintbun test(v2-workspace suite: 102 tests pass; reused helpers are covered byBackgroundTerminalsButton.utils.test.tsandfocusTerminalPane.test.ts)
Design Decisions
- One-shot pass instead of a polling window: earlier drafts kept a 10s window with 2s refetches and min-age/retry timers to catch late-registering sessions. Dropped — the ask is about sessions that exist when the workspace opens; the only near-mount pane creators in v2 (automation deep link) go through the same idempotent
focusOrAddTerminalPane, so races can't produce duplicates. Late arrivals still land in the dropdown as today. - Reuse the dropdown's derivation instead of a parallel selector: one source of truth for "background session", and the new hook carries almost no logic of its own.
Known Limitations
- Background markers are in-memory, so a session deliberately backgrounded before an app restart gets a pane again on next open. Making backgrounding survive restarts would need the marker persisted in local state — deferred until we know it's wanted.
Summary by cubic
Auto-create terminal panes for running sessions when a v2 workspace opens, so users see their terminals immediately. Runs one idempotent pass after pane-layout hydration and a fresh sessions refetch, keeping the active tab focused.
-
New Features
- Added
useAutoAdoptBackgroundSessionsto adopt paneless daemon sessions on workspace open. - Waits for
isLayoutReady, fetches sessions once, and skips sessions with a background marker. - Adopts oldest→newest via
focusOrAddTerminalPane, then restores the previously active tab (no duplicates). - Exposed
isLayoutReadyfromuseV2WorkspacePaneLayoutand mounted the hook in$workspaceId/page.tsx.
- Added
-
Bug Fixes
- Avoids stale cached session lists on remount by waiting for the mount-time refetch before the one-shot pass, falling back only if the refetch fails.
Summary by CodeRabbit
- New Features
- Automatically adopts eligible background terminal sessions after the workspace dashboard layout finishes loading.
- Restores the previously active tab and focuses existing terminal panes when possible; otherwise, creates new panes.
- Skips sessions the workspace has marked to stay in the background, and runs the adoption only once per workspace.