1use schemars::JsonSchema;
2use serde::{Deserialize, Deserializer, Serialize};
3
4#[derive(Debug, Clone, Deserialize)]
7#[serde(deny_unknown_fields)]
8pub struct OpenProjectRequest {
9 pub project_root: String,
10}
11
12#[derive(Debug, Clone, Deserialize, Serialize)]
13pub struct OpenProjectResponse {
14 pub status: String,
15 pub project_root: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub detected_lsp_language: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub lsp: Option<String>,
20}
21
22#[derive(Debug, Clone, Deserialize)]
23#[serde(deny_unknown_fields)]
24pub struct ReadCodeRequest {
25 pub path: String,
26 pub anchor: String,
27 pub mode: ReadCodeMode,
28}
29
30#[derive(Debug, Clone, Copy, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
31#[serde(rename_all = "lowercase")]
32pub enum ReadCodeMode {
33 Around,
34 Full,
35}
36
37#[derive(Debug, Clone, Deserialize, Serialize)]
38pub struct ReadCodeResponse {
39 pub content: String,
41}
42
43#[derive(Debug, Clone, Deserialize, Serialize)]
44pub struct SearchCodeResponse {
45 pub matches: Vec<SearchHit>,
46}
47
48#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
49pub struct SearchHit {
50 pub path: String,
51 pub hit: String,
52}
53
54#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
55#[serde(rename_all = "lowercase")]
56pub enum SearchMode {
57 #[default]
58 Literal,
59 Regex,
60}
61
62#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
63#[serde(rename_all = "lowercase")]
64pub enum SearchCase {
65 Sensitive,
66 Insensitive,
67 #[default]
68 Smart,
69}
70
71#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
72pub struct SearchCodeRequest {
73 pub query: String,
74 #[serde(default)]
75 pub mode: SearchMode,
76 pub path: Option<String>,
77 #[serde(default, deserialize_with = "deserialize_string_list")]
78 pub include: Vec<String>,
79 #[serde(default, deserialize_with = "deserialize_string_list")]
80 pub exclude: Vec<String>,
81 #[serde(default, deserialize_with = "deserialize_string_list")]
82 pub types: Vec<String>,
83 #[serde(default, deserialize_with = "deserialize_string_list")]
84 pub type_not: Vec<String>,
85 #[serde(default, rename = "case")]
86 pub case_mode: SearchCase,
87 #[serde(default)]
88 pub word: bool,
89 #[serde(default)]
90 pub line: bool,
91 #[serde(default)]
92 pub hidden: bool,
93 #[serde(default = "default_respect_ignore")]
94 pub respect_ignore: bool,
95 #[serde(default)]
96 pub follow: bool,
97 pub limit: Option<usize>,
98}
99
100impl Default for SearchCodeRequest {
101 fn default() -> Self {
102 Self {
103 query: String::new(),
104 mode: SearchMode::default(),
105 path: None,
106 include: Vec::new(),
107 exclude: Vec::new(),
108 types: Vec::new(),
109 type_not: Vec::new(),
110 case_mode: SearchCase::default(),
111 word: false,
112 line: false,
113 hidden: false,
114 respect_ignore: true,
115 follow: false,
116 limit: None,
117 }
118 }
119}
120
121fn default_respect_ignore() -> bool {
122 true
123}
124
125fn deserialize_string_list<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
126where
127 D: Deserializer<'de>,
128{
129 #[derive(Deserialize)]
130 #[serde(untagged)]
131 enum StringList {
132 One(String),
133 Many(Vec<String>),
134 }
135
136 let Some(value) = Option::<StringList>::deserialize(deserializer)? else {
137 return Ok(Vec::new());
138 };
139 Ok(match value {
140 StringList::One(value) => vec![value],
141 StringList::Many(values) => values,
142 })
143}
144
145#[derive(Debug, Clone, Deserialize)]
146pub struct EditCodeRequest {
147 pub edits: Vec<StructuredEdit>,
148}
149
150#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
152#[serde(rename_all = "lowercase")]
153pub enum EditOp {
154 Replace,
155 Append,
156 Prepend,
157}
158
159#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
161#[serde(untagged)]
162pub enum EditContent {
163 Lines(Vec<String>),
164 Text(String),
165}
166
167impl EditContent {
168 pub fn into_lines(self) -> Vec<String> {
169 match self {
170 EditContent::Lines(lines) => lines,
171 EditContent::Text(text) => text.lines().map(str::to_string).collect(),
172 }
173 }
174}
175
176#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
178pub struct StructuredEdit {
179 pub path: String,
181 pub op: EditOp,
182 pub start: String,
184 #[serde(skip_serializing_if = "Option::is_none")]
186 pub end: Option<String>,
187 #[serde(skip_serializing_if = "Option::is_none")]
190 pub content: Option<EditContent>,
191}
192
193#[derive(Debug, Clone, Deserialize)]
194pub struct IsResponsibleSourceRequest {
195 pub path: String,
196}
197
198#[derive(Debug, Clone, Deserialize, Serialize)]
199pub struct IsResponsibleSourceResponse {
200 pub is_responsible: bool,
201 pub path: String,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub extension: Option<String>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub language: Option<String>,
206 pub reason: String,
207}
208
209#[derive(Debug, Clone, Deserialize, Serialize)]
210pub struct ScopeUsageResponse {
211 pub usage_markdown: String,
212 pub protocol_items: Vec<ScopeProtocolItemSchema>,
213}
214
215#[derive(Debug, Clone, Deserialize, Serialize)]
216pub struct ScopeProtocolItemSchema {
217 pub item: String,
218 pub syntax: String,
219 pub notes: String,
220}
221
222#[derive(Debug, Clone, Serialize, PartialEq)]
225#[serde(rename_all = "snake_case")]
226pub enum PropagationSource {
227 Lsp,
228 OpenEnded,
229}
230
231#[derive(Debug, Clone, Serialize)]
232pub struct PropagationResponse {
233 pub propagation_results: Vec<PropagationResult>,
234 pub applied_summary: AppliedStructuredEditSummary,
235}
236
237#[derive(Debug, Clone, Serialize)]
238pub struct PropagationResult {
239 pub selector: String,
240 pub reason: String,
241 pub source: PropagationSource,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub lsp_references: Option<Vec<(String, usize, String)>>,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub diff_summary: Option<String>,
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub file_snippet: Option<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub project_files: Option<Vec<String>>,
250}
251
252#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
253#[serde(rename_all = "snake_case")]
254pub enum AppliedStructuredEditOperation {
255 Add,
256 Update,
257}
258
259#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
260pub struct AppliedStructuredEditFile {
261 pub path: String,
262 pub operation: AppliedStructuredEditOperation,
263 pub added_lines: usize,
264 pub removed_lines: usize,
265 pub original_content: String,
266 pub new_content: String,
267}
268
269#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
270pub struct AppliedStructuredEditSummary {
271 pub files: Vec<AppliedStructuredEditFile>,
272}
273
274#[derive(Debug, Clone, Serialize)]
275pub struct NextReviewResponse {
276 pub review: Option<ReviewEvent>,
277 pub reviews: Vec<ReviewEvent>,
278 pub returned: usize,
279 pub remaining: usize,
280}
281
282#[derive(Debug, Clone, Deserialize, Serialize)]
283pub struct NextReviewRequest {
284 pub limit: Option<usize>,
285}
286
287#[derive(Debug, Clone, Serialize)]
288pub struct Reference {
289 pub selector: String,
290 pub line: usize,
291 pub context: String,
292}
293
294#[derive(Debug, Clone, Serialize)]
295#[serde(tag = "type")]
296#[serde(rename_all = "snake_case")]
297pub enum ReviewEvent {
298 KnownReferences {
299 modified_symbol: String,
300 change_summary: String,
301 references: Vec<Reference>,
302 file_snippet: String,
303 },
304 InvestigateImpact {
305 modified_symbol: String,
306 change_summary: String,
307 diff_summary: String,
308 file_snippet: String,
309 project_files: Vec<String>,
310 },
311}