1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, Default)]
5pub enum OutputFormat {
6 #[default]
8 Text,
9 Json,
11 StreamJson,
13}
14
15impl OutputFormat {
16 pub(crate) fn as_arg(&self) -> &'static str {
17 match self {
18 Self::Text => "text",
19 Self::Json => "json",
20 Self::StreamJson => "stream-json",
21 }
22 }
23}
24
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub enum PermissionMode {
29 #[default]
31 Default,
32 AcceptEdits,
34 BypassPermissions,
36 DontAsk,
38 Plan,
40 Auto,
42}
43
44impl PermissionMode {
45 pub(crate) fn as_arg(&self) -> &'static str {
46 match self {
47 Self::Default => "default",
48 Self::AcceptEdits => "acceptEdits",
49 Self::BypassPermissions => "bypassPermissions",
50 Self::DontAsk => "dontAsk",
51 Self::Plan => "plan",
52 Self::Auto => "auto",
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, Default)]
59pub enum InputFormat {
60 #[default]
62 Text,
63 StreamJson,
65}
66
67impl InputFormat {
68 pub(crate) fn as_arg(&self) -> &'static str {
69 match self {
70 Self::Text => "text",
71 Self::StreamJson => "stream-json",
72 }
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "lowercase")]
79pub enum Effort {
80 Low,
82 Medium,
84 High,
86 Max,
88}
89
90impl Effort {
91 pub(crate) fn as_arg(&self) -> &'static str {
92 match self {
93 Self::Low => "low",
94 Self::Medium => "medium",
95 Self::High => "high",
96 Self::Max => "max",
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy, Default)]
103pub enum Scope {
104 #[default]
106 Local,
107 User,
109 Project,
111}
112
113impl Scope {
114 pub(crate) fn as_arg(&self) -> &'static str {
115 match self {
116 Self::Local => "local",
117 Self::User => "user",
118 Self::Project => "project",
119 }
120 }
121}
122
123#[cfg(feature = "json")]
140#[derive(Debug, Clone, Deserialize, Serialize)]
141#[serde(rename_all = "camelCase")]
142pub struct AuthStatus {
143 #[serde(default)]
145 pub logged_in: bool,
146 #[serde(default)]
148 pub auth_method: Option<String>,
149 #[serde(default)]
151 pub api_provider: Option<String>,
152 #[serde(default)]
154 pub email: Option<String>,
155 #[serde(default)]
157 pub org_id: Option<String>,
158 #[serde(default)]
160 pub org_name: Option<String>,
161 #[serde(default)]
163 pub subscription_type: Option<String>,
164 #[serde(flatten)]
166 pub extra: std::collections::HashMap<String, serde_json::Value>,
167}
168
169#[cfg(feature = "json")]
171#[derive(Debug, Clone, Deserialize, Serialize)]
172pub struct QueryMessage {
173 #[serde(default)]
174 pub role: String,
175 #[serde(default)]
176 pub content: serde_json::Value,
177 #[serde(flatten)]
178 pub extra: std::collections::HashMap<String, serde_json::Value>,
179}
180
181#[cfg(feature = "json")]
183#[derive(Debug, Clone, Deserialize, Serialize)]
184pub struct QueryResult {
185 #[serde(default)]
186 pub result: String,
187 #[serde(default)]
188 pub session_id: String,
189 #[serde(default, rename = "total_cost_usd", alias = "cost_usd")]
190 pub cost_usd: Option<f64>,
191 #[serde(default)]
192 pub duration_ms: Option<u64>,
193 #[serde(default)]
194 pub num_turns: Option<u32>,
195 #[serde(default)]
196 pub is_error: bool,
197 #[serde(flatten)]
198 pub extra: std::collections::HashMap<String, serde_json::Value>,
199}
200
201#[cfg(all(test, feature = "json"))]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn query_result_deserializes_total_cost_usd() {
207 let json =
208 r#"{"result":"hello","session_id":"s1","total_cost_usd":0.042,"is_error":false}"#;
209 let qr: QueryResult = serde_json::from_str(json).unwrap();
210 assert_eq!(qr.cost_usd, Some(0.042));
211 }
212
213 #[test]
214 fn query_result_deserializes_cost_usd_alias() {
215 let json = r#"{"result":"hello","session_id":"s1","cost_usd":0.01,"is_error":false}"#;
216 let qr: QueryResult = serde_json::from_str(json).unwrap();
217 assert_eq!(qr.cost_usd, Some(0.01));
218 }
219
220 #[test]
221 fn query_result_missing_cost_defaults_to_none() {
222 let json = r#"{"result":"hello","session_id":"s1","is_error":false}"#;
223 let qr: QueryResult = serde_json::from_str(json).unwrap();
224 assert_eq!(qr.cost_usd, None);
225 }
226
227 #[test]
228 fn query_result_deserializes_num_turns() {
229 let json = r#"{"result":"done","session_id":"s2","total_cost_usd":0.1,"num_turns":5,"is_error":false}"#;
230 let qr: QueryResult = serde_json::from_str(json).unwrap();
231 assert_eq!(qr.num_turns, Some(5));
232 assert_eq!(qr.cost_usd, Some(0.1));
233 }
234
235 #[test]
236 fn query_result_serializes_as_total_cost_usd() {
237 let qr = QueryResult {
238 result: "ok".into(),
239 session_id: "s1".into(),
240 cost_usd: Some(0.05),
241 duration_ms: None,
242 num_turns: Some(3),
243 is_error: false,
244 extra: Default::default(),
245 };
246 let json = serde_json::to_string(&qr).unwrap();
247 assert!(json.contains("\"total_cost_usd\""));
248 assert!(json.contains("\"num_turns\""));
249 }
250}