feat(terminal): add embedded PTY-backed terminal dock with per-tab sessions

Adds a built-in terminal dock that runs a real pseudo-terminal per repository tab.

- Backend: new src-tauri/src/terminal.rs implements TerminalState and Tauri commands
  terminal_open, terminal_write, terminal_resize and terminal_close using the
  portable-pty crate. Terminal output is emitted via "terminal:data" and exits
  via "terminal:exit". Includes unit tests for UTF-8 chunk handling. Cargo.toml
  updated to depend on portable-pty and main.rs registers the state/commands.
- Frontend: App.svelte/UI and app.css updated to show a resizable terminal dock,
  toggleable with Ctrl+` and persisted open/height state. TerminalPanel.svelte is
  lazy-loaded per repo tab (frontend provides session ids like repo:<path>).
  package.json adds @xterm/xterm and @xterm/addon-fit for the frontend terminal
  surface.
- Docs: CHANGELOG.md notes the new embedded terminal feature.

Behavior: each repository tab has its own PTY-backed shell started in the repo
cwd; the user's shell (SHELL/COMSPEC) is used so prompts, aliases and interactive
behavior work as in a normal terminal.
This commit is contained in:
2026-09-22 21:11:48 +02:00
parent 8bac03e3fc
commit 6ef5d3b677
13 changed files with 832 additions and 85 deletions
+7
View File
@@ -5,6 +5,7 @@ mod external_tools;
mod git;
mod integrations;
mod telemetry;
mod terminal;
use badge::set_sync_badge;
use external_tools::{
@@ -46,6 +47,7 @@ use std::path::{Path, PathBuf};
use std::sync::Mutex;
use tauri::{Emitter, Manager};
use telemetry::{emit_frontend_log, emit_frontend_span, set_telemetry_enabled};
use terminal::{TerminalState, terminal_close, terminal_open, terminal_resize, terminal_write};
struct StartupRepository(Mutex<Option<String>>);
@@ -325,6 +327,7 @@ async fn main() {
.manage(StartupRepository(Mutex::new(startup_repository)))
.manage(StartupClone(Mutex::new(startup_clone)))
.manage(SearchCancellationState::default())
.manage(TerminalState::default())
.plugin(tauri_plugin_dialog::init());
// Linux installs are expected to come from the system package manager (see the
@@ -335,6 +338,10 @@ async fn main() {
builder
.invoke_handler(tauri::generate_handler![
terminal_open,
terminal_write,
terminal_resize,
terminal_close,
open_repository,
init_repository,
clone_repository,