1use std::collections::BTreeMap;
4use std::path::PathBuf;
5use std::sync::Arc;
6
7use parking_lot::RwLock;
8
9use crate::{Manifest, Pack, Safety, SkillError};
10
11pub trait Provider: Send + Sync {
13 fn manifests(&self) -> Result<Vec<Manifest>, SkillError>;
15}
16
17pub trait Registry: Send + Sync {
19 fn register(&self, pack: Pack) -> Result<(), SkillError>;
21 fn get(&self, name: &str) -> Option<Pack>;
23 fn list(&self) -> Vec<Manifest>;
25}
26
27#[derive(Default)]
29pub struct InMemoryRegistry {
30 packs: RwLock<BTreeMap<String, Arc<Pack>>>,
31}
32
33impl InMemoryRegistry {
34 pub fn new() -> Self {
36 Self::default()
37 }
38}
39
40impl Registry for InMemoryRegistry {
41 fn register(&self, pack: Pack) -> Result<(), SkillError> {
42 let name = pack.manifest.name.clone();
43 let mut packs = self.packs.write();
44 if packs.contains_key(&name) {
45 return Err(SkillError::AlreadyRegistered(name));
46 }
47 packs.insert(name, Arc::new(pack));
48 Ok(())
49 }
50
51 fn get(&self, name: &str) -> Option<Pack> {
52 self.packs.read().get(name).map(|pack| (**pack).clone())
53 }
54
55 fn list(&self) -> Vec<Manifest> {
56 self.packs
57 .read()
58 .values()
59 .map(|pack| pack.manifest.clone())
60 .collect()
61 }
62}
63
64pub fn register_provider(
66 provider: &dyn Provider,
67 registry: &dyn Registry,
68) -> Result<(), SkillError> {
69 for manifest in provider.manifests()? {
70 let pack = Pack::new(PathBuf::new(), manifest);
71 registry.register(pack)?;
72 }
73 Ok(())
74}
75
76pub fn effective_safety(safeties: impl IntoIterator<Item = Safety>) -> Safety {
78 safeties.into_iter().max().unwrap_or(Safety::ReadOnly)
79}
80
81pub fn effective_envelope(
83 declared_scopes: &[String],
84 principal_grants: &[String],
85 operator_ceiling: &[String],
86 referenced: bool,
87 safety: Safety,
88) -> EffectiveEnvelope {
89 if !referenced {
90 return EffectiveEnvelope {
91 scopes: Vec::new(),
92 safety: Safety::ReadOnly,
93 active: false,
94 };
95 }
96 let scopes = declared_scopes
97 .iter()
98 .filter(|scope| principal_grants.contains(scope) && operator_ceiling.contains(scope))
99 .cloned()
100 .collect();
101 EffectiveEnvelope {
102 scopes,
103 safety,
104 active: true,
105 }
106}
107
108#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct EffectiveEnvelope {
111 pub scopes: Vec<String>,
113 pub safety: Safety,
115 pub active: bool,
117}