1use thiserror::Error;
5
6#[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 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 pub fn technical_details(&self) -> String {
159 format!("{:?}", self)
160 }
161
162 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 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>;