Skip to main content

cnctd_service_ssh/sessions/
types.rs

1//! Data types for interactive shell session management.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// Default terminal width
8pub fn default_cols() -> u16 {
9    120
10}
11
12/// Default terminal height
13pub fn default_rows() -> u16 {
14    40
15}
16
17/// Arguments for creating an interactive shell session
18#[derive(Debug, Clone, Deserialize, JsonSchema)]
19pub struct ShellSessionCreateArgs {
20    /// Target ID previously registered via `ssh_register_target`
21    pub target_id: String,
22
23    /// Optional human-readable name for this session
24    pub name: Option<String>,
25
26    /// Initial shell command (default: user's login shell)
27    pub shell: Option<String>,
28
29    /// Terminal width in columns
30    #[serde(default = "default_cols")]
31    pub cols: u16,
32
33    /// Terminal height in rows
34    #[serde(default = "default_rows")]
35    pub rows: u16,
36
37    /// Client identifier for session association (enables reconnection filtering)
38    pub client_id: Option<String>,
39
40    /// Environment variables to set
41    #[serde(default)]
42    pub env: HashMap<String, String>,
43}
44
45/// Arguments for writing input to a session
46#[derive(Debug, Clone, Deserialize, JsonSchema)]
47pub struct ShellSessionWriteArgs {
48    /// Session ID
49    pub session_id: String,
50
51    /// Input to send (supports escape sequences like \x03 for Ctrl+C)
52    pub input: String,
53
54    /// Whether to append a newline after input (default: false)
55    #[serde(default)]
56    pub newline: bool,
57}
58
59/// Output format for reading session output
60#[derive(Debug, Clone, Copy, Deserialize, Serialize, JsonSchema, Default, PartialEq)]
61#[serde(rename_all = "snake_case")]
62pub enum OutputFormat {
63    /// Raw text output from the buffer (includes ANSI escape sequences)
64    #[default]
65    Raw,
66    /// Current visible terminal screen state (parsed, clean text)
67    Screen,
68    /// Both raw output and screen state
69    Both,
70    /// Raw output with ANSI escape sequences stripped
71    Stripped,
72}
73
74/// Arguments for reading session output
75#[derive(Debug, Clone, Deserialize, JsonSchema)]
76pub struct ShellSessionReadArgs {
77    /// Session ID
78    pub session_id: String,
79
80    /// Output format: raw, screen, both, or stripped
81    #[serde(default)]
82    pub format: OutputFormat,
83
84    /// Whether to consume (clear) the buffer after reading (default: true)
85    #[serde(default = "default_true")]
86    pub consume: bool,
87
88    /// Maximum wait time for new output in milliseconds (0 = no wait)
89    #[serde(default)]
90    pub wait_ms: u64,
91
92    /// Minimum bytes to wait for (with wait_ms timeout)
93    #[serde(default)]
94    pub min_bytes: usize,
95
96    /// Wait until this pattern appears in the screen output (e.g., "❯" or "$ ")
97    /// Takes precedence over wait_ms if both are specified
98    #[serde(default)]
99    pub wait_for_pattern: Option<String>,
100
101    /// Wait until screen output stabilizes (no changes for this many ms)
102    /// Useful for waiting until a TUI finishes rendering
103    #[serde(default)]
104    pub wait_for_stable_ms: Option<u64>,
105}
106
107fn default_true() -> bool {
108    true
109}
110
111/// Arguments for listing sessions
112#[derive(Debug, Clone, Deserialize, JsonSchema)]
113pub struct ShellSessionListArgs {
114    /// Filter by target ID
115    pub target_id: Option<String>,
116
117    /// Filter by client ID
118    pub client_id: Option<String>,
119
120    /// Include disconnected sessions (default: true)
121    #[serde(default = "default_true")]
122    pub include_disconnected: bool,
123}
124
125/// Arguments for reconnecting to a session
126#[derive(Debug, Clone, Deserialize, JsonSchema)]
127pub struct ShellSessionReconnectArgs {
128    /// Session ID to reconnect to
129    pub session_id: String,
130}
131
132/// Arguments for resizing a session
133#[derive(Debug, Clone, Deserialize, JsonSchema)]
134pub struct ShellSessionResizeArgs {
135    /// Session ID
136    pub session_id: String,
137
138    /// New width in columns
139    pub cols: u16,
140
141    /// New height in rows
142    pub rows: u16,
143}
144
145/// Arguments for closing a session
146#[derive(Debug, Clone, Deserialize, JsonSchema)]
147pub struct ShellSessionCloseArgs {
148    /// Session ID to close
149    pub session_id: String,
150
151    /// Forcefully kill even if processes are running (default: false)
152    #[serde(default)]
153    pub force: bool,
154}
155
156/// State of a shell session
157#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
158#[serde(rename_all = "snake_case")]
159pub enum SessionState {
160    /// Session is active and responsive
161    Active,
162    /// SSH connection dropped but tmux session may still exist remotely
163    Disconnected,
164    /// Session has been explicitly closed
165    Closed,
166}
167
168/// Terminal screen state for TUI applications
169#[derive(Debug, Clone, Serialize, JsonSchema)]
170pub struct ScreenState {
171    /// Screen content as text lines
172    pub lines: Vec<String>,
173
174    /// Cursor position (row, col) - 0-indexed
175    pub cursor: (u16, u16),
176
177    /// Terminal dimensions (cols, rows)
178    pub size: (u16, u16),
179
180    /// Whether alternate screen is active (e.g., vim, htop)
181    pub alternate_screen: bool,
182
183    /// Window title if set by application
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub title: Option<String>,
186}
187
188/// Result of creating a session
189#[derive(Debug, Clone, Serialize, JsonSchema)]
190pub struct ShellSessionCreateResult {
191    /// Unique session ID
192    pub session_id: String,
193
194    /// Session info
195    pub info: ShellSessionInfo,
196
197    /// Initial screen state
198    pub screen: ScreenState,
199}
200
201/// Result of writing to a session
202#[derive(Debug, Clone, Serialize, JsonSchema)]
203pub struct ShellSessionWriteResult {
204    /// Session ID
205    pub session_id: String,
206
207    /// Number of bytes sent
208    pub bytes_sent: usize,
209}
210
211/// Result of reading from a session
212#[derive(Debug, Clone, Serialize, JsonSchema)]
213pub struct ShellSessionReadResult {
214    /// Session ID
215    pub session_id: String,
216
217    /// Raw output (if requested, may be with or without ANSI codes based on format)
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub raw: Option<String>,
220
221    /// Screen state (if requested)
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub screen: Option<ScreenState>,
224
225    /// Bytes remaining in buffer (if not consumed)
226    pub buffer_size: usize,
227
228    /// Whether data was truncated due to buffer overflow
229    pub truncated: bool,
230
231    /// Current session state
232    pub state: SessionState,
233
234    /// Whether wait_for_pattern matched (None if pattern wasn't requested)
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub pattern_matched: Option<bool>,
237
238    /// Whether output stabilized within timeout (None if wait_for_stable_ms wasn't requested)
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub stabilized: Option<bool>,
241}
242
243/// Session info for listing
244#[derive(Debug, Clone, Serialize, JsonSchema)]
245pub struct ShellSessionInfo {
246    /// Unique session ID
247    pub id: String,
248
249    /// SSH target ID
250    pub target_id: String,
251
252    /// Human-readable name
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub name: Option<String>,
255
256    /// Client identifier
257    #[serde(skip_serializing_if = "Option::is_none")]
258    pub client_id: Option<String>,
259
260    /// Current state
261    pub state: SessionState,
262
263    /// Session creation timestamp (ISO 8601)
264    pub created_at: String,
265
266    /// Last activity timestamp (ISO 8601)
267    pub last_activity: String,
268
269    /// Terminal dimensions (cols, rows)
270    pub size: (u16, u16),
271}
272
273/// Result of listing sessions
274#[derive(Debug, Clone, Serialize, JsonSchema)]
275pub struct ShellSessionListResult {
276    /// List of sessions
277    pub sessions: Vec<ShellSessionInfo>,
278}
279
280/// Result of reconnecting to a session
281#[derive(Debug, Clone, Serialize, JsonSchema)]
282pub struct ShellSessionReconnectResult {
283    /// Session ID
284    pub session_id: String,
285
286    /// Updated session info
287    pub info: ShellSessionInfo,
288
289    /// Current screen state
290    pub screen: ScreenState,
291}
292
293/// Result of resizing a session
294#[derive(Debug, Clone, Serialize, JsonSchema)]
295pub struct ShellSessionResizeResult {
296    /// Session ID
297    pub session_id: String,
298
299    /// New dimensions (cols, rows)
300    pub size: (u16, u16),
301}
302
303/// Result of closing a session
304#[derive(Debug, Clone, Serialize, JsonSchema)]
305pub struct ShellSessionCloseResult {
306    /// Session ID
307    pub session_id: String,
308
309    /// Whether the session existed and was closed
310    pub closed: bool,
311}