68 lines
2.1 KiB
Rust
68 lines
2.1 KiB
Rust
use std::fs;
|
|||
|
|
use serde_json::{json, Value};
|
||
|
|
use anyhow::{Result, anyhow};
|
||
|
|
use super::super::Tool;
|
||
|
|
use super::super::ToolCtx;
|
||
|
|
|
||
|
|
pub struct DirList;
|
||
|
|
|
||
|
|
impl Tool for DirList {
|
||
|
|
fn name(&self) -> &'static str {
|
||
|
|
"dir_list"
|
||
|
|
}
|
||
|
|
|
||
|
|
fn description(&self) -> &'static str {
|
||
|
|
"List files and directories in a directory. Use this to explore the workspace structure."
|
||
|
|
}
|
||
|
|
|
||
|
|
fn parameters(&self) -> Value {
|
||
|
|
json!({
|
||
|
|
"type": "object",
|
||
|
|
"properties": {
|
||
|
|
"path": {
|
||
|
|
"type": "string",
|
||
|
|
"description": "Directory path to list (relative to workspace root)"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"required": ["path"]
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
fn run(&self, ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||
|
|
let rel = args.get("path")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.ok_or_else(|| anyhow!("missing required argument: path"))?;
|
||
|
|
|
||
|
|
let path = super::super::resolve_path(&ctx.workspaces, rel)?;
|
||
|
|
|
||
|
|
if !path.exists() {
|
||
|
|
return Ok(format!("path '{}' does not exist (resolved to {})", rel, path.display()));
|
||
|
|
}
|
||
|
|
if !path.is_dir() {
|
||
|
|
return Ok(format!("path '{}' is not a directory (resolved to {})", rel, path.display()));
|
||
|
|
}
|
||
|
|
|
||
|
|
let entries: Vec<String> = fs::read_dir(&path)
|
||
|
|
.map_err(|e| anyhow!("failed to read directory '{}': {}", rel, e))?
|
||
|
|
.filter_map(|e| e.ok())
|
||
|
|
.map(|e| {
|
||
|
|
let name = e.file_name().to_string_lossy().to_string();
|
||
|
|
let is_dir = e.file_type().map(|t| t.is_dir()).unwrap_or(false);
|
||
|
|
if is_dir {
|
||
|
|
format!("{}/", name)
|
||
|
|
} else {
|
||
|
|
name
|
||
|
|
}
|
||
|
|
})
|
||
|
|
.collect();
|
||
|
|
|
||
|
|
let canon = path.canonicalize().unwrap_or(path);
|
||
|
|
let header = format!("{} entries in {}:\n", entries.len(), canon.display());
|
||
|
|
if entries.is_empty() {
|
||
|
|
Ok(format!("{} (empty directory)", header.trim()))
|
||
|
|
} else {
|
||
|
|
Ok(header + &entries.join("\n"))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|