1use std::sync::Arc;
2
3use anyhow::{anyhow, Result};
4use assistant_tool::Tool;
5use gpui::{App, Task, WeakEntity, Window};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use workspace::Workspace;
9
10#[derive(Debug, Serialize, Deserialize, JsonSchema)]
11pub struct ListWorktreesToolInput {}
12
13pub struct ListWorktreesTool;
14
15impl Tool for ListWorktreesTool {
16 fn name(&self) -> String {
17 "list-worktrees".into()
18 }
19
20 fn description(&self) -> String {
21 "Lists all worktrees in the current project. Use this tool when you need to find available worktrees and their IDs.".into()
22 }
23
24 fn input_schema(&self) -> serde_json::Value {
25 serde_json::json!(
26 {
27 "type": "object",
28 "properties": {},
29 "required": []
30 }
31 )
32 }
33
34 fn run(
35 self: Arc<Self>,
36 _input: serde_json::Value,
37 workspace: WeakEntity<Workspace>,
38 _window: &mut Window,
39 cx: &mut App,
40 ) -> Task<Result<String>> {
41 let Some(workspace) = workspace.upgrade() else {
42 return Task::ready(Err(anyhow!("workspace dropped")));
43 };
44
45 let project = workspace.read(cx).project().clone();
46
47 cx.spawn(|cx| async move {
48 cx.update(|cx| {
49 #[derive(Debug, Serialize)]
50 struct WorktreeInfo {
51 id: usize,
52 root_name: String,
53 root_dir: Option<String>,
54 }
55
56 let worktrees = project.update(cx, |project, cx| {
57 project
58 .visible_worktrees(cx)
59 .map(|worktree| {
60 worktree.read_with(cx, |worktree, _cx| WorktreeInfo {
61 id: worktree.id().to_usize(),
62 root_dir: worktree
63 .root_dir()
64 .map(|root_dir| root_dir.to_string_lossy().to_string()),
65 root_name: worktree.root_name().to_string(),
66 })
67 })
68 .collect::<Vec<_>>()
69 });
70
71 if worktrees.is_empty() {
72 return Ok("No worktrees found in the current project.".to_string());
73 }
74
75 let mut result = String::from("Worktrees in the current project:\n\n");
76 for worktree in worktrees {
77 result.push_str(&serde_json::to_string(&worktree)?);
78 }
79
80 Ok(result)
81 })?
82 })
83 }
84}