BTerminal/docs/phases.md
Hibryda f97e7391a9 docs: update meta files for unified sidecar bundle
Updated all docs, CLAUDE.md files, README, and CHANGELOG to reflect
the consolidated sidecar approach (single agent-runner.mjs for both
Deno and Node.js). Removed references to agent-runner-deno.ts as
active runner. Added progress log entry for 2026-03-07 session.
2026-03-07 01:07:13 +01:00

15 KiB

BTerminal v2 — Implementation Phases

See task_plan.md for architecture decisions, error handling, and testing strategy.


Phase 1: Project Scaffolding [status: complete] — MVP

  • Create feature branch v2-mission-control
  • Initialize Tauri 2.x project with Svelte 5 frontend
  • Project structure (see below)
  • Basic Tauri window with Catppuccin Mocha CSS variables
  • Verify Tauri builds and launches on target system
  • Set up dev scripts (dev, build, lint)

File Structure

bterminal-v2/
  src-tauri/
    src/
      main.rs              # Tauri app entry
      pty.rs               # PTY management (portable-pty, not plugin)
      sidecar.rs           # Sidecar lifecycle (unified .mjs bundle, Deno-first + Node.js fallback)
      watcher.rs           # File watcher for markdown viewer
      session.rs           # Session + SSH session persistence (SQLite via rusqlite)
      ctx.rs               # Read-only ctx context DB access
    Cargo.toml
  src/
    App.svelte             # Root layout + detached pane mode
    lib/
      components/
        Layout/
          TilingGrid.svelte    # Dynamic tiling manager
          PaneContainer.svelte # Individual pane wrapper
        Terminal/
          TerminalPane.svelte  # xterm.js terminal pane (theme-aware)
        Agent/
          AgentPane.svelte     # SDK agent structured output
          AgentTree.svelte     # Subagent tree visualization (SVG)
        Markdown/
          MarkdownPane.svelte  # Live markdown file viewer (shiki highlighting)
        Context/
          ContextPane.svelte   # ctx database viewer (projects, entries, search)
        SSH/
          SshDialog.svelte     # SSH session create/edit modal
          SshSessionList.svelte # SSH session list in sidebar
        Sidebar/
          SessionList.svelte   # Session browser + SSH list
        StatusBar/
          StatusBar.svelte     # Global status bar (pane counts, cost)
        Notifications/
          ToastContainer.svelte # Toast notification display
        Settings/
          SettingsDialog.svelte # Settings modal (shell, cwd, max panes, theme)
      stores/
        sessions.svelte.ts   # Session state ($state runes)
        agents.svelte.ts     # Active agent tracking
        layout.svelte.ts     # Pane layout state
        notifications.svelte.ts # Toast notification state
        theme.svelte.ts      # Catppuccin theme flavor state
      adapters/
        sdk-messages.ts      # SDK message abstraction layer
        pty-bridge.ts        # PTY IPC wrapper
        settings-bridge.ts   # Settings IPC wrapper
        ctx-bridge.ts        # ctx database IPC wrapper
        ssh-bridge.ts        # SSH session IPC wrapper
      utils/
        agent-tree.ts        # Agent tree builder (hierarchy from messages)
        highlight.ts         # Shiki syntax highlighter (lazy singleton)
        detach.ts            # Detached pane mode (pop-out windows)
        updater.ts           # Tauri auto-updater utility
      styles/
        catppuccin.css       # Theme CSS variables (Mocha defaults)
        themes.ts            # All 4 Catppuccin flavor definitions
    app.css
  sidecar/
    agent-runner.ts          # Sidecar source (compiled to .mjs by esbuild)
    dist/
      agent-runner.mjs       # Bundled sidecar (runs on both Deno and Node.js)
    package.json             # Agent SDK dependency
  package.json
  svelte.config.js
  vite.config.ts
  tauri.conf.json

Key change from v1: Using portable-pty directly from Rust instead of tauri-plugin-pty (38-star community plugin). portable-pty is well-maintained (used by WezTerm). More work upfront, more reliable long-term.


Phase 2: Terminal Pane + Layout [status: complete] — MVP

Layout (responsive)

32:9 (5120px) — full density:

+--------+------------------------------------+--------+
|Sidebar |  2-4 panes, CSS Grid, resizable    | Right  |
| 260px  |                                     | 380px  |
+--------+------------------------------------+--------+

16:9 (1920px) — degraded but functional:

+--------+-------------------------+
|Sidebar |  1-2 panes              |  (right panel collapses to overlay)
| 240px  |                         |
+--------+-------------------------+
  • CSS Grid layout with sidebar + main area + optional right panel
  • Responsive breakpoints (ultrawide / standard / narrow)
  • Pane resize via drag handles (splitter overlays in TilingGrid with mouse drag, min/max 10%/90%)
  • Layout presets: 1-col, 2-col, 3-col, 2x2, master+stack
  • Save/restore layout to SQLite (Phase 4)
  • Keyboard: Ctrl+1-4 focus pane, Ctrl+N new terminal

Terminal

  • xterm.js with Canvas addon (explicit — no WebGL dependency)
  • Catppuccin Mocha theme for xterm.js
  • PTY spawn from Rust (portable-pty), stream to frontend via Tauri events
  • Terminal resize -> PTY resize (100ms debounce)
  • Copy/paste (Ctrl+Shift+C/V) — via attachCustomKeyEventHandler
  • SSH session: spawn ssh command in PTY (via shell args)
  • Local shell: spawn user's $SHELL
  • Claude Code CLI: spawn claude in PTY (via shell args)

Milestone: After Phase 2, we have a working multi-pane terminal. Usable as a daily driver even without agent features.


Phase 3: Agent SDK Integration [status: complete] — MVP

Backend

  • Node.js/Deno sidecar: uses @anthropic-ai/claude-agent-sdk query() function (migrated from raw CLI spawning due to piped stdio hang bug #6775)
  • Sidecar communication: Rust spawns Node.js, stdio NDJSON
  • Sidecar lifecycle: auto-start on app launch, shutdown on exit
  • Sidecar lifecycle: detect crash, offer restart in UI (agent_restart command + restart button)
  • Tauri commands: agent_query, agent_stop, agent_ready, agent_restart

Frontend

  • SDK message adapter: parses stream-json into 9 typed AgentMessage types (abstraction layer)
  • Agent bridge: Tauri IPC adapter (invoke + event listeners)
  • Agent dispatcher: singleton routing sidecar events to store, crash detection
  • Agent store: session state, message history, cost tracking (Svelte 5 $state)
  • Agent pane: renders structured messages
    • Text -> plain text (markdown rendering deferred)
    • Tool calls -> collapsible cards (tool name + input)
    • Tool results -> collapsible cards
    • Thinking -> collapsible details
    • Init -> model badge
    • Cost -> USD/tokens/turns/duration summary
    • Errors -> highlighted error card
    • Subagent spawn -> auto-creates child agent pane with parent/child navigation (Phase 7)
  • Agent status indicator (starting/running/done/error)
  • Start/stop agent from UI (prompt form + stop button)
  • Auto-scroll with scroll-lock on user scroll-up
  • Session resume (follow-up prompt in AgentPane, resume_session_id passed to SDK)
  • Keyboard: Ctrl+Shift+N new agent
  • Sidebar: agent session button

Milestone: After Phase 3, we have the core differentiator. SDK agents run in structured panes alongside raw terminals.


Phase 4: Session Management + Markdown Viewer [status: complete] — MVP

Sessions

  • SQLite persistence for sessions (rusqlite with bundled feature)
  • Session types: terminal, agent, markdown (SSH via terminal args)
  • Session CRUD: save, delete, update_title, touch (last_used_at)
  • Session groups/folders — group_name column, setPaneGroup, grouped sidebar with collapsible headers
  • Remember last layout on restart (preset + pane_ids in layout_state table)
  • Auto-restore panes on app startup (restoreFromDb in layout store)

Markdown Viewer

  • File watcher (notify crate v6) -> Tauri events -> frontend
  • Markdown rendering (marked.js)
  • Syntax highlighting (Shiki) — added in Phase 5 (highlight.ts, 13 preloaded languages)
  • Open from sidebar (file picker button "M")
  • Catppuccin-themed markdown styles (h1-h3, code, pre, tables, blockquotes)
  • Live reload on file change

Milestone: After Phase 4 = MVP ship. Full session management, structured agent panes, terminal panes, markdown viewer.


Phase 5: Agent Tree + Polish [status: complete] — Post-MVP

  • Agent tree visualization (SVG, compact horizontal layout) — AgentTree.svelte + agent-tree.ts utility
  • Click tree node -> scroll to message (handleTreeNodeClick in AgentPane, scrollIntoView smooth)
  • Aggregate cost per subtree (subtreeCost displayed in yellow below each tree node label)
  • Terminal copy/paste (Ctrl+Shift+C/V via attachCustomKeyEventHandler)
  • Terminal theme hot-swap (onThemeChange callback registry in theme.svelte.ts, TerminalPane subscribes)
  • Pane drag-resize handles (splitter overlays in TilingGrid with mouse drag)
  • Session resume (follow-up prompt, resume_session_id to SDK)
  • Global status bar (terminal/agent counts, active agents pulse, token/cost totals) — StatusBar.svelte
  • Notification system (toast: success/error/warning/info, auto-dismiss 4s, max 5) — notifications.svelte.ts + ToastContainer.svelte
  • Agent dispatcher toast integration (agent complete, error, sidecar crash notifications)
  • Global keyboard shortcuts — Ctrl+W close focused pane, Ctrl+, open settings
  • Settings dialog (default shell, cwd, max panes, theme flavor) — SettingsDialog.svelte + settings-bridge.ts
  • Settings backend — settings table in SQLite (session.rs), Tauri commands settings_get/set/list (lib.rs)
  • ctx integration — read-only access to ~/.claude-context/context.db (ctx.rs, ctx-bridge.ts, ContextPane.svelte)
  • SSH session management — CRUD in SQLite (SshSession struct, SshDialog.svelte, SshSessionList.svelte, ssh-bridge.ts)
  • Catppuccin theme flavors — Latte/Frappe/Macchiato/Mocha selectable (themes.ts, theme.svelte.ts)
  • Detached pane mode — pop-out terminal/agent into standalone windows (detach.ts, App.svelte)
  • Syntax highlighting — Shiki integration for markdown + agent messages (highlight.ts, shiki dep)

Phase 6: Packaging + Distribution [status: complete] — Post-MVP

  • install-v2.sh — build-from-source installer with dependency checks (Node.js 20+, Rust 1.77+, system libs)
    • Checks: WebKit2GTK, GTK3, GLib, libayatana-appindicator, librsvg, openssl, build-essential, pkg-config, curl, wget, FUSE
    • Prompts to install missing packages via apt
    • Builds with npx tauri build, installs binary as bterminal-v2 in ~/.local/bin/
    • Creates desktop entry and installs SVG icon
  • Tauri bundle configuration — targets: ["deb", "appimage"], category: DeveloperTool
    • .deb depends: libwebkit2gtk-4.1-0, libgtk-3-0, libayatana-appindicator3-1
    • AppImage: bundleMediaFramework disabled
  • Icons regenerated from bterminal.svg — RGBA PNGs (32x32, 128x128, 128x128@2x, 512x512, .ico)
  • GitHub Actions release workflow (.github/workflows/release.yml)
    • Triggered on v* tags, Ubuntu 22.04 runner
    • Caches Rust and npm dependencies
    • Builds .deb + AppImage, uploads as GitHub Release artifacts
  • Build verified: .deb (4.3 MB), AppImage (103 MB)
  • Auto-updater plugin integrated (tauri-plugin-updater Rust + @tauri-apps/plugin-updater npm + updater.ts)
  • Auto-update latest.json generation in CI (version, platform URL, signature from .sig file)
  • release.yml: TAURI_SIGNING_PRIVATE_KEY env vars passed to build step
  • Auto-update signing key generated, pubkey set in tauri.conf.json
  • TAURI_SIGNING_PRIVATE_KEY secret set in GitHub repo settings via gh secret set

Phase 7: Agent Teams / Subagent Support [status: complete] — Post-MVP

  • Agent store parent/child hierarchy — parentSessionId, parentToolUseId, childSessionIds fields on AgentSession
  • Agent store functions — findChildByToolUseId(), getChildSessions(), parent-aware createAgentSession()
  • Agent dispatcher subagent detection — SUBAGENT_TOOL_NAMES Set ('Agent', 'Task', 'dispatch_agent')
  • Agent dispatcher message routing — parentId-bearing messages routed to child panes via toolUseToChildPane Map
  • Agent dispatcher pane spawning — spawnSubagentPane() creates child session + layout pane, auto-grouped under parent
  • AgentPane parent navigation — SUB badge + button to focus parent agent
  • AgentPane children bar — clickable chips per child subagent with status colors (running/done/error)
  • SessionList subagent icon — '↳' for subagent panes
  • Subagent cost aggregation — getTotalCost() recursive helper in agents.svelte.ts, total cost shown in parent pane done-bar
  • Dispatcher tests for subagent routing — 10 tests covering spawn, dedup, child message routing, init/cost forwarding, fallbacks (28 total dispatcher tests)
  • Test with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1

System Requirements

  • Node.js 20+ (for Agent SDK sidecar)
  • Rust 1.77+ (for building from source)
  • WebKit2GTK 4.1+ (Tauri runtime)
  • Linux x86_64 (primary target)

Multi-Machine Support (Phases A-D) [status: complete]

Architecture designed in multi-machine.md. Implementation extends BTerminal to manage agents and terminals on remote machines over WebSocket.

Phase A: Extract bterminal-core crate [status: complete]

  • Created Cargo workspace at v2/ level (v2/Cargo.toml with members)
  • Extracted PtyManager and SidecarManager into shared bterminal-core crate
  • Created EventSink trait to abstract Tauri event emission (bterminal-core/src/event.rs)
  • TauriEventSink in src-tauri/src/event_sink.rs implements EventSink
  • src-tauri pty.rs and sidecar.rs now thin re-exports from bterminal-core

Phase B: Build bterminal-relay binary [status: complete]

  • WebSocket server using tokio-tungstenite with token auth
  • CLI flags: --port, --token, --insecure (clap)
  • Routes RelayCommand to PtyManager/SidecarManager, forwards RelayEvent over WebSocket
  • Rate limiting on auth failures (10 attempts, 5min lockout)
  • Per-connection isolated PTY + sidecar managers
  • Command response propagation: structured responses (pty_created, pong, error) via shared event channel
  • send_error() helper for consistent error reporting with commandId correlation
  • PTY creation confirmation: pty_created event with session ID and commandId

Phase C: Add RemoteManager to controller [status: complete]

  • New remote.rs module in src-tauri — WebSocket client connections to relay instances
  • Machine lifecycle: add/remove/connect/disconnect
  • 12 new Tauri commands for remote operations
  • Heartbeat ping every 15s
  • PTY creation event: emits remote-pty-created Tauri event with machineId, ptyId, commandId
  • Exponential backoff reconnection on disconnect (1s/2s/4s/8s/16s/30s cap)
  • attempt_tcp_probe() function: TCP-only probe (5s timeout, default port 9750) — avoids allocating per-connection resources on relay during probes
  • Reconnection events: remote-machine-reconnecting, remote-machine-reconnect-ready

Phase D: Frontend integration [status: complete]

  • remote-bridge.ts adapter for machine management + remote events
  • machines.svelte.ts store for remote machine state
  • Layout store: Pane.remoteMachineId field
  • agent-bridge.ts and pty-bridge.ts route to remote commands when remoteMachineId is set
  • SettingsDialog "Remote Machines" section (add/remove/connect/disconnect)
  • Sidebar auto-groups remote panes by machine label

Remaining Work

  • Reconnection logic with exponential backoff — implemented in remote.rs
  • Relay command response propagation — implemented in bterminal-relay main.rs
  • Real-world relay testing (2 machines)
  • TLS/certificate pinning