feat(mobile): terminal-first — delete chat stacks, terminals as sessions, agent launch from home

Merged
SA
3mo ago
+2614-5213

The terminal-first pivot lands: both mobile chat surfaces are deleted, terminals become the session rows, and the home widget launches terminal agents. Stacked on #6356 (native composer) → #6342 (terminal screen); merges main, so it carries #6340's per-user relay resolution (every dial resolves relay2 for flagged users) and the #6341 terminal.list rename.

Deleted (~3k LOC, mobile-side only — host-service chat/ACP routers untouched)

  • ACP chat stack (chat/acp/[sessionId], 25 files) and the dead legacy Mastra stack (chat/[sessionId], 16 files), their routes and layout entries.
  • lib/trpc/host-chat-types.ts (the lossy hand-typed facade) + lib/trpc/host-client.ts (4 fps polling transport) — both documented INTERIM debts.
  • Mobile ACP client binding, SessionRow chat UI + fork stub + ClaudeLogo hardcode, useHostAcpSessions, the unused tab-bar native module.

Replaced with

  • Home rows = live terminals (terminal.list, host-wide per host) left-joined with agent bindings (terminalAgents.list) — agent mark + status when an agent is attached, plain shell rows otherwise. Tapping opens the terminal screen.
  • NewChatWidget launches terminal agents. Existing workspaces: terminalAgents.findActive → terminal.send into a live agent terminal, else agents.run. New workspaces: workspaces.create with the agent sugar. Voice dictation and target chips unchanged; the model picker is replaced by an agent picker (see below).
  • Finish-review handoff launches/reuses a terminal agent the same way.

Fix found during E2E

The first re-plumb called terminalAgents.getOrCreate bare — which spawns a plain shell and waits for an agent that nothing launched (10s timeout, terminal disposed). The launch responsibility belongs to agents.run; the hook now uses findActive→send / agents.run, matching desktop semantics.

Workspace = tabbed terminal shell (final cut on this branch)

  • WorkspaceScreen is the terminal now: tab strip (agent mark + name, attention dots, long-press to close) + one live TerminalWebView keyed by the active tab + the glass TerminalComposer. The session-list screen is deleted; home rows land directly on a tab via workspace/[id]?tab=, and terminal/[terminalId] redirects there for old links.
  • The tab strip's + opens a native action sheet of the host's settings.agentConfigs presets (launched via agents.run with an empty prompt — host-side refine relaxed for terminal agents) plus a plain Shell (terminal.createSession).
  • new-chat/ routes renamed new-session/; the model picker became an agent picker over the target host's configs. The persisted preference is the presetId (portable across hosts), not the per-host row UUID.
  • settings/presets: read-only per-host listing of agent presets; editing stays on desktop.
  • Compact header: workspace name (pressable → bottom action sheet) + top-right glass Review pill with +/− changeset stats.

Verified E2E on iOS 26.5 simulator against prod

  • Home renders terminal-first; tapping a session row lands on the tabbed shell with the live claude stream.
  • Composer: type → send → claude responded on-screen; composer rides above the keyboard.
  • + sheet listed the host's real presets (Claude, Amp, Codex, Gemini, Copilot) + Shell; Shell launched in the workspace's worktree and became the active tab; tab switch re-attached the claude stream; long-press → Close killed the session and the strip updated.
  • Agent picker showed the target host's configs with marks and the persisted selection checked.
  • Repo typecheck and lint clean.

Dogfooding polish batch (day 2)

  • Home is a flat workspace list — nested session rows folded into an overlapping agent-mark stack per row; desktop WorkspaceIcon semantics in the leading slot (braille AsciiSpinner while working beats the PR icon, corner ping overlays for permission/failed, FolderGit2 when idle); PR icon routes to the in-app Changes screen.
  • Desktop's notification model, whole — review (green, unseen Stop) derived against a persisted host-clock monotonic seen map, cleared by viewing the tab; failed joins the set; rollups use STATUS_PRIORITY; dot colors match StatusIndicator, with the animate-ping halo ported to reanimated.
  • Perf: in-page terminal switching — one WebView per shell; tab switches send a switch message (generation-counter guarded) instead of remounting, keeping the 400KB xterm parse and TLS pool warm. Also a guard dropping NaN-corrupted SGR mouse reports that leaked as aN;NaNM… input spam.
  • Sheets — new-session preset menu is a native formSheet (ActionSheetIOS renders as a centered dialog on iOS 26); workspace sheet is Cursor's layout (centered name, circular edit/pin/share, Info list with project logo, Delete at bottom). Pin is a device-local pinnedAt map floating pins to the top of home.
  • iOS 26 header/tabs — no glass-in-glass Review pill (icon-only Stack.Toolbar.Button now), title width fits the floating bar items, tab strip is square chips with a + that opens the sheet; tabs hold creation order instead of re-sorting by activity mid-session.
  • Fixes from the fresh-session gym test — quick keys were dead (glass Host's oversized invisible frame swallowed chip taps; z-10 fix, verified with a dd|xxd byte probe), home composer always launches a new session (the findActive reuse path contradicted the "New agent in …" label), and workspace share links go through one env-based helper (/workspaces/<id> kept canonical — web side tracked in SUPER-1846).
  • Agent brand marks ship as PNGs rendered from desktop's preset-icons catalog (all 15 presets, composer/tabs/picker/settings); @gorhom/bottom-sheet removed (last consumer was dead chat-era code).

Notes for review

  • chat_sessions Electric collection consumers are gone from mobile; the cloud rows remain (desktop still writes them) — coordinate final removal with #6328.
  • Snapshot previews on home rows and push notifications on agent transitions are the next items in the plan, not in this PR.
  • Composer input stays expo-ui SwiftUI for now; a fully-native spike is ticketed as SUPER-1849.

Summary by cubic

Makes mobile terminal-first: deletes chat stacks, turns Workspace into a tabbed terminal shell, and launches agents from Home or a New session sheet. Share links now use an env-based helper, with EXPO_PUBLIC_WEB_URL defaulting to https://app.superset.sh.

  • Workspace: tabbed terminal shell with one live WebView and in-page tab switching; “+” launches host settings.agentConfigs or a plain shell; compact header with an icon-only Review button; stable tab order; drops NaN-corrupted wheel reports.
  • Home: flat workspace list with stacked agent marks and pinging attention dots; defaults to the most recently active project; native cell highlight and context‑menu lift; PR icon opens in‑app Changes; device‑local pins float to the top.
  • New session and agents: new-chat/* → new-session/*; model picker → Agent picker; selected agentId persists across hosts; read‑only presets at settings/presets; agent brand marks bundled via expo-asset; Home composer always runs a fresh agent via agents.run and returns to the shell with the new tab active.
  • Host access: overlays _whoowns tunnel probes on v2_hosts.is_online; routes all host calls through the per‑user relay URL (typed clients in lib/host-service/client).
  • Removals: delete ACP and legacy chat stacks, the mobile @superset/host-client binding and chat types, the chat‑era model selector, @superset/tab-bar, and @gorhom/bottom-sheet.
  • Links: share links use workspaceShareUrl on EXPO_PUBLIC_WEB_URL; /workspaces/<id> stays canonical; the legacy terminal redirect route is removed.

Migration

  • Update links from /new-chat/* to /new-session/*; deep links should target /workspace/[id]?tab=<terminalId>.
  • Remove usages of deleted packages and routes: @superset/host-client, @superset/tab-bar, @gorhom/bottom-sheet.
  • Install/pin deps: add react-native-webview, @xterm/xterm, @xterm/addon-fit, expo-asset, and pin expo-font to 56.0.5.

Summary by CodeRabbit

  • New Features

    • Added live terminal tabs with session switching, creation, closing, connection status, retry controls, input, and quick keys.
    • Added agent selection when starting a new session, with persisted preferences.
    • Added workspace actions for renaming, sharing, copying IDs, and deleting eligible workspaces.
    • Added read-only agent presets in Settings.
    • Added terminal deep-link routing and improved workspace session indicators.
  • Updates

    • Workspace views now prioritize terminal sessions instead of chat threads.