Skip to main content

matrixcode_core/tools/
ls.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use serde_json::{Value, json};
4
5use super::{Tool, ToolDefinition};
6
7pub struct LsTool;
8
9#[async_trait]
10impl Tool for LsTool {
11    fn definition(&self) -> ToolDefinition {
12        ToolDefinition {
13            name: "ls".to_string(),
14            description: "列出目录的直接条目。每行一个条目,目录在前(以 / 结尾),\
15                 文件在后并显示字节大小。不递归——递归查找请使用 'glob'。"
16                .to_string(),
17            parameters: json!({
18                "type": "object",
19                "properties": {
20                    "path": {
21                        "type": "string",
22                        "description": "目录路径(默认 '.')"
23                    }
24                },
25                "required": []
26            }),
27        }
28    }
29
30    async fn execute(&self, params: Value) -> Result<String> {
31        let path = params["path"].as_str().unwrap_or(".").to_string();
32
33        // Show spinner while listing - RAII guard ensures cleanup on error
34        // let mut spinner = ToolSpinner::new(&format!("listing {}", path));
35
36        let mut dirs: Vec<String> = Vec::new();
37        let mut files: Vec<(String, u64)> = Vec::new();
38
39        let mut rd = tokio::fs::read_dir(&path).await?;
40        while let Some(entry) = rd.next_entry().await? {
41            let name = entry.file_name().to_string_lossy().into_owned();
42            let ft = entry.file_type().await?;
43            if ft.is_dir() {
44                dirs.push(format!("{}/", name));
45            } else {
46                let size = entry.metadata().await.map(|m| m.len()).unwrap_or(0);
47                files.push((name, size));
48            }
49        }
50
51        dirs.sort();
52        files.sort_by(|a, b| a.0.cmp(&b.0));
53
54        if dirs.is_empty() && files.is_empty() {
55            // spinner.finish_success("(empty)");
56            return Ok(format!("(empty) {}", path));
57        }
58
59        let mut out = String::new();
60        for d in dirs {
61            out.push_str(&d);
62            out.push('\n');
63        }
64        for (n, s) in files {
65            out.push_str(&format!("{}  ({} B)\n", n, s));
66        }
67        while out.ends_with('\n') {
68            out.pop();
69        }
70
71        // spinner.finish_success(&format!("{} entries", total));
72        Ok(out)
73    }
74}