Skip to main content

crabtalk_runtime/skill/
handler.rs

1//! Crabtalk skill handler — initial load from disk.
2
3use crate::skill::{SkillRegistry, loader};
4use anyhow::Result;
5use std::path::PathBuf;
6use tokio::sync::Mutex;
7
8/// Skill registry owner.
9pub struct SkillHandler {
10    /// The skill registry (Mutex for interior-mutability from `dispatch_load_skill`).
11    pub registry: Mutex<SkillRegistry>,
12    /// Skill directories to search (local first, then packages).
13    pub skill_dirs: Vec<PathBuf>,
14}
15
16impl Default for SkillHandler {
17    fn default() -> Self {
18        Self {
19            registry: Mutex::new(SkillRegistry::new()),
20            skill_dirs: Vec::new(),
21        }
22    }
23}
24
25impl SkillHandler {
26    /// Load skills from multiple directories. Tolerates missing directories
27    /// by skipping them. Returns a handler with all discovered skills.
28    pub fn load(skill_dirs: Vec<PathBuf>) -> Result<Self> {
29        let mut registry = SkillRegistry::new();
30        for dir in &skill_dirs {
31            if !dir.exists() {
32                continue;
33            }
34            match loader::load_skills_dir(dir) {
35                Ok(r) => {
36                    let count = r.len();
37                    for skill in r.skills() {
38                        if registry.contains(&skill.name) {
39                            tracing::warn!(
40                                "skill '{}' from {} conflicts with already-loaded skill, skipping",
41                                skill.name,
42                                dir.display()
43                            );
44                        } else {
45                            registry.add(skill.clone());
46                        }
47                    }
48                    tracing::info!("loaded {count} skill(s) from {}", dir.display());
49                }
50                Err(e) => {
51                    tracing::warn!("could not load skills from {}: {e}", dir.display());
52                }
53            }
54        }
55        tracing::info!("total {} skill(s) loaded", registry.len());
56        Ok(Self {
57            registry: Mutex::new(registry),
58            skill_dirs,
59        })
60    }
61}