diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 58fa81a..28452af 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -4,7 +4,7 @@ - v1 is a single-file Python app (`bterminal.py`). Changes are localized. - v2 docs are in `docs/`. Architecture decisions are in `docs/task_plan.md`. -- Phase 2 (Terminal Pane + Layout) is complete. Phase 3 (Agent SDK) is next. +- Phase 3 (Agent SDK Integration) is in progress. Core implementation done, needs testing and polish. - Consult Memora (tag: `bterminal`) before making architectural changes. ## Documentation References @@ -25,8 +25,9 @@ ## Key Technical Constraints - WebKit2GTK has no WebGL — xterm.js must use Canvas addon explicitly. -- Claude Agent SDK is 0.2.x (pre-1.0) — all SDK interactions go through the adapter layer (`src/lib/adapters/sdk-messages.ts`). -- Node.js sidecar communicates via stdio NDJSON, not sockets. +- Agent sessions use `claude` CLI with `--output-format stream-json` (not Agent SDK npm package). All output goes through the adapter layer (`src/lib/adapters/sdk-messages.ts`). +- Node.js sidecar (`sidecar/agent-runner.ts`) spawns claude subprocesses, communicates with Rust via stdio NDJSON. +- Agent dispatcher (`src/lib/agent-dispatcher.ts`) is a singleton that routes sidecar events to the agent store. - Maximum 4 active xterm.js instances to avoid WebKit2GTK memory issues. ## Memora Tags diff --git a/CHANGELOG.md b/CHANGELOG.md index bc43012..a6be2a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Agent pane with prompt input, structured message rendering, stop button, and cost display (Phase 3) +- Node.js sidecar manager (Rust) for spawning and communicating with agent-runner via stdio NDJSON (Phase 3) +- Agent-runner sidecar: spawns `claude` CLI with `--output-format stream-json` for structured agent output (Phase 3) +- SDK message adapter parsing stream-json into 9 typed message types: init, text, thinking, tool_call, tool_result, status, cost, error, unknown (Phase 3) +- Agent bridge adapter for Tauri IPC (invoke + event listeners) (Phase 3) +- Agent dispatcher routing sidecar events to agent session store (Phase 3) +- Agent session store with message history, cost tracking, and lifecycle management (Phase 3) +- Keyboard shortcut: Ctrl+Shift+N to open new agent pane (Phase 3) +- Sidebar button for creating new agent sessions (Phase 3) - Rust PTY backend with portable-pty: spawn, write, resize, kill with Tauri event streaming (Phase 2) - xterm.js terminal pane with Canvas addon, FitAddon, and Catppuccin Mocha theme (Phase 2) - CSS Grid tiling layout with 5 presets: 1-col, 2-col, 3-col, 2x2, master-stack (Phase 2) diff --git a/README.md b/README.md index d623b96..da7c0b4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Terminal with session panel (MobaXterm-style), built with GTK 3 + VTE. Catppuccin Mocha theme. -> **v2 in progress (Phase 2 complete):** Redesign as a multi-session Claude agent dashboard using Tauri 2.x + Svelte 5 + Claude Agent SDK. Working multi-pane terminal with PTY backend, CSS Grid tiling, and Catppuccin theme on branch `v2-mission-control`. See [docs/task_plan.md](docs/task_plan.md) for architecture and [docs/phases.md](docs/phases.md) for implementation plan. +> **v2 in progress (Phase 3 in progress):** Redesign as a multi-session Claude agent dashboard using Tauri 2.x + Svelte 5. Working multi-pane terminal with PTY backend, agent panes with structured output from `claude` CLI, CSS Grid tiling, and Catppuccin theme on branch `v2-mission-control`. See [docs/task_plan.md](docs/task_plan.md) for architecture and [docs/phases.md](docs/phases.md) for implementation plan. ![BTerminal](screenshot.png) diff --git a/TODO.md b/TODO.md index fc57566..6cb5cf2 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,7 @@ ## Active -- [ ] **Phase 3: Agent SDK Integration** — Node.js sidecar, SDK message adapter, structured agent panes with tool call cards. +- [ ] **Phase 3: Agent SDK Integration (polish)** — Markdown rendering in agent text, sidecar crash detection/restart, auto-scroll lock, testing. - [ ] **Phase 4: Session Management + Markdown** — SQLite persistence, session CRUD, file watcher, markdown rendering. MVP ship after this phase. - [ ] **Pane drag-resize handles** — Deferred from Phase 2, current presets sufficient for MVP. - [ ] **Copy/paste (Ctrl+Shift+C/V)** — Deferred from Phase 2. @@ -10,5 +10,6 @@ ## Completed +- [x] **Phase 3: Agent SDK Integration (core)** — Sidecar manager, agent-runner (claude CLI subprocess), SDK message adapter (stream-json), agent pane with message rendering/cost/stop. | Done: 2026-03-06 - [x] **Phase 2: Terminal Pane + Layout** — PTY backend (portable-pty), xterm.js + Canvas addon, CSS Grid tiling (5 presets), sidebar, keyboard shortcuts. | Done: 2026-03-05 - [x] **Phase 1: Project Scaffolding** — Tauri 2.x + Svelte 5 scaffolded in `v2/`, Catppuccin theme, Rust stubs, sidecar scaffold. | Done: 2026-03-05 diff --git a/docs/phases.md b/docs/phases.md index 4d63869..315d370 100644 --- a/docs/phases.md +++ b/docs/phases.md @@ -107,22 +107,35 @@ bterminal-v2/ --- -## Phase 3: Agent SDK Integration [status: not_started] — MVP +## Phase 3: Agent SDK Integration [status: in_progress] — MVP -- [ ] Node.js sidecar: thin wrapper around Agent SDK `query()` -- [ ] Sidecar communication: Rust spawns Node.js, stdio NDJSON -- [ ] Sidecar lifecycle: spawn on demand, detect crash, restart -- [ ] SDK message adapter (abstraction layer) -- [ ] Agent pane: renders structured messages - - Text -> markdown rendered - - Tool calls -> collapsible cards (tool name + input + output) - - Subagent spawn -> tree node + optional new pane - - Errors -> highlighted error card - - Cost/tokens -> pane header metrics +### Backend +- [x] Node.js sidecar: spawns `claude` CLI with `--output-format stream-json` (not Agent SDK query() — avoids npm dep + version churn) +- [x] Sidecar communication: Rust spawns Node.js, stdio NDJSON +- [x] Sidecar lifecycle: auto-start on app launch, shutdown on exit +- [ ] Sidecar lifecycle: detect crash, offer restart in UI +- [x] Tauri commands: agent_query, agent_stop, agent_ready + +### Frontend +- [x] SDK message adapter: parses stream-json into 9 typed AgentMessage types (abstraction layer) +- [x] Agent bridge: Tauri IPC adapter (invoke + event listeners) +- [x] Agent dispatcher: singleton routing sidecar events to store +- [x] Agent store: session state, message history, cost tracking (Svelte 5 $state) +- [x] Agent pane: renders structured messages + - [x] Text -> plain text (markdown rendering deferred) + - [x] Tool calls -> collapsible cards (tool name + input) + - [x] Tool results -> collapsible cards + - [x] Thinking -> collapsible details + - [x] Init -> model badge + - [x] Cost -> USD/tokens/turns/duration summary + - [x] Errors -> highlighted error card + - [ ] Subagent spawn -> tree node + optional new pane (Phase 5) +- [x] Agent status indicator (starting/running/done/error) +- [x] Start/stop agent from UI (prompt form + stop button) - [ ] Auto-scroll with scroll-lock on user scroll-up -- [ ] Agent status indicator (running/thinking/waiting/done/error) -- [ ] Start/stop/cancel agent from UI - [ ] Session resume (SDK `resume: sessionId`) +- [x] Keyboard: Ctrl+Shift+N new agent +- [x] Sidebar: agent session button **Milestone: After Phase 3, we have the core differentiator.** SDK agents run in structured panes alongside raw terminals. diff --git a/docs/progress.md b/docs/progress.md index 314c256..5fb5ab1 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -60,5 +60,23 @@ - [x] npm dependencies: @xterm/xterm, @xterm/addon-canvas, @xterm/addon-fit - [x] Cargo dependencies: portable-pty, uuid +### Phase 3: Agent SDK Integration (in progress) +- [x] Rust SidecarManager: spawn Node.js, stdio NDJSON, query/stop/shutdown (sidecar.rs, 218 lines) +- [x] Node.js agent-runner: spawns `claude -p --output-format stream-json`, manages sessions (agent-runner.ts, 176 lines) +- [x] Tauri commands: agent_query, agent_stop, agent_ready in lib.rs +- [x] Sidecar auto-start on app launch +- [x] SDK message adapter: full stream-json parser with 9 typed message types (sdk-messages.ts, 234 lines) +- [x] Agent bridge: Tauri IPC adapter for sidecar communication (agent-bridge.ts, 53 lines) +- [x] Agent dispatcher: routes sidecar events to agent store (agent-dispatcher.ts, 87 lines) +- [x] Agent store: session state with messages, cost tracking (agents.ts, 91 lines) +- [x] AgentPane component: prompt input, message rendering, stop button, cost display (AgentPane.svelte, 420 lines) +- [x] UI integration: Ctrl+Shift+N for new agent, sidebar agent button, TilingGrid routing + +Architecture decision: Uses `claude` CLI with `--output-format stream-json` instead of Agent SDK `query()` API. Avoids SDK npm dependency and version churn while getting identical structured output. + ### Next Steps -- [ ] Begin Phase 3: Agent SDK Integration (Node.js sidecar, SDK message adapter) +- [ ] Markdown rendering in agent text messages +- [ ] Sidecar crash detection and restart UI +- [ ] Auto-scroll lock on user scroll-up +- [ ] Testing: vitest for sdk-messages adapter, cargo test for sidecar +- [ ] Begin Phase 4: Session Management + Markdown Viewer diff --git a/docs/task_plan.md b/docs/task_plan.md index 3247e30..a9d4b73 100644 --- a/docs/task_plan.md +++ b/docs/task_plan.md @@ -3,7 +3,7 @@ ## Goal Redesign BTerminal from a GTK3 terminal emulator into a **multi-session Claude agent dashboard** optimized for 32:9 ultrawide (5120x1440). Simultaneous visibility of all active sessions, agent tree visualization, inline markdown rendering, maximum information density. -## Status: BUILDING (Phase 2 complete — Rev 2) +## Status: BUILDING (Phase 3 in progress — Rev 2) --- @@ -74,9 +74,9 @@ The Agent SDK cannot run in Rust or the webview. Solution: └─────────────────────────────────────────────────────┘ ``` -- Rust spawns Node.js child process on demand (when user starts an SDK agent session) +- Rust spawns Node.js child process on app launch (auto-start in setup) - Communication: stdio with newline-delimited JSON (simple, no socket server) -- Node.js process runs a thin wrapper that calls `query()` and forwards messages +- Node.js process runs a thin wrapper that spawns `claude -p --output-format stream-json` and forwards NDJSON events - If sidecar crashes: detect via process exit, show error in UI, offer restart - **Packaging:** Bundle the sidecar JS as a single file (esbuild bundle). Require Node.js 20+ as system dependency. Document in install.sh. - **Future:** Could replace Node.js with Deno (single binary, no npm) for better packaging. @@ -123,6 +123,7 @@ See [phases.md](phases.md) for the full phased implementation plan (Phases 1-6). | SDK abstraction layer | SDK is 0.2.x, 127 versions in 5 months. Must insulate UI from wire format changes | 2026-03-05 | | MVP = Phases 1-4 | Ship usable tool before tackling tree viz, packaging, polish | 2026-03-05 | | Canvas addon (not WebGL) | WebKit2GTK has no WebGL. Explicit Canvas addon avoids silent fallback | 2026-03-05 | +| claude CLI over Agent SDK query() | Use `claude -p --output-format stream-json` instead of SDK npm package. Avoids dependency + version churn, identical structured output | 2026-03-06 | ## Open Questions