1use thiserror::Error;
2
3#[derive(Debug, Error, Clone)]
5#[error("{message}")]
6pub struct OpencodeSDKError {
7 pub message: String,
9}
10
11impl OpencodeSDKError {
12 pub fn new(message: impl Into<String>) -> Self {
13 Self {
14 message: message.into(),
15 }
16 }
17}
18
19#[derive(Debug, Error, Clone)]
21#[error("{message}")]
22pub struct CLINotFoundError {
23 pub message: String,
25 pub cli_path: Option<String>,
27}
28
29impl CLINotFoundError {
30 pub fn new(message: impl Into<String>, cli_path: Option<String>) -> Self {
31 let base = message.into();
32 let message = match &cli_path {
33 Some(path) => format!("{base}: {path}"),
34 None => base,
35 };
36 Self { message, cli_path }
37 }
38}
39
40#[derive(Debug, Error, Clone)]
42#[error("{message}")]
43pub struct ProcessError {
44 pub message: String,
46 pub exit_code: Option<i32>,
48 pub output: Option<String>,
50}
51
52impl ProcessError {
53 pub fn new(message: impl Into<String>, exit_code: Option<i32>, output: Option<String>) -> Self {
54 let base = message.into();
55 let mut message = base;
56 if let Some(code) = exit_code {
57 message = format!("{message} (exit code: {code})");
58 }
59 if let Some(content) = &output {
60 if !content.trim().is_empty() {
61 message = format!("{message}\nOutput: {content}");
62 }
63 }
64
65 Self {
66 message,
67 exit_code,
68 output,
69 }
70 }
71}
72
73#[derive(Debug, Error, Clone)]
75#[error("OpenCode API error: status {status}, body: {body}")]
76pub struct ApiError {
77 pub status: u16,
79 pub body: String,
81}
82
83#[derive(Debug, Error)]
85pub enum Error {
86 #[error(transparent)]
88 OpencodeSDK(#[from] OpencodeSDKError),
89 #[error(transparent)]
91 CLINotFound(#[from] CLINotFoundError),
92 #[error(transparent)]
94 Process(#[from] ProcessError),
95 #[error(transparent)]
97 Api(#[from] ApiError),
98 #[error(transparent)]
100 Io(#[from] std::io::Error),
101 #[error(transparent)]
103 Json(#[from] serde_json::Error),
104 #[error(transparent)]
106 Http(#[from] reqwest::Error),
107 #[error(transparent)]
109 InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
110 #[error(transparent)]
112 InvalidHeaderName(#[from] reqwest::header::InvalidHeaderName),
113 #[error("Timeout waiting for server to start after {timeout_ms}ms")]
115 ServerStartupTimeout { timeout_ms: u64 },
116 #[error("Missing required path parameter: {0}")]
118 MissingPathParameter(String),
119}
120
121pub type Result<T> = std::result::Result<T, Error>;