Skip to main content
Glama
by 8b-is
st_unified.rs5.46 kB
// ST Unified Tool System - Replace all traditional tools with Smart Tree! // "Why use 20 tools when ST can do it all?" - The Cheet 🎸 use anyhow::{Context, Result}; use std::path::{Path, PathBuf}; use std::process::Command; /// Unified ST interface for all file operations pub struct StUnified { st_binary: PathBuf, } impl StUnified { pub fn new() -> Result<Self> { // Find st binary let st_binary = std::env::current_exe() .ok() .and_then(|p| { let dir = p.parent()?; let st = dir.join("st"); if st.exists() { Some(st) } else { None } }) .unwrap_or_else(|| PathBuf::from("./target/release/st")); Ok(Self { st_binary }) } /// List files (replaces LS tool) pub fn ls(&self, path: &Path, pattern: Option<&str>) -> Result<String> { let mut cmd = Command::new(&self.st_binary); cmd.arg("--mode") .arg("ls") .arg("--depth") .arg("1") .arg("--no-emoji") .arg(path); if let Some(pat) = pattern { cmd.arg("--find").arg(pat); } let output = cmd.output().context("Failed to run st for ls")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Read file (replaces Read tool) pub fn read(&self, path: &Path, offset: Option<usize>, limit: Option<usize>) -> Result<String> { // ST doesn't read file contents, so use standard fs let content = std::fs::read_to_string(path).context("Failed to read file")?; let lines: Vec<&str> = content.lines().collect(); let start = offset.unwrap_or(0); let end = start + limit.unwrap_or(lines.len()); Ok(lines[start.min(lines.len())..end.min(lines.len())] .iter() .enumerate() .map(|(i, line)| format!("{:6}→{}", start + i + 1, line)) .collect::<Vec<_>>() .join("\n")) } /// Search in files (replaces Grep tool) pub fn grep(&self, pattern: &str, path: &Path, file_type: Option<&str>) -> Result<String> { let mut cmd = Command::new(&self.st_binary); cmd.arg("--search") .arg(pattern) .arg("--mode") .arg("ai") .arg("--depth") .arg("0") .arg(path); if let Some(ft) = file_type { cmd.arg("--type").arg(ft); } let output = cmd.output().context("Failed to run st for search")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Find files by pattern (replaces Glob tool) pub fn glob(&self, pattern: &str, path: &Path) -> Result<String> { let output = Command::new(&self.st_binary) .arg("--find") .arg(pattern) .arg("--mode") .arg("json") .arg("--depth") .arg("0") .arg("--compact") .arg(path) .output() .context("Failed to run st for glob")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Analyze directory (replaces basic tree viewing) pub fn analyze(&self, path: &Path, mode: &str, depth: usize) -> Result<String> { let output = Command::new(&self.st_binary) .arg("--mode") .arg(mode) .arg("--depth") .arg(depth.to_string()) .arg(path) .output() .context("Failed to run st for analysis")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Get file/directory stats pub fn stats(&self, path: &Path) -> Result<String> { let output = Command::new(&self.st_binary) .arg("--mode") .arg("stats") .arg("--depth") .arg("0") .arg(path) .output() .context("Failed to run st for stats")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Semantic analysis (unique to ST!) pub fn semantic_analyze(&self, path: &Path) -> Result<String> { let output = Command::new(&self.st_binary) .arg("--mode") .arg("semantic") .arg("--depth") .arg("0") .arg(path) .output() .context("Failed to run st for semantic analysis")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Quick overview (replaces quick checks) pub fn quick(&self, path: &Path) -> Result<String> { let output = Command::new(&self.st_binary) .arg("--mode") .arg("summary-ai") .arg("--depth") .arg("3") .arg(path) .output() .context("Failed to run st for quick view")?; Ok(String::from_utf8_lossy(&output.stdout).to_string()) } /// Project understanding (replaces multiple analysis tools) pub fn understand_project(&self, path: &Path) -> Result<String> { let results = [ "=== QUICK OVERVIEW ===".to_string(), self.quick(path)?, "\n=== SEMANTIC GROUPS ===".to_string(), self.semantic_analyze(path)?, "\n=== STATISTICS ===".to_string(), self.stats(path)?, ]; Ok(results.join("\n")) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server