codex_mobile_bridge/bridge_protocol/
runtime.rs1use serde::{Deserialize, Serialize};
2
3use super::helpers::now_millis;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct ApiError {
7 pub code: String,
8 pub message: String,
9}
10
11impl ApiError {
12 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
13 Self {
14 code: code.into(),
15 message: message.into(),
16 }
17 }
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct RuntimeRecord {
23 pub runtime_id: String,
24 pub display_name: String,
25 pub codex_home: Option<String>,
26 pub codex_binary: String,
27 pub is_primary: bool,
28 pub auto_start: bool,
29 pub created_at_ms: i64,
30 pub updated_at_ms: i64,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct AppServerHandshakeSummary {
36 pub state: String,
37 pub protocol: String,
38 pub transport: String,
39 pub experimental_api_enabled: bool,
40 pub notification_mode: String,
41 #[serde(default)]
42 pub opt_out_notification_methods: Vec<String>,
43 pub detail: Option<String>,
44 pub updated_at_ms: i64,
45}
46
47impl Default for AppServerHandshakeSummary {
48 fn default() -> Self {
49 Self::inactive()
50 }
51}
52
53impl AppServerHandshakeSummary {
54 pub fn new(
55 state: impl Into<String>,
56 experimental_api_enabled: bool,
57 opt_out_notification_methods: Vec<String>,
58 detail: Option<String>,
59 ) -> Self {
60 let notification_mode = if opt_out_notification_methods.is_empty() {
61 "full".to_string()
62 } else {
63 "optimized".to_string()
64 };
65 Self {
66 state: state.into(),
67 protocol: "jsonrpc2.0".to_string(),
68 transport: "stdio".to_string(),
69 experimental_api_enabled,
70 notification_mode,
71 opt_out_notification_methods,
72 detail,
73 updated_at_ms: now_millis(),
74 }
75 }
76
77 pub fn inactive() -> Self {
78 Self::new("inactive", false, Vec::new(), None)
79 }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct RuntimeStatusSnapshot {
85 pub runtime_id: String,
86 pub status: String,
87 pub codex_home: Option<String>,
88 pub user_agent: Option<String>,
89 pub platform_family: Option<String>,
90 pub platform_os: Option<String>,
91 pub last_error: Option<String>,
92 pub pid: Option<u32>,
93 #[serde(default)]
94 pub app_server_handshake: AppServerHandshakeSummary,
95 pub updated_at_ms: i64,
96}
97
98impl RuntimeStatusSnapshot {
99 pub fn stopped(runtime_id: impl Into<String>) -> Self {
100 Self {
101 runtime_id: runtime_id.into(),
102 status: "stopped".to_string(),
103 codex_home: None,
104 user_agent: None,
105 platform_family: None,
106 platform_os: None,
107 last_error: None,
108 pid: None,
109 app_server_handshake: AppServerHandshakeSummary::inactive(),
110 updated_at_ms: now_millis(),
111 }
112 }
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct RuntimeSummary {
118 pub runtime_id: String,
119 pub display_name: String,
120 pub codex_home: Option<String>,
121 pub codex_binary: String,
122 pub is_primary: bool,
123 pub auto_start: bool,
124 pub created_at_ms: i64,
125 pub updated_at_ms: i64,
126 pub status: RuntimeStatusSnapshot,
127}
128
129impl RuntimeSummary {
130 pub fn from_parts(record: &RuntimeRecord, status: RuntimeStatusSnapshot) -> Self {
131 Self {
132 runtime_id: record.runtime_id.clone(),
133 display_name: record.display_name.clone(),
134 codex_home: record.codex_home.clone(),
135 codex_binary: record.codex_binary.clone(),
136 is_primary: record.is_primary,
137 auto_start: record.auto_start,
138 created_at_ms: record.created_at_ms,
139 updated_at_ms: record.updated_at_ms,
140 status,
141 }
142 }
143}