2026-07-12 11:28:39 +07:00
|
|
|
//! Wire message types exchanged between an attached client and the
|
|
|
|
|
//! daemon over the `Connection`/framing layer (`conn.rs`, `frame.rs`).
|
|
|
|
|
//!
|
|
|
|
|
//! Flow: client input events are captured as `KeyAction`/`ClientRequest`
|
|
|
|
|
//! and sent to the daemon → the daemon applies them to its `AppStateRest`
|
|
|
|
|
//! and replies with `DaemonFrame` variants (a flattened `StatePayload`
|
|
|
|
|
//! for redraw, streamed tokens, system notes, or a close signal).
|
|
|
|
|
//!
|
|
|
|
|
//! Why: `StatePayload`/`MessageEntry`/`ToastEntry` are deliberately flat,
|
|
|
|
|
//! serializable projections of daemon-side state so the client can
|
|
|
|
|
//! redraw its TUI without sharing any in-process state with the daemon.
|
|
|
|
|
|
2026-07-11 20:21:59 +07:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Wire-serializable subset of `crossterm::event::KeyCode`, sent from
|
|
|
|
|
/// an attached client to the daemon over IPC.
|
2026-07-11 20:21:59 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub enum KeyAction {
|
|
|
|
|
Char(char),
|
|
|
|
|
Enter,
|
|
|
|
|
Escape,
|
|
|
|
|
Backspace,
|
|
|
|
|
Delete,
|
|
|
|
|
Tab,
|
|
|
|
|
Up,
|
|
|
|
|
Down,
|
|
|
|
|
Left,
|
|
|
|
|
Right,
|
|
|
|
|
Home,
|
|
|
|
|
End,
|
|
|
|
|
PageUp,
|
|
|
|
|
PageDown,
|
|
|
|
|
Function(u8),
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Messages an attached client sends to the daemon: input events, a
|
|
|
|
|
/// full-line submit, terminal resize, and connection lifecycle.
|
2026-07-11 20:21:59 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub enum ClientRequest {
|
|
|
|
|
Tick,
|
|
|
|
|
KeyPress {
|
|
|
|
|
key: KeyAction,
|
|
|
|
|
ctrl: bool,
|
|
|
|
|
alt: bool,
|
|
|
|
|
shift: bool,
|
|
|
|
|
},
|
|
|
|
|
Submit(String),
|
|
|
|
|
Resize(u16, u16),
|
|
|
|
|
Close,
|
2026-07-12 18:09:03 +07:00
|
|
|
ScrollUp,
|
|
|
|
|
ScrollDown,
|
2026-07-11 20:21:59 +07:00
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Flattened chat message sent from daemon to client for transcript display.
|
2026-07-11 20:21:59 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct MessageEntry {
|
|
|
|
|
pub role: String,
|
|
|
|
|
pub content: String,
|
|
|
|
|
pub timestamp: i64,
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Flattened toast notification sent from daemon to client for rendering.
|
2026-07-11 20:21:59 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct ToastEntry {
|
|
|
|
|
pub kind: String,
|
|
|
|
|
pub message: String,
|
|
|
|
|
pub created_at: i64,
|
|
|
|
|
pub lifetime_ms: u64,
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Snapshot of daemon-side `AppStateRest` sent to the client after every
|
|
|
|
|
/// action, enough for the client to redraw its TUI without shared state.
|
2026-07-11 20:21:59 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct StatePayload {
|
|
|
|
|
pub session_id: String,
|
|
|
|
|
pub messages: Vec<MessageEntry>,
|
|
|
|
|
pub edit_count: u32,
|
|
|
|
|
pub message_count: usize,
|
|
|
|
|
pub overlay: Option<String>,
|
|
|
|
|
pub toasts: Vec<ToastEntry>,
|
|
|
|
|
pub dirty: bool,
|
|
|
|
|
pub input_buffer: String,
|
|
|
|
|
pub input_cursor: usize,
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Messages the daemon sends back to an attached client.
|
2026-07-11 20:21:59 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub enum DaemonFrame {
|
|
|
|
|
StateUpdate(Box<StatePayload>),
|
|
|
|
|
StreamToken(String),
|
|
|
|
|
SystemNote { kind: String, message: String },
|
|
|
|
|
Closed,
|
|
|
|
|
}
|