Skip to main content

hm_plugin_protocol/
error.rs

1//! Error and exit-info types returned by plugin capability exports.
2
3use schemars::JsonSchema as DeriveJsonSchema;
4use serde::{Deserialize, Serialize};
5
6/// Returned by a subcommand plugin from `hm_subcommand_run`. The host
7/// translates `exit_code` into the process exit code.
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema)]
9pub struct ExitInfo {
10    pub exit_code: i32,
11    /// Optional message written to stderr by the host before exit.
12    /// Used for the rare case where the plugin wants to add context
13    /// beyond the bytes it already streamed via `hm_log`.
14    pub message: Option<String>,
15}
16
17/// Error returned from any capability export. The host renders these
18/// with the `code` field; downstream tooling matches on it.
19#[derive(
20    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema, thiserror::Error,
21)]
22#[error("{message}")]
23pub struct PluginError {
24    /// Stable `snake_case` identifier scoped to the plugin, e.g.
25    /// `cloud_auth_token_invalid`. Downstream tooling matches on this.
26    pub code: String,
27    pub message: String,
28    /// Optional URL the host renders alongside the message.
29    pub doc_url: Option<String>,
30}
31
32impl PluginError {
33    #[must_use]
34    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
35        Self {
36            code: code.into(),
37            message: message.into(),
38            doc_url: None,
39        }
40    }
41
42    #[must_use]
43    pub fn with_doc(mut self, url: impl Into<String>) -> Self {
44        self.doc_url = Some(url.into());
45        self
46    }
47}