1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(deny_unknown_fields)]
6pub struct MailboxEventRequest {
7 pub key: String,
9 pub text: String,
11 #[serde(default)]
12 pub wake: bool,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(deny_unknown_fields)]
17pub struct MailboxEventResponse {
18 pub key: String,
19 pub inserted: bool,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26#[serde(deny_unknown_fields)]
27pub struct SessionMessageResponse {
28 pub session_id: String,
29 pub via: String,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub turn_id: Option<u64>,
32 #[serde(skip)]
35 pub(crate) managed_child: bool,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(deny_unknown_fields)]
41pub struct SessionMessageRequest {
42 pub request_id: String,
44 pub text: String,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub sender_session_id: Option<String>,
49}
50
51#[derive(Debug, Default)]
53pub struct GithubTokenQuery {
54 pub owner: Option<String>,
55 pub repo: Vec<String>,
56}
57
58#[derive(Debug, Serialize, Deserialize)]
61#[serde(deny_unknown_fields)]
62pub struct GithubTokenResponse {
63 pub token: String,
64}
65
66#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(deny_unknown_fields)]
69pub struct DiffOptions {
70 pub base: Option<String>,
71 #[serde(default)]
72 pub json: bool,
73}
74
75#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
77pub struct ApiBackgroundWork {
78 pub known: Option<bool>,
79 pub tasks: Vec<mj_core::relay::BackgroundCommand>,
80}
81
82impl From<&mj_core::relay::RelayOperationalState> for ApiBackgroundWork {
83 fn from(state: &mj_core::relay::RelayOperationalState) -> Self {
84 Self {
85 known: state.background_work_known,
86 tasks: state.background_commands.clone(),
87 }
88 }
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
95pub struct ApiSession {
96 #[serde(default)]
98 pub background_tasks: Vec<crate::server::ViewerBackgroundTask>,
99 #[serde(default, skip_serializing_if = "Option::is_none")]
100 pub assessment: Option<mj_core::assessment::Summary>,
101 #[serde(default)]
102 pub subagents: mj_core::subagent::SubagentPolicy,
103 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub at: Option<String>,
108 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub branch: Option<String>,
111 #[serde(default, skip_serializing_if = "Option::is_none")]
113 pub base: Option<String>,
114 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub background_work: Option<ApiBackgroundWork>,
116 pub id: String,
117 pub workspace_id: String,
118 pub title: String,
119 pub harness_kind: String,
120 pub profile_id: String,
121 pub target_id: String,
122 pub bundle_id: String,
123 pub state: String,
124 pub lifecycle: ViewerLifecycleCategory,
125 pub chat_phase: crate::server::ViewerChatPhase,
126 pub is_idle: bool,
127 #[serde(default, skip_serializing_if = "Option::is_none")]
132 pub activity_state: Option<mj_core::activity::ActivityState>,
133 pub has_error: bool,
134 #[serde(default, skip_serializing_if = "Option::is_none")]
139 pub error: Option<String>,
140 #[serde(default, skip_serializing_if = "Option::is_none")]
142 pub storage_problem: Option<String>,
143 pub created_at: String,
144 pub updated_at: String,
145 #[serde(default, skip_serializing_if = "Option::is_none")]
149 pub last_turn_outcome: Option<MaterializedTurnOutcome>,
150 #[serde(default, skip_serializing_if = "Option::is_none")]
151 pub last_turn_diagnostic: Option<mj_core::diagnostic::TurnDiagnostic>,
152 #[serde(default)]
153 pub config_options: Vec<crate::server::ViewerConfigOption>,
154 #[serde(default, skip_serializing_if = "Vec::is_empty")]
155 pub pending_elicitations: Vec<mj_core::elicitation::ElicitationRequest>,
156}
157
158impl From<&ViewerSession> for ApiSession {
159 fn from(session: &ViewerSession) -> Self {
160 Self {
161 background_tasks: session.background_tasks.clone(),
162 assessment: None,
163 subagents: session.subagents.clone(),
164 background_work: None,
165 at: session.at.clone(),
166 branch: session.branch.clone(),
167 base: session.base.clone(),
168 id: session.id.clone(),
169 workspace_id: session.workspace_id.clone(),
170 title: session.title.clone(),
171 harness_kind: session.harness_kind.clone(),
172 profile_id: session.profile_id.clone(),
173 target_id: session.target_id.clone(),
174 bundle_id: session.bundle_id.clone(),
175 state: session.state.clone(),
176 lifecycle: session.lifecycle,
177 chat_phase: session.chat_phase,
178 is_idle: session.is_idle,
179 activity_state: session.activity_state.clone(),
180 has_error: session.has_error,
181 error: session.launch_error.clone(),
182 storage_problem: session.storage_problem.clone(),
183 created_at: session.created_at.clone(),
184 updated_at: session.updated_at.clone(),
185 last_turn_outcome: None,
186 last_turn_diagnostic: None,
187 config_options: session.config_options.clone(),
188 pending_elicitations: session.pending_elicitations.clone(),
189 }
190 }
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
194#[serde(deny_unknown_fields)]
195pub struct StopBackgroundTaskRequest {
196 pub background_task_id: String,
197}
198
199#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
200pub struct SessionListResponse {
201 pub sessions: Vec<ApiSession>,
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
207pub struct WorkspaceListResponse {
208 pub workspaces: Vec<mj_core::workspace::WorkspaceRecord>,
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
215#[serde(deny_unknown_fields)]
216pub struct CreateWorkspaceRequest {
217 pub name: String,
218}
219
220#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
221pub struct CreateWorkspaceResponse {
222 pub workspace: mj_core::workspace::WorkspaceRecord,
223}
224
225#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
238#[serde(deny_unknown_fields)]
239pub struct StartSessionRequest {
240 #[serde(default)]
241 pub create_managed_worktree: Option<bool>,
242 #[serde(default, skip_serializing_if = "Option::is_none")]
245 pub at: Option<String>,
246 #[serde(default, skip_serializing_if = "Option::is_none")]
249 pub branch: Option<String>,
250 #[serde(default, skip_serializing_if = "Option::is_none")]
253 pub base: Option<String>,
254 #[serde(default)]
256 pub subagents: Option<mj_core::subagent::SubagentPolicy>,
257 #[serde(default, skip_serializing_if = "Option::is_none")]
259 pub review: Option<mj_core::config::SessionReview>,
260 #[serde(default)]
261 pub workspace_id: Option<String>,
262 #[serde(default)]
265 pub profile_id: Option<String>,
266 #[serde(default)]
268 pub target_id: Option<String>,
269 #[serde(default)]
270 pub bundle_id: Option<String>,
271 #[serde(default)]
272 pub project_directory: Option<PathBuf>,
273 #[serde(default)]
274 pub title: Option<String>,
275 #[serde(default)]
276 pub model: Option<String>,
277 #[serde(default)]
278 pub effort: Option<String>,
279 #[serde(default)]
280 pub prompt: Option<String>,
281 #[serde(default, skip_serializing_if = "Option::is_none")]
284 pub cpus: Option<u64>,
285 #[serde(default, skip_serializing_if = "Option::is_none")]
287 pub memory_bytes: Option<u64>,
288}
289
290#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
295#[serde(deny_unknown_fields)]
296pub struct ResumeSessionRequest {
297 #[serde(default)]
299 pub profile_id: Option<String>,
300 #[serde(default)]
302 pub target_id: Option<String>,
303 #[serde(default)]
305 pub workspace_id: Option<String>,
306 #[serde(default)]
310 pub queue: Option<mj_core::state::ResumeQueueDisposition>,
311}
312
313#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
316pub struct ResumeSessionResponse {
317 pub session_id: String,
318 pub workspace_id: String,
319 pub profile_id: String,
320 pub target_id: String,
321}
322
323#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
326pub struct SuspendSessionResponse {
327 #[serde(default)]
328 pub session_id: String,
329 #[serde(default)]
331 pub stopped_subagents: usize,
332 #[serde(default)]
334 pub subagents_not_handed_back: usize,
335 #[serde(default, skip_serializing_if = "Option::is_none")]
338 pub warning: Option<String>,
339}
340
341#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
342pub struct StartSessionResponse {
343 pub session_id: String,
344 #[serde(default, skip_serializing_if = "Option::is_none")]
347 pub turn_id: Option<u64>,
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
351#[serde(deny_unknown_fields)]
352pub struct SpawnSubagentRequest {
353 pub task_name: String,
354 pub instructions: String,
355 #[serde(default)]
356 pub profile_id: Option<String>,
357 #[serde(default)]
358 pub model: Option<String>,
359 #[serde(default)]
360 pub effort: Option<String>,
361 #[serde(default)]
362 pub working_directory: Option<PathBuf>,
363}
364
365#[derive(Debug, Clone, PartialEq, Eq)]
367pub struct SubagentCandidate {
368 pub profile_id: String,
369 pub harness: mj_core::config::HarnessKind,
370 pub choices: mj_core::worker_launch::ProfileConfig,
371 pub remaining_percent: Option<u8>,
375}
376
377#[derive(Debug, Clone, Default, PartialEq, Eq)]
380pub struct SubagentCandidates {
381 pub offered: Vec<SubagentCandidate>,
382 pub unavailable: Vec<(String, String)>,
383}
384
385#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
386pub struct SubagentView {
387 pub parent_session_id: String,
388 pub task_name: String,
389 pub session: ApiSession,
390}
391
392#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
393pub struct SubagentListResponse {
394 pub subagents: Vec<SubagentView>,
395}
396
397#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
398#[serde(deny_unknown_fields)]
399pub struct PromptRequest {
400 pub text: String,
401 #[serde(default, skip_serializing_if = "Option::is_none")]
403 pub command_id: Option<String>,
404}
405
406#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
407#[serde(deny_unknown_fields)]
408pub struct ClearQueueRequest {
409 #[serde(default, skip_serializing_if = "Option::is_none")]
410 pub command_id: Option<String>,
411}
412
413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
414pub struct PromptResponse {
415 pub turn_id: u64,
418}
419
420#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
421#[serde(deny_unknown_fields)]
422pub struct WaitRequest {
423 #[serde(default)]
425 pub return_on_input: bool,
426 #[serde(default)]
430 pub turn_id: Option<u64>,
431 #[serde(default)]
432 pub timeout_secs: Option<u64>,
433}
434
435#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
437#[serde(rename_all = "snake_case")]
438pub enum WaitOutcome {
439 InputRequired,
441 Finished,
443 Error,
445 Cancelled,
447 QuotaLimit,
449 Timeout,
451 Stopped,
453}
454
455#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
456pub struct WaitCapacityRetry {
457 pub attempt: u32,
458 pub retry_at_ms: i64,
459}
460
461impl From<&CapacityRetry> for WaitCapacityRetry {
462 fn from(retry: &CapacityRetry) -> Self {
463 Self {
464 attempt: retry.attempt,
465 retry_at_ms: retry.retry_at_ms,
466 }
467 }
468}
469
470#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
476#[serde(rename_all = "snake_case")]
477pub enum RelayState {
478 Connected,
480 Disconnected,
482 Unreachable,
484 TargetMissing,
486 ProjectionIntegrity,
488}
489
490#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
491pub struct RelayHealth {
492 pub state: RelayState,
493 #[serde(default, skip_serializing_if = "Option::is_none")]
495 pub detail: Option<String>,
496}
497
498impl From<&mj_client::session::ManagedSessionView> for RelayHealth {
499 fn from(view: &mj_client::session::ManagedSessionView) -> Self {
500 use mj_client::session::ViewError;
501 match &view.error {
504 Some(error) => Self {
505 state: match error {
506 ViewError::Unreachable(_) => RelayState::Unreachable,
507 ViewError::TargetMissing(_) => RelayState::TargetMissing,
508 ViewError::ProjectionIntegrity(_) => RelayState::ProjectionIntegrity,
509 },
510 detail: Some(error.detail().to_owned()),
511 },
512 None if view.connected => Self {
513 state: RelayState::Connected,
514 detail: None,
515 },
516 None => Self {
517 state: RelayState::Disconnected,
518 detail: None,
519 },
520 }
521 }
522}
523
524#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
525pub struct WaitResponse {
526 #[serde(default, skip_serializing_if = "Option::is_none")]
527 pub diagnostic: Option<mj_core::diagnostic::TurnDiagnostic>,
528
529 #[serde(default, skip_serializing_if = "Vec::is_empty")]
530 pub pending_elicitations: Vec<mj_core::elicitation::ElicitationRequest>,
531 #[serde(default, skip_serializing_if = "Option::is_none")]
532 pub usage: Option<mj_core::usage::TokenUsage>,
533 pub outcome: WaitOutcome,
534 #[serde(default, skip_serializing_if = "Option::is_none")]
536 pub stop_reason: Option<String>,
537 #[serde(default, skip_serializing_if = "Option::is_none")]
539 pub message: Option<String>,
540 #[serde(default, skip_serializing_if = "Option::is_none")]
543 pub final_message: Option<String>,
544 #[serde(default, skip_serializing_if = "Option::is_none")]
548 pub report_source: Option<String>,
549 #[serde(default, skip_serializing_if = "Option::is_none")]
552 pub turn_id: Option<u64>,
553 #[serde(default, skip_serializing_if = "Option::is_none")]
556 pub requested_turn_id: Option<u64>,
557 #[serde(default, skip_serializing_if = "Option::is_none")]
559 pub turn_number: Option<u64>,
560 #[serde(default, skip_serializing_if = "Option::is_none")]
561 pub elapsed_ms: Option<i64>,
562 #[serde(default, skip_serializing_if = "Option::is_none")]
565 pub tool_calls: Option<u64>,
566 #[serde(default, skip_serializing_if = "Option::is_none")]
568 pub capacity_retry: Option<WaitCapacityRetry>,
569 #[serde(default, skip_serializing_if = "Option::is_none")]
570 pub server_retry: Option<WaitCapacityRetry>,
571 #[serde(default)]
572 pub retry_assessment_pending: bool,
573 #[serde(default, skip_serializing_if = "Option::is_none")]
574 pub quota_recovery: Option<mj_core::continuation::QuotaRecovery>,
575 #[serde(default, skip_serializing_if = "Option::is_none")]
579 pub relay: Option<RelayHealth>,
580 pub session: ApiSession,
581}
582
583pub const DEFAULT_TRANSCRIPT_LIMIT: usize = 200;
588pub const MAX_TRANSCRIPT_LIMIT: usize = 1_000;
589
590#[derive(Debug, Clone, Default, PartialEq, Serialize)]
591pub struct TranscriptQuery {
592 pub role: Vec<mj_core::transcript::TranscriptRole>,
593 pub finished_only: bool,
595 pub after_seq: Option<u64>,
597 pub limit: Option<usize>,
598}
599
600impl<'de> serde::Deserialize<'de> for TranscriptQuery {
601 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
602 where
603 D: serde::Deserializer<'de>,
604 {
605 struct TranscriptQueryVisitor;
606
607 impl<'de> serde::de::Visitor<'de> for TranscriptQueryVisitor {
608 type Value = TranscriptQuery;
609
610 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
611 formatter.write_str("transcript query parameters")
612 }
613
614 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
615 where
616 M: serde::de::MapAccess<'de>,
617 {
618 let mut role = Vec::new();
619 let mut finished_only = None;
620 let mut after_seq = None;
621 let mut limit = None;
622
623 while let Some(key) = map.next_key::<String>()? {
624 match key.as_str() {
625 "role" => role.push(map.next_value()?),
626 "finished_only" => {
627 if finished_only.replace(map.next_value()?).is_some() {
628 return Err(serde::de::Error::duplicate_field("finished_only"));
629 }
630 }
631 "after_seq" => {
632 if after_seq.replace(map.next_value()?).is_some() {
633 return Err(serde::de::Error::duplicate_field("after_seq"));
634 }
635 }
636 "limit" => {
637 if limit.replace(map.next_value()?).is_some() {
638 return Err(serde::de::Error::duplicate_field("limit"));
639 }
640 }
641 _ => {
642 let _: serde::de::IgnoredAny = map.next_value()?;
643 }
644 }
645 }
646
647 Ok(TranscriptQuery {
648 role,
649 finished_only: finished_only.unwrap_or_default(),
650 after_seq,
651 limit,
652 })
653 }
654 }
655
656 deserializer.deserialize_map(TranscriptQueryVisitor)
657 }
658}
659
660#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
661pub struct TranscriptItemView {
662 pub stable_id: String,
663 pub position: u64,
664 pub seq: u64,
667 pub role: String,
668 pub text: String,
670 pub created_at_ms: i64,
671 pub last_changed_at_ms: i64,
672 pub body: mj_core::transcript::TranscriptBody,
674}
675
676#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
677pub struct TranscriptResponse {
678 #[serde(default)]
679 pub next_after_seq: u64,
680 pub session_id: String,
681 pub latest_seq: u64,
684 pub execution: MaterializedExecutionState,
685 pub items: Vec<TranscriptItemView>,
686}
687
688#[derive(Debug, Clone, PartialEq, Eq)]
695pub struct TurnState {
696 pub execution: MaterializedExecutionState,
697 pub active_turn: Option<MaterializedTurn>,
698 pub last_turn_outcome: Option<MaterializedTurnOutcome>,
699}
700
701pub use crate::database::TurnSummary;
702
703#[derive(Debug, Clone, Default, PartialEq, Eq)]
706pub struct StartFollowup {
707 pub model: Option<String>,
708 pub effort: Option<String>,
709 pub prompt: Option<String>,
710 pub fast_mode: bool,
711}
712
713#[derive(Debug, Clone, PartialEq, Eq)]
715pub enum StartStatus {
716 Pending,
718 Submitted { turn_id: u64 },
720 Failed { message: String },
722}
723
724pub use crate::database::TranscriptPage;
726
727#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
729pub struct PushedBranch {
730 pub branch: String,
731 pub remote: String,
732}
733
734#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
736pub struct FileQuery {
737 pub path: String,
739}
740
741#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
743#[serde(rename_all = "snake_case")]
744pub enum ExportKind {
745 Patch,
747 Branch,
749 Bundle,
751}
752
753#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
754pub struct ExportRequest {
755 pub kind: ExportKind,
756 #[serde(default, skip_serializing_if = "Option::is_none")]
758 pub branch: Option<String>,
759}
760
761#[derive(Debug, Clone)]
763pub struct BundleExport {
764 pub repository: String,
765 pub bytes: Vec<u8>,
766}
767
768#[derive(Debug)]
770pub enum ExportError {
771 Refused(String),
774 Failed(anyhow::Error),
776}
777
778impl From<ExportError> for ApiFailure {
779 fn from(error: ExportError) -> Self {
780 match error {
781 ExportError::Refused(message) => Self::conflict(message),
782 ExportError::Failed(error) => Self::from(error),
783 }
784 }
785}
786
787#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
790pub struct StartReviewResponse {
791 pub session_id: String,
792 pub started: bool,
793}
794
795#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
797pub struct ResolveReviewResponse {
798 pub session_id: String,
799 pub resolution: String,
801}
802
803#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
807pub struct ReviewStatusResponse {
808 pub session_id: String,
809 #[serde(default)]
810 pub review: Option<crate::server::ViewerTurnReview>,
811}
812
813#[derive(Debug, Default, Deserialize)]
818#[serde(deny_unknown_fields)]
819pub struct WikiSearchQuery {
820 #[serde(default)]
821 pub q: Option<String>,
822 #[serde(default)]
823 pub limit: Option<usize>,
824}
825
826#[derive(Debug, Default, Deserialize)]
827#[serde(deny_unknown_fields)]
828pub struct WikiBriefQuery {
829 #[serde(default)]
830 pub max_chars: Option<usize>,
831}
832
833#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
834pub struct WikiBriefResponse {
835 pub markdown: String,
836}
837
838#[derive(Debug, Default, Deserialize)]
840#[serde(deny_unknown_fields)]
841pub struct WikiHitsQuery {
842 pub q: String,
843 #[serde(default)]
844 pub context_messages: Option<usize>,
845 #[serde(default)]
846 pub per_message_chars: Option<usize>,
847}
848
849#[derive(Debug, Clone, Default, Serialize, Deserialize)]
852#[serde(deny_unknown_fields)]
853pub struct WikiRestoreBody {
854 #[serde(default)]
855 pub workspace_id: Option<String>,
856 pub profile_id: String,
857 pub target_id: String,
858 #[serde(default)]
859 pub project_directory: Option<PathBuf>,
860 #[serde(default)]
861 pub model: Option<String>,
862 #[serde(default)]
863 pub effort: Option<String>,
864}
865
866#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
880#[serde(deny_unknown_fields)]
881pub struct LaunchOptions {
882 pub revision: u64,
886 pub profiles: Vec<LaunchProfile>,
887 pub targets: Vec<LaunchTarget>,
888 pub bundles: Vec<LaunchBundle>,
889 #[serde(default, skip_serializing_if = "Vec::is_empty")]
892 pub hosts: Vec<LaunchHost>,
893 #[serde(default, skip_serializing_if = "Option::is_none")]
897 pub default: Option<LaunchDefault>,
898}
899
900#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
902#[serde(deny_unknown_fields)]
903pub struct LaunchProfile {
904 pub id: String,
905 pub harness: String,
908}
909
910#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
912#[serde(deny_unknown_fields)]
913pub struct LaunchTarget {
914 pub id: String,
915 pub kind: String,
917 pub requires_project_directory: bool,
920 pub availability: LaunchAvailability,
921 #[serde(default, skip_serializing_if = "Option::is_none")]
925 pub unavailable_reason: Option<String>,
926 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
931 pub runtime_missing: bool,
932 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
937 pub default_candidate: bool,
938 #[serde(default, skip_serializing_if = "Option::is_none")]
940 pub host: Option<String>,
941}
942
943#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
950#[serde(rename_all = "lowercase")]
951pub enum LaunchAvailability {
952 Ready,
954 Stale,
956 Unavailable,
958 Unknown,
960}
961
962#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
964#[serde(deny_unknown_fields)]
965pub struct LaunchBundle {
966 pub id: String,
967 pub primary_repository: String,
968 pub repositories: Vec<LaunchRepository>,
969}
970
971#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
972#[serde(deny_unknown_fields)]
973pub struct LaunchRepository {
974 pub id: String,
975 #[serde(default, skip_serializing_if = "Option::is_none")]
979 pub github: Option<String>,
980 pub destination: String,
981}
982
983#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
986#[serde(deny_unknown_fields)]
987pub struct LaunchHost {
988 pub id: String,
989 pub label: String,
990 pub targets: Vec<String>,
992 pub stale: bool,
993 pub refreshing: bool,
994 pub has_error: bool,
995}
996
997#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
999#[serde(deny_unknown_fields)]
1000pub struct LaunchDefault {
1001 pub profile_id: String,
1002 pub target_id: String,
1003}