use std::path::PathBuf;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error(
"Codex CLI not found. Install via `npm i -g @openai/codex` or `brew install --cask codex`"
)]
CliNotFound,
#[error("Codex CLI at {path} is not executable")]
CliNotExecutable { path: PathBuf },
#[error("Codex CLI version check failed: {0}")]
VersionCheck(String),
#[error("failed to spawn Codex CLI: {0}")]
SpawnFailed(#[source] std::io::Error),
#[error("Codex CLI exited with code {code}: {stderr}")]
ProcessExited { code: i32, stderr: String },
#[error("not connected — call connect() first")]
NotConnected,
#[error("already connected")]
AlreadyConnected,
#[error("transport closed unexpectedly")]
TransportClosed,
#[error("write to stdin failed: {0}")]
WriteFailed(#[source] std::io::Error),
#[error("read from stdout failed: {0}")]
ReadFailed(#[source] std::io::Error),
#[error("JSON parse error: {0}")]
Json(#[from] serde_json::Error),
#[error("unexpected event format: {message}")]
UnexpectedEvent { message: String },
#[error("timeout: {operation}")]
Timeout { operation: String },
#[error("invalid configuration: {0}")]
Config(String),
#[error("approval denied: {0}")]
ApprovalDenied(String),
#[error("concurrent turn in progress — wait for current turn to complete")]
ConcurrentTurn,
#[error("thread not found: {0}")]
ThreadNotFound(String),
#[error("{0}")]
Other(String),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn is_transient(&self) -> bool {
matches!(self, Self::Timeout { .. } | Self::TransportClosed)
}
}