Skip to main content

claude_rust_tools/infrastructure/
enter_worktree_tool.rs

1use claude_rust_errors::{AppError, AppResult};
2use claude_rust_types::{PermissionLevel, Tool};
3use serde_json::{Value, json};
4use tokio::process::Command;
5
6pub struct EnterWorktreeTool;
7
8impl EnterWorktreeTool {
9    pub fn new() -> Self {
10        Self
11    }
12}
13
14#[async_trait::async_trait]
15impl Tool for EnterWorktreeTool {
16    fn name(&self) -> &str {
17        "enter_worktree"
18    }
19
20    fn description(&self) -> &str {
21        "Create a git worktree for the specified branch."
22    }
23
24    fn input_schema(&self) -> Value {
25        json!({
26            "type": "object",
27            "properties": {
28                "branch": {
29                    "type": "string",
30                    "description": "Branch name to create the worktree for"
31                },
32                "path": {
33                    "type": "string",
34                    "description": "Path for the worktree directory (defaults to ../branch-name)"
35                }
36            },
37            "required": ["branch"]
38        })
39    }
40
41    fn permission_level(&self) -> PermissionLevel {
42        PermissionLevel::Dangerous
43    }
44
45    fn is_destructive(&self, _input: &Value) -> bool { true }
46
47    async fn execute(&self, input: Value) -> AppResult<String> {
48        let branch = input
49            .get("branch")
50            .and_then(|v| v.as_str())
51            .ok_or_else(|| AppError::Tool("missing 'branch' field".into()))?;
52
53        let default_path = format!("../{branch}");
54        let path = input
55            .get("path")
56            .and_then(|v| v.as_str())
57            .unwrap_or(&default_path);
58
59        tracing::info!(branch, path, "creating worktree");
60
61        // Try creating a new branch first; if that fails, use existing branch
62        let output = Command::new("git")
63            .args(["worktree", "add", path, "-b", branch])
64            .output()
65            .await
66            .map_err(|e| AppError::Tool(format!("failed to run git: {e}")))?;
67
68        if output.status.success() {
69            return Ok(format!("Created worktree at '{path}' on new branch '{branch}'."));
70        }
71
72        // Fall back to existing branch
73        let output = Command::new("git")
74            .args(["worktree", "add", path, branch])
75            .output()
76            .await
77            .map_err(|e| AppError::Tool(format!("failed to run git: {e}")))?;
78
79        if output.status.success() {
80            Ok(format!("Created worktree at '{path}' on existing branch '{branch}'."))
81        } else {
82            let stderr = String::from_utf8_lossy(&output.stderr);
83            Err(AppError::Tool(format!("git worktree add failed: {stderr}")))
84        }
85    }
86}