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, skip_serializing_if = "std::ops::Not::not")]
264 pub no_project_memory: bool,
265 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
271 pub no_mailbox: bool,
272 #[serde(default)]
273 pub workspace_id: Option<String>,
274 #[serde(default)]
277 pub profile_id: Option<String>,
278 #[serde(default)]
280 pub target_id: Option<String>,
281 #[serde(default)]
282 pub bundle_id: Option<String>,
283 #[serde(default)]
284 pub project_directory: Option<PathBuf>,
285 #[serde(default)]
286 pub title: Option<String>,
287 #[serde(default)]
288 pub model: Option<String>,
289 #[serde(default)]
290 pub effort: Option<String>,
291 #[serde(default)]
292 pub prompt: Option<String>,
293 #[serde(default, skip_serializing_if = "Option::is_none")]
296 pub cpus: Option<u64>,
297 #[serde(default, skip_serializing_if = "Option::is_none")]
299 pub memory_bytes: Option<u64>,
300}
301
302#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
307#[serde(deny_unknown_fields)]
308pub struct ResumeSessionRequest {
309 #[serde(default)]
311 pub profile_id: Option<String>,
312 #[serde(default)]
314 pub target_id: Option<String>,
315 #[serde(default)]
317 pub workspace_id: Option<String>,
318 #[serde(default)]
322 pub queue: Option<mj_core::state::ResumeQueueDisposition>,
323}
324
325#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
328pub struct ResumeSessionResponse {
329 pub session_id: String,
330 pub workspace_id: String,
331 pub profile_id: String,
332 pub target_id: String,
333}
334
335#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
338pub struct SuspendSessionResponse {
339 #[serde(default)]
340 pub session_id: String,
341 #[serde(default)]
343 pub stopped_subagents: usize,
344 #[serde(default)]
346 pub subagents_not_handed_back: usize,
347 #[serde(default, skip_serializing_if = "Option::is_none")]
350 pub warning: Option<String>,
351}
352
353#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
354pub struct StartSessionResponse {
355 pub session_id: String,
356 #[serde(default, skip_serializing_if = "Option::is_none")]
359 pub turn_id: Option<u64>,
360}
361
362#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
363#[serde(deny_unknown_fields)]
364pub struct SpawnSubagentRequest {
365 pub task_name: String,
366 pub instructions: String,
367 #[serde(default)]
368 pub task_type: Option<mj_core::subagent::SubagentTaskType>,
369 #[serde(default)]
370 pub working_directory: Option<PathBuf>,
371}
372
373#[derive(Debug, Clone, PartialEq, Eq)]
375pub struct SubagentCandidate {
376 pub profile_id: String,
377 pub harness: mj_core::config::HarnessKind,
378 pub choices: mj_core::worker_launch::ProfileConfig,
379 pub remaining_percent: Option<u8>,
383}
384
385#[derive(Debug, Clone, Default, PartialEq, Eq)]
388pub struct SubagentCandidates {
389 pub offered: Vec<SubagentCandidate>,
390 pub unavailable: Vec<(String, String)>,
391}
392
393#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
394pub struct SubagentView {
395 pub parent_session_id: String,
396 pub task_name: String,
397 pub session: ApiSession,
398}
399
400#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
401pub struct SubagentListResponse {
402 pub subagents: Vec<SubagentView>,
403}
404
405#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
406#[serde(deny_unknown_fields)]
407pub struct PromptRequest {
408 pub text: String,
409 #[serde(default, skip_serializing_if = "Option::is_none")]
411 pub command_id: Option<String>,
412}
413
414#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
415#[serde(deny_unknown_fields)]
416pub struct ClearQueueRequest {
417 #[serde(default, skip_serializing_if = "Option::is_none")]
418 pub command_id: Option<String>,
419}
420
421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
422pub struct PromptResponse {
423 pub turn_id: u64,
426}
427
428#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
429#[serde(deny_unknown_fields)]
430pub struct WaitRequest {
431 #[serde(default)]
433 pub return_on_input: bool,
434 #[serde(default)]
438 pub turn_id: Option<u64>,
439 #[serde(default)]
440 pub timeout_secs: Option<u64>,
441}
442
443#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
445#[serde(rename_all = "snake_case")]
446pub enum WaitOutcome {
447 InputRequired,
449 Finished,
451 Error,
453 Cancelled,
455 QuotaLimit,
457 Timeout,
459 Stopped,
461}
462
463#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
464pub struct WaitCapacityRetry {
465 pub attempt: u32,
466 pub retry_at_ms: i64,
467}
468
469impl From<&CapacityRetry> for WaitCapacityRetry {
470 fn from(retry: &CapacityRetry) -> Self {
471 Self {
472 attempt: retry.attempt,
473 retry_at_ms: retry.retry_at_ms,
474 }
475 }
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
484#[serde(rename_all = "snake_case")]
485pub enum RelayState {
486 Connected,
488 Disconnected,
490 Unreachable,
492 TargetMissing,
494 ProjectionIntegrity,
496}
497
498#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
499pub struct RelayHealth {
500 pub state: RelayState,
501 #[serde(default, skip_serializing_if = "Option::is_none")]
503 pub detail: Option<String>,
504}
505
506impl From<&mj_client::session::ManagedSessionView> for RelayHealth {
507 fn from(view: &mj_client::session::ManagedSessionView) -> Self {
508 use mj_client::session::ViewError;
509 match &view.error {
512 Some(error) => Self {
513 state: match error {
514 ViewError::Unreachable(_) => RelayState::Unreachable,
515 ViewError::TargetMissing(_) => RelayState::TargetMissing,
516 ViewError::ProjectionIntegrity(_) => RelayState::ProjectionIntegrity,
517 },
518 detail: Some(error.detail().to_owned()),
519 },
520 None if view.connected => Self {
521 state: RelayState::Connected,
522 detail: None,
523 },
524 None => Self {
525 state: RelayState::Disconnected,
526 detail: None,
527 },
528 }
529 }
530}
531
532#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
533pub struct WaitResponse {
534 #[serde(default, skip_serializing_if = "Option::is_none")]
535 pub diagnostic: Option<mj_core::diagnostic::TurnDiagnostic>,
536
537 #[serde(default, skip_serializing_if = "Vec::is_empty")]
538 pub pending_elicitations: Vec<mj_core::elicitation::ElicitationRequest>,
539 #[serde(default, skip_serializing_if = "Option::is_none")]
540 pub usage: Option<mj_core::usage::TokenUsage>,
541 pub outcome: WaitOutcome,
542 #[serde(default, skip_serializing_if = "Option::is_none")]
544 pub stop_reason: Option<String>,
545 #[serde(default, skip_serializing_if = "Option::is_none")]
547 pub message: Option<String>,
548 #[serde(default, skip_serializing_if = "Option::is_none")]
551 pub final_message: Option<String>,
552 #[serde(default, skip_serializing_if = "Option::is_none")]
556 pub report_source: Option<String>,
557 #[serde(default, skip_serializing_if = "Option::is_none")]
560 pub turn_id: Option<u64>,
561 #[serde(default, skip_serializing_if = "Option::is_none")]
564 pub requested_turn_id: Option<u64>,
565 #[serde(default, skip_serializing_if = "Option::is_none")]
567 pub turn_number: Option<u64>,
568 #[serde(default, skip_serializing_if = "Option::is_none")]
569 pub elapsed_ms: Option<i64>,
570 #[serde(default, skip_serializing_if = "Option::is_none")]
573 pub tool_calls: Option<u64>,
574 #[serde(default, skip_serializing_if = "Option::is_none")]
576 pub capacity_retry: Option<WaitCapacityRetry>,
577 #[serde(default, skip_serializing_if = "Option::is_none")]
578 pub server_retry: Option<WaitCapacityRetry>,
579 #[serde(default)]
580 pub retry_assessment_pending: bool,
581 #[serde(default, skip_serializing_if = "Option::is_none")]
582 pub quota_recovery: Option<mj_core::continuation::QuotaRecovery>,
583 #[serde(default, skip_serializing_if = "Option::is_none")]
587 pub relay: Option<RelayHealth>,
588 pub session: ApiSession,
589}
590
591pub const DEFAULT_TRANSCRIPT_LIMIT: usize = 200;
596pub const MAX_TRANSCRIPT_LIMIT: usize = 1_000;
597
598#[derive(Debug, Clone, Default, PartialEq, Serialize)]
599pub struct TranscriptQuery {
600 pub role: Vec<mj_core::transcript::TranscriptRole>,
601 pub finished_only: bool,
603 pub after_seq: Option<u64>,
605 pub limit: Option<usize>,
606}
607
608impl<'de> serde::Deserialize<'de> for TranscriptQuery {
609 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
610 where
611 D: serde::Deserializer<'de>,
612 {
613 struct TranscriptQueryVisitor;
614
615 impl<'de> serde::de::Visitor<'de> for TranscriptQueryVisitor {
616 type Value = TranscriptQuery;
617
618 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
619 formatter.write_str("transcript query parameters")
620 }
621
622 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
623 where
624 M: serde::de::MapAccess<'de>,
625 {
626 let mut role = Vec::new();
627 let mut finished_only = None;
628 let mut after_seq = None;
629 let mut limit = None;
630
631 while let Some(key) = map.next_key::<String>()? {
632 match key.as_str() {
633 "role" => role.push(map.next_value()?),
634 "finished_only" => {
635 if finished_only.replace(map.next_value()?).is_some() {
636 return Err(serde::de::Error::duplicate_field("finished_only"));
637 }
638 }
639 "after_seq" => {
640 if after_seq.replace(map.next_value()?).is_some() {
641 return Err(serde::de::Error::duplicate_field("after_seq"));
642 }
643 }
644 "limit" => {
645 if limit.replace(map.next_value()?).is_some() {
646 return Err(serde::de::Error::duplicate_field("limit"));
647 }
648 }
649 _ => {
650 let _: serde::de::IgnoredAny = map.next_value()?;
651 }
652 }
653 }
654
655 Ok(TranscriptQuery {
656 role,
657 finished_only: finished_only.unwrap_or_default(),
658 after_seq,
659 limit,
660 })
661 }
662 }
663
664 deserializer.deserialize_map(TranscriptQueryVisitor)
665 }
666}
667
668#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
669pub struct TranscriptItemView {
670 pub stable_id: String,
671 pub position: u64,
672 pub seq: u64,
675 pub role: String,
676 pub text: String,
678 pub created_at_ms: i64,
679 pub last_changed_at_ms: i64,
680 pub body: mj_core::transcript::TranscriptBody,
682}
683
684#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
685pub struct TranscriptResponse {
686 #[serde(default)]
687 pub next_after_seq: u64,
688 pub session_id: String,
689 pub latest_seq: u64,
692 pub execution: MaterializedExecutionState,
693 pub items: Vec<TranscriptItemView>,
694}
695
696#[derive(Debug, Clone, PartialEq, Eq)]
703pub struct TurnState {
704 pub execution: MaterializedExecutionState,
705 pub active_turn: Option<MaterializedTurn>,
706 pub last_turn_outcome: Option<MaterializedTurnOutcome>,
707}
708
709pub use crate::database::TurnSummary;
710
711#[derive(Debug, Clone, Default, PartialEq, Eq)]
714pub struct StartFollowup {
715 pub model: Option<String>,
716 pub effort: Option<String>,
717 pub prompt: Option<String>,
718 pub fast_mode: bool,
719}
720
721#[derive(Debug, Clone, PartialEq, Eq)]
723pub enum StartStatus {
724 Pending,
726 Submitted { turn_id: u64 },
728 Failed { message: String },
730}
731
732pub use crate::database::TranscriptPage;
734
735#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
737pub struct PushedBranch {
738 pub branch: String,
739 pub remote: String,
740}
741
742#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
744pub struct FileQuery {
745 pub path: String,
747}
748
749#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
751#[serde(rename_all = "snake_case")]
752pub enum ExportKind {
753 Patch,
755 Branch,
757 Bundle,
759}
760
761#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
762pub struct ExportRequest {
763 pub kind: ExportKind,
764 #[serde(default, skip_serializing_if = "Option::is_none")]
766 pub branch: Option<String>,
767}
768
769#[derive(Debug, Clone)]
771pub struct BundleExport {
772 pub repository: String,
773 pub bytes: Vec<u8>,
774}
775
776#[derive(Debug)]
778pub enum ExportError {
779 Refused(String),
782 Failed(anyhow::Error),
784}
785
786impl From<ExportError> for ApiFailure {
787 fn from(error: ExportError) -> Self {
788 match error {
789 ExportError::Refused(message) => Self::conflict(message),
790 ExportError::Failed(error) => Self::from(error),
791 }
792 }
793}
794
795#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
798pub struct StartReviewResponse {
799 pub session_id: String,
800 pub started: bool,
801}
802
803#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
805pub struct ResolveReviewResponse {
806 pub session_id: String,
807 pub resolution: String,
809}
810
811#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
815pub struct ReviewStatusResponse {
816 pub session_id: String,
817 #[serde(default)]
818 pub review: Option<crate::server::ViewerTurnReview>,
819}
820
821#[derive(Debug, Default, Deserialize)]
826#[serde(deny_unknown_fields)]
827pub struct WikiSearchQuery {
828 #[serde(default)]
829 pub q: Option<String>,
830 #[serde(default)]
831 pub limit: Option<usize>,
832}
833
834#[derive(Debug, Default, Deserialize)]
835#[serde(deny_unknown_fields)]
836pub struct WikiBriefQuery {
837 #[serde(default)]
838 pub max_chars: Option<usize>,
839}
840
841#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
842pub struct WikiBriefResponse {
843 pub markdown: String,
844}
845
846#[derive(Debug, Default, Deserialize)]
848#[serde(deny_unknown_fields)]
849pub struct WikiHitsQuery {
850 pub q: String,
851 #[serde(default)]
852 pub context_messages: Option<usize>,
853 #[serde(default)]
854 pub per_message_chars: Option<usize>,
855}
856
857#[derive(Debug, Clone, Default, Serialize, Deserialize)]
860#[serde(deny_unknown_fields)]
861pub struct WikiRestoreBody {
862 #[serde(default)]
863 pub workspace_id: Option<String>,
864 pub profile_id: String,
865 pub target_id: String,
866 #[serde(default)]
867 pub project_directory: Option<PathBuf>,
868 #[serde(default)]
869 pub model: Option<String>,
870 #[serde(default)]
871 pub effort: Option<String>,
872}
873
874#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
888#[serde(deny_unknown_fields)]
889pub struct LaunchOptions {
890 pub revision: u64,
894 pub profiles: Vec<LaunchProfile>,
895 pub targets: Vec<LaunchTarget>,
896 pub bundles: Vec<LaunchBundle>,
897 #[serde(default, skip_serializing_if = "Vec::is_empty")]
900 pub hosts: Vec<LaunchHost>,
901 #[serde(default, skip_serializing_if = "Option::is_none")]
905 pub default: Option<LaunchDefault>,
906}
907
908#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
910#[serde(deny_unknown_fields)]
911pub struct LaunchProfile {
912 pub id: String,
913 pub harness: String,
916}
917
918#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
920#[serde(deny_unknown_fields)]
921pub struct LaunchTarget {
922 pub id: String,
923 pub kind: String,
925 pub requires_project_directory: bool,
928 pub availability: LaunchAvailability,
929 #[serde(default, skip_serializing_if = "Option::is_none")]
933 pub unavailable_reason: Option<String>,
934 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
939 pub runtime_missing: bool,
940 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
945 pub default_candidate: bool,
946 #[serde(default, skip_serializing_if = "Option::is_none")]
948 pub host: Option<String>,
949}
950
951#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
958#[serde(rename_all = "lowercase")]
959pub enum LaunchAvailability {
960 Ready,
962 Stale,
964 Unavailable,
966 Unknown,
968}
969
970#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
972#[serde(deny_unknown_fields)]
973pub struct LaunchBundle {
974 pub id: String,
975 pub primary_repository: String,
976 pub repositories: Vec<LaunchRepository>,
977}
978
979#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
980#[serde(deny_unknown_fields)]
981pub struct LaunchRepository {
982 pub id: String,
983 #[serde(default, skip_serializing_if = "Option::is_none")]
987 pub github: Option<String>,
988 pub destination: String,
989}
990
991#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
994#[serde(deny_unknown_fields)]
995pub struct LaunchHost {
996 pub id: String,
997 pub label: String,
998 pub targets: Vec<String>,
1000 pub stale: bool,
1001 pub refreshing: bool,
1002 pub has_error: bool,
1003}
1004
1005#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1007#[serde(deny_unknown_fields)]
1008pub struct LaunchDefault {
1009 pub profile_id: String,
1010 pub target_id: String,
1011}