mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
## Why
Remote-control runtime enablement and persisted enrollment preference
were represented by separate flags. That made startup rehydration, RPC
persistence, and new-enrollment seeding race with one another, and it
did not cleanly distinguish runtime-only CLI or daemon starts from
durable app-server RPC changes.
## What Changed
- Replace the parallel enablement, seed, and rehydration flags with one
transport-owned `RemoteControlDesiredState`.
- Add nullable enrollment-scoped persistence and preserve existing
preferences during enrollment upserts.
- Rehydrate plain startup only after auth and client scope resolve,
without overwriting a concurrent RPC transition.
- Make ordinary `remoteControl/enable` and `remoteControl/disable`
durable while retaining `ephemeral: true` for runtime-only callers.
- Have the daemon explicitly request ephemeral enablement and regenerate
the app-server schemas.
## Verification
- Covered migration and `NULL`/`0`/`1` persistence round trips.
- Covered plain-start rehydration and runtime-only versus durable
enrollment seeding.
- Covered durable enable, durable disable, and ephemeral enable through
app-server RPC.
- Covered the daemon's exact `{ "ephemeral": true }` request payload.
Related issue: N/A (internal remote-control persistence architecture
change).
205 lines
6.4 KiB
Rust
205 lines
6.4 KiB
Rust
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use ts_rs::TS;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlEnableParams {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub ephemeral: bool,
|
|
}
|
|
|
|
pub type NullableRemoteControlEnableParams = Option<RemoteControlEnableParams>;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlDisableParams {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub ephemeral: bool,
|
|
}
|
|
|
|
pub type NullableRemoteControlDisableParams = Option<RemoteControlDisableParams>;
|
|
|
|
/// Current remote-control connection status and remote identity exposed to clients.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlStatusChangedNotification {
|
|
pub status: RemoteControlConnectionStatus,
|
|
pub server_name: String,
|
|
pub installation_id: String,
|
|
pub environment_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlEnableResponse {
|
|
pub status: RemoteControlConnectionStatus,
|
|
pub server_name: String,
|
|
pub installation_id: String,
|
|
pub environment_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlDisableResponse {
|
|
pub status: RemoteControlConnectionStatus,
|
|
pub server_name: String,
|
|
pub installation_id: String,
|
|
pub environment_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlStatusReadResponse {
|
|
pub status: RemoteControlConnectionStatus,
|
|
pub server_name: String,
|
|
pub installation_id: String,
|
|
pub environment_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlPairingStartParams {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub manual_code: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlPairingStartResponse {
|
|
pub pairing_code: String,
|
|
pub manual_pairing_code: Option<String>,
|
|
pub environment_id: String,
|
|
pub expires_at: i64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlPairingStatusParams {
|
|
#[ts(optional = nullable)]
|
|
pub pairing_code: Option<String>,
|
|
#[ts(optional = nullable)]
|
|
pub manual_pairing_code: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlPairingStatusResponse {
|
|
pub claimed: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlClientsListParams {
|
|
pub environment_id: String,
|
|
#[ts(optional = nullable)]
|
|
pub cursor: Option<String>,
|
|
#[ts(optional = nullable)]
|
|
pub limit: Option<u32>,
|
|
#[ts(optional = nullable)]
|
|
pub order: Option<RemoteControlClientsListOrder>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
|
pub enum RemoteControlClientsListOrder {
|
|
Asc,
|
|
Desc,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlClientsListResponse {
|
|
pub data: Vec<RemoteControlClient>,
|
|
pub next_cursor: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlClient {
|
|
pub client_id: String,
|
|
pub display_name: Option<String>,
|
|
pub device_type: Option<String>,
|
|
pub platform: Option<String>,
|
|
pub os_version: Option<String>,
|
|
pub device_model: Option<String>,
|
|
pub app_version: Option<String>,
|
|
pub last_seen_at: Option<i64>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlClientsRevokeParams {
|
|
pub environment_id: String,
|
|
pub client_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RemoteControlClientsRevokeResponse {}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
|
pub enum RemoteControlConnectionStatus {
|
|
Disabled,
|
|
Connecting,
|
|
Connected,
|
|
Errored,
|
|
}
|
|
|
|
impl From<RemoteControlStatusChangedNotification> for RemoteControlEnableResponse {
|
|
fn from(notification: RemoteControlStatusChangedNotification) -> Self {
|
|
let RemoteControlStatusChangedNotification {
|
|
status,
|
|
server_name,
|
|
installation_id,
|
|
environment_id,
|
|
} = notification;
|
|
Self {
|
|
status,
|
|
server_name,
|
|
installation_id,
|
|
environment_id,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<RemoteControlStatusChangedNotification> for RemoteControlDisableResponse {
|
|
fn from(notification: RemoteControlStatusChangedNotification) -> Self {
|
|
let RemoteControlStatusChangedNotification {
|
|
status,
|
|
server_name,
|
|
installation_id,
|
|
environment_id,
|
|
} = notification;
|
|
Self {
|
|
status,
|
|
server_name,
|
|
installation_id,
|
|
environment_id,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "remote_control_tests.rs"]
|
|
mod tests;
|