Skip to main content

ai_session/core/
terminal.rs

1//! Terminal handle abstraction that can wrap either a PTY or the headless fallback.
2
3use anyhow::Result;
4
5use super::headless::HeadlessHandle;
6use super::pty::PtyHandle;
7
8/// Unified terminal handle used by `AISession`.
9pub enum TerminalHandle {
10    /// Native PTY backed terminal.
11    Pty(PtyHandle),
12    /// Headless (pipe) fallback terminal.
13    Headless(HeadlessHandle),
14}
15
16impl TerminalHandle {
17    /// Write data to the underlying terminal.
18    pub async fn write(&self, data: &[u8]) -> Result<()> {
19        match self {
20            TerminalHandle::Pty(handle) => handle.write(data).await,
21            TerminalHandle::Headless(handle) => handle.write(data).await,
22        }
23    }
24
25    /// Read data from the underlying terminal.
26    pub async fn read(&self) -> Result<Vec<u8>> {
27        match self {
28            TerminalHandle::Pty(handle) => handle.read().await,
29            TerminalHandle::Headless(handle) => handle.read().await,
30        }
31    }
32
33    /// Read data with a timeout from the underlying terminal.
34    pub async fn read_with_timeout(&self, timeout_ms: u64) -> Result<Vec<u8>> {
35        match self {
36            TerminalHandle::Pty(handle) => handle.read_with_timeout(timeout_ms).await,
37            TerminalHandle::Headless(handle) => handle.read_with_timeout(timeout_ms).await,
38        }
39    }
40
41    /// Check whether the terminal is still running.
42    pub async fn is_running(&self) -> bool {
43        match self {
44            TerminalHandle::Pty(handle) => handle.is_running(),
45            TerminalHandle::Headless(handle) => handle.is_running().await,
46        }
47    }
48
49    /// Shutdown the terminal, freeing all resources.
50    pub async fn shutdown(self) -> Result<()> {
51        match self {
52            TerminalHandle::Pty(_handle) => Ok(()),
53            TerminalHandle::Headless(handle) => handle.shutdown().await,
54        }
55    }
56}