Skip to main content

astrid_plugins/
context.rs

1//! Plugin context types.
2//!
3//! Provides the execution context for plugin lifecycle and tool invocations.
4//! Combines relevant fields from `HookContext` (session/user), `ToolContext`
5//! (workspace), and `ScopedKvStore` (plugin-scoped storage).
6
7use std::collections::HashMap;
8use std::path::PathBuf;
9use std::sync::Arc;
10
11use astrid_core::SessionId;
12use astrid_storage::kv::ScopedKvStore;
13use uuid::Uuid;
14
15use crate::PluginId;
16
17/// Context provided to a plugin during lifecycle operations (load/unload).
18///
19/// Contains the information a plugin needs to initialize itself.
20#[derive(Debug, Clone)]
21pub struct PluginContext {
22    /// The workspace root directory.
23    pub workspace_root: PathBuf,
24    /// Pre-scoped KV store for this plugin (`plugin:{plugin_id}` namespace).
25    pub kv: ScopedKvStore,
26    /// Plugin configuration from the manifest.
27    pub config: HashMap<String, serde_json::Value>,
28}
29
30impl PluginContext {
31    /// Create a new plugin context.
32    #[must_use]
33    pub fn new(
34        workspace_root: PathBuf,
35        kv: ScopedKvStore,
36        config: HashMap<String, serde_json::Value>,
37    ) -> Self {
38        Self {
39            workspace_root,
40            kv,
41            config,
42        }
43    }
44
45    /// Create a plugin context with a `MemoryKvStore` for testing.
46    ///
47    /// # Errors
48    ///
49    /// Returns an error if the scoped KV store cannot be created.
50    pub fn for_testing(
51        plugin_id: &PluginId,
52        workspace_root: PathBuf,
53    ) -> crate::error::PluginResult<Self> {
54        let store = Arc::new(astrid_storage::MemoryKvStore::new());
55        let kv = ScopedKvStore::new(store, format!("plugin:{plugin_id}"))?;
56        Ok(Self {
57            workspace_root,
58            kv,
59            config: HashMap::new(),
60        })
61    }
62}
63
64/// Context provided to a plugin tool during execution.
65///
66/// Combines:
67/// - Plugin identity (`plugin_id`)
68/// - Workspace root (from `ToolContext`)
69/// - Scoped KV store (pre-bound to `plugin:{plugin_id}`)
70/// - Plugin config
71/// - Session/user info (from `HookContext`)
72#[derive(Debug, Clone)]
73pub struct PluginToolContext {
74    /// The plugin this tool belongs to.
75    pub plugin_id: PluginId,
76    /// The workspace root directory.
77    pub workspace_root: PathBuf,
78    /// Pre-scoped KV store (`plugin:{plugin_id}` namespace).
79    pub kv: ScopedKvStore,
80    /// Plugin configuration from the manifest.
81    pub config: HashMap<String, serde_json::Value>,
82    /// Current session ID, if available.
83    pub session_id: Option<SessionId>,
84    /// Current user ID, if available.
85    pub user_id: Option<Uuid>,
86}
87
88impl PluginToolContext {
89    /// Create a new plugin tool context.
90    #[must_use]
91    pub fn new(plugin_id: PluginId, workspace_root: PathBuf, kv: ScopedKvStore) -> Self {
92        Self {
93            plugin_id,
94            workspace_root,
95            kv,
96            config: HashMap::new(),
97            session_id: None,
98            user_id: None,
99        }
100    }
101
102    /// Set the plugin configuration.
103    #[must_use]
104    pub fn with_config(mut self, config: HashMap<String, serde_json::Value>) -> Self {
105        self.config = config;
106        self
107    }
108
109    /// Set the session ID.
110    #[must_use]
111    pub fn with_session(mut self, session_id: SessionId) -> Self {
112        self.session_id = Some(session_id);
113        self
114    }
115
116    /// Set the user ID.
117    #[must_use]
118    pub fn with_user(mut self, user_id: Uuid) -> Self {
119        self.user_id = Some(user_id);
120        self
121    }
122}