1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
//! Error types for command execution and presentation.
use std::ffi::OsString;
use std::path::PathBuf;
use thiserror::Error;
use crate::{
AnchorError, CharmError, ConfigError, EntryAddress, EntryAddressError, EntryArtifactPathError,
EntryAtomError, EntryDirectoryError, EntryParseError, GeneratedLinkError, MistError, TideError,
TideFileError, UpstreamError, UpstreamFileError, WitnessError,
};
/// Error raised while running the CLI.
#[derive(Debug, Error)]
pub enum CommandError {
/// An artifact source path did not have a file name for the default artifact path.
#[error("artifact source has no file name: {0}")]
ArtifactSourceHasNoFileName(PathBuf),
/// A configured path move cannot replace an existing destination.
#[error("move destination already exists: {0}")]
MoveDestinationExists(PathBuf),
/// A configured path move could not inspect its destination.
#[error("failed to inspect move destination {path}")]
ReadMoveDestination {
/// Destination path that could not be inspected.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A configured path move could not prepare a temporary staging path.
#[error("failed to prepare move staging path near {path}")]
PrepareMoveStagingPath {
/// Directory where the staging path would be created.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A configured path move could not create the destination parent.
#[error("failed to create move destination parent {path}")]
CreateMoveDestinationParent {
/// Destination parent path.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A configured path could not be moved.
#[error("failed to move {source_path} to {destination_path}")]
MovePath {
/// Source path configured before the move.
source_path: PathBuf,
/// Destination path configured by the move.
destination_path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A configured path move failed after staging and could not restore the source path.
#[error(
"failed to move {source_path} to {destination_path}; rollback from {staging_path} failed: {rollback}"
)]
MovePathRollback {
/// Source path configured before the move.
source_path: PathBuf,
/// Destination path configured by the move.
destination_path: PathBuf,
/// Temporary staging path that still holds the moved directory.
staging_path: PathBuf,
/// Underlying move error.
#[source]
source: std::io::Error,
/// Rollback rename error.
rollback: std::io::Error,
},
/// A config write failed after a configured path was moved, and the rollback also failed.
#[error(
"failed to write config after moving {source_path} to {destination_path}; rollback failed: {rollback}"
)]
MoveConfigWriteRollback {
/// Source path configured before the move.
source_path: PathBuf,
/// Destination path already moved into place.
destination_path: PathBuf,
/// Config write error.
#[source]
source: Box<ConfigError>,
/// Rollback rename error.
rollback: std::io::Error,
},
/// Witness lookup requires configured repo members.
#[error("repo members are not configured; add [repo].members to Sirno.toml")]
RepoMembersNotConfigured,
/// Witness lookup requires an existing entry address.
#[error("entry `{0}` does not exist")]
MissingWitnessEntry(EntryAddress),
/// The MCP server selects its project only through the config path.
#[error("`--lake-path` cannot be used with `sirno util mcp`; configure the lake in Sirno.toml")]
McpRejectsLakePath,
/// The config utility only inspects the config file.
#[error("`--lake-path` cannot be used with `sirno util config`; use `--config` only")]
ConfigRejectsLakePath,
/// The terminal UI failed.
#[error("terminal UI failed")]
TerminalUi(#[source] std::io::Error),
/// The interactive init prompt failed while reading or writing the terminal.
#[error("interactive init prompt failed")]
InteractiveInit(#[source] std::io::Error),
/// The interactive init prompt reached the end of its input.
#[error("interactive init prompt reached end of input")]
InteractiveInitEof,
/// The async MCP runtime could not be created.
#[error("failed to create MCP runtime")]
CreateMcpRuntime(#[source] std::io::Error),
/// The MCP server failed.
#[error("MCP server failed: {0}")]
McpServer(String),
/// The skill wrapper utility uses bundled wrapper constants.
#[error("`--lake-path` cannot be used with `sirno util skills`; wrappers are bundled")]
SkillsRejectsLakePath,
/// A skill wrapper package target could not be read.
#[error("failed to read skill wrapper target {path}")]
ReadSkillWrapperTarget {
/// Target path that could not be read.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A skill wrapper package directory could not be created.
#[error("failed to create skill wrapper target directory {path}")]
CreateSkillWrapperTargetDirectory {
/// Target directory that could not be created.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A skill wrapper package target could not be written.
#[error("failed to write skill wrapper target {path}")]
WriteSkillWrapperTarget {
/// Target path that could not be written.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A skill wrapper link target already exists as a non-link filesystem object.
#[error("skill wrapper target exists and is not a symlink: {0}")]
SkillWrapperTargetExists(PathBuf),
/// A stale skill wrapper symlink could not be removed.
#[error("failed to remove skill wrapper target {path}")]
RemoveSkillWrapperTarget {
/// Target path that could not be removed.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A skill wrapper package target could not be linked.
#[error("failed to link skill wrapper target {target_path} to {source_path}")]
LinkSkillWrapperTarget {
/// Link source path.
source_path: PathBuf,
/// Link target path.
target_path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// Dry-run mode applies only to render writing.
#[error("`--dry` only applies to `sirno mist render` without a subcommand")]
DryWithRenderSubcommand,
/// Render JSON overrides apply only to generated-link writing.
#[error("`--override-json` only applies to `sirno mist render` without a subcommand")]
OverrideJsonWithRenderSubcommand,
/// A command named a link relation not defined in the lake.
#[error(
"link relation `{0}` is not defined in the lake; add `{0}` with `meta.type: \"structural\"`"
)]
UndefinedStructuralField(String),
/// Generated-footer masking cannot compose with another ripgrep preprocessor.
#[error(
"generated-footer filtering cannot be combined with `rg --pre`; use `--with-generated-footer`"
)]
RgPreprocessorConflict,
/// Anchor update requires all current tide workitems to be reviewed.
#[error("anchor update blocked by {open_workitems} open tide workitems")]
AnchorUpdateOpenTide {
/// Number of open workitems.
open_workitems: usize,
},
/// Anchor update requires editable mist projections to be clean.
#[error("anchor update blocked by mist state: {0}")]
AnchorUpdateMist(String),
/// Mist intake requires a fresh editable projection.
#[error("mist intake blocked: {0}")]
MistIntakeBlocked(String),
/// Ripgrep generated-footer preprocessor received an unexpected argument shape.
#[error("rg generated-footer preprocessor expects one path argument")]
RgPreprocessorArgumentCount,
/// The current executable path could not be resolved.
#[error("failed to locate current executable for rg preprocessor")]
LocateCurrentExe(#[source] std::io::Error),
/// The process current working directory could not be changed.
#[error("failed to change current working directory to {path}")]
ChangeCurrentDirectory {
/// Target working directory.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// The current working directory could not be resolved.
#[error("failed to locate current working directory")]
CurrentDirectory(#[source] std::io::Error),
/// A temporary ripgrep preprocessor invoker could not be created.
#[error("failed to create rg preprocessor invoker at {path}")]
CreateRgPreprocessorInvoker {
/// Invoker path that could not be created.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// The generated-footer preprocessor could not read one file.
#[error("failed to read rg preprocessor input {path}")]
ReadRgPreprocessorInput {
/// Path passed by ripgrep.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// The generated-footer preprocessor could not write masked output.
#[error("failed to write rg preprocessor output")]
WriteRgPreprocessorOutput(#[source] std::io::Error),
/// Git could not be started.
#[error("failed to run git")]
RunGit(#[source] std::io::Error),
/// Git exited unsuccessfully.
#[error("git command failed: {stderr}")]
GitFailed {
/// Captured standard error.
stderr: String,
},
/// Git output was not valid UTF-8.
#[error("git output is not valid UTF-8")]
GitOutput(#[source] std::string::FromUtf8Error),
/// A charm command requires an enabled charm.
#[error("charm `{0}` is not enabled; run `sirno charm enable {0}` first")]
CharmNotEnabled(EntryAddress),
/// A charm process could not be started.
#[error("failed to run {phase} command for charm `{id}`")]
RunCharmProcess {
/// Entry address whose charm was selected.
id: EntryAddress,
/// Operation phase.
phase: &'static str,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A spell cache directory could not be created.
#[error("failed to create spell cache directory {path}")]
CreateSpellCache {
/// Cache path.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// A spell cache directory could not be removed.
#[error("failed to remove spell cache directory {path}")]
RemoveSpellCache {
/// Cache path.
path: PathBuf,
/// Underlying I/O error.
#[source]
source: std::io::Error,
},
/// Config-backed command failed.
#[error(transparent)]
Config(#[from] ConfigError),
/// Mist-backed command failed.
#[error(transparent)]
Mist(#[from] MistError),
/// Charm-backed command failed.
#[error(transparent)]
Charm(#[from] CharmError),
/// Anchor-backed command failed.
#[error(transparent)]
Anchor(#[from] AnchorError),
/// Upstream-file-backed command failed.
#[error(transparent)]
UpstreamFile(#[from] UpstreamFileError),
/// Witness lookup failed.
#[error(transparent)]
Witness(#[from] WitnessError),
/// Sirno Lake entry directory command failed.
#[error(transparent)]
EntryDirectory(#[from] EntryDirectoryError),
/// Entry address parsing failed.
#[error(transparent)]
EntryAddress(#[from] EntryAddressError),
/// Entry atom parsing failed.
#[error(transparent)]
EntryAtom(#[from] EntryAtomError),
/// Entry artifact path parsing failed.
#[error(transparent)]
ArtifactPath(#[from] EntryArtifactPathError),
/// Entry metadata construction failed.
#[error(transparent)]
EntryParse(#[from] EntryParseError),
/// Generated-link footer handling failed.
#[error(transparent)]
GeneratedLink(#[from] GeneratedLinkError),
/// Tide operation failed.
#[error(transparent)]
Tide(#[from] TideError),
/// Tide file operation failed.
#[error(transparent)]
TideFile(#[from] TideFileError),
/// Upstream operation failed.
#[error(transparent)]
Upstream(#[from] UpstreamError),
/// Ripgrep could not be started.
#[error("failed to run rg")]
RunRg(#[source] std::io::Error),
/// JSON-oriented ripgrep execution needs UTF-8 arguments.
#[error("rg argument is not valid UTF-8: {0:?}")]
RgArgumentNotUtf8(OsString),
/// JSON parsing or rendering failed.
#[error(transparent)]
Json(#[from] serde_json::Error),
}