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