crabtalk_runtime/skill/
handler.rs1use crate::skill::{SkillRegistry, loader};
4use anyhow::Result;
5use std::path::PathBuf;
6use tokio::sync::Mutex;
7
8pub struct SkillHandler {
10 pub registry: Mutex<SkillRegistry>,
12 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 pub fn load(skill_dirs: Vec<PathBuf>, disabled: &[String]) -> 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.skills.len();
37 for skill in &r.skills {
38 if disabled.contains(&skill.name) {
39 tracing::info!("skill '{}' disabled, skipping", skill.name);
40 } else if registry.contains(&skill.name) {
41 tracing::warn!(
42 "skill '{}' from {} conflicts with already-loaded skill, skipping",
43 skill.name,
44 dir.display()
45 );
46 } else {
47 registry.add(skill.clone());
48 }
49 }
50 tracing::info!("loaded {count} skill(s) from {}", dir.display());
51 }
52 Err(e) => {
53 tracing::warn!("could not load skills from {}: {e}", dir.display());
54 }
55 }
56 }
57 tracing::info!("total {} skill(s) loaded", registry.skills.len());
58 Ok(Self {
59 registry: Mutex::new(registry),
60 skill_dirs,
61 })
62 }
63}