Skip to main content

gatekpr_opencode/
error.rs

1//! Error types for OpenCode CLI integration
2
3use thiserror::Error;
4
5/// Result type for OpenCode operations
6pub type Result<T> = std::result::Result<T, OpenCodeError>;
7
8/// Errors that can occur when using OpenCode CLI
9#[derive(Error, Debug)]
10pub enum OpenCodeError {
11    /// OpenCode CLI binary not found
12    #[error(
13        "OpenCode CLI not found: {0}. Install with: curl -fsSL https://opencode.ai/install | bash"
14    )]
15    CliNotFound(String),
16
17    /// CLI execution failed
18    #[error("CLI execution failed: {0}")]
19    CliExecution(String),
20
21    /// CLI returned non-zero exit code
22    #[error("CLI exited with code {code}: {stderr}")]
23    CliExitError { code: i32, stderr: String },
24
25    /// CLI timed out
26    #[error("CLI operation timed out after {0} seconds")]
27    Timeout(u64),
28
29    /// Failed to parse CLI output
30    #[error("Failed to parse CLI output: {0}")]
31    OutputParse(String),
32
33    /// Failed to serialize/deserialize JSON
34    #[error("JSON error: {0}")]
35    Json(#[from] serde_json::Error),
36
37    /// IO error during file operations
38    #[error("IO error: {0}")]
39    Io(#[from] std::io::Error),
40
41    /// Invalid configuration
42    #[error("Invalid configuration: {0}")]
43    InvalidConfig(String),
44
45    /// MCP server error
46    #[error("MCP server error: {0}")]
47    McpError(String),
48
49    /// Authentication required
50    #[error("OpenCode authentication required. Run: opencode auth login")]
51    AuthRequired,
52
53    /// No results found
54    #[error("No results found for: {0}")]
55    NoResults(String),
56
57    /// Rate limit exceeded
58    #[error("Rate limit exceeded. Try again later.")]
59    RateLimited,
60
61    /// Model not available
62    #[error("Model not available: {0}. Check your subscription.")]
63    ModelUnavailable(String),
64
65    /// File collection error
66    #[error("Failed to collect files: {0}")]
67    FileCollection(String),
68}
69
70impl OpenCodeError {
71    /// Create a CLI execution error
72    pub fn cli_error(message: impl Into<String>) -> Self {
73        Self::CliExecution(message.into())
74    }
75
76    /// Create a CLI exit error
77    pub fn exit_error(code: i32, stderr: impl Into<String>) -> Self {
78        Self::CliExitError {
79            code,
80            stderr: stderr.into(),
81        }
82    }
83
84    /// Create a timeout error
85    pub fn timeout(seconds: u64) -> Self {
86        Self::Timeout(seconds)
87    }
88
89    /// Create a parse error
90    pub fn parse_error(message: impl Into<String>) -> Self {
91        Self::OutputParse(message.into())
92    }
93
94    /// Check if error is retryable
95    pub fn is_retryable(&self) -> bool {
96        matches!(
97            self,
98            Self::Timeout(_) | Self::RateLimited | Self::CliExecution(_)
99        )
100    }
101
102    /// Check if error requires authentication
103    pub fn needs_auth(&self) -> bool {
104        matches!(self, Self::AuthRequired)
105    }
106
107    /// Check if this is a configuration error
108    pub fn is_config_error(&self) -> bool {
109        matches!(
110            self,
111            Self::CliNotFound(_) | Self::InvalidConfig(_) | Self::ModelUnavailable(_)
112        )
113    }
114}