Skip to main content

ai_agent/tools/
worktree.rs

1// Source: /data/home/swei/claudecode/openclaudecode/src/utils/worktree.ts
2//! Git worktree tools.
3//!
4//! Provides tools for managing git worktrees.
5
6use crate::types::*;
7
8/// EnterWorktree tool - create and enter a git worktree
9pub struct EnterWorktreeTool;
10
11impl EnterWorktreeTool {
12    pub fn new() -> Self {
13        Self
14    }
15
16    pub fn input_schema(&self) -> ToolInputSchema {
17        ToolInputSchema {
18            schema_type: "object".to_string(),
19            properties: serde_json::json!({
20                "name": {
21                    "type": "string",
22                    "description": "Optional name for the worktree. If not provided, a random name is generated."
23                }
24            }),
25            required: None,
26        }
27    }
28
29    pub async fn execute(
30        &self,
31        input: serde_json::Value,
32        _context: &ToolContext,
33    ) -> Result<ToolResult, crate::error::AgentError> {
34        let name = input["name"].as_str();
35
36        let response = if let Some(n) = name {
37            format!(
38                "Creating worktree '{}'...\nNote: Full implementation would create a new git worktree at .ai/worktrees/{} and switch to it.",
39                n, n
40            )
41        } else {
42            "Creating worktree with random name...\nNote: Full implementation would create a new git worktree.".to_string()
43        };
44
45        Ok(ToolResult {
46            result_type: "text".to_string(),
47            tool_use_id: "enter_worktree".to_string(),
48            content: response,
49            is_error: Some(false),
50        })
51    }
52}
53
54impl Default for EnterWorktreeTool {
55    fn default() -> Self {
56        Self::new()
57    }
58}
59
60/// ExitWorktree tool - exit a worktree and return to original directory
61pub struct ExitWorktreeTool;
62
63impl ExitWorktreeTool {
64    pub fn new() -> Self {
65        Self
66    }
67
68    pub fn input_schema(&self) -> ToolInputSchema {
69        ToolInputSchema {
70            schema_type: "object".to_string(),
71            properties: serde_json::json!({
72                "action": {
73                    "type": "string",
74                    "enum": ["keep", "remove"],
75                    "description": "What to do with the worktree: 'keep' leaves it on disk, 'remove' deletes it"
76                },
77                "discardChanges": {
78                    "type": "boolean",
79                    "description": "If true, discard uncommitted changes before removing"
80                }
81            }),
82            required: None,
83        }
84    }
85
86    pub async fn execute(
87        &self,
88        input: serde_json::Value,
89        _context: &ToolContext,
90    ) -> Result<ToolResult, crate::error::AgentError> {
91        let action = input["action"].as_str().unwrap_or("keep");
92        let discard = input["discardChanges"].as_bool().unwrap_or(false);
93
94        let response = format!(
95            "Exiting worktree...\nAction: {}\nDiscard changes: {}\nNote: Full implementation would restore the session to the original working directory.",
96            action, discard
97        );
98
99        Ok(ToolResult {
100            result_type: "text".to_string(),
101            tool_use_id: "exit_worktree".to_string(),
102            content: response,
103            is_error: Some(false),
104        })
105    }
106}
107
108impl Default for ExitWorktreeTool {
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_enter_worktree_schema() {
120        let tool = EnterWorktreeTool::new();
121        let schema = tool.input_schema();
122        assert!(schema.properties.get("name").is_some());
123    }
124
125    #[test]
126    fn test_exit_worktree_schema() {
127        let tool = ExitWorktreeTool::new();
128        let schema = tool.input_schema();
129        assert!(schema.properties.get("action").is_some());
130    }
131}