aboutsummaryrefslogtreecommitdiff
path: root/src/api/schema
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/schema')
-rw-r--r--src/api/schema/commands.rs16
-rw-r--r--src/api/schema/common.rs19
-rw-r--r--src/api/schema/integrations.rs17
-rw-r--r--src/api/schema/panes.rs80
-rw-r--r--src/api/schema/response.rs29
-rw-r--r--src/api/schema/tests.rs75
-rw-r--r--src/api/schema/workspaces.rs3
7 files changed, 230 insertions, 9 deletions
diff --git a/src/api/schema/commands.rs b/src/api/schema/commands.rs
new file mode 100644
index 00000000..c9ccd4bc
--- /dev/null
+++ b/src/api/schema/commands.rs
@@ -0,0 +1,16 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct CommandInvokeParams {
+ /// Opaque endpoint-issued command identifier from the client-shell projection.
+ pub command_id: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub workspace_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub tab_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub pane_id: Option<String>,
+ /// Client-owned selection coordinates, validated against the pane's content revision.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub selection: Option<super::PaneSelectionReadParams>,
+}
diff --git a/src/api/schema/common.rs b/src/api/schema/common.rs
index 7313002c..15f56e6c 100644
--- a/src/api/schema/common.rs
+++ b/src/api/schema/common.rs
@@ -36,6 +36,17 @@ pub struct PaneTarget {
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct ProductAnnouncementDismissParams {
+ pub version: String,
+ pub id: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct ReleaseNotesDismissParams {
+ pub version: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
pub struct TabTarget {
pub tab_id: String,
}
@@ -109,14 +120,6 @@ impl NotificationShowSound {
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
-
- pub fn to_sound(self) -> Option<crate::sound::Sound> {
- match self {
- Self::None => None,
- Self::Done => Some(crate::sound::Sound::Done),
- Self::Request => Some(crate::sound::Sound::Request),
- }
- }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
diff --git a/src/api/schema/integrations.rs b/src/api/schema/integrations.rs
index 6151dedb..0fce2913 100644
--- a/src/api/schema/integrations.rs
+++ b/src/api/schema/integrations.rs
@@ -1,5 +1,22 @@
use serde::{Deserialize, Serialize};
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum IntegrationState {
+ NotInstalled,
+ Current,
+ Outdated,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct IntegrationInfo {
+ pub target: IntegrationTarget,
+ pub label: String,
+ pub command: String,
+ pub available: bool,
+ pub state: IntegrationState,
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
pub struct IntegrationInstallParams {
pub target: IntegrationTarget,
diff --git a/src/api/schema/panes.rs b/src/api/schema/panes.rs
index 6435a422..517870f7 100644
--- a/src/api/schema/panes.rs
+++ b/src/api/schema/panes.rs
@@ -48,6 +48,17 @@ pub struct PaneInputSetParams {
pub right_click: PaneRightClickTarget,
}
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneLinkActivateParams {
+ pub pane_id: String,
+ pub viewport_row: u16,
+ pub col: u16,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub content_revision: Option<u64>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub offset_from_bottom: Option<u64>,
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PaneDirection {
@@ -231,6 +242,75 @@ pub struct PaneResizeParams {
pub amount: Option<f32>,
}
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneScrollParams {
+ pub pane_id: String,
+ pub offset_from_bottom: u64,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneTextPoint {
+ pub row: u32,
+ pub col: u16,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneSelectionReadParams {
+ pub pane_id: String,
+ pub anchor: PaneTextPoint,
+ pub cursor: PaneTextPoint,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub content_revision: Option<u64>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum PaneCopyMotion {
+ LineEnd,
+ FirstNonBlank,
+ NextWordStart,
+ PreviousWordStart,
+ NextWordEnd,
+ NextBigWordStart,
+ PreviousBigWordStart,
+ NextBigWordEnd,
+ PreviousParagraph,
+ NextParagraph,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneCopyMotionParams {
+ pub pane_id: String,
+ pub cursor: PaneTextPoint,
+ pub motion: PaneCopyMotion,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub content_revision: Option<u64>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum PaneCopySearchDirection {
+ Forward,
+ Backward,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneTextRange {
+ pub start: PaneTextPoint,
+ pub end: PaneTextPoint,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
+pub struct PaneCopySearchParams {
+ pub pane_id: String,
+ pub query: String,
+ pub direction: PaneCopySearchDirection,
+ pub cursor: PaneTextPoint,
+ pub content_revision: u64,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub previous: Option<PaneTextRange>,
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema, Default)]
pub struct PaneListParams {
#[serde(default, skip_serializing_if = "Option::is_none")]
diff --git a/src/api/schema/response.rs b/src/api/schema/response.rs
index da2813a6..180d6645 100644
--- a/src/api/schema/response.rs
+++ b/src/api/schema/response.rs
@@ -9,7 +9,7 @@ use super::integrations::{
use super::panes::{
LayoutDescription, PaneEdgesResult, PaneFocusDirectionResult, PaneInfo, PaneLayoutSnapshot,
PaneMoveResult, PaneNeighborResult, PaneProcessInfo, PaneReadResult, PaneResizeResult,
- PaneSwapResult, PaneZoomResult,
+ PaneSwapResult, PaneTextPoint, PaneTextRange, PaneZoomResult,
};
use super::plugins::{
InstalledPluginInfo, PluginActionInfo, PluginCommandLogInfo, PluginInvocationContext,
@@ -162,6 +162,25 @@ pub enum ResponseResult {
PaneRead {
read: PaneReadResult,
},
+ PaneSelection {
+ pane_id: String,
+ text: String,
+ },
+ PaneCopyMotion {
+ pane_id: String,
+ cursor: PaneTextPoint,
+ content_revision: u64,
+ },
+ PaneCopySearch {
+ pane_id: String,
+ content_revision: u64,
+ matches: Vec<PaneTextRange>,
+ total: u64,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ current: Option<u32>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ current_global: Option<u64>,
+ },
PaneGraphicsFrameAck {
sequence: u64,
revision: u64,
@@ -210,6 +229,9 @@ pub enum ResponseResult {
changed: bool,
reason: ClientWindowTitleReason,
},
+ IntegrationList {
+ integrations: Vec<super::integrations::IntegrationInfo>,
+ },
IntegrationInstall {
target: IntegrationTarget,
details: IntegrationInstallResult,
@@ -252,6 +274,11 @@ pub enum ResponseResult {
context: PluginInvocationContext,
log: PluginCommandLogInfo,
},
+ PaneLinkActivated {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ url: Option<String>,
+ handled: bool,
+ },
PluginLogList {
logs: Vec<PluginCommandLogInfo>,
},
diff --git a/src/api/schema/tests.rs b/src/api/schema/tests.rs
index 663f3fc4..e4a7f2a3 100644
--- a/src/api/schema/tests.rs
+++ b/src/api/schema/tests.rs
@@ -50,6 +50,7 @@ fn request_uses_dot_method_names() {
let request = Request {
id: "req_1".into(),
method: Method::WorkspaceCreate(WorkspaceCreateParams {
+ source_workspace_id: None,
cwd: Some("/tmp".into()),
focus: true,
label: Some("api".into()),
@@ -273,6 +274,54 @@ fn request_round_trips_for_agent_explain() {
}
#[test]
+fn integration_list_request_and_response_round_trip() {
+ let request = Request {
+ id: "req_integrations".into(),
+ method: Method::IntegrationList(EmptyParams::default()),
+ };
+ let json = serde_json::to_value(&request).unwrap();
+ assert_eq!(json["method"], "integration.list");
+ assert_eq!(serde_json::from_value::<Request>(json).unwrap(), request);
+
+ let response = SuccessResponse {
+ id: "req_integrations".into(),
+ result: ResponseResult::IntegrationList {
+ integrations: vec![IntegrationInfo {
+ target: IntegrationTarget::Codex,
+ label: "codex".into(),
+ command: "codex".into(),
+ available: true,
+ state: IntegrationState::Outdated,
+ }],
+ },
+ };
+ let json = serde_json::to_value(&response).unwrap();
+ assert_eq!(json["result"]["type"], "integration_list");
+ assert_eq!(json["result"]["integrations"][0]["state"], "outdated");
+ assert_eq!(
+ serde_json::from_value::<SuccessResponse>(json).unwrap(),
+ response
+ );
+}
+
+#[test]
+fn command_invoke_request_round_trips_without_command_text() {
+ let request = Request {
+ id: "req_command".into(),
+ method: Method::CommandInvoke(CommandInvokeParams {
+ command_id: "cmd_0123456789abcdef0123456789abcdef".into(),
+ workspace_id: Some("w1".into()),
+ tab_id: Some("w1:t1".into()),
+ pane_id: Some("w1:p1".into()),
+ selection: None,
+ }),
+ };
+ let json = serde_json::to_value(&request).unwrap();
+ assert_eq!(json["method"], "command.invoke");
+ assert_eq!(serde_json::from_value::<Request>(json).unwrap(), request);
+}
+
+#[test]
fn notification_show_request_parses() {
let json = r#"{"id":"req_1","method":"notification.show","params":{"title":"build failed","body":"api workspace","position":"top-left","sound":"request"}}"#;
let request: Request = serde_json::from_str(json).unwrap();
@@ -1264,6 +1313,32 @@ fn event_wait_parses_typed_match() {
}
#[test]
+fn pane_link_activate_round_trips() {
+ let request = Request {
+ id: "req_pane_link".into(),
+ method: Method::PaneLinkActivate(PaneLinkActivateParams {
+ pane_id: "w1:p1".into(),
+ viewport_row: 3,
+ col: 7,
+ content_revision: Some(42),
+ offset_from_bottom: Some(5),
+ }),
+ };
+ let json = serde_json::to_value(&request).unwrap();
+ assert_eq!(json["method"], "pane.link.activate");
+ let restored: Request = serde_json::from_value(json).unwrap();
+ assert_eq!(restored, request);
+
+ let response = ResponseResult::PaneLinkActivated {
+ url: Some("https://example.test".into()),
+ handled: false,
+ };
+ let json = serde_json::to_string(&response).unwrap();
+ let restored: ResponseResult = serde_json::from_str(&json).unwrap();
+ assert_eq!(restored, response);
+}
+
+#[test]
fn plugin_action_list_and_invoke_round_trips() {
let list = Request {
id: "req_plugin_action_list".into(),
diff --git a/src/api/schema/workspaces.rs b/src/api/schema/workspaces.rs
index bfc63252..1b7132c4 100644
--- a/src/api/schema/workspaces.rs
+++ b/src/api/schema/workspaces.rs
@@ -6,6 +6,9 @@ use super::common::AgentStatus;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
pub struct WorkspaceCreateParams {
+ /// Workspace whose focused pane supplies the `follow` cwd policy.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub source_workspace_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cwd: Option<String>,
#[serde(default)]