aboutsummaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-02 02:45:20 +0300
committerGitHub <noreply@github.com>2026-09-02 02:45:20 +0300
commitcc88b3b8e5bb9f7d9f23ed6ae85a52fd7b5b9ed6 (patch)
tree4d37c760099070f1a1488b61c7b7271875aafef8 /src/api
parent18e69891dca486d669a584facd80644bb51f54a2 (diff)
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
Diffstat (limited to 'src/api')
-rw-r--r--src/api/mod.rs2
-rw-r--r--src/api/schema/server.rs3
-rw-r--r--src/api/schema/tests.rs7
-rw-r--r--src/api/server.rs6
4 files changed, 16 insertions, 2 deletions
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<u32>,
}
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
@@ -708,6 +708,12 @@ fn scroll_changed_subscription_event_round_trips() {
}
#[test]
+fn agent_status_request_values_remain_strict() {
+ assert!(serde_json::from_str::<AgentStatus>(r#""working""#).is_ok());
+ assert!(serde_json::from_str::<AgentStatus>(r#""future_status""#).is_err());
+}
+
+#[test]
fn success_response_round_trips() {
let response = SuccessResponse {
id: "req_1".into(),
@@ -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<ServerCapabilities> {
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,