Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions artifacts/github/bundles/openai-codex-pr-26449.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"analysis_mode": "pr_first",
"commits": [
{
"author": "hefuc-oai",
"committed_at": "2026-06-04T19:16:00Z",
"message": "feat(remote-control): add pairing status transport",
"sha": "acf4f7a893034a677d89703bc6236842b923ee23",
"url": "https://github.com/openai/codex/commit/acf4f7a893034a677d89703bc6236842b923ee23"
}
],
"default_branch": "main",
"docs_refs": [],
"examples_refs": [],
"extracted_flags": [
"URL",
"--manifest-path",
"--all",
"--check",
"REMOTE_CONTROL_PAIRING_TIMEOUT",
"HTTP",
"JSONRPCM",
"POST",
"ABCD",
"TEST_REMOTE_CONTROL_SERVER_TOKEN",
"TEST_REFRESHED_REMOTE_CONTROL_SERVER_TOKEN"
],
"files": [
{
"additions": 17,
"deletions": 0,
"patch_excerpt": "@@ -62,6 +62,23 @@ pub struct RemoteControlPairingStartResponse {\n pub expires_at: i64,\n }\n \n+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]\n+#[serde(rename_all = \"camelCase\")]\n+#[ts(export_to = \"v2/\")]\n+pub struct RemoteControlPairingStatusParams {\n+ #[ts(optional = nullable)]\n+ pub pairing_code: Option<String>,\n+ #[ts(optional = nullable)]\n+ pub manual_pairing_code: Option<String>,\n+}\n+\n+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]\n+#[serde(rename_all = \"camelCase\")]\n+#[ts(export_to = \"v2/\")]\n+pub struct RemoteControlPairingStatusResponse {\n+ pub claimed: bool,\n+}\n+\n #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]\n #[serde(rename_all = \"camelCase\")]\n #[ts(export_to = \"v2/\")]",
"path": "codex-rs/app-server-protocol/src/protocol/v2/remote_control.rs",
"status": "modified"
},
{
"additions": 66,
"deletions": 0,
"patch_excerpt": "@@ -3,11 +3,14 @@ use super::pairing_unavailable_error;\n use super::protocol::EnrollRemoteServerRequest;\n use super::protocol::EnrollRemoteServerResponse;\n use super::protocol::RefreshRemoteServerRequest;\n+use super::protocol::RemoteControlPairingStatusRequest;\n+use super::protocol::RemoteControlPairingStatusResponse as BackendRemoteControlPairingStatusResponse;\n use super::protocol::RemoteControlTarget;\n use super::protocol::StartRemoteControlPairingRequest;\n use super::protocol::StartRemoteControlPairingResponse;\n use axum::http::HeaderMap;\n use codex_app_server_protocol::RemoteControlPairingStartResponse;\n+use codex_app_server_protocol::RemoteControlPairingStatusResponse;\n use codex_login::default_client::build_reqwest_client;\n use codex_state::RemoteControlEnrollmentRecord;\n use codex_state::StateRuntime;\n@@ -136,6 +139,69 @@ impl RemoteControlEnrollment {\n })\n }\n \n+ p...",
"path": "codex-rs/app-server-transport/src/transport/remote_control/enroll.rs",
"status": "modified"
},
{
"additions": 114,
"deletions": 0,
"patch_excerpt": "@@ -18,6 +18,7 @@ use crate::transport::remote_control::websocket::RemoteControlStatusPublisher;\n use crate::transport::remote_control::websocket::RemoteControlWebsocket;\n \n pub use self::protocol::ClientId;\n+use self::protocol::RemoteControlPairingStatusCode;\n use self::protocol::ServerEvent;\n use self::protocol::StreamId;\n use self::protocol::normalize_remote_control_url;\n@@ -31,6 +32,8 @@ use codex_app_server_protocol::RemoteControlClientsRevokeResponse;\n use codex_app_server_protocol::RemoteControlConnectionStatus;\n use codex_app_server_protocol::RemoteControlPairingStartParams;\n use codex_app_server_protocol::RemoteControlPairingStartResponse;\n+use codex_app_server_protocol::RemoteControlPairingStatusParams;\n+use codex_app_server_protocol::RemoteControlPairingStatusResponse;\n use codex_app_server_protocol::RemoteControlStatusChangedNotification;\n use codex_login::AuthManager;\n use c...",
"path": "codex-rs/app-server-transport/src/transport/remote_control/mod.rs",
"status": "modified"
},
{
"additions": 51,
"deletions": 0,
"patch_excerpt": "@@ -13,6 +13,7 @@ pub(super) struct RemoteControlTarget {\n pub(super) enroll_url: String,\n pub(super) refresh_url: String,\n pub(super) pair_url: String,\n+ pub(super) pair_status_url: String,\n }\n \n #[derive(Debug, Serialize)]\n@@ -52,6 +53,40 @@ pub(super) struct StartRemoteControlPairingResponse {\n pub(super) expires_at: String,\n }\n \n+#[derive(Debug, Serialize)]\n+pub(super) struct RemoteControlPairingStatusRequest {\n+ #[serde(skip_serializing_if = \"Option::is_none\")]\n+ pub(super) pairing_code: Option<String>,\n+ #[serde(skip_serializing_if = \"Option::is_none\")]\n+ pub(super) manual_pairing_code: Option<String>,\n+}\n+\n+#[derive(Clone)]\n+pub(super) enum RemoteControlPairingStatusCode {\n+ PairingCode(String),\n+ ManualPairingCode(String),\n+}\n+\n+impl From<RemoteControlPairingStatusCode> for RemoteControlPairingStatusRequest {\n+ fn from(code: RemoteControlPa...",
"path": "codex-rs/app-server-transport/src/transport/remote_control/protocol.rs",
"status": "modified"
},
{
"additions": 1,
"deletions": 0,
"patch_excerpt": "@@ -21,6 +21,7 @@ use codex_app_server_protocol::ConfigWarningNotification;\n use codex_app_server_protocol::JSONRPCMessage;\n use codex_app_server_protocol::RemoteControlConnectionStatus;\n use codex_app_server_protocol::RemoteControlPairingStartParams;\n+use codex_app_server_protocol::RemoteControlPairingStatusParams;\n use codex_app_server_protocol::RemoteControlStatusChangedNotification;\n use codex_app_server_protocol::ServerNotification;\n use codex_config::types::AuthCredentialsStoreMode;",
"path": "codex-rs/app-server-transport/src/transport/remote_control/tests.rs",
"status": "modified"
},
{
"additions": 216,
"deletions": 0,
"patch_excerpt": "@@ -1,6 +1,8 @@\n+use super::super::protocol::RemoteControlPairingStatusRequest;\n use super::super::protocol::StartRemoteControlPairingRequest;\n use super::*;\n use pretty_assertions::assert_eq;\n+use std::io;\n \n fn remote_control_enrollment(\n remote_control_url: &str,\n@@ -66,6 +68,36 @@ async fn pairing_response_error(body: serde_json::Value) -> String {\n err.to_string()\n }\n \n+async fn pairing_status_error(status: &'static str, body: &'static str) -> (io::Error, String) {\n+ let listener = TcpListener::bind(\"127.0.0.1:0\")\n+ .await\n+ .expect(\"listener should bind\");\n+ let remote_control_url = remote_control_url_for_listener(&listener);\n+ let expected_status_url = normalize_remote_control_url(&remote_control_url)\n+ .expect(\"target should normalize\")\n+ .pair_status_url;\n+ let server_task = tokio::spawn(async move {\n+ let status_request = a...",
"path": "codex-rs/app-server-transport/src/transport/remote_control/tests/pairing_tests.rs",
"status": "modified"
}
],
"linked_issues": [],
"notes": [
"Built from GitHub pull-request, commits, files, and repo endpoints."
],
"primary_pr": {
"body": "## What\n\nAdds transport support for checking remote-control pairing status against the backend.\n\n- Adds the normalized `server/pair/status` backend URL.\n- Adds backend request/response structs for exactly one lookup key: `pairing_code` or `manual_pairing_code`, returning `{ claimed }`.\n- Adds `RemoteControlEnrollment::pairing_status` and `RemoteControlHandle::pairing_status`.\n- Preserves auth refresh/retry behavior and backend error mapping.\n- Adds transport coverage for pending, claimed, manual-code payloads, token refresh, mapped backend errors, malformed responses, and URL normalization.\n\n## Why\n\nDesktop needs a host-authenticated way to poll whether a QR or manual pairing code has been claimed.\n\nRelated backend change: https://github.com/openai/openai/pull/990244\n\n## Verification\n\n- `cargo test --manifest-path app-server-transport/Cargo.toml remote_control::tests::pairing_tests`\n- `cargo fmt --all --check`\n- `git diff --check`",
"labels": [],
"merged_at": "2026-06-05T17:07:25Z",
"number": 26449,
"state": "merged",
"title": "feat(remote-control): add pairing status transport",
"url": "https://github.com/openai/codex/pull/26449"
},
"repo": "openai/codex",
"schema": "github_change_bundle/v1"
}
106 changes: 106 additions & 0 deletions artifacts/github/bundles/openai-codex-pr-26450.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"analysis_mode": "pr_first",
"commits": [
{
"author": "hefuc-oai",
"committed_at": "2026-06-04T19:20:55Z",
"message": "feat(app-server): add remote control pairing status RPC",
"sha": "7d3240b290464a9102fd68f4438c1bd7ecb2431d",
"url": "https://github.com/openai/codex/commit/7d3240b290464a9102fd68f4438c1bd7ecb2431d"
}
],
"default_branch": "main",
"docs_refs": [
"codex-rs/app-server/README.md"
],
"examples_refs": [],
"extracted_flags": [
"RPC",
"README",
"JSON",
"--manifest-path",
"--all",
"--check",
"JSONRPCE",
"INTERNAL_ERROR_CODE",
"INVALID_REQUEST_ERROR_CODE",
"ABCD",
"JSONRPCR",
"DEFAULT_TIMEOUT",
"POST",
"HTTP"
],
"files": [
{
"additions": 3,
"deletions": 0,
"patch_excerpt": "@@ -2963,11 +2963,14 @@ permissionProfile?: string | null};\n \n let client_request_json = fs::read_to_string(output_dir.join(\"ClientRequest.json\"))?;\n assert!(client_request_json.contains(\"remoteControl/pairing/start\"));\n+ assert!(client_request_json.contains(\"remoteControl/pairing/status\"));\n assert!(client_request_json.contains(\"remoteControl/client/list\"));\n assert!(client_request_json.contains(\"remoteControl/client/revoke\"));\n for schema in [\n \"RemoteControlPairingStartParams.json\",\n \"RemoteControlPairingStartResponse.json\",\n+ \"RemoteControlPairingStatusParams.json\",\n+ \"RemoteControlPairingStatusResponse.json\",\n \"RemoteControlClientsListParams.json\",\n \"RemoteControlClientsListResponse.json\",\n \"RemoteControlClientsRevokeParams.json\",",
"path": "codex-rs/app-server-protocol/src/export.rs",
"status": "modified"
},
{
"additions": 19,
"deletions": 0,
"patch_excerpt": "@@ -849,6 +849,12 @@ client_request_definitions! {\n serialization: global(\"remote-control-pairing\"),\n response: v2::RemoteControlPairingStartResponse,\n },\n+ #[experimental(\"remoteControl/pairing/status\")]\n+ RemoteControlPairingStatus => \"remoteControl/pairing/status\" {\n+ params: v2::RemoteControlPairingStatusParams,\n+ serialization: global_shared_read(\"remote-control-pairing\"),\n+ response: v2::RemoteControlPairingStatusResponse,\n+ },\n #[experimental(\"remoteControl/client/list\")]\n RemoteControlClientsList => \"remoteControl/client/list\" {\n params: v2::RemoteControlClientsListParams,\n@@ -2014,6 +2020,19 @@ mod tests {\n \"remote-control-pairing\"\n ))\n );\n+ let remote_control_pairing_status = ClientRequest::RemoteControlPairingStatus {\n+ request_id: request_id(),\n+ ...",
"path": "codex-rs/app-server-protocol/src/protocol/common.rs",
"status": "modified"
},
{
"additions": 1,
"deletions": 0,
"patch_excerpt": "@@ -211,6 +211,7 @@ Example with notification opt-out:\n - `remoteControl/disable` — experimental; disable remote control for the current app-server process and return the current remote-control status snapshot. This does not revoke already enrolled controller devices.\n - `remoteControl/status/read` — experimental; read the current remote-control status snapshot. `status` is one of `disabled`, `connecting`, `connected`, or `errored`; `serverName` is the local machine name used by this app-server process; `environmentId` is a string when the app-server has a current enrollment and `null` when that enrollment is cleared, invalidated, or remote control is disabled.\n - `remoteControl/pairing/start` — experimental; start a short-lived remote-control pairing artifact for the current app-server process. Pass `manualCode: true` to also request a manual pairing code. Returns `pairingCode`, `manual...",
"path": "codex-rs/app-server/README.md",
"status": "modified"
},
{
"additions": 5,
"deletions": 0,
"patch_excerpt": "@@ -921,6 +921,11 @@ impl MessageProcessor {\n .pairing_start(params, app_server_client_name.as_deref())\n .await\n .map(|response| Some(response.into())),\n+ ClientRequest::RemoteControlPairingStatus { params, .. } => self\n+ .remote_control_processor\n+ .pairing_status(params)\n+ .await\n+ .map(|response| Some(response.into())),\n ClientRequest::RemoteControlClientsList { params, .. } => self\n .remote_control_processor\n .clients_list(params)",
"path": "codex-rs/app-server/src/message_processor.rs",
"status": "modified"
},
{
"additions": 27,
"deletions": 0,
"patch_excerpt": "@@ -11,6 +11,8 @@ use codex_app_server_protocol::RemoteControlDisableResponse;\n use codex_app_server_protocol::RemoteControlEnableResponse;\n use codex_app_server_protocol::RemoteControlPairingStartParams;\n use codex_app_server_protocol::RemoteControlPairingStartResponse;\n+use codex_app_server_protocol::RemoteControlPairingStatusParams;\n+use codex_app_server_protocol::RemoteControlPairingStatusResponse;\n use codex_app_server_protocol::RemoteControlStatusReadResponse;\n use std::io;\n \n@@ -60,6 +62,17 @@ impl RemoteControlRequestProcessor {\n .map_err(map_pairing_start_error)\n }\n \n+ pub(crate) async fn pairing_status(\n+ &self,\n+ params: RemoteControlPairingStatusParams,\n+ ) -> Result<RemoteControlPairingStatusResponse, JSONRPCErrorError> {\n+ validate_pairing_status_params(&params)?;\n+ self.handle()?\n+ .pairing_status(params)\n+ ...",
"path": "codex-rs/app-server/src/request_processors/remote_control_processor.rs",
"status": "modified"
},
{
"additions": 53,
"deletions": 0,
"patch_excerpt": "@@ -23,6 +23,59 @@ async fn pairing_start_returns_internal_error_when_remote_control_is_unavailable\n );\n }\n \n+#[tokio::test]\n+async fn pairing_status_returns_internal_error_when_remote_control_is_unavailable() {\n+ let err = RemoteControlRequestProcessor::new(/*remote_control_handle*/ None)\n+ .pairing_status(RemoteControlPairingStatusParams {\n+ pairing_code: Some(\"pairing-code\".to_string()),\n+ manual_pairing_code: None,\n+ })\n+ .await\n+ .expect_err(\"missing remote control should fail pairing status\");\n+\n+ assert_eq!(\n+ err,\n+ JSONRPCErrorError {\n+ code: INTERNAL_ERROR_CODE,\n+ data: None,\n+ message: \"remote control is unavailable for this app-server\".to_string(),\n+ }\n+ );\n+}\n+\n+#[test]\n+fn pairing_status_rejects_missing_pairing_codes() {\n+ assert_eq!(\n+ validate_pai...",
"path": "codex-rs/app-server/src/request_processors/remote_control_processor/remote_control_processor_tests.rs",
"status": "modified"
},
{
"additions": 11,
"deletions": 0,
"patch_excerpt": "@@ -70,6 +70,7 @@ use codex_app_server_protocol::ProcessWriteStdinParams;\n use codex_app_server_protocol::RemoteControlClientsListParams;\n use codex_app_server_protocol::RemoteControlClientsRevokeParams;\n use codex_app_server_protocol::RemoteControlPairingStartParams;\n+use codex_app_server_protocol::RemoteControlPairingStatusParams;\n use codex_app_server_protocol::RequestId;\n use codex_app_server_protocol::ReviewStartParams;\n use codex_app_server_protocol::SendAddCreditsNudgeEmailParams;\n@@ -656,6 +657,16 @@ impl TestAppServer {\n .await\n }\n \n+ /// Send a `remoteControl/pairing/status` JSON-RPC request.\n+ pub async fn send_remote_control_pairing_status_request(\n+ &mut self,\n+ params: RemoteControlPairingStatusParams,\n+ ) -> anyhow::Result<i64> {\n+ let params = Some(serde_json::to_value(params)?);\n+ self.send_request(\"remoteControl/pairi...",
"path": "codex-rs/app-server/tests/common/test_app_server.rs",
"status": "modified"
},
{
"additions": 74,
"deletions": 0,
"patch_excerpt": "@@ -19,12 +19,15 @@ use codex_app_server_protocol::RemoteControlDisableResponse;\n use codex_app_server_protocol::RemoteControlEnableResponse;\n use codex_app_server_protocol::RemoteControlPairingStartParams;\n use codex_app_server_protocol::RemoteControlPairingStartResponse;\n+use codex_app_server_protocol::RemoteControlPairingStatusParams;\n+use codex_app_server_protocol::RemoteControlPairingStatusResponse;\n use codex_app_server_protocol::RemoteControlStatusReadResponse;\n use codex_app_server_protocol::RequestId;\n use codex_config::types::AuthCredentialsStoreMode;\n use pretty_assertions::assert_eq;\n use tempfile::TempDir;\n use tokio::io::AsyncBufReadExt;\n+use tokio::io::AsyncReadExt;\n use tokio::io::AsyncWriteExt;\n use tokio::io::BufReader;\n use tokio::net::TcpListener;\n@@ -190,6 +193,44 @@ async fn remote_control_pairing_start_returns_pairing_artifacts() -> Result<()>\n expires_...",
"path": "codex-rs/app-server/tests/suite/v2/remote_control.rs",
"status": "modified"
}
],
"linked_issues": [],
"notes": [
"Built from GitHub pull-request, commits, files, and repo endpoints."
],
"primary_pr": {
"body": "## What\n\nExposes the pairing status transport as experimental app-server v2 RPC `remoteControl/pairing/status`.\n\n- Adds request/response protocol types for exactly one lookup key: `pairingCode` or `manualPairingCode`, returning `{ claimed }`.\n- Registers the RPC with `global_shared_read(\"remote-control-pairing\")`.\n- Wires the method through `MessageProcessor` and `RemoteControlRequestProcessor`.\n- Validates missing/conflicting pairing-code params as invalid requests.\n- Documents the RPC in `app-server/README.md`.\n- Adds processor, protocol export, and JSON-RPC integration coverage for both code paths.\n\n## Why\n\nThis is the app-server surface the desktop app can poll while the QR/manual pairing modal is active.\n\nDepends on https://github.com/openai/codex/pull/26449\nRelated backend change: https://github.com/openai/openai/pull/990244\n\n## Verification\n\n- `cargo test --manifest-path app-server-protocol/Cargo.toml remote_control`\n- `cargo test --manifest-path app-server/Cargo.toml remote_control`\n- `cargo fmt --all --check`\n- `git diff --check`",
"labels": [],
"merged_at": "2026-06-05T17:33:57Z",
"number": 26450,
"state": "merged",
"title": "feat(app-server): add remote control pairing status RPC",
"url": "https://github.com/openai/codex/pull/26450"
},
"repo": "openai/codex",
"schema": "github_change_bundle/v1"
}
Loading