matrixcode-core 0.4.6

MatrixCode Agent Core - Pure logic, no UI
Documentation
use anyhow::Result;
use async_trait::async_trait;
use serde_json::{Value, json};

use super::{Tool, ToolDefinition};

pub struct LsTool;

#[async_trait]
impl Tool for LsTool {
    fn definition(&self) -> ToolDefinition {
        ToolDefinition {
            name: "ls".to_string(),
            description: "列出目录的直接条目。每行一个条目,目录在前(以 / 结尾),\
                 文件在后并显示字节大小。不递归——递归查找请使用 'glob'。"
                .to_string(),
            parameters: json!({
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "目录路径(默认 '.')"
                    }
                },
                "required": []
            }),
        }
    }

    async fn execute(&self, params: Value) -> Result<String> {
        let path = params["path"].as_str().unwrap_or(".").to_string();

        // Show spinner while listing - RAII guard ensures cleanup on error
        // let mut spinner = ToolSpinner::new(&format!("listing {}", path));

        let mut dirs: Vec<String> = Vec::new();
        let mut files: Vec<(String, u64)> = Vec::new();

        let mut rd = tokio::fs::read_dir(&path).await?;
        while let Some(entry) = rd.next_entry().await? {
            let name = entry.file_name().to_string_lossy().into_owned();
            let ft = entry.file_type().await?;
            if ft.is_dir() {
                dirs.push(format!("{}/", name));
            } else {
                let size = entry.metadata().await.map(|m| m.len()).unwrap_or(0);
                files.push((name, size));
            }
        }

        dirs.sort();
        files.sort_by(|a, b| a.0.cmp(&b.0));

        if dirs.is_empty() && files.is_empty() {
            // spinner.finish_success("(empty)");
            return Ok(format!("(empty) {}", path));
        }

        let mut out = String::new();
        for d in dirs {
            out.push_str(&d);
            out.push('\n');
        }
        for (n, s) in files {
            out.push_str(&format!("{}  ({} B)\n", n, s));
        }
        while out.ends_with('\n') {
            out.pop();
        }

        // spinner.finish_success(&format!("{} entries", total));
        Ok(out)
    }
}