use std::collections::HashMap;
use std::path::{Path, PathBuf};
use skilllite_core::skill::metadata::SkillMetadata;
use super::types::ToolDefinition;
use loader::{load_evolved_skills, load_single_skill, sanitize_tool_name};
mod executor;
pub mod infer_entry;
mod loader;
pub(crate) mod security;
pub(crate) mod usage_stats;
pub use executor::execute_skill;
pub use security::{read_lock_file, write_lock_file, LockFile};
#[derive(Debug, Clone)]
pub struct LoadedSkill {
pub name: String,
pub skill_dir: PathBuf,
pub metadata: SkillMetadata,
pub tool_definitions: Vec<ToolDefinition>,
pub multi_script_entries: HashMap<String, String>,
}
pub fn load_skills(skill_dirs: &[String]) -> Vec<LoadedSkill> {
let mut skills = Vec::new();
for dir_path in skill_dirs {
let path = Path::new(dir_path);
if !path.exists() || !path.is_dir() {
tracing::debug!("Skill directory not found: {}", dir_path);
continue;
}
if path.join("SKILL.md").exists() {
if let Some(skill) = load_single_skill(path) {
skills.push(skill);
}
} else {
if let Ok(entries) = skilllite_fs::read_dir(path) {
for (entry_path, is_dir) in entries {
if is_dir && entry_path.join("SKILL.md").exists() {
if let Some(skill) = load_single_skill(&entry_path) {
skills.push(skill);
}
}
}
}
}
let evolved_dir = path.join("_evolved");
if evolved_dir.exists() && evolved_dir.is_dir() {
let evolved = load_evolved_skills(&evolved_dir);
tracing::debug!(
"Loaded {} evolved skills from {}",
evolved.len(),
evolved_dir.display()
);
skills.extend(evolved);
}
}
skills
}
pub fn find_skill_by_tool_name<'a>(
skills: &'a [LoadedSkill],
tool_name: &str,
) -> Option<&'a LoadedSkill> {
if let Some(skill) = skills.iter().find(|s| {
s.tool_definitions
.iter()
.any(|td| td.function.name == tool_name)
}) {
return Some(skill);
}
let normalized = sanitize_tool_name(tool_name);
skills.iter().find(|s| {
s.tool_definitions
.iter()
.any(|td| td.function.name == normalized)
})
}
pub fn find_skill_by_name<'a>(skills: &'a [LoadedSkill], name: &str) -> Option<&'a LoadedSkill> {
if let Some(skill) = skills.iter().find(|s| s.name == name) {
return Some(skill);
}
let with_hyphens = name.replace('_', "-");
let with_underscores = name.replace('-', "_");
skills
.iter()
.find(|s| s.name == with_hyphens || s.name == with_underscores)
}