Skip to main content

codineer_plugins/
error.rs

1use std::fmt::{Display, Formatter};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum PluginManifestValidationError {
6    EmptyField {
7        field: &'static str,
8    },
9    EmptyEntryField {
10        kind: &'static str,
11        field: &'static str,
12        name: Option<String>,
13    },
14    InvalidPermission {
15        permission: String,
16    },
17    DuplicatePermission {
18        permission: String,
19    },
20    DuplicateEntry {
21        kind: &'static str,
22        name: String,
23    },
24    MissingPath {
25        kind: &'static str,
26        path: PathBuf,
27    },
28    InvalidToolInputSchema {
29        tool_name: String,
30    },
31    InvalidToolRequiredPermission {
32        tool_name: String,
33        permission: String,
34    },
35}
36
37impl Display for PluginManifestValidationError {
38    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39        match self {
40            Self::EmptyField { field } => {
41                write!(f, "plugin manifest {field} cannot be empty")
42            }
43            Self::EmptyEntryField { kind, field, name } => match name {
44                Some(name) if !name.is_empty() => {
45                    write!(f, "plugin {kind} `{name}` {field} cannot be empty")
46                }
47                _ => write!(f, "plugin {kind} {field} cannot be empty"),
48            },
49            Self::InvalidPermission { permission } => {
50                write!(
51                    f,
52                    "plugin manifest permission `{permission}` must be one of read, write, or execute"
53                )
54            }
55            Self::DuplicatePermission { permission } => {
56                write!(f, "plugin manifest permission `{permission}` is duplicated")
57            }
58            Self::DuplicateEntry { kind, name } => {
59                write!(f, "plugin {kind} `{name}` is duplicated")
60            }
61            Self::MissingPath { kind, path } => {
62                write!(f, "{kind} path `{}` does not exist", path.display())
63            }
64            Self::InvalidToolInputSchema { tool_name } => {
65                write!(
66                    f,
67                    "plugin tool `{tool_name}` inputSchema must be a JSON object"
68                )
69            }
70            Self::InvalidToolRequiredPermission {
71                tool_name,
72                permission,
73            } => write!(
74                f,
75                "plugin tool `{tool_name}` requiredPermission `{permission}` must be read-only, workspace-write, or danger-full-access"
76            ),
77        }
78    }
79}
80
81#[derive(Debug)]
82pub enum PluginError {
83    Io(std::io::Error),
84    Json(serde_json::Error),
85    ManifestValidation(Vec<PluginManifestValidationError>),
86    InvalidManifest(String),
87    NotFound(String),
88    CommandFailed(String),
89}
90
91impl Display for PluginError {
92    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93        match self {
94            Self::Io(error) => write!(f, "{error}"),
95            Self::Json(error) => write!(f, "{error}"),
96            Self::ManifestValidation(errors) => {
97                for (index, error) in errors.iter().enumerate() {
98                    if index > 0 {
99                        write!(f, "; ")?;
100                    }
101                    write!(f, "{error}")?;
102                }
103                Ok(())
104            }
105            Self::InvalidManifest(message)
106            | Self::NotFound(message)
107            | Self::CommandFailed(message) => write!(f, "{message}"),
108        }
109    }
110}
111
112impl std::error::Error for PluginError {}
113
114impl From<std::io::Error> for PluginError {
115    fn from(value: std::io::Error) -> Self {
116        Self::Io(value)
117    }
118}
119
120impl From<serde_json::Error> for PluginError {
121    fn from(value: serde_json::Error) -> Self {
122        Self::Json(value)
123    }
124}