Skip to main content

vtcode_commons/
errors.rs

1use std::borrow::Cow;
2
3use anyhow::{Error, Result};
4
5// File operation errors
6pub const ERR_READ_FILE: &str = "failed to read file";
7pub const ERR_WRITE_FILE: &str = "failed to write file";
8pub const ERR_READ_DIR: &str = "failed to read directory";
9pub const ERR_CREATE_DIR: &str = "failed to create directory";
10pub const ERR_REMOVE_FILE: &str = "failed to remove file";
11pub const ERR_REMOVE_DIR: &str = "failed to remove directory";
12pub const ERR_READ_DIR_ENTRY: &str = "failed to read directory entry";
13pub const ERR_GET_FILE_TYPE: &str = "failed to read file type";
14pub const ERR_GET_METADATA: &str = "failed to read file metadata";
15pub const ERR_CANONICALIZE_PATH: &str = "failed to canonicalize path";
16pub const ERR_READ_SYMLINK: &str = "failed to read symlink";
17
18// Session/State errors
19pub const ERR_CREATE_SESSION_DIR: &str = "failed to create session directory";
20pub const ERR_READ_SESSION: &str = "failed to read session";
21pub const ERR_WRITE_SESSION: &str = "failed to write session";
22pub const ERR_DELETE_SESSION: &str = "failed to delete session";
23pub const ERR_ARCHIVE_SESSION: &str = "failed to archive session";
24
25// Skill/Tool errors
26pub const ERR_CREATE_SKILLS_DIR: &str = "failed to create skills directory";
27pub const ERR_CREATE_SKILL_DIR: &str = "failed to create skill directory";
28pub const ERR_READ_SKILL_CODE: &str = "failed to read skill code";
29pub const ERR_WRITE_SKILL_CODE: &str = "failed to write skill code";
30pub const ERR_READ_SKILL_METADATA: &str = "failed to read skill metadata";
31pub const ERR_WRITE_SKILL_METADATA: &str = "failed to write skill metadata";
32pub const ERR_PARSE_SKILL_METADATA: &str = "failed to parse skill metadata";
33pub const ERR_WRITE_SKILL_DOCS: &str = "failed to write skill documentation";
34pub const ERR_DELETE_SKILL: &str = "failed to delete skill";
35pub const ERR_READ_SKILLS_DIR: &str = "failed to read skills directory";
36pub const ERR_TOOL_DENIED: &str = "tool denied or unavailable by policy";
37
38// Audit/Logging errors
39pub const ERR_CREATE_AUDIT_DIR: &str = "Failed to create audit directory";
40pub const ERR_WRITE_AUDIT_LOG: &str = "failed to write audit log";
41
42// Checkpoint/Snapshot errors
43pub const ERR_CREATE_CHECKPOINT_DIR: &str = "failed to create checkpoint directory";
44pub const ERR_WRITE_CHECKPOINT: &str = "failed to write checkpoint";
45pub const ERR_READ_CHECKPOINT: &str = "failed to read checkpoint";
46
47// Policy errors
48pub const ERR_CREATE_POLICY_DIR: &str = "Failed to create directory for tool policy config";
49pub const ERR_CREATE_WORKSPACE_POLICY_DIR: &str = "Failed to create workspace policy directory";
50
51// Serialization errors
52pub const ERR_SERIALIZE_METADATA: &str = "failed to serialize skill metadata";
53pub const ERR_SERIALIZE_STATE: &str = "failed to serialize state";
54pub const ERR_DESERIALIZE: &str = "failed to deserialize data";
55
56// IPC/SDK errors
57pub const ERR_CREATE_IPC_DIR: &str = "failed to create IPC directory";
58pub const ERR_READ_REQUEST_FILE: &str = "failed to read request file";
59pub const ERR_READ_REQUEST_JSON: &str = "failed to read request JSON";
60pub const ERR_PARSE_REQUEST_JSON: &str = "failed to parse request JSON";
61pub const ERR_PARSE_ARGS: &str = "failed to parse tokenized args";
62pub const ERR_PARSE_RESULT: &str = "failed to parse de-tokenized result";
63
64/// Helper macro for file operation errors with context
65/// Usage: file_err!("path", "read") -> "failed to read path"
66#[macro_export]
67macro_rules! file_err {
68    ($path:expr, read) => {
69        format!("failed to read {}", $path)
70    };
71    ($path:expr, write) => {
72        format!("failed to write {}", $path)
73    };
74    ($path:expr, delete) => {
75        format!("failed to delete {}", $path)
76    };
77    ($path:expr, create) => {
78        format!("failed to create {}", $path)
79    };
80}
81
82/// Helper macro for context errors
83/// Usage: ctx_err!(operation, context) -> "operation context"
84#[macro_export]
85macro_rules! ctx_err {
86    ($op:expr, $ctx:expr) => {
87        format!("{}: {}", $op, $ctx)
88    };
89}
90
91/// Formats an error into a user-facing description. This allows extracted
92/// components to present consistent error messaging without depending on the
93/// CLI presentation layer.
94pub trait ErrorFormatter: Send + Sync {
95    /// Render the error into a user-facing string.
96    fn format_error(&self, error: &Error) -> Cow<'_, str>;
97}
98
99/// Reports non-fatal errors to an observability backend.
100pub trait ErrorReporter: Send + Sync {
101    /// Capture the provided error for later inspection.
102    fn capture(&self, error: &Error) -> Result<()>;
103
104    /// Convenience helper to capture a simple message.
105    fn capture_message(&self, message: impl Into<Cow<'static, str>>) -> Result<()> {
106        let message: Cow<'static, str> = message.into();
107        self.capture(&Error::msg(message))
108    }
109}
110
111/// Error reporting implementation that drops every event. Useful for tests or
112/// when a consumer does not yet integrate with error monitoring.
113#[derive(Debug, Default, Clone, Copy)]
114pub struct NoopErrorReporter;
115
116impl ErrorReporter for NoopErrorReporter {
117    fn capture(&self, _error: &Error) -> Result<()> {
118        Ok(())
119    }
120}
121
122/// Default formatter that surfaces the error's display output.
123#[derive(Debug, Default, Clone, Copy)]
124pub struct DisplayErrorFormatter;
125
126impl ErrorFormatter for DisplayErrorFormatter {
127    fn format_error(&self, error: &Error) -> Cow<'_, str> {
128        Cow::Owned(format!("{error}"))
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn formatter_uses_display() {
138        let formatter = DisplayErrorFormatter;
139        let error = Error::msg("test error");
140        assert_eq!(formatter.format_error(&error), "test error");
141    }
142
143    #[test]
144    fn noop_reporter_drops_errors() {
145        let reporter = NoopErrorReporter;
146        let error = Error::msg("test");
147        assert!(reporter.capture(&error).is_ok());
148        assert!(reporter.capture_message("message").is_ok());
149    }
150}