diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-23 15:11:48 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-23 15:19:36 +0300 |
| commit | 9817820af1f0468402934122538f658299ff71de (patch) | |
| tree | 1bf668cf866213d10eec30a85401aedc54fb714f /src/api/schema.rs | |
| parent | ed11779fcaebea7cc3223c4e221ea43674057891 (diff) | |
feat: add worktree cli and socket api
Diffstat (limited to 'src/api/schema.rs')
| -rw-r--r-- | src/api/schema.rs | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/api/schema.rs b/src/api/schema.rs index 7224d419..17a5d35e 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -28,6 +28,14 @@ pub enum Method { WorkspaceRename(WorkspaceRenameParams), #[serde(rename = "workspace.close")] WorkspaceClose(WorkspaceTarget), + #[serde(rename = "worktree.list")] + WorktreeList(WorktreeListParams), + #[serde(rename = "worktree.create")] + WorktreeCreate(WorktreeCreateParams), + #[serde(rename = "worktree.open")] + WorktreeOpen(WorktreeOpenParams), + #[serde(rename = "worktree.remove")] + WorktreeRemove(WorktreeRemoveParams), #[serde(rename = "tab.create")] TabCreate(TabCreateParams), #[serde(rename = "tab.list")] @@ -127,6 +135,55 @@ pub struct WorkspaceRenameParams { pub label: String, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct WorktreeListParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub workspace_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cwd: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct WorktreeCreateParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub workspace_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cwd: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub base: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub label: Option<String>, + #[serde(default)] + pub focus: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct WorktreeOpenParams { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub workspace_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cwd: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub label: Option<String>, + #[serde(default)] + pub focus: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorktreeRemoveParams { + pub workspace_id: String, + #[serde(default)] + pub force: bool, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct TabCreateParams { #[serde(default, skip_serializing_if = "Option::is_none")] @@ -320,6 +377,10 @@ pub struct EventsSubscribeParams { pub enum Subscription { #[serde(rename = "workspace.created")] WorkspaceCreated {}, + #[serde(rename = "workspace.updated")] + WorkspaceUpdated {}, + #[serde(rename = "workspace.renamed")] + WorkspaceRenamed {}, #[serde(rename = "workspace.closed")] WorkspaceClosed {}, #[serde(rename = "workspace.focused")] @@ -415,6 +476,9 @@ pub enum EventMatch { #[serde(default, skip_serializing_if = "Option::is_none")] workspace_id: Option<String>, }, + WorkspaceUpdated { + workspace_id: String, + }, WorkspaceClosed { workspace_id: String, }, @@ -478,6 +542,7 @@ pub enum EventMatch { #[serde(rename_all = "snake_case")] pub enum EventKind { WorkspaceCreated, + WorkspaceUpdated, WorkspaceClosed, WorkspaceRenamed, WorkspaceFocused, @@ -530,6 +595,28 @@ pub enum ResponseResult { WorkspaceList { workspaces: Vec<WorkspaceInfo>, }, + WorktreeList { + source: WorktreeSourceInfo, + worktrees: Vec<WorktreeInfo>, + }, + WorktreeCreated { + workspace: WorkspaceInfo, + tab: TabInfo, + root_pane: PaneInfo, + worktree: WorktreeInfo, + }, + WorktreeOpened { + workspace: WorkspaceInfo, + tab: TabInfo, + root_pane: PaneInfo, + worktree: WorktreeInfo, + already_open: bool, + }, + WorktreeRemoved { + workspace_id: String, + path: String, + forced: bool, + }, TabInfo { tab: TabInfo, }, @@ -594,6 +681,41 @@ pub struct WorkspaceInfo { pub tab_count: usize, pub active_tab_id: String, pub agent_status: AgentStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub worktree: Option<WorkspaceWorktreeInfo>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorkspaceWorktreeInfo { + pub repo_key: String, + pub repo_name: String, + pub repo_root: String, + pub checkout_path: String, + pub is_linked_worktree: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorktreeSourceInfo { + pub repo_key: String, + pub repo_name: String, + pub repo_root: String, + pub source_checkout_path: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub source_workspace_id: Option<String>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct WorktreeInfo { + pub path: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch: Option<String>, + pub is_bare: bool, + pub is_detached: bool, + pub is_prunable: bool, + pub is_linked_worktree: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub open_workspace_id: Option<String>, + pub label: String, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -716,6 +838,9 @@ pub enum EventData { WorkspaceCreated { workspace: WorkspaceInfo, }, + WorkspaceUpdated { + workspace: WorkspaceInfo, + }, WorkspaceClosed { workspace_id: String, }, @@ -1103,6 +1228,83 @@ mod tests { } #[test] + fn worktree_request_and_response_round_trip() { + let request = Request { + id: "req_worktree".into(), + method: Method::WorktreeCreate(WorktreeCreateParams { + workspace_id: Some("1".into()), + branch: Some("worktree/api".into()), + base: Some("HEAD".into()), + focus: true, + ..WorktreeCreateParams::default() + }), + }; + let json = serde_json::to_string(&request).unwrap(); + let restored: Request = serde_json::from_str(&json).unwrap(); + assert_eq!(restored, request); + + let response = SuccessResponse { + id: "req_worktree".into(), + result: ResponseResult::WorktreeCreated { + workspace: WorkspaceInfo { + workspace_id: "w_1".into(), + number: 2, + label: "herdr".into(), + focused: true, + pane_count: 1, + tab_count: 1, + active_tab_id: "w_1:1".into(), + agent_status: AgentStatus::Unknown, + worktree: Some(WorkspaceWorktreeInfo { + repo_key: "/repo/herdr/.git".into(), + repo_name: "herdr".into(), + repo_root: "/repo/herdr".into(), + checkout_path: "/worktrees/herdr/worktree-api".into(), + is_linked_worktree: true, + }), + }, + tab: TabInfo { + tab_id: "w_1:1".into(), + workspace_id: "w_1".into(), + number: 1, + label: "herdr".into(), + focused: true, + pane_count: 1, + agent_status: AgentStatus::Unknown, + }, + root_pane: PaneInfo { + pane_id: "w_1-1".into(), + terminal_id: "term_1".into(), + workspace_id: "w_1".into(), + tab_id: "w_1:1".into(), + focused: true, + cwd: Some("/worktrees/herdr/worktree-api".into()), + label: None, + agent: None, + agent_status: AgentStatus::Unknown, + custom_status: None, + revision: 0, + }, + worktree: WorktreeInfo { + path: "/worktrees/herdr/worktree-api".into(), + branch: Some("worktree/api".into()), + is_bare: false, + is_detached: false, + is_prunable: false, + is_linked_worktree: true, + open_workspace_id: Some("w_1".into()), + label: "herdr".into(), + }, + }, + }; + let json = serde_json::to_string(&response).unwrap(); + assert!(json.contains("\"type\":\"worktree_created\"")); + assert!(json.contains("\"worktree\"")); + let restored: SuccessResponse = serde_json::from_str(&json).unwrap(); + assert_eq!(restored, response); + } + + #[test] fn create_response_round_trips_with_root_pane() { let response = SuccessResponse { id: "req_2".into(), |
