1use thiserror::Error;
2
3#[derive(Debug, Error)]
5pub enum RemoteError {
6 #[error("Git clone failed for {url}: {message}")]
8 CloneFailed { url: String, message: String },
9
10 #[error("Invalid repository URL: {0}")]
12 InvalidUrl(String),
13
14 #[error("Repository not found: {0}")]
16 NotFound(String),
17
18 #[error("Authentication required for private repository: {0}")]
20 AuthRequired(String),
21
22 #[error("GitHub rate limit exceeded, retry after {reset_at}")]
24 RateLimitExceeded { reset_at: String },
25
26 #[error("Network error: {0}")]
28 Network(#[from] std::io::Error),
29
30 #[error("HTTP error {status}: {message}")]
32 Http { status: u16, message: String },
33
34 #[error("Failed to parse awesome-claude-code: {0}")]
36 ParseError(String),
37
38 #[error("Temporary directory error: {0}")]
40 TempDir(String),
41
42 #[error("Git command not found. Please install git.")]
44 GitNotFound,
45
46 #[error("Clone timeout exceeded for {url} (timeout: {timeout_secs}s)")]
48 CloneTimeout { url: String, timeout_secs: u64 },
49
50 #[error("Repository too large: {url} (size: {size_mb}MB, limit: {limit_mb}MB)")]
52 RepositoryTooLarge {
53 url: String,
54 size_mb: u64,
55 limit_mb: u64,
56 },
57}
58
59impl RemoteError {
60 pub fn is_retryable(&self) -> bool {
62 matches!(
63 self,
64 RemoteError::RateLimitExceeded { .. }
65 | RemoteError::Network(_)
66 | RemoteError::CloneTimeout { .. }
67 )
68 }
69
70 pub fn is_auth_error(&self) -> bool {
72 matches!(self, RemoteError::AuthRequired(_))
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_clone_failed_error() {
82 let err = RemoteError::CloneFailed {
83 url: "https://github.com/user/repo".to_string(),
84 message: "Connection refused".to_string(),
85 };
86 assert!(err.to_string().contains("github.com/user/repo"));
87 assert!(err.to_string().contains("Connection refused"));
88 }
89
90 #[test]
91 fn test_is_retryable() {
92 assert!(
93 RemoteError::RateLimitExceeded {
94 reset_at: "2026-01-25T12:00:00Z".to_string()
95 }
96 .is_retryable()
97 );
98
99 assert!(
100 RemoteError::CloneTimeout {
101 url: "https://github.com/user/repo".to_string(),
102 timeout_secs: 60
103 }
104 .is_retryable()
105 );
106
107 assert!(!RemoteError::InvalidUrl("bad".to_string()).is_retryable());
108 assert!(!RemoteError::NotFound("repo".to_string()).is_retryable());
109 }
110
111 #[test]
112 fn test_is_auth_error() {
113 assert!(
114 RemoteError::AuthRequired("https://github.com/private/repo".to_string())
115 .is_auth_error()
116 );
117 assert!(!RemoteError::NotFound("repo".to_string()).is_auth_error());
118 }
119}