Skip to main content

claude_rust_tools/infrastructure/
exit_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 ExitWorktreeTool;
7
8impl ExitWorktreeTool {
9    pub fn new() -> Self {
10        Self
11    }
12}
13
14#[async_trait::async_trait]
15impl Tool for ExitWorktreeTool {
16    fn name(&self) -> &str {
17        "exit_worktree"
18    }
19
20    fn description(&self) -> &str {
21        "Exit and optionally remove a git worktree."
22    }
23
24    fn input_schema(&self) -> Value {
25        json!({
26            "type": "object",
27            "properties": {
28                "path": {
29                    "type": "string",
30                    "description": "Path of the worktree to exit/remove"
31                },
32                "remove": {
33                    "type": "boolean",
34                    "description": "Whether to remove the worktree (default false)"
35                }
36            },
37            "required": ["path"]
38        })
39    }
40
41    fn permission_level(&self) -> PermissionLevel {
42        PermissionLevel::Dangerous
43    }
44
45    async fn execute(&self, input: Value) -> AppResult<String> {
46        let path = input
47            .get("path")
48            .and_then(|v| v.as_str())
49            .ok_or_else(|| AppError::Tool("missing 'path' field".into()))?;
50
51        let remove = input
52            .get("remove")
53            .and_then(|v| v.as_bool())
54            .unwrap_or(false);
55
56        tracing::info!(path, remove, "exiting worktree");
57
58        if remove {
59            let output = Command::new("git")
60                .args(["worktree", "remove", path])
61                .output()
62                .await
63                .map_err(|e| AppError::Tool(format!("failed to run git: {e}")))?;
64
65            if output.status.success() {
66                Ok(format!("Removed worktree at '{path}'."))
67            } else {
68                let stderr = String::from_utf8_lossy(&output.stderr);
69                Err(AppError::Tool(format!("git worktree remove failed: {stderr}")))
70            }
71        } else {
72            Ok(format!("Exited worktree at '{path}'. Use remove=true to delete it."))
73        }
74    }
75}