use std::path::PathBuf;
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("config error: {0}")]
Config(String),
#[error("io error at {context}: {source}")]
Io {
context: String,
#[source]
source: std::io::Error,
},
#[error("could not spawn subprocess: {0}")]
Spawn(#[source] std::io::Error),
#[error("schema error: {0}")]
Schema(String),
#[error("editor config: read failed at {path}: {source}")]
EditorConfigRead {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("editor config: JSON error at {path}: {source}")]
EditorConfigJson {
path: PathBuf,
#[source]
source: serde_json::Error,
},
#[error("editor config: backup failed for {path}: {source}")]
EditorConfigBackup {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("editor config: write failed at {path}: {source}")]
EditorConfigWrite {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("panic: {0}")]
Panic(String),
#[error("mcp initialize error: {0}")]
McpInitialize(#[source] Box<rmcp::service::ServerInitializeError>),
#[error("mcp protocol error: {0}")]
Mcp(#[source] Box<rmcp::ServiceError>),
}
impl From<rmcp::service::ServerInitializeError> for Error {
fn from(err: rmcp::service::ServerInitializeError) -> Self {
Self::McpInitialize(Box::new(err))
}
}
impl From<Box<rmcp::service::ServerInitializeError>> for Error {
fn from(err: Box<rmcp::service::ServerInitializeError>) -> Self {
Self::McpInitialize(err)
}
}
impl From<rmcp::ServiceError> for Error {
fn from(err: rmcp::ServiceError) -> Self {
Self::Mcp(Box::new(err))
}
}
impl From<Box<rmcp::ServiceError>> for Error {
fn from(err: Box<rmcp::ServiceError>) -> Self {
Self::Mcp(err)
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_error_renders() {
let e = Error::Config("bad path".into());
assert_eq!(e.to_string(), "config error: bad path");
}
#[test]
fn spawn_error_wraps_io() {
let e = Error::Spawn(std::io::Error::other("nope"));
assert!(e.to_string().contains("could not spawn subprocess"));
}
}