use std::fs;
use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::skills::{parse_skill_meta, SkillMeta, Source};
pub fn cache_dir() -> PathBuf {
if let Ok(dir) = std::env::var("SKILL_CACHE_DIR") {
return PathBuf::from(dir);
}
dirs::cache_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join("skill-library")
}
pub fn list_cached_skills() -> Result<Vec<SkillMeta>> {
let dir = cache_dir();
if !dir.exists() {
return Ok(Vec::new());
}
let mut skills = Vec::new();
for entry in fs::read_dir(&dir).with_context(|| format!("read_dir {}", dir.display()))? {
let entry = entry?;
if !entry.file_type()?.is_dir() {
continue;
}
let skill_file = entry.path().join("SKILL.md");
if !skill_file.exists() {
continue;
}
let Some(name) = entry.file_name().to_str().map(str::to_string) else {
continue;
};
let content = fs::read_to_string(&skill_file)
.with_context(|| format!("read {}", skill_file.display()))?;
skills.push(parse_skill_meta(&name, &content, Source::Local));
}
skills.sort_by(|a, b| a.name.cmp(&b.name));
Ok(skills)
}
pub fn read_cached_skill(name: &str) -> Result<Option<String>> {
let path = cache_dir().join(name).join("SKILL.md");
if !path.exists() {
return Ok(None);
}
Ok(Some(
fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?,
))
}
pub fn write_cached_skill(name: &str, content: &str) -> Result<()> {
let dir = cache_dir().join(name);
fs::create_dir_all(&dir).with_context(|| format!("mkdir {}", dir.display()))?;
let path = dir.join("SKILL.md");
fs::write(&path, content).with_context(|| format!("write {}", path.display()))?;
Ok(())
}