1use std::fmt;
2
3use engram_consolidate::ConsolidateError;
4use engram_hnsw::HnswError;
5use engram_llm_client::ApiError;
6use engram_storage::StorageError;
7
8#[derive(Debug)]
9pub enum CoreError {
10 ConfigNotFound,
11 ConfigParseError(String),
12 InvalidProvider(String),
13 IndexCorrupted(String),
14 RebuildFailed(String),
15 SocketError(String),
16 DispatchError(String),
17 ConfigReadOnly,
18 ExportFailed(String),
19 ImportVersionMismatch(u64),
20 ImportFailed(String),
21 InitFailed(String),
22 Storage(StorageError),
23 Hnsw(HnswError),
24 Api(ApiError),
25 TrainerFailed(String),
26 TrainerTimeout,
27 TrainerMalformedOutput(String),
28 ProjectDirNotFound,
29 LegacyDatabaseDetected {
30 legacy_path: String,
31 project_path: String,
32 },
33 MigrationSourceNotFound,
34 MigrationFailed(String),
35 Consolidation(ConsolidateError),
36}
37
38impl fmt::Display for CoreError {
39 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Self::ConfigNotFound => {
42 write!(formatter, "[6001] config not found")
43 }
44 Self::ConfigParseError(message) => {
45 write!(formatter, "[6002] config parse error: {message}")
46 }
47 Self::InvalidProvider(message) => {
48 write!(formatter, "[6003] invalid provider: {message}")
49 }
50 Self::IndexCorrupted(message) => {
51 write!(formatter, "[6004] index corrupted: {message}")
52 }
53 Self::RebuildFailed(message) => {
54 write!(formatter, "[6005] rebuild failed: {message}")
55 }
56 Self::SocketError(message) => {
57 write!(formatter, "[6006] socket error: {message}")
58 }
59 Self::DispatchError(message) => {
60 write!(formatter, "[6007] dispatch error: {message}")
61 }
62 Self::ConfigReadOnly => {
63 write!(formatter, "[6008] config is read-only")
64 }
65 Self::ExportFailed(message) => {
66 write!(formatter, "[6009] export failed: {message}")
67 }
68 Self::ImportVersionMismatch(version) => {
69 write!(
70 formatter,
71 "[6010] import version mismatch: expected 1, got {version}"
72 )
73 }
74 Self::ImportFailed(message) => {
75 write!(formatter, "[6011] import failed: {message}")
76 }
77 Self::InitFailed(message) => {
78 write!(formatter, "[6012] init failed: {message}")
79 }
80 Self::TrainerFailed(message) => {
81 write!(formatter, "[6013] trainer failed: {message}")
82 }
83 Self::TrainerTimeout => {
84 write!(formatter, "[6014] trainer timeout")
85 }
86 Self::TrainerMalformedOutput(message) => {
87 write!(formatter, "[6015] trainer malformed output: {message}")
88 }
89 Self::ProjectDirNotFound => {
90 write!(
91 formatter,
92 "[6016] project directory not found: no .engram/ in cwd or ancestors (run 'engram init')"
93 )
94 }
95 Self::LegacyDatabaseDetected {
96 legacy_path,
97 project_path,
98 } => {
99 write!(
100 formatter,
101 "[6017] legacy global database detected at {legacy_path}. Run `engram migrate` to import into project {project_path}, or `engram init` to start fresh."
102 )
103 }
104 Self::MigrationSourceNotFound => {
105 write!(
106 formatter,
107 "[6018] migration source not found: no legacy database at ~/.engram/engram.db (nothing to migrate)"
108 )
109 }
110 Self::MigrationFailed(message) => {
111 write!(formatter, "[6019] migration failed: {message}")
112 }
113 Self::Storage(error) => error.fmt(formatter),
114 Self::Hnsw(error) => error.fmt(formatter),
115 Self::Api(error) => error.fmt(formatter),
116 Self::Consolidation(error) => error.fmt(formatter),
117 }
118 }
119}
120
121impl std::error::Error for CoreError {
122 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123 match self {
124 Self::Storage(error) => Some(error),
125 Self::Hnsw(error) => Some(error),
126 Self::Api(error) => Some(error),
127 Self::Consolidation(error) => Some(error),
128 _ => None,
129 }
130 }
131}
132
133impl From<StorageError> for CoreError {
134 fn from(error: StorageError) -> Self {
135 Self::Storage(error)
136 }
137}
138
139impl From<HnswError> for CoreError {
140 fn from(error: HnswError) -> Self {
141 Self::Hnsw(error)
142 }
143}
144
145impl From<ApiError> for CoreError {
146 fn from(error: ApiError) -> Self {
147 Self::Api(error)
148 }
149}
150
151impl From<ConsolidateError> for CoreError {
152 fn from(error: ConsolidateError) -> Self {
153 Self::Consolidation(error)
154 }
155}