orchflow_terminal/
protocol.rs

1// Terminal Stream Protocol
2//
3// Defines the message types for terminal communication between
4// the Rust backend and frontend via IPC.
5
6use serde::{Deserialize, Serialize};
7
8/// Main terminal message wrapper
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(tag = "type", content = "payload")]
11pub enum TerminalMessage {
12    Input(TerminalInput),
13    Output(TerminalOutput),
14    Control(ControlMessage),
15    Status(StatusMessage),
16}
17
18/// Input from frontend to terminal
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(tag = "type", content = "data")]
21pub enum TerminalInput {
22    /// Regular text input
23    Text(String),
24    /// Binary data (base64 encoded in JSON)
25    Binary(Vec<u8>),
26    /// Special key sequences
27    SpecialKey(String),
28}
29
30/// Output from terminal to frontend
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct TerminalOutput {
33    /// The actual terminal output data (base64 encoded for binary safety)
34    pub data: String,
35    /// Timestamp of the output
36    pub timestamp: chrono::DateTime<chrono::Utc>,
37    /// Optional sequence number for ordering
38    pub sequence: Option<u64>,
39}
40
41/// Control messages for terminal management
42#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(tag = "command", content = "params")]
44pub enum ControlMessage {
45    /// Resize the terminal
46    Resize { rows: u16, cols: u16 },
47    /// Change terminal mode
48    ModeChange { mode: String },
49    /// Terminal gained focus
50    Focus,
51    /// Terminal lost focus
52    Blur,
53}
54
55/// Status messages from terminal
56#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(tag = "status")]
58pub enum StatusMessage {
59    /// Terminal is ready
60    Ready {
61        terminal_id: String,
62        rows: u16,
63        cols: u16,
64    },
65    /// Process exited
66    Exited {
67        terminal_id: String,
68        exit_code: Option<i32>,
69    },
70    /// Error occurred
71    Error { terminal_id: String, error: String },
72}
73
74/// Terminal creation options
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct CreateTerminalOptions {
77    /// Terminal ID
78    pub id: String,
79    /// Shell to use (None for default)
80    pub shell: Option<String>,
81    /// Initial rows
82    pub rows: u16,
83    /// Initial columns
84    pub cols: u16,
85    /// Working directory
86    pub cwd: Option<String>,
87    /// Environment variables
88    pub env: Option<std::collections::HashMap<String, String>>,
89    /// Initial command to run
90    pub command: Option<String>,
91}
92
93/// Batch input for performance
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct BatchInput {
96    pub terminal_id: String,
97    pub inputs: Vec<TerminalInput>,
98}
99
100/// Terminal metadata
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct TerminalMetadata {
103    pub id: String,
104    pub title: String,
105    pub shell: String,
106    pub rows: u16,
107    pub cols: u16,
108    pub created_at: chrono::DateTime<chrono::Utc>,
109    pub last_activity: chrono::DateTime<chrono::Utc>,
110    pub process_id: Option<u32>,
111}
112
113impl TerminalInput {
114    /// Create text input
115    pub fn text(text: impl Into<String>) -> Self {
116        Self::Text(text.into())
117    }
118
119    /// Create special key input
120    pub fn key(key: impl Into<String>) -> Self {
121        Self::SpecialKey(key.into())
122    }
123
124    /// Create paste input (handles large text efficiently)
125    pub fn paste(text: impl Into<String>) -> Self {
126        // For paste, we might want to send as binary to handle special chars
127        let text = text.into();
128        Self::Binary(text.as_bytes().to_vec())
129    }
130}