Skip to main content

caliban_plugins/
loaded.rs

1//! `LoadedPlugin` and friends — the in-memory representation handed to the
2//! caliban binary after discovery.
3
4use std::path::PathBuf;
5
6use crate::manifest::{PluginManifest, ResolvedComponents};
7
8/// Where a plugin was discovered. Determines override semantics.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum PluginSource {
11    /// `<workspace>/.caliban/plugins/<name>/`
12    Project,
13    /// `$XDG_DATA_HOME/caliban/plugins/<name>/`
14    User,
15    /// `/etc/caliban/plugins/<name>/` (Linux), platform analogues elsewhere.
16    Managed,
17}
18
19impl PluginSource {
20    /// Stable lower-case label for logs / overlays.
21    #[must_use]
22    pub fn as_str(self) -> &'static str {
23        match self {
24            Self::Project => "project",
25            Self::User => "user",
26            Self::Managed => "managed",
27        }
28    }
29}
30
31/// A namespaced item produced by a plugin (`pluginA:skill-foo`).
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct NamespacedItem {
34    /// `<plugin>:<bare-name>` (e.g. `superpowers:brainstorming`).
35    pub namespaced: String,
36    /// The bare item name (e.g. `brainstorming`).
37    pub bare: String,
38    /// The plugin namespace (e.g. `superpowers`).
39    pub plugin: String,
40}
41
42impl NamespacedItem {
43    /// Construct from a plugin name + bare item name.
44    #[must_use]
45    pub fn new(plugin: &str, bare: &str) -> Self {
46        Self {
47            namespaced: format!("{plugin}:{bare}"),
48            bare: bare.to_string(),
49            plugin: plugin.to_string(),
50        }
51    }
52}
53
54/// A plugin that successfully passed manifest validation and platform/version
55/// gating. `components` is already resolved to absolute paths under `root_dir`.
56#[derive(Debug, Clone)]
57pub struct LoadedPlugin {
58    /// Parsed manifest.
59    pub manifest: PluginManifest,
60    /// Absolute path to the plugin directory.
61    pub root_dir: PathBuf,
62    /// Namespace string — always == `manifest.name`. Kept separately for
63    /// quick access by overlays.
64    pub namespace: String,
65    /// Source root the plugin was discovered in.
66    pub source: PluginSource,
67    /// Component paths resolved against `root_dir`.
68    pub components: ResolvedComponents,
69}
70
71impl LoadedPlugin {
72    /// Compose `<namespace>:<bare>` for a discovered item.
73    #[must_use]
74    pub fn namespace_item(&self, bare: &str) -> String {
75        format!("{}:{bare}", self.namespace)
76    }
77}