feat: plugin hooks + tool registry + CLI integration

This commit is contained in:
Yeachan-Heo
2026-04-01 06:55:39 +00:00
parent bea025b585
commit 0a4cea5ab2
6 changed files with 526 additions and 102 deletions

View File

@@ -1,4 +1,4 @@
use plugins::{PluginError, PluginKind, PluginManager, PluginSummary};
use plugins::{PluginError, PluginManager, PluginSummary};
use runtime::{compact_session, CompactionConfig, Session};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -134,7 +134,7 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
name: "plugins",
summary: "List or manage plugins",
argument_hint: Some(
"[list|install <source>|enable <id>|disable <id>|uninstall <id>|update <id>]",
"[list|install <path>|enable <name>|disable <name>|uninstall <id>|update <id>]",
),
resume_supported: false,
},
@@ -278,6 +278,7 @@ pub struct PluginsCommandResult {
pub reload_runtime: bool,
}
#[allow(clippy::too_many_lines)]
pub fn handle_plugins_slash_command(
action: Option<&str>,
target: Option<&str>,
@@ -397,15 +398,14 @@ pub fn render_plugins_report(plugins: &[PluginSummary]) -> String {
return lines.join("\n");
}
for plugin in plugins {
let kind = match plugin.metadata.kind {
PluginKind::Builtin => "builtin",
PluginKind::Bundled => "bundled",
PluginKind::External => "external",
let enabled = if plugin.enabled {
"enabled"
} else {
"disabled"
};
let enabled = if plugin.enabled { "enabled" } else { "disabled" };
lines.push(format!(
" {id:<24} {kind:<8} {enabled:<8} v{version}",
id = plugin.metadata.id,
" {name:<20} v{version:<10} {enabled}",
name = plugin.metadata.name,
version = plugin.metadata.version,
));
}
@@ -606,6 +606,20 @@ mod tests {
target: None
})
);
assert_eq!(
SlashCommand::parse("/plugins enable demo"),
Some(SlashCommand::Plugins {
action: Some("enable".to_string()),
target: Some("demo".to_string())
})
);
assert_eq!(
SlashCommand::parse("/plugins disable demo"),
Some(SlashCommand::Plugins {
action: Some("disable".to_string()),
target: Some("demo".to_string())
})
);
}
#[test]
@@ -628,7 +642,7 @@ mod tests {
assert!(help.contains("/export [file]"));
assert!(help.contains("/session [list|switch <session-id>]"));
assert!(help.contains(
"/plugins [list|install <source>|enable <id>|disable <id>|uninstall <id>|update <id>]"
"/plugins [list|install <path>|enable <name>|disable <name>|uninstall <id>|update <id>]"
));
assert_eq!(slash_command_specs().len(), 16);
assert_eq!(resume_supported_slash_commands().len(), 11);
@@ -748,10 +762,10 @@ mod tests {
},
]);
assert!(rendered.contains("demo@external"));
assert!(rendered.contains("demo"));
assert!(rendered.contains("v1.2.3"));
assert!(rendered.contains("enabled"));
assert!(rendered.contains("sample@external"));
assert!(rendered.contains("sample"));
assert!(rendered.contains("v0.9.0"));
assert!(rendered.contains("disabled"));
}
@@ -778,7 +792,7 @@ mod tests {
let list = handle_plugins_slash_command(Some("list"), None, &mut manager)
.expect("list command should succeed");
assert!(!list.reload_runtime);
assert!(list.message.contains("demo@external"));
assert!(list.message.contains("demo"));
assert!(list.message.contains("v1.0.0"));
assert!(list.message.contains("enabled"));
@@ -809,7 +823,7 @@ mod tests {
let list = handle_plugins_slash_command(Some("list"), None, &mut manager)
.expect("list command should succeed");
assert!(list.message.contains("demo@external"));
assert!(list.message.contains("demo"));
assert!(list.message.contains("disabled"));
let enable = handle_plugins_slash_command(Some("enable"), Some("demo"), &mut manager)
@@ -821,7 +835,7 @@ mod tests {
let list = handle_plugins_slash_command(Some("list"), None, &mut manager)
.expect("list command should succeed");
assert!(list.message.contains("demo@external"));
assert!(list.message.contains("demo"));
assert!(list.message.contains("enabled"));
let _ = fs::remove_dir_all(config_home);
@@ -842,8 +856,8 @@ mod tests {
let list = handle_plugins_slash_command(Some("list"), None, &mut manager)
.expect("list command should succeed");
assert!(!list.reload_runtime);
assert!(list.message.contains("starter@bundled"));
assert!(list.message.contains("bundled"));
assert!(list.message.contains("starter"));
assert!(list.message.contains("v0.1.0"));
assert!(list.message.contains("disabled"));
let _ = fs::remove_dir_all(config_home);