ricecoder_cli/
error.rs

1// Adapted from automation/src/cli/error.rs
2// Enhanced with better error messages, suggestions, and documentation links
3
4use thiserror::Error;
5
6/// CLI-specific errors with enhanced context and suggestions
7#[derive(Error, Debug)]
8pub enum CliError {
9    #[error("Command not found: {command}. Did you mean: {suggestion}?")]
10    CommandNotFound { command: String, suggestion: String },
11
12    #[error("Invalid argument: {message}")]
13    InvalidArgument { message: String },
14
15    #[error("IO error: {0}")]
16    Io(#[from] std::io::Error),
17
18    #[error("Configuration error: {0}")]
19    Config(String),
20
21    #[error("Provider error: {0}")]
22    Provider(String),
23
24    #[error("Generation error: {0}")]
25    Generation(String),
26
27    #[error("Storage error: {0}")]
28    Storage(String),
29
30    #[error("Internal error: {0}")]
31    Internal(String),
32
33    #[error("File not found: {path}")]
34    FileNotFound { path: String },
35
36    #[error("Permission denied: {path}")]
37    PermissionDenied { path: String },
38
39    #[error("Invalid configuration format: {details}")]
40    InvalidConfigFormat { details: String },
41
42    #[error("Missing required field: {field}")]
43    MissingField { field: String },
44
45    #[error("Network error: {details}")]
46    NetworkError { details: String },
47
48    #[error("Timeout: {operation}")]
49    Timeout { operation: String },
50}
51
52impl CliError {
53    /// Get a user-friendly error message with suggestions and documentation links
54    pub fn user_message(&self) -> String {
55        match self {
56            CliError::CommandNotFound {
57                command,
58                suggestion,
59            } => {
60                format!(
61                    "āŒ Command '{}' not found.\n\nšŸ’” Did you mean: {}\n\nšŸ“š Run 'rice help' for available commands.\nšŸ“– Documentation: https://ricecoder.dev/docs/commands",
62                    command, suggestion
63                )
64            }
65            CliError::InvalidArgument { message } => {
66                format!(
67                    "āŒ Invalid argument: {}\n\nšŸ’” Suggestion: Check the argument syntax and try again.\n\nšŸ“š Run 'rice help' for usage information.\nšŸ“– Documentation: https://ricecoder.dev/docs/cli-usage",
68                    message
69                )
70            }
71            CliError::Io(e) => {
72                let suggestion = match e.kind() {
73                    std::io::ErrorKind::NotFound => {
74                        "šŸ’” Suggestion: Check that the file or directory exists.\nšŸ“– Documentation: https://ricecoder.dev/docs/file-operations"
75                    }
76                    std::io::ErrorKind::PermissionDenied => {
77                        "šŸ’” Suggestion: Check file permissions or run with appropriate privileges.\nšŸ“– Documentation: https://ricecoder.dev/docs/permissions"
78                    }
79                    _ => {
80                        "šŸ’” Suggestion: Check your file system and try again.\nšŸ“– Documentation: https://ricecoder.dev/docs/troubleshooting"
81                    }
82                };
83                format!(
84                    "āŒ File operation failed: {}\n\n{}\n\nšŸ”§ Technical details: {}",
85                    e, suggestion, e
86                )
87            }
88            CliError::Config(msg) => {
89                format!(
90                    "āŒ Configuration error: {}\n\nšŸ’” Suggestion: Run 'rice config' to check your configuration.\n\nšŸ“š Common issues:\n  • Missing RICECODER_HOME environment variable\n  • Invalid configuration file format\n  • Missing required configuration fields\n\nšŸ“– Documentation: https://ricecoder.dev/docs/configuration",
91                    msg
92                )
93            }
94            CliError::Provider(msg) => {
95                format!(
96                    "āŒ Provider error: {}\n\nšŸ’” Suggestion: Check your provider configuration with 'rice config'.\n\nšŸ“š Common issues:\n  • Invalid API key\n  • Provider service unavailable\n  • Network connectivity issues\n\nšŸ“– Documentation: https://ricecoder.dev/docs/providers",
97                    msg
98                )
99            }
100            CliError::Generation(msg) => {
101                format!(
102                    "āŒ Code generation failed: {}\n\nšŸ’” Suggestion: Check your specification and try again.\n\nšŸ“š Common issues:\n  • Invalid specification format\n  • Missing required fields in specification\n  • Provider rate limit exceeded\n\nšŸ“– Documentation: https://ricecoder.dev/docs/generation",
103                    msg
104                )
105            }
106            CliError::Storage(msg) => {
107                format!(
108                    "āŒ Storage error: {}\n\nšŸ’” Suggestion: Check your storage configuration.\n\nšŸ“š Common issues:\n  • Insufficient disk space\n  • Invalid storage path\n  • Permission issues\n\nšŸ“– Documentation: https://ricecoder.dev/docs/storage",
109                    msg
110                )
111            }
112            CliError::Internal(msg) => {
113                format!(
114                    "āŒ Internal error: {}\n\nšŸ’” This is unexpected. Please report this issue.\n\nšŸ“š How to report:\n  1. Run 'rice --verbose' to get more details\n  2. Include the output in your bug report\n  3. Visit: https://github.com/ricecoder/ricecoder/issues\n\nšŸ“– Documentation: https://ricecoder.dev/docs/troubleshooting",
115                    msg
116                )
117            }
118            CliError::FileNotFound { path } => {
119                format!(
120                    "āŒ File not found: {}\n\nšŸ’” Suggestion: Check that the file exists and the path is correct.\n\nšŸ“š Common issues:\n  • Typo in file path\n  • File was deleted or moved\n  • Relative path is incorrect\n\nšŸ“– Documentation: https://ricecoder.dev/docs/file-operations",
121                    path
122                )
123            }
124            CliError::PermissionDenied { path } => {
125                format!(
126                    "āŒ Permission denied: {}\n\nšŸ’” Suggestion: Check file permissions or run with appropriate privileges.\n\nšŸ“š To fix:\n  • Check file ownership: ls -l {}\n  • Change permissions: chmod u+r {}\n  • Or run with sudo (not recommended)\n\nšŸ“– Documentation: https://ricecoder.dev/docs/permissions",
127                    path, path, path
128                )
129            }
130            CliError::InvalidConfigFormat { details } => {
131                format!(
132                    "āŒ Invalid configuration format: {}\n\nšŸ’” Suggestion: Check your configuration file syntax.\n\nšŸ“š Supported formats:\n  • YAML (.yaml, .yml)\n  • TOML (.toml)\n  • JSON (.json)\n\nšŸ“– Documentation: https://ricecoder.dev/docs/configuration-format",
133                    details
134                )
135            }
136            CliError::MissingField { field } => {
137                format!(
138                    "āŒ Missing required field: {}\n\nšŸ’” Suggestion: Add the missing field to your configuration.\n\nšŸ“š Required fields depend on your use case.\n\nšŸ“– Documentation: https://ricecoder.dev/docs/configuration-reference",
139                    field
140                )
141            }
142            CliError::NetworkError { details } => {
143                format!(
144                    "āŒ Network error: {}\n\nšŸ’” Suggestion: Check your internet connection and try again.\n\nšŸ“š Common issues:\n  • No internet connection\n  • Firewall blocking the connection\n  • Provider service is down\n\nšŸ“– Documentation: https://ricecoder.dev/docs/network-troubleshooting",
145                    details
146                )
147            }
148            CliError::Timeout { operation } => {
149                format!(
150                    "āŒ Timeout: {} took too long\n\nšŸ’” Suggestion: Try again or increase the timeout.\n\nšŸ“š Common issues:\n  • Slow internet connection\n  • Provider service is slow\n  • Large input data\n\nšŸ“– Documentation: https://ricecoder.dev/docs/performance",
151                    operation
152                )
153            }
154        }
155    }
156
157    /// Get technical details for verbose mode
158    pub fn technical_details(&self) -> String {
159        format!("{:?}", self)
160    }
161
162    /// Get a short error message (for inline display)
163    pub fn short_message(&self) -> String {
164        match self {
165            CliError::CommandNotFound { command, .. } => {
166                format!("Command '{}' not found", command)
167            }
168            CliError::InvalidArgument { message } => {
169                format!("Invalid argument: {}", message)
170            }
171            CliError::Io(e) => format!("File operation failed: {}", e),
172            CliError::Config(msg) => format!("Configuration error: {}", msg),
173            CliError::Provider(msg) => format!("Provider error: {}", msg),
174            CliError::Generation(msg) => format!("Generation failed: {}", msg),
175            CliError::Storage(msg) => format!("Storage error: {}", msg),
176            CliError::Internal(msg) => format!("Internal error: {}", msg),
177            CliError::FileNotFound { path } => format!("File not found: {}", path),
178            CliError::PermissionDenied { path } => format!("Permission denied: {}", path),
179            CliError::InvalidConfigFormat { details } => {
180                format!("Invalid config format: {}", details)
181            }
182            CliError::MissingField { field } => format!("Missing field: {}", field),
183            CliError::NetworkError { details } => format!("Network error: {}", details),
184            CliError::Timeout { operation } => format!("Timeout: {}", operation),
185        }
186    }
187
188    /// Get actionable suggestions for this error
189    pub fn suggestions(&self) -> Vec<String> {
190        match self {
191            CliError::CommandNotFound { .. } => vec![
192                "Run 'rice help' to see available commands".to_string(),
193                "Check the command spelling".to_string(),
194            ],
195            CliError::InvalidArgument { .. } => vec![
196                "Check the argument syntax".to_string(),
197                "Run 'rice help <command>' for usage".to_string(),
198            ],
199            CliError::Config(_) => vec![
200                "Run 'rice config' to check configuration".to_string(),
201                "Check RICECODER_HOME environment variable".to_string(),
202                "Verify configuration file format".to_string(),
203            ],
204            CliError::Provider(_) => vec![
205                "Check provider API key".to_string(),
206                "Verify provider is available".to_string(),
207                "Check network connectivity".to_string(),
208            ],
209            CliError::FileNotFound { .. } => vec![
210                "Check file path spelling".to_string(),
211                "Verify file exists".to_string(),
212                "Use absolute path if relative path fails".to_string(),
213            ],
214            CliError::PermissionDenied { .. } => vec![
215                "Check file permissions".to_string(),
216                "Run with appropriate privileges".to_string(),
217            ],
218            CliError::NetworkError { .. } => vec![
219                "Check internet connection".to_string(),
220                "Check firewall settings".to_string(),
221                "Try again later if service is down".to_string(),
222            ],
223            CliError::Timeout { .. } => vec![
224                "Try again".to_string(),
225                "Check internet speed".to_string(),
226                "Increase timeout if available".to_string(),
227            ],
228            _ => vec!["Check documentation for more details".to_string()],
229        }
230    }
231}
232
233pub type CliResult<T> = Result<T, CliError>;