haematite-cli 0.21.7

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use super::{USAGE, adapter, rpc};
use crate::client;
use std::{fmt, io};

#[derive(Debug)]
pub enum RelayError {
    Input(io::Error),
    ReceiptOutput {
        cause: io::Error,
        response: Vec<u8>,
    },
    ResultEncoding {
        refusal: rpc::Refusal,
        result: adapter::ToolResult,
    },
    Encoding(serde_json::Error),
    Adapter(adapter::EncodeError),
    Arguments(&'static str),
    ConfigRead(io::Error),
    ConfigDecode(serde_json::Error),
    Runtime(crate::serve::runtime::Refusal),
    SocketCap(client::Ended),
    CapNotRepresentable,
}

impl fmt::Display for RelayError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Diagnostics name the stage without exposing request or record text.
        let code = match self {
            Self::Input(_) => "mcp_input_read_failed",
            Self::ReceiptOutput { .. } => "mcp_output_write_failed",
            Self::ResultEncoding { .. } | Self::Encoding(_) => "mcp_response_encoding_failed",
            Self::Adapter(_) => "mcp_result_encoding_failed",
            Self::Arguments(why) => {
                return write!(formatter, "mcp_arguments_invalid: {why}; {USAGE}");
            }
            Self::ConfigRead(_) => "mcp_config_read_failed",
            Self::ConfigDecode(_) => "mcp_config_invalid",
            Self::Runtime(error) => return fmt::Display::fmt(error, formatter),
            Self::SocketCap(_) => "mcp_socket_cap_unavailable",
            Self::CapNotRepresentable => "mcp_frame_cap_unrepresentable",
        };
        formatter.write_str(code)
    }
}

impl std::error::Error for RelayError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Input(error) | Self::ConfigRead(error) => Some(error),
            Self::Encoding(error) | Self::ConfigDecode(error) => Some(error),
            Self::Adapter(error) => Some(error),
            Self::Runtime(error) => Some(error),
            Self::ReceiptOutput { cause, .. } => Some(cause),
            Self::ResultEncoding { .. }
            | Self::Arguments(_)
            | Self::SocketCap(_)
            | Self::CapNotRepresentable => None,
        }
    }
}