From cc88b3b8e5bb9f7d9f23ed6ae85a52fd7b5b9ed6 Mon Sep 17 00:00:00 2001 From: Can Celik Date: Wed, 2 Sep 2026 02:45:20 +0300 Subject: feat: add stable client endpoint compatibility (#3509) * feat: add stable client endpoint compatibility * fix: keep portable-pty patch checks composable * ci: run maintenance checks in pull requests * fix: reject endpoint errors from terminal clients * feat: keep compatible servers running across updates --- src/api/mod.rs | 2 +- src/api/schema/server.rs | 3 +++ src/api/schema/tests.rs | 7 +++++++ src/api/server.rs | 6 +++++- 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/api') diff --git a/src/api/mod.rs b/src/api/mod.rs index 363d7702..d28a82ae 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -7,8 +7,8 @@ mod subscriptions; mod wait; pub use event_hub::EventHub; -pub(crate) use server::start_server_with_stop_control; pub use server::ServerHandle; +pub(crate) use server::{api_method_name, start_server_with_stop_control}; pub use status::{read_runtime_status_at, RuntimeStatus}; use std::path::PathBuf; diff --git a/src/api/schema/server.rs b/src/api/schema/server.rs index 7ceda633..96e51564 100644 --- a/src/api/schema/server.rs +++ b/src/api/schema/server.rs @@ -18,4 +18,7 @@ pub struct ServerCapabilities { pub live_handoff: bool, #[serde(default)] pub detached_server_daemon: bool, + /// Stable client-owned endpoint generation supported by this server. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub endpoint_protocol_generation: Option, } diff --git a/src/api/schema/tests.rs b/src/api/schema/tests.rs index e4a7f2a3..06529f5e 100644 --- a/src/api/schema/tests.rs +++ b/src/api/schema/tests.rs @@ -707,6 +707,12 @@ fn scroll_changed_subscription_event_round_trips() { assert_eq!(restored, event); } +#[test] +fn agent_status_request_values_remain_strict() { + assert!(serde_json::from_str::(r#""working""#).is_ok()); + assert!(serde_json::from_str::(r#""future_status""#).is_err()); +} + #[test] fn success_response_round_trips() { let response = SuccessResponse { @@ -717,6 +723,7 @@ fn success_response_round_trips() { capabilities: Some(ServerCapabilities { live_handoff: true, detached_server_daemon: true, + endpoint_protocol_generation: Some(1), }), }, }; diff --git a/src/api/server.rs b/src/api/server.rs index ff0b6fdf..64beec33 100644 --- a/src/api/server.rs +++ b/src/api/server.rs @@ -68,6 +68,7 @@ fn default_capabilities() -> Option { Some(ServerCapabilities { live_handoff: crate::platform::capabilities().live_handoff, detached_server_daemon: crate::platform::current_process_is_detached_server_daemon(), + endpoint_protocol_generation: Some(crate::protocol::endpoint::ENDPOINT_PROTOCOL_GENERATION), }) } @@ -371,7 +372,7 @@ fn handle_request( dispatch_to_app(request, api_tx, None, response_write_complete, None) } -fn api_method_name(method: &Method) -> &'static str { +pub(crate) fn api_method_name(method: &Method) -> &'static str { match method { Method::Ping(_) => "ping", Method::ServerStop(_) => "server.stop", @@ -1090,6 +1091,9 @@ mod tests { Some(ServerCapabilities { live_handoff: true, detached_server_daemon: true, + endpoint_protocol_generation: Some( + crate::protocol::endpoint::ENDPOINT_PROTOCOL_GENERATION, + ), }), None, None, -- cgit v1.2.3