nexus_core/app/
skills_popup.rs1use super::App;
2use tokio::sync::mpsc;
3
4impl App {
5 pub fn reload_skills(&mut self) {
9 let skills =
10 crate::skills::load_skills_from_dirs(&crate::skills::app_skill_roots(&self.space.root));
11 if skills != self.skills {
12 self.skills = skills;
13 self.bump_cache_epoch();
14 }
15 }
16
17 pub fn skill_is_app_managed(&self, skill: &crate::skills::Skill) -> bool {
21 crate::skills::is_app_managed(skill, &self.space.root)
22 }
23
24 pub fn start_skill_install(&mut self, spec: &str) {
30 let spec = spec.trim().to_string();
31 let Some((owner, repo, path)) = crate::skills::parse_gh_shorthand(&spec) else {
32 self.push_status(format!("expected owner/repo/path, got: {spec}"));
33 return;
34 };
35 let dest = crate::skills::skills_dir(&self.space.root);
36 let (tx, rx) = mpsc::unbounded_channel();
37 self.skills_rx = Some(rx);
38 self.push_status(format!("installing {spec}…"));
39 tokio::spawn(async move {
40 let client = reqwest::Client::new();
41 let result = crate::skills::install_from_github(&client, &owner, &repo, &path, &dest)
42 .await
43 .map_err(|e| e.to_string());
44 let _ = tx.send(result);
45 });
46 }
47
48 pub fn on_skill_install_result(&mut self, result: Option<Result<String, String>>) {
49 self.skills_rx = None;
50 match result {
51 Some(Ok(name)) => {
52 self.reload_skills();
53 self.push_status(format!("installed skill: {name}"));
54 }
55 Some(Err(e)) => self.push_status(format!("skill install failed: {e}")),
56 None => {}
57 }
58 }
59}