matrixcode_core/tools/
ls.rs1use 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 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 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 Ok(out)
74 }
75}