aboutsummaryrefslogtreecommitdiff
path: root/src/api/schema/plugins.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/schema/plugins.rs')
-rw-r--r--src/api/schema/plugins.rs343
1 files changed, 343 insertions, 0 deletions
diff --git a/src/api/schema/plugins.rs b/src/api/schema/plugins.rs
new file mode 100644
index 00000000..535733ec
--- /dev/null
+++ b/src/api/schema/plugins.rs
@@ -0,0 +1,343 @@
+use std::collections::HashMap;
+
+use serde::{Deserialize, Serialize};
+
+use super::common::AgentStatus;
+use super::common::SplitDirection;
+use super::panes::PaneInfo;
+use super::workspaces::WorkspaceWorktreeInfo;
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginLinkParams {
+ pub path: String,
+ #[serde(default = "super::common::default_true")]
+ pub enabled: bool,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub source: Option<PluginSourceInfo>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
+pub struct PluginListParams {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub plugin_id: Option<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginUnlinkParams {
+ pub plugin_id: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginSetEnabledParams {
+ pub plugin_id: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct InstalledPluginInfo {
+ pub plugin_id: String,
+ pub name: String,
+ pub version: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub description: Option<String>,
+ pub manifest_path: String,
+ pub plugin_root: String,
+ pub enabled: bool,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub build: Vec<PluginManifestBuild>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub actions: Vec<PluginManifestAction>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub events: Vec<PluginManifestEventHook>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub panes: Vec<PluginManifestPane>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub link_handlers: Vec<PluginManifestLinkHandler>,
+ #[serde(default)]
+ pub source: PluginSourceInfo,
+ /// Warnings collected at link time or on registry load (e.g. unknown event names,
+ /// missing manifest file). Non-fatal — the entry is kept and surfaced by plugin.list.
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub warnings: Vec<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginSourceInfo {
+ #[serde(default)]
+ pub kind: PluginSourceKind,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub owner: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub repo: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub subdir: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub requested_ref: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub resolved_commit: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub managed_path: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub installed_unix_ms: Option<u64>,
+}
+
+impl Default for PluginSourceInfo {
+ fn default() -> Self {
+ Self {
+ kind: PluginSourceKind::Local,
+ owner: None,
+ repo: None,
+ subdir: None,
+ requested_ref: None,
+ resolved_commit: None,
+ managed_path: None,
+ installed_unix_ms: None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
+#[serde(rename_all = "snake_case")]
+pub enum PluginSourceKind {
+ #[default]
+ Local,
+ Github,
+}
+
+pub(crate) fn plugin_managed_path_component(value: &str) -> String {
+ value
+ .chars()
+ .map(|ch| {
+ if ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.') {
+ ch
+ } else {
+ '_'
+ }
+ })
+ .collect()
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginManifestBuild {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+ pub command: Vec<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginManifestAction {
+ pub id: String,
+ pub title: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub description: Option<String>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub contexts: Vec<PluginActionContext>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+ pub command: Vec<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginManifestEventHook {
+ pub on: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+ pub command: Vec<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginManifestPane {
+ pub id: String,
+ pub title: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub description: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+ #[serde(default)]
+ pub placement: PluginPanePlacement,
+ pub command: Vec<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginManifestLinkHandler {
+ pub id: String,
+ pub title: String,
+ pub pattern: String,
+ pub action: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
+pub struct PluginActionListParams {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub plugin_id: Option<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
+pub struct PluginLogListParams {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub plugin_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub limit: Option<usize>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginActionInvokeParams {
+ pub action_id: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub plugin_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub context: Option<PluginInvocationContext>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginCommandLogInfo {
+ pub log_id: String,
+ pub plugin_id: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub action_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub event: Option<String>,
+ pub command: Vec<String>,
+ pub status: PluginCommandStatus,
+ pub started_unix_ms: u64,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub finished_unix_ms: Option<u64>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub exit_code: Option<i32>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub stdout: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub stderr: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub error: Option<String>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum PluginCommandStatus {
+ Running,
+ Succeeded,
+ Failed,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum PluginPlatform {
+ Linux,
+ Macos,
+ Windows,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum PluginActionContext {
+ Global,
+ Workspace,
+ Tab,
+ Pane,
+ Selection,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginInvocationContext {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub workspace_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub workspace_label: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub workspace_cwd: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub worktree: Option<WorkspaceWorktreeInfo>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub tab_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub tab_label: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub focused_pane_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub focused_pane_cwd: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub focused_pane_agent: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub focused_pane_status: Option<AgentStatus>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub selected_text: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub invocation_source: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub correlation_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub clicked_url: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub link_handler_id: Option<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginActionInfo {
+ pub plugin_id: String,
+ pub action_id: String,
+ pub title: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub description: Option<String>,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub contexts: Vec<PluginActionContext>,
+ pub command: Vec<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub platforms: Option<Vec<PluginPlatform>>,
+}
+
+impl PluginActionInfo {
+ pub fn qualified_id(&self) -> String {
+ format!("{}.{}", self.plugin_id, self.action_id)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginPaneOpenParams {
+ pub plugin_id: String,
+ pub entrypoint: String,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub placement: Option<PluginPanePlacement>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub workspace_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub target_pane_id: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub direction: Option<SplitDirection>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cwd: Option<String>,
+ #[serde(default)]
+ pub focus: bool,
+ #[serde(default, skip_serializing_if = "HashMap::is_empty")]
+ pub env: HashMap<String, String>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
+#[serde(rename_all = "snake_case")]
+pub enum PluginPanePlacement {
+ #[default]
+ Overlay,
+ Split,
+ Tab,
+ Zoomed,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginPaneFocusParams {
+ pub pane_id: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginPaneCloseParams {
+ pub pane_id: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct PluginPaneInfo {
+ pub plugin_id: String,
+ pub entrypoint: String,
+ pub pane: PaneInfo,
+}