1use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12use crate::{
13 ContentBlock, ExtNotification, ExtResponse, Plan, SessionId, SessionModeId, ToolCall,
14 ToolCallUpdate, ext::ExtRequest,
15};
16
17#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
25#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
26#[serde(rename_all = "camelCase")]
27#[non_exhaustive]
28pub struct SessionNotification {
29 pub session_id: SessionId,
31 pub update: SessionUpdate,
33 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
35 pub meta: Option<serde_json::Value>,
36}
37
38impl SessionNotification {
39 #[must_use]
40 pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
41 Self {
42 session_id: session_id.into(),
43 update,
44 meta: None,
45 }
46 }
47
48 #[must_use]
50 pub fn meta(mut self, meta: serde_json::Value) -> Self {
51 self.meta = Some(meta);
52 self
53 }
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
62#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
63#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
64#[non_exhaustive]
65pub enum SessionUpdate {
66 UserMessageChunk(ContentChunk),
68 AgentMessageChunk(ContentChunk),
70 AgentThoughtChunk(ContentChunk),
72 ToolCall(ToolCall),
74 ToolCallUpdate(ToolCallUpdate),
76 Plan(Plan),
79 AvailableCommandsUpdate(AvailableCommandsUpdate),
81 CurrentModeUpdate(CurrentModeUpdate),
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
91#[serde(rename_all = "camelCase")]
92#[non_exhaustive]
93pub struct CurrentModeUpdate {
94 pub current_mode_id: SessionModeId,
96 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
98 pub meta: Option<serde_json::Value>,
99}
100
101impl CurrentModeUpdate {
102 #[must_use]
103 pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
104 Self {
105 current_mode_id: current_mode_id.into(),
106 meta: None,
107 }
108 }
109
110 #[must_use]
112 pub fn meta(mut self, meta: serde_json::Value) -> Self {
113 self.meta = Some(meta);
114 self
115 }
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
120#[serde(rename_all = "camelCase")]
121#[non_exhaustive]
122pub struct ContentChunk {
123 pub content: ContentBlock,
125 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
127 pub meta: Option<serde_json::Value>,
128}
129
130impl ContentChunk {
131 #[must_use]
132 pub fn new(content: ContentBlock) -> Self {
133 Self {
134 content,
135 meta: None,
136 }
137 }
138
139 #[must_use]
141 pub fn meta(mut self, meta: serde_json::Value) -> Self {
142 self.meta = Some(meta);
143 self
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
149#[serde(rename_all = "camelCase")]
150#[non_exhaustive]
151pub struct AvailableCommandsUpdate {
152 pub available_commands: Vec<AvailableCommand>,
154 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
156 pub meta: Option<serde_json::Value>,
157}
158
159impl AvailableCommandsUpdate {
160 #[must_use]
161 pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
162 Self {
163 available_commands,
164 meta: None,
165 }
166 }
167
168 #[must_use]
170 pub fn meta(mut self, meta: serde_json::Value) -> Self {
171 self.meta = Some(meta);
172 self
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
178#[serde(rename_all = "camelCase")]
179#[non_exhaustive]
180pub struct AvailableCommand {
181 pub name: String,
183 pub description: String,
185 pub input: Option<AvailableCommandInput>,
187 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
189 pub meta: Option<serde_json::Value>,
190}
191
192impl AvailableCommand {
193 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
194 Self {
195 name: name.into(),
196 description: description.into(),
197 input: None,
198 meta: None,
199 }
200 }
201
202 #[must_use]
204 pub fn input(mut self, input: AvailableCommandInput) -> Self {
205 self.input = Some(input);
206 self
207 }
208
209 #[must_use]
211 pub fn meta(mut self, meta: serde_json::Value) -> Self {
212 self.meta = Some(meta);
213 self
214 }
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
219#[serde(untagged, rename_all = "camelCase")]
220#[non_exhaustive]
221pub enum AvailableCommandInput {
222 Unstructured(UnstructuredCommandInput),
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
228#[serde(rename_all = "camelCase")]
229#[non_exhaustive]
230pub struct UnstructuredCommandInput {
231 pub hint: String,
233 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
235 pub meta: Option<serde_json::Value>,
236}
237
238impl UnstructuredCommandInput {
239 pub fn new(hint: impl Into<String>) -> Self {
240 Self {
241 hint: hint.into(),
242 meta: None,
243 }
244 }
245
246 #[must_use]
248 pub fn meta(mut self, meta: serde_json::Value) -> Self {
249 self.meta = Some(meta);
250 self
251 }
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
262#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
263#[serde(rename_all = "camelCase")]
264#[non_exhaustive]
265pub struct RequestPermissionRequest {
266 pub session_id: SessionId,
268 pub tool_call: ToolCallUpdate,
270 pub options: Vec<PermissionOption>,
272 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
274 pub meta: Option<serde_json::Value>,
275}
276
277impl RequestPermissionRequest {
278 #[must_use]
279 pub fn new(
280 session_id: SessionId,
281 tool_call: ToolCallUpdate,
282 options: Vec<PermissionOption>,
283 ) -> Self {
284 Self {
285 session_id,
286 tool_call,
287 options,
288 meta: None,
289 }
290 }
291
292 #[must_use]
294 pub fn meta(mut self, meta: serde_json::Value) -> Self {
295 self.meta = Some(meta);
296 self
297 }
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
302#[serde(rename_all = "camelCase")]
303#[non_exhaustive]
304pub struct PermissionOption {
305 pub option_id: PermissionOptionId,
307 pub name: String,
309 pub kind: PermissionOptionKind,
311 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
313 pub meta: Option<serde_json::Value>,
314}
315
316impl PermissionOption {
317 pub fn new(
318 option_id: PermissionOptionId,
319 name: impl Into<String>,
320 kind: PermissionOptionKind,
321 ) -> Self {
322 Self {
323 option_id,
324 name: name.into(),
325 kind,
326 meta: None,
327 }
328 }
329
330 #[must_use]
332 pub fn meta(mut self, meta: serde_json::Value) -> Self {
333 self.meta = Some(meta);
334 self
335 }
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
340#[serde(transparent)]
341#[from(Arc<str>, String, &'static str)]
342#[non_exhaustive]
343pub struct PermissionOptionId(pub Arc<str>);
344
345impl PermissionOptionId {
346 pub fn new(id: impl Into<Arc<str>>) -> Self {
347 Self(id.into())
348 }
349}
350
351#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
355#[serde(rename_all = "snake_case")]
356#[non_exhaustive]
357pub enum PermissionOptionKind {
358 AllowOnce,
360 AllowAlways,
362 RejectOnce,
364 RejectAlways,
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
370#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
371#[serde(rename_all = "camelCase")]
372#[non_exhaustive]
373pub struct RequestPermissionResponse {
374 pub outcome: RequestPermissionOutcome,
377 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
379 pub meta: Option<serde_json::Value>,
380}
381
382impl RequestPermissionResponse {
383 #[must_use]
384 pub fn new(outcome: RequestPermissionOutcome) -> Self {
385 Self {
386 outcome,
387 meta: None,
388 }
389 }
390
391 #[must_use]
393 pub fn meta(mut self, meta: serde_json::Value) -> Self {
394 self.meta = Some(meta);
395 self
396 }
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
401#[serde(tag = "outcome", rename_all = "snake_case")]
402#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
403#[non_exhaustive]
404pub enum RequestPermissionOutcome {
405 Cancelled,
413 #[serde(rename_all = "camelCase")]
415 Selected(SelectedPermissionOutcome),
416}
417
418#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
420#[serde(rename_all = "camelCase")]
421#[non_exhaustive]
422pub struct SelectedPermissionOutcome {
423 pub option_id: PermissionOptionId,
425 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
427 pub meta: Option<serde_json::Value>,
428}
429
430impl SelectedPermissionOutcome {
431 #[must_use]
432 pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
433 Self {
434 option_id: option_id.into(),
435 meta: None,
436 }
437 }
438
439 #[must_use]
441 pub fn meta(mut self, meta: serde_json::Value) -> Self {
442 self.meta = Some(meta);
443 self
444 }
445}
446
447#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
453#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
454#[serde(rename_all = "camelCase")]
455#[non_exhaustive]
456pub struct WriteTextFileRequest {
457 pub session_id: SessionId,
459 pub path: PathBuf,
461 pub content: String,
463 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
465 pub meta: Option<serde_json::Value>,
466}
467
468impl WriteTextFileRequest {
469 pub fn new(
470 session_id: SessionId,
471 path: impl Into<PathBuf>,
472 content: impl Into<String>,
473 ) -> Self {
474 Self {
475 session_id,
476 path: path.into(),
477 content: content.into(),
478 meta: None,
479 }
480 }
481
482 #[must_use]
484 pub fn meta(mut self, meta: serde_json::Value) -> Self {
485 self.meta = Some(meta);
486 self
487 }
488}
489
490#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
492#[serde(default, rename_all = "camelCase")]
493#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
494#[non_exhaustive]
495pub struct WriteTextFileResponse {
496 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
498 pub meta: Option<serde_json::Value>,
499}
500
501impl WriteTextFileResponse {
502 #[must_use]
503 pub fn new() -> Self {
504 Self::default()
505 }
506
507 #[must_use]
509 pub fn meta(mut self, meta: serde_json::Value) -> Self {
510 self.meta = Some(meta);
511 self
512 }
513}
514
515#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
521#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
522#[serde(rename_all = "camelCase")]
523#[non_exhaustive]
524pub struct ReadTextFileRequest {
525 pub session_id: SessionId,
527 pub path: PathBuf,
529 #[serde(skip_serializing_if = "Option::is_none")]
531 pub line: Option<u32>,
532 #[serde(skip_serializing_if = "Option::is_none")]
534 pub limit: Option<u32>,
535 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
537 pub meta: Option<serde_json::Value>,
538}
539
540impl ReadTextFileRequest {
541 pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
542 Self {
543 session_id: session_id.into(),
544 path: path.into(),
545 line: None,
546 limit: None,
547 meta: None,
548 }
549 }
550
551 #[must_use]
553 pub fn line(mut self, line: u32) -> Self {
554 self.line = Some(line);
555 self
556 }
557
558 #[must_use]
560 pub fn limit(mut self, limit: u32) -> Self {
561 self.limit = Some(limit);
562 self
563 }
564
565 #[must_use]
567 pub fn meta(mut self, meta: serde_json::Value) -> Self {
568 self.meta = Some(meta);
569 self
570 }
571}
572
573#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
575#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
576#[serde(rename_all = "camelCase")]
577#[non_exhaustive]
578pub struct ReadTextFileResponse {
579 pub content: String,
580 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
582 pub meta: Option<serde_json::Value>,
583}
584
585impl ReadTextFileResponse {
586 pub fn new(content: impl Into<String>) -> Self {
587 Self {
588 content: content.into(),
589 meta: None,
590 }
591 }
592
593 #[must_use]
595 pub fn meta(mut self, meta: serde_json::Value) -> Self {
596 self.meta = Some(meta);
597 self
598 }
599}
600
601#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
604#[serde(transparent)]
605#[from(Arc<str>, String, &'static str)]
606#[non_exhaustive]
607pub struct TerminalId(pub Arc<str>);
608
609impl TerminalId {
610 pub fn new(id: impl Into<Arc<str>>) -> Self {
611 Self(id.into())
612 }
613}
614
615#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
617#[serde(rename_all = "camelCase")]
618#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
619#[non_exhaustive]
620pub struct CreateTerminalRequest {
621 pub session_id: SessionId,
623 pub command: String,
625 #[serde(default, skip_serializing_if = "Vec::is_empty")]
627 pub args: Vec<String>,
628 #[serde(default, skip_serializing_if = "Vec::is_empty")]
630 pub env: Vec<crate::EnvVariable>,
631 #[serde(skip_serializing_if = "Option::is_none")]
633 pub cwd: Option<PathBuf>,
634 #[serde(skip_serializing_if = "Option::is_none")]
643 pub output_byte_limit: Option<u64>,
644 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
646 pub meta: Option<serde_json::Value>,
647}
648
649impl CreateTerminalRequest {
650 pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
651 Self {
652 session_id: session_id.into(),
653 command: command.into(),
654 args: Vec::new(),
655 env: Vec::new(),
656 cwd: None,
657 output_byte_limit: None,
658 meta: None,
659 }
660 }
661
662 #[must_use]
664 pub fn args(mut self, args: Vec<String>) -> Self {
665 self.args = args;
666 self
667 }
668
669 #[must_use]
671 pub fn env(mut self, env: Vec<crate::EnvVariable>) -> Self {
672 self.env = env;
673 self
674 }
675
676 #[must_use]
678 pub fn cwd(mut self, cwd: impl Into<PathBuf>) -> Self {
679 self.cwd = Some(cwd.into());
680 self
681 }
682
683 #[must_use]
692 pub fn output_byte_limit(mut self, output_byte_limit: u64) -> Self {
693 self.output_byte_limit = Some(output_byte_limit);
694 self
695 }
696
697 #[must_use]
699 pub fn meta(mut self, meta: serde_json::Value) -> Self {
700 self.meta = Some(meta);
701 self
702 }
703}
704
705#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
707#[serde(rename_all = "camelCase")]
708#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
709#[non_exhaustive]
710pub struct CreateTerminalResponse {
711 pub terminal_id: TerminalId,
713 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
715 pub meta: Option<serde_json::Value>,
716}
717
718impl CreateTerminalResponse {
719 #[must_use]
720 pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
721 Self {
722 terminal_id: terminal_id.into(),
723 meta: None,
724 }
725 }
726
727 #[must_use]
729 pub fn meta(mut self, meta: serde_json::Value) -> Self {
730 self.meta = Some(meta);
731 self
732 }
733}
734
735#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
737#[serde(rename_all = "camelCase")]
738#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
739#[non_exhaustive]
740pub struct TerminalOutputRequest {
741 pub session_id: SessionId,
743 pub terminal_id: TerminalId,
745 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
747 pub meta: Option<serde_json::Value>,
748}
749
750impl TerminalOutputRequest {
751 #[must_use]
752 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
753 Self {
754 session_id: session_id.into(),
755 terminal_id: terminal_id.into(),
756 meta: None,
757 }
758 }
759
760 #[must_use]
762 pub fn meta(mut self, meta: serde_json::Value) -> Self {
763 self.meta = Some(meta);
764 self
765 }
766}
767
768#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
770#[serde(rename_all = "camelCase")]
771#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
772#[non_exhaustive]
773pub struct TerminalOutputResponse {
774 pub output: String,
776 pub truncated: bool,
778 pub exit_status: Option<TerminalExitStatus>,
780 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
782 pub meta: Option<serde_json::Value>,
783}
784
785impl TerminalOutputResponse {
786 pub fn new(output: impl Into<String>, truncated: bool) -> Self {
787 Self {
788 output: output.into(),
789 truncated,
790 exit_status: None,
791 meta: None,
792 }
793 }
794
795 #[must_use]
797 pub fn exit_status(mut self, exit_status: TerminalExitStatus) -> Self {
798 self.exit_status = Some(exit_status);
799 self
800 }
801
802 #[must_use]
804 pub fn meta(mut self, meta: serde_json::Value) -> Self {
805 self.meta = Some(meta);
806 self
807 }
808}
809
810#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
812#[serde(rename_all = "camelCase")]
813#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
814#[non_exhaustive]
815pub struct ReleaseTerminalRequest {
816 pub session_id: SessionId,
818 pub terminal_id: TerminalId,
820 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
822 pub meta: Option<serde_json::Value>,
823}
824
825impl ReleaseTerminalRequest {
826 #[must_use]
827 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
828 Self {
829 session_id: session_id.into(),
830 terminal_id: terminal_id.into(),
831 meta: None,
832 }
833 }
834
835 #[must_use]
837 pub fn meta(mut self, meta: serde_json::Value) -> Self {
838 self.meta = Some(meta);
839 self
840 }
841}
842
843#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
845#[serde(rename_all = "camelCase")]
846#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
847#[non_exhaustive]
848pub struct ReleaseTerminalResponse {
849 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
851 pub meta: Option<serde_json::Value>,
852}
853
854impl ReleaseTerminalResponse {
855 #[must_use]
856 pub fn new() -> Self {
857 Self::default()
858 }
859
860 #[must_use]
862 pub fn meta(mut self, meta: serde_json::Value) -> Self {
863 self.meta = Some(meta);
864 self
865 }
866}
867
868#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
870#[serde(rename_all = "camelCase")]
871#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
872#[non_exhaustive]
873pub struct KillTerminalCommandRequest {
874 pub session_id: SessionId,
876 pub terminal_id: TerminalId,
878 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
880 pub meta: Option<serde_json::Value>,
881}
882
883impl KillTerminalCommandRequest {
884 #[must_use]
885 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
886 Self {
887 session_id: session_id.into(),
888 terminal_id: terminal_id.into(),
889 meta: None,
890 }
891 }
892
893 #[must_use]
895 pub fn meta(mut self, meta: serde_json::Value) -> Self {
896 self.meta = Some(meta);
897 self
898 }
899}
900
901#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
903#[serde(rename_all = "camelCase")]
904#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
905#[non_exhaustive]
906pub struct KillTerminalCommandResponse {
907 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
909 pub meta: Option<serde_json::Value>,
910}
911
912impl KillTerminalCommandResponse {
913 #[must_use]
914 pub fn new() -> Self {
915 Self::default()
916 }
917
918 #[must_use]
920 pub fn meta(mut self, meta: serde_json::Value) -> Self {
921 self.meta = Some(meta);
922 self
923 }
924}
925
926#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
928#[serde(rename_all = "camelCase")]
929#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
930#[non_exhaustive]
931pub struct WaitForTerminalExitRequest {
932 pub session_id: SessionId,
934 pub terminal_id: TerminalId,
936 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
938 pub meta: Option<serde_json::Value>,
939}
940
941impl WaitForTerminalExitRequest {
942 #[must_use]
943 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
944 Self {
945 session_id: session_id.into(),
946 terminal_id: terminal_id.into(),
947 meta: None,
948 }
949 }
950
951 #[must_use]
953 pub fn meta(mut self, meta: serde_json::Value) -> Self {
954 self.meta = Some(meta);
955 self
956 }
957}
958
959#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
961#[serde(rename_all = "camelCase")]
962#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
963#[non_exhaustive]
964pub struct WaitForTerminalExitResponse {
965 #[serde(flatten)]
967 pub exit_status: TerminalExitStatus,
968 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
970 pub meta: Option<serde_json::Value>,
971}
972
973impl WaitForTerminalExitResponse {
974 #[must_use]
975 pub fn new(exit_status: TerminalExitStatus) -> Self {
976 Self {
977 exit_status,
978 meta: None,
979 }
980 }
981
982 #[must_use]
984 pub fn meta(mut self, meta: serde_json::Value) -> Self {
985 self.meta = Some(meta);
986 self
987 }
988}
989
990#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
992#[serde(rename_all = "camelCase")]
993#[non_exhaustive]
994pub struct TerminalExitStatus {
995 pub exit_code: Option<u32>,
997 pub signal: Option<String>,
999 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1001 pub meta: Option<serde_json::Value>,
1002}
1003
1004impl TerminalExitStatus {
1005 #[must_use]
1006 pub fn new() -> Self {
1007 Self::default()
1008 }
1009
1010 #[must_use]
1012 pub fn exit_code(mut self, exit_code: u32) -> Self {
1013 self.exit_code = Some(exit_code);
1014 self
1015 }
1016
1017 #[must_use]
1019 pub fn signal(mut self, signal: impl Into<String>) -> Self {
1020 self.signal = Some(signal.into());
1021 self
1022 }
1023
1024 #[must_use]
1026 pub fn meta(mut self, meta: serde_json::Value) -> Self {
1027 self.meta = Some(meta);
1028 self
1029 }
1030}
1031
1032#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1041#[serde(rename_all = "camelCase")]
1042#[non_exhaustive]
1043pub struct ClientCapabilities {
1044 #[serde(default)]
1047 pub fs: FileSystemCapability,
1048 #[serde(default)]
1050 pub terminal: bool,
1051 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1053 pub meta: Option<serde_json::Value>,
1054}
1055
1056impl ClientCapabilities {
1057 #[must_use]
1058 pub fn new() -> Self {
1059 Self::default()
1060 }
1061
1062 #[must_use]
1065 pub fn fs(mut self, fs: FileSystemCapability) -> Self {
1066 self.fs = fs;
1067 self
1068 }
1069
1070 #[must_use]
1072 pub fn terminal(mut self, terminal: bool) -> Self {
1073 self.terminal = terminal;
1074 self
1075 }
1076
1077 #[must_use]
1079 pub fn meta(mut self, meta: serde_json::Value) -> Self {
1080 self.meta = Some(meta);
1081 self
1082 }
1083}
1084
1085#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1090#[serde(rename_all = "camelCase")]
1091#[non_exhaustive]
1092pub struct FileSystemCapability {
1093 #[serde(default)]
1095 pub read_text_file: bool,
1096 #[serde(default)]
1098 pub write_text_file: bool,
1099 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1101 pub meta: Option<serde_json::Value>,
1102}
1103
1104impl FileSystemCapability {
1105 #[must_use]
1106 pub fn new() -> Self {
1107 Self::default()
1108 }
1109
1110 #[must_use]
1112 pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1113 self.read_text_file = read_text_file;
1114 self
1115 }
1116
1117 #[must_use]
1119 pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1120 self.write_text_file = write_text_file;
1121 self
1122 }
1123
1124 #[must_use]
1126 pub fn meta(mut self, meta: serde_json::Value) -> Self {
1127 self.meta = Some(meta);
1128 self
1129 }
1130}
1131
1132#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1138#[non_exhaustive]
1139pub struct ClientMethodNames {
1140 pub session_request_permission: &'static str,
1142 pub session_update: &'static str,
1144 pub fs_write_text_file: &'static str,
1146 pub fs_read_text_file: &'static str,
1148 pub terminal_create: &'static str,
1150 pub terminal_output: &'static str,
1152 pub terminal_release: &'static str,
1154 pub terminal_wait_for_exit: &'static str,
1156 pub terminal_kill: &'static str,
1158}
1159
1160pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1162 session_update: SESSION_UPDATE_NOTIFICATION,
1163 session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1164 fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1165 fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1166 terminal_create: TERMINAL_CREATE_METHOD_NAME,
1167 terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1168 terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1169 terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1170 terminal_kill: TERMINAL_KILL_METHOD_NAME,
1171};
1172
1173pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1175pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1177pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1179pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1181pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1183pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1185pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1187pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1189pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1191
1192#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1199#[serde(untagged)]
1200#[schemars(inline)]
1201#[non_exhaustive]
1202pub enum AgentRequest {
1203 WriteTextFileRequest(WriteTextFileRequest),
1210 ReadTextFileRequest(ReadTextFileRequest),
1217 RequestPermissionRequest(RequestPermissionRequest),
1228 CreateTerminalRequest(CreateTerminalRequest),
1243 TerminalOutputRequest(TerminalOutputRequest),
1250 ReleaseTerminalRequest(ReleaseTerminalRequest),
1263 WaitForTerminalExitRequest(WaitForTerminalExitRequest),
1267 KillTerminalCommandRequest(KillTerminalCommandRequest),
1280 ExtMethodRequest(ExtRequest),
1288}
1289
1290impl AgentRequest {
1291 #[must_use]
1293 pub fn method(&self) -> &str {
1294 match self {
1295 Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
1296 Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
1297 Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
1298 Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
1299 Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
1300 Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
1301 Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
1302 Self::KillTerminalCommandRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
1303 Self::ExtMethodRequest(ext_request) => &ext_request.method,
1304 }
1305 }
1306}
1307
1308#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1315#[serde(untagged)]
1316#[schemars(inline)]
1317#[non_exhaustive]
1318pub enum ClientResponse {
1319 WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
1320 ReadTextFileResponse(ReadTextFileResponse),
1321 RequestPermissionResponse(RequestPermissionResponse),
1322 CreateTerminalResponse(CreateTerminalResponse),
1323 TerminalOutputResponse(TerminalOutputResponse),
1324 ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
1325 WaitForTerminalExitResponse(WaitForTerminalExitResponse),
1326 KillTerminalResponse(#[serde(default)] KillTerminalCommandResponse),
1327 ExtMethodResponse(ExtResponse),
1328}
1329
1330#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1337#[serde(untagged)]
1338#[expect(clippy::large_enum_variant)]
1339#[schemars(inline)]
1340#[non_exhaustive]
1341pub enum AgentNotification {
1342 SessionNotification(SessionNotification),
1354 ExtNotification(ExtNotification),
1362}
1363
1364impl AgentNotification {
1365 #[must_use]
1367 pub fn method(&self) -> &str {
1368 match self {
1369 Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
1370 Self::ExtNotification(ext_notification) => &ext_notification.method,
1371 }
1372 }
1373}