use std::collections::HashMap; use std::path::PathBuf; use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; use codex_sandboxing::SandboxLaunchConfig; use codex_sandboxing::SandboxType; use serde::Deserialize; use serde::Serialize; use crate::ProcessId; pub const INITIALIZE_METHOD: &str = "initialize"; pub const INITIALIZED_METHOD: &str = "initialized"; pub const EXEC_METHOD: &str = "process/start"; pub const EXEC_READ_METHOD: &str = "process/read"; pub const EXEC_WRITE_METHOD: &str = "process/write"; pub const EXEC_TERMINATE_METHOD: &str = "process/terminate"; pub const EXEC_OUTPUT_DELTA_METHOD: &str = "process/output"; pub const EXEC_EXITED_METHOD: &str = "process/exited"; pub const EXEC_CLOSED_METHOD: &str = "process/closed"; pub const FS_READ_FILE_METHOD: &str = "fs/readFile"; pub const FS_WRITE_FILE_METHOD: &str = "fs/writeFile"; pub const FS_CREATE_DIRECTORY_METHOD: &str = "fs/createDirectory"; pub const FS_GET_METADATA_METHOD: &str = "fs/getMetadata"; pub const FS_READ_DIRECTORY_METHOD: &str = "fs/readDirectory"; pub const FS_REMOVE_METHOD: &str = "fs/remove"; pub const FS_COPY_METHOD: &str = "fs/copy"; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] pub struct ByteChunk(#[serde(with = "base64_bytes")] pub Vec); impl ByteChunk { pub fn into_inner(self) -> Vec { self.0 } } impl From> for ByteChunk { fn from(value: Vec) -> Self { Self(value) } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct InitializeParams { pub client_name: String, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct InitializeResponse {} #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExecParams { /// Client-chosen logical process handle scoped to this connection/session. /// This is a protocol key, not an OS pid. pub process_id: ProcessId, pub argv: Vec, pub cwd: PathBuf, pub env: HashMap, pub tty: bool, pub arg0: Option, pub sandbox: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExecResponse { pub process_id: ProcessId, pub sandbox_type: SandboxType, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ReadParams { pub process_id: ProcessId, pub after_seq: Option, pub max_bytes: Option, pub wait_ms: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProcessOutputChunk { pub seq: u64, pub stream: ExecOutputStream, pub chunk: ByteChunk, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ReadResponse { pub chunks: Vec, pub next_seq: u64, pub exited: bool, pub exit_code: Option, pub closed: bool, pub failure: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WriteParams { pub process_id: ProcessId, pub chunk: ByteChunk, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum WriteStatus { Accepted, UnknownProcess, StdinClosed, Starting, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WriteResponse { pub status: WriteStatus, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TerminateParams { pub process_id: ProcessId, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TerminateResponse { pub running: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum ExecOutputStream { Stdout, Stderr, Pty, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExecOutputDeltaNotification { pub process_id: ProcessId, pub seq: u64, pub stream: ExecOutputStream, pub chunk: ByteChunk, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExecExitedNotification { pub process_id: ProcessId, pub seq: u64, pub exit_code: i32, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ExecClosedNotification { pub process_id: ProcessId, pub seq: u64, } mod base64_bytes { use super::BASE64_STANDARD; use base64::Engine as _; use serde::Deserialize; use serde::Deserializer; use serde::Serializer; pub fn serialize(bytes: &[u8], serializer: S) -> Result where S: Serializer, { serializer.serialize_str(&BASE64_STANDARD.encode(bytes)) } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let encoded = String::deserialize(deserializer)?; BASE64_STANDARD .decode(encoded) .map_err(serde::de::Error::custom) } }