Frontend terminal view — VTE4 embedding #17

Open
opened 2026-04-16 11:31:59 +00:00 by claude-desktop · 0 comments
Collaborator

User story

As a user, I want an embedded terminal (VTE4) in the forge-agent window that connects to the backend PTY session, supports input, resize, and reconnection via replay buffer, so that I can use a shell alongside the AI agent.

Acceptance criteria

TerminalViewModel (RELM4 component, components/terminal_view.rs)

  • Embeds a vte4::Terminal widget in the bottom pane (toggle-able)
  • On thread selection: sends TerminalCommand::Open via IPC with the project's working directory
  • Stores the terminal_id returned from the backend

Input handling

  • vte.connect_commit() captures user input and sends TerminalCommand::Write via IPC
  • Non-blocking send via glib::spawn_future_local

Output rendering

  • Receives AppEvent::TerminalOutput and calls vte.feed(data) to render
  • On reconnection/tab switch: requests TerminalSnapshot and feeds history for replay

Resize

  • vte.connect_char_size_changed() sends TerminalCommand::Resize via IPC
  • Resize debounced to avoid flooding

Configuration

  • Font family and size from AppConfig.terminal.embedded (font_family, font_size)
  • Scrollback lines from config (default 10,000)
  • Bold text enabled, sixel support if available

Toggle

  • `Ctrl+`` toggles terminal visibility
  • Terminal panel is in the bottom of a gtk::Paned splitter

Tests

  • Test: terminal widget initializes without error
  • Test: feed_data renders content (headless test if VTE4 supports it)

Out of scope

  • Kitty/Foot external terminal UI (backend handles the launch; no frontend widget needed)
  • Multiple terminal tabs per thread (post-v1)

References

  • Spec §10.5 (TerminalView VTE4)
  • Spec §9.2 (Kitty/Foot option — backend only)

Dependencies

  • Blocked by: #3 (TerminalConfig.embedded), #10 (terminal_id + snapshot contract), #13 (AppModel, AppMsg)
  • Blocks: none (v0.1 leaf)
  • Branch off: issue-13-app-shell
  • Full graph: #21
## User story As a **user**, I want an embedded terminal (VTE4) in the forge-agent window that connects to the backend PTY session, supports input, resize, and reconnection via replay buffer, so that I can use a shell alongside the AI agent. ## Acceptance criteria ### TerminalViewModel (RELM4 component, `components/terminal_view.rs`) - [ ] Embeds a `vte4::Terminal` widget in the bottom pane (toggle-able) - [ ] On thread selection: sends `TerminalCommand::Open` via IPC with the project's working directory - [ ] Stores the `terminal_id` returned from the backend ### Input handling - [ ] `vte.connect_commit()` captures user input and sends `TerminalCommand::Write` via IPC - [ ] Non-blocking send via `glib::spawn_future_local` ### Output rendering - [ ] Receives `AppEvent::TerminalOutput` and calls `vte.feed(data)` to render - [ ] On reconnection/tab switch: requests `TerminalSnapshot` and feeds history for replay ### Resize - [ ] `vte.connect_char_size_changed()` sends `TerminalCommand::Resize` via IPC - [ ] Resize debounced to avoid flooding ### Configuration - [ ] Font family and size from `AppConfig.terminal.embedded` (font_family, font_size) - [ ] Scrollback lines from config (default 10,000) - [ ] Bold text enabled, sixel support if available ### Toggle - [ ] `Ctrl+\`` toggles terminal visibility - [ ] Terminal panel is in the bottom of a `gtk::Paned` splitter ### Tests - [ ] Test: terminal widget initializes without error - [ ] Test: feed_data renders content (headless test if VTE4 supports it) ## Out of scope - Kitty/Foot external terminal UI (backend handles the launch; no frontend widget needed) - Multiple terminal tabs per thread (post-v1) ## References - Spec §10.5 (TerminalView VTE4) - Spec §9.2 (Kitty/Foot option — backend only) ## Dependencies - **Blocked by:** #3 (TerminalConfig.embedded), #10 (terminal_id + snapshot contract), #13 (AppModel, AppMsg) - **Blocks:** none (v0.1 leaf) - **Branch off:** `issue-13-app-shell` - **Full graph:** #21
claude-desktop added this to the v0.1.0 milestone 2026-04-16 11:31:59 +00:00
Sign in to join this conversation.
No description provided.