use thiserror::Error;
#[derive(Error, Debug)]
pub enum ClaudeError {
#[error("Claude Code CLI not found: {0}")]
CliNotFound(String),
#[error("Connection error: {0}")]
Connection(String),
#[error("Process error (exit code {exit_code}): {message}")]
Process {
message: String,
exit_code: i32,
stderr: Option<String>,
},
#[error("JSON decode error: {0}")]
JsonDecode(#[from] serde_json::Error),
#[error("Message parse error: {message}")]
MessageParse {
message: String,
data: Option<serde_json::Value>,
},
#[error("Transport error: {0}")]
Transport(String),
#[error("Control protocol error: {0}")]
ControlProtocol(String),
#[error("Hook error: {0}")]
Hook(String),
#[error("MCP error: {0}")]
Mcp(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Timeout: {0}")]
Timeout(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
}
pub type Result<T> = std::result::Result<T, ClaudeError>;
impl ClaudeError {
pub fn cli_not_found() -> Self {
Self::CliNotFound(
"Claude Code not found. Install with:\n\
npm install -g @anthropic-ai/claude-code\n\
\n\
If already installed locally, try:\n\
export PATH=\"$HOME/node_modules/.bin:$PATH\"\n\
\n\
Or specify the path when creating transport"
.to_string(),
)
}
pub fn connection(msg: impl Into<String>) -> Self {
Self::Connection(msg.into())
}
pub fn process(msg: impl Into<String>, exit_code: i32, stderr: Option<String>) -> Self {
Self::Process {
message: msg.into(),
exit_code,
stderr,
}
}
pub fn message_parse(msg: impl Into<String>, data: Option<serde_json::Value>) -> Self {
Self::MessageParse {
message: msg.into(),
data,
}
}
pub fn transport(msg: impl Into<String>) -> Self {
Self::Transport(msg.into())
}
pub fn control_protocol(msg: impl Into<String>) -> Self {
Self::ControlProtocol(msg.into())
}
pub fn protocol_error(msg: impl Into<String>) -> Self {
Self::ControlProtocol(msg.into())
}
pub fn json_encode(msg: impl Into<String>) -> Self {
Self::JsonDecode(serde_json::Error::io(std::io::Error::new(
std::io::ErrorKind::InvalidData,
msg.into(),
)))
}
pub fn json_decode(msg: impl Into<String>) -> Self {
Self::JsonDecode(serde_json::Error::io(std::io::Error::new(
std::io::ErrorKind::InvalidData,
msg.into(),
)))
}
pub fn hook(msg: impl Into<String>) -> Self {
Self::Hook(msg.into())
}
pub fn mcp(msg: impl Into<String>) -> Self {
Self::Mcp(msg.into())
}
pub fn timeout(msg: impl Into<String>) -> Self {
Self::Timeout(msg.into())
}
pub fn invalid_config(msg: impl Into<String>) -> Self {
Self::InvalidConfig(msg.into())
}
}