feat(desktop): v1→v2 terminal migration — lazy recreation at the v1 cwd on workspace open

Merged
KI
4mo ago
+336-1

Summary

PR 3 of the v1→v2 auto-migration (SUPER-1534 / SUPER-1577, decision D2: lazy terminal recreation, no boot-time PTY storm). Live v1 PTYs can't hand off (separate daemon owners), so the contract is a fresh shell at the persisted v1 cwd, in the right workspace.

  • migration.readV1TerminalPanes: first read of app-state.json by the migration router — resolves each v1 terminal pane to its workspace (via tab) and best-known cwd (cwd ?? initialCwd).
  • migrateTerminals stage in runV1Migration() (after settings, before presets): assigns each pane a fresh v2 terminal id (v1 pane ids double as v1 daemon session ids — reusing them risks colliding with the live v1 daemon; idempotence comes from the ledger, kind terminal, v1Id = paneId) and queues {terminalId, cwd} per mapped workspace via an injected terminalTarget. Panes on unmigrated workspaces defer to the next run. Never gates the flip.
  • pendingMigratedTerminals field on v2WorkspaceLocalState (healed like the other optional fields) + appendPendingMigratedTerminals helper that upserts the row (adopted-but-never-opened workspaces have none yet).
  • useCreatePendingMigratedTerminals hook on the v2 workspace page: on first open (layout-ready), creates the queued sessions via the existing idempotent launcher, removes created entries (failures stay queued), and invalidates terminal.listSessions so #5740's useAutoAdoptBackgroundSessions builds the panes immediately.

Dormant until the PR 4 boot trigger wires terminalTarget — the page hook no-ops on an empty queue for all existing users.

Test Plan

  • bun test src/renderer/lib/v1-migration/ — 21 tests incl. planTerminalMigration (fresh-id assignment, per-workspace grouping, unmapped deferral)
  • Desktop typecheck + root lint clean
  • CDP E2E once PR 4 wires the runner (v1 terminal panes → sessions at cwd → auto-adopted panes)

Summary by cubic

Adds v1→v2 terminal migration with lazy recreation: on first open of a migrated workspace, we spawn fresh v2 terminals at the v1 cwd instead of at boot to avoid a PTY storm. Aligns with Linear SUPER-1534 / SUPER-1577 (D2).

  • New Features
    • Migration router exposes readV1TerminalPanes to read v1 panes from app-state.json, mapped to workspace and cwd.
    • New migrateTerminals stage: assigns fresh v2 terminal IDs, records a terminal ledger entry per v1 pane, and queues {terminalId, cwd} per migrated workspace via an injected terminalTarget. Unmapped panes defer; never gates the flip.
    • Adds pendingMigratedTerminals to v2 workspace local state with an append helper; healed by schema defaults.
    • New useCreatePendingMigratedTerminals hook: on first workspace open, creates queued sessions via the idempotent launcher, prunes created entries, and invalidates terminal.listSessions so auto-adopt builds panes.
    • Tests cover terminal planning (fresh ID assignment, per-workspace grouping, unmapped deferral). Feature remains dormant until PR 4 wires terminalTarget.

Summary by CodeRabbit

  • New Features
    • Migrating from v1 to v2 now includes terminal panes, preserving their workspace assignments and working directories where available.
    • Migrated terminals are queued and recreated automatically when the corresponding v2 workspace is opened.
    • Terminal migration progress is tracked, including deferred items and migration failures.
    • Duplicate terminal creation is prevented, and failed creations remain available for retry.
  • Tests
    • Added coverage for mapped and unmapped workspace terminal migrations.