diff options
| author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-10 22:01:45 +0200 |
|---|---|---|
| committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-10 22:01:45 +0200 |
| commit | 5e31a81cd2207f053b8cd8ad84ebe2a2f691b29d (patch) | |
| tree | 5d76811ab0d693c01fa472d41aa2ceaf3bd0b415 /crates/atuin-ai/src/skills/walker.rs | |
| parent | chore: Remove unneeded files (diff) | |
| download | atuin-5e31a81cd2207f053b8cd8ad84ebe2a2f691b29d.zip | |
chore: Remove some unused rust code
Diffstat (limited to 'crates/atuin-ai/src/skills/walker.rs')
| -rw-r--r-- | crates/atuin-ai/src/skills/walker.rs | 178 |
1 files changed, 0 insertions, 178 deletions
diff --git a/crates/atuin-ai/src/skills/walker.rs b/crates/atuin-ai/src/skills/walker.rs deleted file mode 100644 index b93845f9..00000000 --- a/crates/atuin-ai/src/skills/walker.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Filesystem discovery for `SKILL.md` files. -//! -//! Recursively scans `.atuin/skills/` directories at the project and global -//! levels. Supports nested directories for organization (e.g. -//! `.atuin/skills/ops/deploy/SKILL.md`). - -use std::path::{Path, PathBuf}; - -const SKILL_FILENAME: &str = "SKILL.md"; - -/// A skill file found on disk, before body interpolation. -#[derive(Debug)] -pub(crate) struct RawSkillFile { - /// Full path to the SKILL.md file. - pub path: PathBuf, - /// The parent directory name, used as fallback skill name. - pub dir_name: String, - /// Whether this is a project-level skill (vs global). - #[allow(dead_code)] - pub is_project: bool, - /// Raw file content. - pub content: String, -} - -/// Discover all `SKILL.md` files across project and global skill directories. -/// -/// Project skills come first in the returned list (higher priority for -/// deduplication). -pub(crate) async fn discover( - project_skills_dir: Option<&Path>, - global_skills_dir: &Path, -) -> Vec<RawSkillFile> { - let mut files = Vec::new(); - - // Project skills first (higher priority) - if let Some(dir) = project_skills_dir.filter(|d| d.is_dir()) { - scan_dir(dir, true, &mut files).await; - } - - // Global skills second - if global_skills_dir.is_dir() { - scan_dir(global_skills_dir, false, &mut files).await; - } - - files -} - -/// The default global skills directory (`~/.config/atuin/skills/`). -pub(crate) fn global_skills_dir() -> PathBuf { - atuin_common::utils::config_dir().join("skills") -} - -/// Given a project working directory, return the project skills directory. -pub(crate) fn project_skills_dir(project_root: &Path) -> PathBuf { - project_root.join(".atuin").join("skills") -} - -/// Recursively scan a directory for `SKILL.md` files. -async fn scan_dir(dir: &Path, is_project: bool, out: &mut Vec<RawSkillFile>) { - let mut entries = match tokio::fs::read_dir(dir).await { - Ok(entries) => entries, - Err(e) => { - tracing::debug!("Could not read skills directory {}: {e}", dir.display()); - return; - } - }; - - let mut subdirs = Vec::new(); - - while let Ok(Some(entry)) = entries.next_entry().await { - let path = entry.path(); - - if path.is_dir() { - // Check for SKILL.md directly in this directory - let skill_path = path.join(SKILL_FILENAME); - if skill_path.is_file() { - let dir_name = path - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or("unknown") - .to_string(); - - match tokio::fs::read_to_string(&skill_path).await { - Ok(content) => { - out.push(RawSkillFile { - path: skill_path, - dir_name, - is_project, - content, - }); - } - Err(e) => { - tracing::warn!("Failed to read skill file {}: {e}", skill_path.display()); - } - } - } - - // Collect subdirectories for recursive scanning - subdirs.push(path); - } - } - - for subdir in subdirs { - Box::pin(scan_dir(&subdir, is_project, out)).await; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn setup_skill(dir: &Path, rel_path: &str, content: &str) { - let skill_dir = dir.join(rel_path); - std::fs::create_dir_all(&skill_dir).unwrap(); - std::fs::write(skill_dir.join(SKILL_FILENAME), content).unwrap(); - } - - #[tokio::test] - async fn discovers_project_skills() { - let dir = tempfile::tempdir().unwrap(); - let skills_dir = dir.path().join("skills"); - setup_skill(&skills_dir, "deploy", "---\nname: deploy\n---\nDeploy."); - - let files = discover(Some(&skills_dir), Path::new("/nonexistent")).await; - assert_eq!(files.len(), 1); - assert_eq!(files[0].dir_name, "deploy"); - assert!(files[0].is_project); - } - - #[tokio::test] - async fn discovers_global_skills() { - let dir = tempfile::tempdir().unwrap(); - let skills_dir = dir.path().join("skills"); - setup_skill(&skills_dir, "review", "---\nname: review\n---\nReview."); - - let files = discover(None, &skills_dir).await; - assert_eq!(files.len(), 1); - assert_eq!(files[0].dir_name, "review"); - assert!(!files[0].is_project); - } - - #[tokio::test] - async fn discovers_nested_skills() { - let dir = tempfile::tempdir().unwrap(); - let skills_dir = dir.path().join("skills"); - setup_skill(&skills_dir, "ops/deploy", "---\nname: deploy\n---\n"); - setup_skill(&skills_dir, "ops/rollback", "---\nname: rollback\n---\n"); - - let files = discover(Some(&skills_dir), Path::new("/nonexistent")).await; - assert_eq!(files.len(), 2); - } - - #[tokio::test] - async fn project_comes_before_global() { - let project = tempfile::tempdir().unwrap(); - let global = tempfile::tempdir().unwrap(); - let project_skills = project.path().join("skills"); - let global_skills = global.path().join("skills"); - - setup_skill(&project_skills, "a-skill", "project"); - setup_skill(&global_skills, "b-skill", "global"); - - let files = discover(Some(&project_skills), &global_skills).await; - assert_eq!(files.len(), 2); - assert!(files[0].is_project); - assert!(!files[1].is_project); - } - - #[tokio::test] - async fn missing_directories_handled() { - let files = discover( - Some(Path::new("/does/not/exist")), - Path::new("/also/missing"), - ) - .await; - assert!(files.is_empty()); - } -} |
