1use std::path::PathBuf;
2
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum XurlError {
7 #[error("invalid uri: {0}")]
8 InvalidUri(String),
9
10 #[error("unsupported scheme: {0}")]
11 UnsupportedScheme(String),
12
13 #[error("invalid skills uri: {0}")]
14 InvalidSkillsUri(String),
15
16 #[error("unsupported skills host: {0}")]
17 UnsupportedSkillsHost(String),
18
19 #[error("invalid session id: {0}")]
20 InvalidSessionId(String),
21
22 #[error("invalid mode: {0}")]
23 InvalidMode(String),
24
25 #[error("provider does not support subagent queries: {0}")]
26 UnsupportedSubagentProvider(String),
27
28 #[error("provider does not support write mode: {0}")]
29 UnsupportedProviderWrite(String),
30
31 #[error("command not found: {command}")]
32 CommandNotFound { command: String },
33
34 #[error("command failed: {command} (exit code: {code:?}): {stderr}")]
35 CommandFailed {
36 command: String,
37 code: Option<i32>,
38 stderr: String,
39 },
40
41 #[error("write protocol error: {0}")]
42 WriteProtocol(String),
43
44 #[error("serialization error: {0}")]
45 Serialization(String),
46
47 #[error("cannot determine home directory")]
48 HomeDirectoryNotFound,
49
50 #[error("thread not found for provider={provider} session_id={session_id}")]
51 ThreadNotFound {
52 provider: String,
53 session_id: String,
54 searched_roots: Vec<PathBuf>,
55 },
56
57 #[error("skill not found for uri={uri}")]
58 SkillNotFound { uri: String },
59
60 #[error("multiple skills matched for uri={uri}; choose one of: {candidates:?}")]
61 SkillSelectionRequired {
62 uri: String,
63 candidates: Vec<String>,
64 },
65
66 #[error("skill file is empty: {path}")]
67 EmptySkillFile { path: PathBuf },
68
69 #[error("skill file is not valid UTF-8: {path}")]
70 NonUtf8SkillFile { path: PathBuf },
71
72 #[error("git command failed: {command} (exit code: {code:?}): {stderr}")]
73 GitCommandFailed {
74 command: String,
75 code: Option<i32>,
76 stderr: String,
77 },
78
79 #[error("entry not found for provider={provider} session_id={session_id} entry_id={entry_id}")]
80 EntryNotFound {
81 provider: String,
82 session_id: String,
83 entry_id: String,
84 },
85
86 #[error("thread file is empty: {path}")]
87 EmptyThreadFile { path: PathBuf },
88
89 #[error("thread file is not valid UTF-8: {path}")]
90 NonUtf8ThreadFile { path: PathBuf },
91
92 #[error("i/o error on {path}: {source}")]
93 Io {
94 path: PathBuf,
95 #[source]
96 source: std::io::Error,
97 },
98
99 #[error("sqlite error on {path}: {source}")]
100 Sqlite {
101 path: PathBuf,
102 #[source]
103 source: rusqlite::Error,
104 },
105
106 #[error("invalid json line in {path} at line {line}: {source}")]
107 InvalidJsonLine {
108 path: PathBuf,
109 line: usize,
110 #[source]
111 source: serde_json::Error,
112 },
113}
114
115pub type Result<T> = std::result::Result<T, XurlError>;