1use thiserror::Error;
8
9#[derive(Debug, Error)]
10pub enum OneharnessError {
11 #[error("no harness selected: pass --all or --harness <id>, or set `all`/`harnesses` in oneharness.toml (see `oneharness list`)")]
12 NoSelection,
13
14 #[error("unknown harness id `{id}`. valid ids: {valid}")]
15 UnknownHarness { id: String, valid: String },
16
17 #[error("no prompt provided: pass --prompt <text> or --prompt-file <path>")]
18 NoPrompt,
19
20 #[error("--prompt-file - (stdin) can be given only once, but it was passed {count} times")]
21 MultipleStdinPrompts { count: usize },
22
23 #[error("stdin ('-') can be read only once, but {count} inputs request it (across --prompt-file and --system-file)")]
24 MultipleStdinConsumers { count: usize },
25
26 #[error("a batch run (more than one prompt) needs exactly one harness (a shared cache prefix is per harness/model), but {count} were selected: {selected}. Select one with --harness <id>")]
27 BatchMultipleHarnesses { count: usize, selected: String },
28
29 #[error("a batch run (more than one prompt) cannot be combined with --resume/--fork (those continue a single session with a single prompt)")]
30 BatchResume,
31
32 #[error("--resume needs exactly one harness (a session belongs to one harness), but {count} were selected: {selected}")]
33 ResumeMultipleHarnesses { count: usize, selected: String },
34
35 #[error("harness `{id}` does not support --resume. supported: {supported}")]
36 ResumeUnsupported { id: String, supported: String },
37
38 #[error("harness `{id}` does not support --fork (it resumes linearly, appending in place). supported: {supported}")]
39 ForkUnsupported { id: String, supported: String },
40
41 #[error("--session needs exactly one harness (a named session belongs to one harness), but {count} were selected: {selected}")]
42 SessionMultipleHarnesses { count: usize, selected: String },
43
44 #[error("--session cannot be combined with a batch run (more than one prompt): a named session is one continued conversation, not a fan-out")]
45 SessionBatch,
46
47 #[error("harness `{id}` does not support --session: it exposes no session id headlessly, so a named handle cannot be mapped to it. supported: {supported}")]
48 SessionUnsupported { id: String, supported: String },
49
50 #[error("session `{name}` was created on harness `{was}`, so it cannot be continued on `{now}` (a named session is bound to one harness; use a different --session name)")]
51 SessionHarnessConflict {
52 name: String,
53 was: String,
54 now: String,
55 },
56
57 #[error("cannot resolve a session store directory (no --session-dir and no platform state dir): set --session-dir <DIR>")]
58 SessionNoStore,
59
60 #[error("harness `{id}` does not support `--mode {mode}`. supported modes: {supported}")]
61 ModeUnsupported {
62 id: String,
63 mode: String,
64 supported: String,
65 },
66
67 #[error("could not read harness config `{path}`: {source}")]
68 HarnessConfigRead {
69 path: String,
70 #[source]
71 source: std::io::Error,
72 },
73
74 #[error("cannot sync into `{path}`: {message} (oneharness only rewrites files it can parse, so it never destroys content it does not understand)")]
75 HarnessConfigUnmergeable { path: String, message: String },
76
77 #[error("harness `{id}` has no hook mapping, so oneharness cannot install a hook into it")]
78 HookUnsupported { id: String },
79
80 #[error("harness `{id}` has no user-global hook location, so oneharness cannot install a global hook into it")]
81 HookGlobalUnsupported { id: String },
82
83 #[error("cannot resolve the user-global hook directory for `{id}`: {var} is not set")]
84 HookGlobalDirMissing { id: String, var: &'static str },
85
86 #[error("`oneharness sync --global` installs hooks only, but permission rules or `settings` are configured for `{id}` — those are project-scoped (sync them without --global, or remove them)")]
87 GlobalSyncOnlyHooks { id: String },
88
89 #[error(
90 "harness `{id}` has no pre-tool gate, so `oneharness gate {id}` cannot emit a verdict"
91 )]
92 GateUnsupported { id: String },
93
94 #[error("could not read mock rules file `{path}`: {source}")]
95 MockRulesFile {
96 path: String,
97 #[source]
98 source: std::io::Error,
99 },
100
101 #[error("invalid mock rules file `{path}`: {message}")]
102 MockRulesInvalid { path: String, message: String },
103
104 #[error("harness `{id}` cannot express the mock action `{action}`, so `oneharness mock {id}` refuses this ruleset (see `mock_rewrite`/`supports_mock_deny` in `oneharness list`)")]
105 MockActionUnsupported { id: String, action: &'static str },
106
107 #[error(
108 "harness `{id}` cannot take a one-shot mock hook (`--mock-rules`/`--spy-file`): {reason}"
109 )]
110 MockDeliveryUnsupported { id: String, reason: &'static str },
111
112 #[error("cannot embed `{path}` into a hook command: it contains whitespace (hook commands are tokenized on spaces by some harnesses; use space-free paths)")]
113 MockPathWhitespace { path: String },
114
115 #[error("could not wire the one-shot mock hook: {message}")]
116 MockSetup { message: String },
117
118 #[error("could not write harness config `{path}`: {source}")]
119 HarnessConfigWrite {
120 path: String,
121 #[source]
122 source: std::io::Error,
123 },
124
125 #[error("could not read prompt file `{path}`: {source}")]
126 PromptFile {
127 path: String,
128 #[source]
129 source: std::io::Error,
130 },
131
132 #[error("could not read system prompt file `{path}`: {source}")]
133 SystemFile {
134 path: String,
135 #[source]
136 source: std::io::Error,
137 },
138
139 #[error("could not read schema file `{path}`: {source}")]
140 SchemaFile {
141 path: String,
142 #[source]
143 source: std::io::Error,
144 },
145
146 #[error("invalid --schema: {0}")]
147 Schema(String),
148
149 #[error("invalid --stream: {0}")]
150 StreamInvalid(String),
151
152 #[error("could not read config file `{path}`: {source}")]
153 ConfigRead {
154 path: String,
155 #[source]
156 source: std::io::Error,
157 },
158
159 #[error("invalid config file `{path}`: {message}")]
160 ConfigInvalid { path: String, message: String },
161
162 #[error("invalid environment-variable config override: {0}")]
163 EnvConfigInvalid(String),
164
165 #[error("invalid --bin override `{0}`: expected the form ID=PATH")]
166 BadBinOverride(String),
167
168 #[error("invalid --env `{0}`: expected the form KEY=VALUE")]
169 BadEnv(String),
170
171 #[error("could not write output to `{path}`: {source}")]
172 OutputDir {
173 path: String,
174 #[source]
175 source: std::io::Error,
176 },
177
178 #[error("could not access history under `{path}`: {source}")]
179 HistoryIo {
180 path: String,
181 #[source]
182 source: std::io::Error,
183 },
184
185 #[error("no history directory: pass --history-dir, set `history_dir` in config, or ONEHARNESS_HISTORY_DIR (a default under the platform state dir could not be resolved)")]
186 HistoryNoDir,
187
188 #[error("failed to write JSON output: {0}")]
189 Serialize(#[from] serde_json::Error),
190}