claude_agent_sdk/types/
plugin.rs

1//! Plugin configuration types for Claude Agent SDK
2//!
3//! Plugins allow you to extend Claude Code functionality with custom features,
4//! tools, and integrations. This module provides types for configuring and
5//! loading plugins from local paths.
6
7use serde::{Deserialize, Serialize};
8use std::path::PathBuf;
9
10/// Plugin configuration for extending Claude Code functionality
11///
12/// Plugins can be loaded from local filesystem paths and provide additional
13/// tools, features, or integrations that Claude can use during execution.
14///
15/// # Examples
16///
17/// ```
18/// use claude_agent_sdk::SdkPluginConfig;
19/// use std::path::PathBuf;
20///
21/// // Load a local plugin
22/// let plugin = SdkPluginConfig::Local {
23///     path: PathBuf::from("./my-plugin"),
24/// };
25/// ```
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27#[serde(tag = "type")]
28#[serde(rename_all = "lowercase")]
29pub enum SdkPluginConfig {
30    /// Local filesystem plugin
31    ///
32    /// Loads a plugin from a local directory path. The path should point to
33    /// a valid Claude Code plugin directory structure.
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// use claude_agent_sdk::SdkPluginConfig;
39    /// use std::path::PathBuf;
40    ///
41    /// let plugin = SdkPluginConfig::Local {
42    ///     path: PathBuf::from("~/.claude/plugins/my-plugin"),
43    /// };
44    /// ```
45    Local {
46        /// Path to the plugin directory
47        path: PathBuf,
48    },
49}
50
51impl SdkPluginConfig {
52    /// Create a new local plugin configuration
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use claude_agent_sdk::SdkPluginConfig;
58    ///
59    /// let plugin = SdkPluginConfig::local("./my-plugin");
60    /// ```
61    pub fn local(path: impl Into<PathBuf>) -> Self {
62        SdkPluginConfig::Local { path: path.into() }
63    }
64
65    /// Get the path for a local plugin
66    ///
67    /// Returns `Some(&PathBuf)` for local plugins, `None` for other types.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use claude_agent_sdk::SdkPluginConfig;
73    ///
74    /// let plugin = SdkPluginConfig::local("./my-plugin");
75    /// assert!(plugin.path().is_some());
76    /// ```
77    pub fn path(&self) -> Option<&PathBuf> {
78        match self {
79            SdkPluginConfig::Local { path } => Some(path),
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_plugin_local_creation() {
90        let plugin = SdkPluginConfig::local("/path/to/plugin");
91        assert!(matches!(plugin, SdkPluginConfig::Local { .. }));
92    }
93
94    #[test]
95    fn test_plugin_path_getter() {
96        let plugin = SdkPluginConfig::local("/path/to/plugin");
97        assert_eq!(plugin.path(), Some(&PathBuf::from("/path/to/plugin")));
98    }
99
100    #[test]
101    fn test_plugin_serialization() {
102        let plugin = SdkPluginConfig::Local {
103            path: PathBuf::from("/test/path"),
104        };
105
106        let json = serde_json::to_value(&plugin).unwrap();
107        assert_eq!(json["type"], "local");
108        assert_eq!(json["path"], "/test/path");
109    }
110
111    #[test]
112    fn test_plugin_deserialization() {
113        let json = serde_json::json!({
114            "type": "local",
115            "path": "/test/path"
116        });
117
118        let plugin: SdkPluginConfig = serde_json::from_value(json).unwrap();
119        assert_eq!(
120            plugin,
121            SdkPluginConfig::Local {
122                path: PathBuf::from("/test/path")
123            }
124        );
125    }
126
127    #[test]
128    fn test_plugin_roundtrip() {
129        let original = SdkPluginConfig::local("~/.claude/plugins/test");
130        let json = serde_json::to_string(&original).unwrap();
131        let deserialized: SdkPluginConfig = serde_json::from_str(&json).unwrap();
132        assert_eq!(original, deserialized);
133    }
134
135    #[test]
136    fn test_plugin_with_relative_path() {
137        let plugin = SdkPluginConfig::local("./plugins/my-plugin");
138        assert_eq!(
139            plugin.path().unwrap().to_str().unwrap(),
140            "./plugins/my-plugin"
141        );
142    }
143
144    #[test]
145    fn test_plugin_with_home_directory() {
146        let plugin = SdkPluginConfig::local("~/my-plugin");
147        assert!(
148            plugin
149                .path()
150                .unwrap()
151                .to_str()
152                .unwrap()
153                .contains("my-plugin")
154        );
155    }
156}