Skip to main content

mai_cli/
error.rs

1//! Error types for the MAI CLI.
2//!
3//! This module provides a unified error type using `thiserror` for automatic
4//! trait implementations and seamless error conversion via the `From` trait.
5
6use std::path::PathBuf;
7
8/// Unified error type for all MAI operations.
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11    #[error(
12        "Pack not found: {0}\n\nHint: Use 'mai list' to see installed packs, or 'mai install {0}' to install it."
13    )]
14    PackNotFound(String),
15
16    #[error(
17        "Tool not found: {0}\n\nAvailable tools: claude, cursor, windsurf\nHint: Use 'mai use <tool>' to switch tools."
18    )]
19    ToolNotFound(String),
20
21    #[error(
22        "Version conflict: {0}\n\nHint: Try specifying an explicit version or run 'mai update' to resolve conflicts."
23    )]
24    VersionConflict(String),
25
26    #[error(
27        "IO error: {0}\n\nContext: Failed to perform file operation. Check permissions and disk space."
28    )]
29    Io(#[from] std::io::Error),
30
31    #[error("Parse error: {0}\n\nHint: Check the syntax and ensure the file format is valid.")]
32    Parse(String),
33
34    #[error("Registry error: {0}")]
35    Registry(String),
36
37    #[error("Project error: {0}\n\nHint: Run 'mai project init' to create a new project manifest.")]
38    Project(String),
39
40    #[error("Lock file error: {0}\n\nHint: Run 'mai project sync' to regenerate the lock file.")]
41    LockFile(String),
42
43    #[error(
44        "Network error: {0}\n\nContext: Failed to fetch remote resource. Check your internet connection."
45    )]
46    Network(String),
47
48    #[error("TOML error: {0}\n\nContext: Failed to parse or serialize TOML configuration.")]
49    Toml(#[from] toml::de::Error),
50
51    #[error("TOML serialization error: {0}\n\nContext: Failed to serialize TOML configuration.")]
52    TomlSerialize(#[from] toml::ser::Error),
53
54    #[error("Version error: {0}")]
55    Version(String),
56
57    #[error("Config error: {0}")]
58    Config(String),
59
60    #[error("Path error: {0}")]
61    Path(PathBuf),
62}
63
64/// Result type alias using the unified Error type.
65pub type Result<T, E = Error> = std::result::Result<T, E>;
66
67impl Error {
68    #[allow(dead_code)]
69    pub fn pack_not_found(pack: impl Into<String>) -> Self {
70        Error::PackNotFound(pack.into())
71    }
72
73    #[allow(dead_code)]
74    pub fn tool_not_found(tool: impl Into<String>) -> Self {
75        Error::ToolNotFound(tool.into())
76    }
77
78    #[allow(dead_code)]
79    pub fn version_conflict(msg: impl Into<String>) -> Self {
80        Error::VersionConflict(msg.into())
81    }
82
83    #[allow(dead_code)]
84    pub fn registry_error(msg: impl Into<String>) -> Self {
85        Error::Registry(msg.into())
86    }
87
88    #[allow(dead_code)]
89    pub fn project_error(msg: impl Into<String>) -> Self {
90        Error::Project(msg.into())
91    }
92
93    #[allow(dead_code)]
94    pub fn lock_file_error(msg: impl Into<String>) -> Self {
95        Error::LockFile(msg.into())
96    }
97
98    #[allow(dead_code)]
99    pub fn network_error(msg: impl Into<String>) -> Self {
100        Error::Network(msg.into())
101    }
102
103    #[allow(dead_code)]
104    pub fn parse_error(msg: impl Into<String>) -> Self {
105        Error::Parse(msg.into())
106    }
107
108    #[allow(dead_code)]
109    pub fn version_error(msg: impl Into<String>) -> Self {
110        Error::Version(msg.into())
111    }
112
113    #[allow(dead_code)]
114    pub fn config_error(msg: impl Into<String>) -> Self {
115        Error::Config(msg.into())
116    }
117
118    #[allow(dead_code)]
119    pub fn path_error(path: PathBuf) -> Self {
120        Error::Path(path)
121    }
122}