mur_common/skill/
peers.rs1use std::path::{Path, PathBuf};
7
8#[derive(Debug, Clone, serde::Serialize)]
9pub struct PeerAgent {
10 pub name: String,
11 pub home_path: PathBuf,
12 pub skills_count: usize,
13}
14
15pub fn list_peer_agents(mur_home: &Path) -> std::io::Result<Vec<PeerAgent>> {
19 let agents_dir = mur_home.join("agents");
20 if !agents_dir.exists() {
21 return Ok(vec![]);
22 }
23 let mut peers = Vec::new();
24 for entry in std::fs::read_dir(&agents_dir)? {
25 let entry = entry?;
26 if !entry.file_type()?.is_dir() {
27 continue;
28 }
29 let name = entry.file_name().to_string_lossy().into_owned();
30 if name.starts_with('.') {
31 continue;
32 }
33 let home_path = entry.path();
34 let skills_dir = home_path.join("skills");
35 let skills_count = if skills_dir.exists() {
36 std::fs::read_dir(&skills_dir)?
37 .filter_map(|e| e.ok())
38 .filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
39 .count()
40 } else {
41 0
42 };
43 peers.push(PeerAgent {
44 name,
45 home_path,
46 skills_count,
47 });
48 }
49 peers.sort_by(|a, b| a.name.cmp(&b.name));
50 Ok(peers)
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use tempfile::tempdir;
57
58 #[test]
59 fn lists_agent_directories() {
60 let dir = tempdir().unwrap();
61 let home = dir.path();
62 std::fs::create_dir_all(home.join("agents").join("alice").join("skills").join("s1"))
63 .unwrap();
64 std::fs::create_dir_all(home.join("agents").join("bob").join("skills")).unwrap();
65 std::fs::create_dir_all(home.join("agents").join(".hidden")).unwrap();
66
67 let peers = list_peer_agents(home).unwrap();
68 assert_eq!(peers.len(), 2);
69 assert_eq!(peers[0].name, "alice");
70 assert_eq!(peers[0].skills_count, 1);
71 assert_eq!(peers[1].name, "bob");
72 assert_eq!(peers[1].skills_count, 0);
73 }
74
75 #[test]
76 fn empty_when_agents_dir_missing() {
77 let dir = tempdir().unwrap();
78 assert!(list_peer_agents(dir.path()).unwrap().is_empty());
79 }
80}