synaps_cli/extensions/runtime/
mod.rs1pub mod process;
4pub mod restart;
5
6pub use restart::RestartPolicy;
7
8use async_trait::async_trait;
9use serde_json::Value;
10use crate::extensions::hooks::events::{HookEvent, HookResult};
11use self::process::{ProviderCompleteParams, ProviderCompleteResult, ProviderStreamEvent};
12use crate::extensions::info::PluginInfo;
13use crate::extensions::commands::CommandOutputEvent;
14use crate::extensions::tasks::TaskEvent;
15
16#[derive(Debug, Clone, PartialEq)]
18pub enum InvokeCommandEvent {
19 Output(CommandOutputEvent),
21 Task(TaskEvent),
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum ExtensionHealth {
28 Loaded,
30 FailedValidation,
32 FailedInitialize,
34 Running,
36 Restarting,
38 Degraded,
40 Failed,
42}
43
44impl ExtensionHealth {
45 pub fn as_str(self) -> &'static str {
46 match self {
47 Self::Loaded => "loaded",
48 Self::FailedValidation => "failed_validation",
49 Self::FailedInitialize => "failed_initialize",
50 Self::Running => "running",
51 Self::Restarting => "restarting",
52 Self::Degraded => "degraded",
53 Self::Failed => "failed",
54 }
55 }
56}
57
58#[cfg(test)]
59#[allow(clippy::items_after_test_module)]
60mod health_tests {
61 use super::ExtensionHealth;
62
63 #[test]
64 fn as_str_covers_all_variants() {
65 assert_eq!(ExtensionHealth::Loaded.as_str(), "loaded");
66 assert_eq!(ExtensionHealth::FailedValidation.as_str(), "failed_validation");
67 assert_eq!(ExtensionHealth::FailedInitialize.as_str(), "failed_initialize");
68 assert_eq!(ExtensionHealth::Running.as_str(), "running");
69 assert_eq!(ExtensionHealth::Restarting.as_str(), "restarting");
70 assert_eq!(ExtensionHealth::Degraded.as_str(), "degraded");
71 assert_eq!(ExtensionHealth::Failed.as_str(), "failed");
72 }
73}
74
75#[async_trait]
77pub trait ExtensionHandler: Send + Sync {
78 fn id(&self) -> &str;
80
81 async fn handle(&self, event: &HookEvent) -> HookResult;
83
84 async fn call_tool(&self, _name: &str, _input: Value) -> Result<Value, String> {
86 Err("extension runtime does not support tool.call".to_string())
87 }
88
89 async fn provider_complete(&self, _params: ProviderCompleteParams) -> Result<ProviderCompleteResult, String> {
91 Err("extension runtime does not support provider.complete".to_string())
92 }
93
94 async fn provider_stream(
102 &self,
103 _params: ProviderCompleteParams,
104 _sink: tokio::sync::mpsc::UnboundedSender<ProviderStreamEvent>,
105 ) -> Result<ProviderCompleteResult, String> {
106 Err("provider.stream is not supported by this extension".to_string())
107 }
108
109 async fn invoke_command(
113 &self,
114 _command: &str,
115 _args: Vec<String>,
116 _request_id: &str,
117 _sink: tokio::sync::mpsc::UnboundedSender<InvokeCommandEvent>,
118 ) -> Result<Value, String> {
119 Err("extension runtime does not support command.invoke".to_string())
120 }
121
122 async fn get_info(&self) -> Result<PluginInfo, String> {
124 Err("extension runtime does not support info.get".to_string())
125 }
126
127 async fn sidecar_spawn_args(&self) -> Result<crate::sidecar::spawn::SidecarSpawnArgs, String> {
133 Err("extension runtime does not support sidecar.spawn_args".to_string())
134 }
135
136 async fn settings_editor_open(&self, _category: &str, _field: &str) -> Result<Value, String> {
138 Err("extension runtime does not support settings.editor.open".to_string())
139 }
140
141 async fn settings_editor_key(&self, _category: &str, _field: &str, _key: &str) -> Result<Value, String> {
143 Err("extension runtime does not support settings.editor.key".to_string())
144 }
145
146 async fn settings_editor_commit(&self, _category: &str, _field: &str, _value: Value) -> Result<Value, String> {
148 Err("extension runtime does not support settings.editor.commit".to_string())
149 }
150
151 async fn shutdown(&self);
153
154 async fn health(&self) -> ExtensionHealth {
156 ExtensionHealth::Running
157 }
158
159 async fn restart_count(&self) -> usize {
161 0
162 }
163}