@crewhaus/errors 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +93 -1
- package/dist/index.js +126 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export declare class CompilerError extends CrewhausError {
|
|
|
31
31
|
constructor(message: string, cause?: unknown);
|
|
32
32
|
}
|
|
33
33
|
export declare class RuntimeError extends CrewhausError {
|
|
34
|
-
readonly name
|
|
34
|
+
readonly name: string;
|
|
35
35
|
constructor(message: string, cause?: unknown);
|
|
36
36
|
}
|
|
37
37
|
export declare class ConfigError extends CrewhausError {
|
|
@@ -69,3 +69,95 @@ export declare class ProviderAuthError extends AdapterError {
|
|
|
69
69
|
readonly name = "ProviderAuthError";
|
|
70
70
|
constructor(providerId: string, message: string, cause?: unknown);
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Terminal failure classes a run can die with. Broader than `ErrorCode`
|
|
74
|
+
* (which tags where an error was raised): a `FailureClass` tags *why the run
|
|
75
|
+
* stopped*, in end-user vocabulary, and maps 1:1 onto an exit code.
|
|
76
|
+
*/
|
|
77
|
+
export type FailureClass = "billing" | "auth" | "rate_limit" | "crewhaus_budget" | "mcp_boot" | "context_overflow" | "spec" | "config" | "tool" | "unknown";
|
|
78
|
+
/**
|
|
79
|
+
* The single structured description of a terminal run failure. `detail`
|
|
80
|
+
* carries the raw provider text (with attribution, e.g. `Anthropic said:
|
|
81
|
+
* "…"`); `remediation` is the one actionable next step; `exitCode` comes
|
|
82
|
+
* from `EXIT_CODES` so fleet / the UI host can dispatch without parsing.
|
|
83
|
+
*/
|
|
84
|
+
export type FailureReport = {
|
|
85
|
+
readonly class: FailureClass;
|
|
86
|
+
readonly title: string;
|
|
87
|
+
readonly detail: string;
|
|
88
|
+
readonly remediation?: string;
|
|
89
|
+
readonly exitCode: number;
|
|
90
|
+
readonly docsUrl?: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Process exit-code table (documented in CLI-REFERENCE). Everything fatal
|
|
94
|
+
* used to be exit 1; these codes let `fleet run` and the UI host tell
|
|
95
|
+
* "account out of funding" from "bad spec" from "tool crash".
|
|
96
|
+
*/
|
|
97
|
+
export declare const EXIT_CODES: {
|
|
98
|
+
/** Clean run. */
|
|
99
|
+
readonly ok: 0;
|
|
100
|
+
/** Unclassified fatal error (the pre-0.3.0 catch-all). */
|
|
101
|
+
readonly generic: 1;
|
|
102
|
+
/** Spec parse / validation failure. */
|
|
103
|
+
readonly spec: 20;
|
|
104
|
+
/** Config / missing-env failure. */
|
|
105
|
+
readonly config: 21;
|
|
106
|
+
/** Provider rejected the credentials at runtime (401/403). */
|
|
107
|
+
readonly auth: 30;
|
|
108
|
+
/** Provider account out of funding (credit balance, insufficient_quota, 402). */
|
|
109
|
+
readonly billing: 31;
|
|
110
|
+
/** Provider quota / rate limit exhausted after retries. */
|
|
111
|
+
readonly rate_limit: 32;
|
|
112
|
+
/** CrewHaus's own configured budget cap ended the run. */
|
|
113
|
+
readonly crewhaus_budget: 33;
|
|
114
|
+
/** Tool or MCP failure (including MCP boot). */
|
|
115
|
+
readonly tool: 40;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Terminal error carrying a `FailureReport`. Thrown by runtime-core when the
|
|
119
|
+
* recovery engine returns a `halt` action. Extends `RuntimeError` so every
|
|
120
|
+
* existing `instanceof CrewhausError` catch (e.g. `crewhaus run`'s die()
|
|
121
|
+
* routing) keeps working unchanged; PR 3 upgrades those catch sites to
|
|
122
|
+
* render the report and exit with `report.exitCode`.
|
|
123
|
+
*/
|
|
124
|
+
export declare class RunFailedError extends RuntimeError {
|
|
125
|
+
readonly name = "RunFailedError";
|
|
126
|
+
readonly report: FailureReport;
|
|
127
|
+
constructor(report: FailureReport, cause?: unknown);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Render a `FailureReport` as the canonical multi-line failure message:
|
|
131
|
+
*
|
|
132
|
+
* ✗ run stopped — provider account out of funding
|
|
133
|
+
* Anthropic said: "Your credit balance is too low to access the Anthropic API."
|
|
134
|
+
* Fix: add credits at https://console.anthropic.com/settings/billing, then rerun.
|
|
135
|
+
* (exit 31)
|
|
136
|
+
*
|
|
137
|
+
* `opts.prefix` replaces the leading `✗` (e.g. `crewhaus:` for the CLI).
|
|
138
|
+
* `opts.notes` are surface-specific trailing lines rendered after Fix/Docs
|
|
139
|
+
* and before the exit line (e.g. `crewhaus run`'s "Your session is saved —
|
|
140
|
+
* …" resume hint). Dependency-free by design — emitted bundles inline-import
|
|
141
|
+
* this.
|
|
142
|
+
*/
|
|
143
|
+
export declare function formatRunFailure(report: FailureReport, opts?: {
|
|
144
|
+
prefix?: string;
|
|
145
|
+
notes?: readonly string[];
|
|
146
|
+
}): string;
|
|
147
|
+
/**
|
|
148
|
+
* Is `err` a RunFailedError (or a structurally identical wire twin)? The
|
|
149
|
+
* duck-typed fallback matters for compiled bundles: a bundle and the runtime
|
|
150
|
+
* it embeds can end up with two copies of this package (duplicated install,
|
|
151
|
+
* bundler realm split), in which case `instanceof` lies but the shape —
|
|
152
|
+
* `name === "RunFailedError"` plus a report with a numeric `exitCode` —
|
|
153
|
+
* does not.
|
|
154
|
+
*/
|
|
155
|
+
export declare function isRunFailedError(err: unknown): err is RunFailedError;
|
|
156
|
+
/**
|
|
157
|
+
* Coerce any thrown value into a `FailureReport`: a RunFailedError yields
|
|
158
|
+
* its own classified report; everything else synthesizes a best-effort
|
|
159
|
+
* generic report (class `"unknown"`, exit {@link EXIT_CODES.generic}) so
|
|
160
|
+
* every terminal surface — compiled bundles' catch wrappers, daemon mains,
|
|
161
|
+
* `crewhaus run` — renders ONE shape regardless of what escaped.
|
|
162
|
+
*/
|
|
163
|
+
export declare function toFailureReport(err: unknown): FailureReport;
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ export class CompilerError extends CrewhausError {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
export class RuntimeError extends CrewhausError {
|
|
47
|
+
// `: string` (not the literal) so subclasses (RunFailedError) can narrow.
|
|
47
48
|
name = "RuntimeError";
|
|
48
49
|
constructor(message, cause) {
|
|
49
50
|
super("runtime", message, cause);
|
|
@@ -100,3 +101,128 @@ export class ProviderAuthError extends AdapterError {
|
|
|
100
101
|
super(providerId, message, cause);
|
|
101
102
|
}
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Process exit-code table (documented in CLI-REFERENCE). Everything fatal
|
|
106
|
+
* used to be exit 1; these codes let `fleet run` and the UI host tell
|
|
107
|
+
* "account out of funding" from "bad spec" from "tool crash".
|
|
108
|
+
*/
|
|
109
|
+
export const EXIT_CODES = {
|
|
110
|
+
/** Clean run. */
|
|
111
|
+
ok: 0,
|
|
112
|
+
/** Unclassified fatal error (the pre-0.3.0 catch-all). */
|
|
113
|
+
generic: 1,
|
|
114
|
+
/** Spec parse / validation failure. */
|
|
115
|
+
spec: 20,
|
|
116
|
+
/** Config / missing-env failure. */
|
|
117
|
+
config: 21,
|
|
118
|
+
/** Provider rejected the credentials at runtime (401/403). */
|
|
119
|
+
auth: 30,
|
|
120
|
+
/** Provider account out of funding (credit balance, insufficient_quota, 402). */
|
|
121
|
+
billing: 31,
|
|
122
|
+
/** Provider quota / rate limit exhausted after retries. */
|
|
123
|
+
rate_limit: 32,
|
|
124
|
+
/** CrewHaus's own configured budget cap ended the run. */
|
|
125
|
+
crewhaus_budget: 33,
|
|
126
|
+
/** Tool or MCP failure (including MCP boot). */
|
|
127
|
+
tool: 40,
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Terminal error carrying a `FailureReport`. Thrown by runtime-core when the
|
|
131
|
+
* recovery engine returns a `halt` action. Extends `RuntimeError` so every
|
|
132
|
+
* existing `instanceof CrewhausError` catch (e.g. `crewhaus run`'s die()
|
|
133
|
+
* routing) keeps working unchanged; PR 3 upgrades those catch sites to
|
|
134
|
+
* render the report and exit with `report.exitCode`.
|
|
135
|
+
*/
|
|
136
|
+
export class RunFailedError extends RuntimeError {
|
|
137
|
+
name = "RunFailedError";
|
|
138
|
+
report;
|
|
139
|
+
constructor(report, cause) {
|
|
140
|
+
super(`run stopped — ${report.title}: ${report.detail}`, cause);
|
|
141
|
+
this.report = report;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Render a `FailureReport` as the canonical multi-line failure message:
|
|
146
|
+
*
|
|
147
|
+
* ✗ run stopped — provider account out of funding
|
|
148
|
+
* Anthropic said: "Your credit balance is too low to access the Anthropic API."
|
|
149
|
+
* Fix: add credits at https://console.anthropic.com/settings/billing, then rerun.
|
|
150
|
+
* (exit 31)
|
|
151
|
+
*
|
|
152
|
+
* `opts.prefix` replaces the leading `✗` (e.g. `crewhaus:` for the CLI).
|
|
153
|
+
* `opts.notes` are surface-specific trailing lines rendered after Fix/Docs
|
|
154
|
+
* and before the exit line (e.g. `crewhaus run`'s "Your session is saved —
|
|
155
|
+
* …" resume hint). Dependency-free by design — emitted bundles inline-import
|
|
156
|
+
* this.
|
|
157
|
+
*/
|
|
158
|
+
export function formatRunFailure(report, opts) {
|
|
159
|
+
const prefix = opts?.prefix ?? "✗";
|
|
160
|
+
const lines = [`${prefix} run stopped — ${report.title}`];
|
|
161
|
+
if (report.detail.length > 0) {
|
|
162
|
+
for (const detailLine of report.detail.split("\n")) {
|
|
163
|
+
lines.push(` ${detailLine}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (report.remediation !== undefined && report.remediation.length > 0) {
|
|
167
|
+
lines.push(` Fix: ${report.remediation}`);
|
|
168
|
+
}
|
|
169
|
+
if (report.docsUrl !== undefined && report.docsUrl.length > 0) {
|
|
170
|
+
lines.push(` Docs: ${report.docsUrl}`);
|
|
171
|
+
}
|
|
172
|
+
for (const note of opts?.notes ?? []) {
|
|
173
|
+
lines.push(` ${note}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push(` (exit ${report.exitCode})`);
|
|
176
|
+
return lines.join("\n");
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Is `err` a RunFailedError (or a structurally identical wire twin)? The
|
|
180
|
+
* duck-typed fallback matters for compiled bundles: a bundle and the runtime
|
|
181
|
+
* it embeds can end up with two copies of this package (duplicated install,
|
|
182
|
+
* bundler realm split), in which case `instanceof` lies but the shape —
|
|
183
|
+
* `name === "RunFailedError"` plus a report with a numeric `exitCode` —
|
|
184
|
+
* does not.
|
|
185
|
+
*/
|
|
186
|
+
export function isRunFailedError(err) {
|
|
187
|
+
if (err instanceof RunFailedError)
|
|
188
|
+
return true;
|
|
189
|
+
const duck = err;
|
|
190
|
+
return (duck !== null &&
|
|
191
|
+
typeof duck === "object" &&
|
|
192
|
+
duck.name === "RunFailedError" &&
|
|
193
|
+
typeof duck.report === "object" &&
|
|
194
|
+
duck.report !== null &&
|
|
195
|
+
typeof duck.report.exitCode === "number");
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Coerce any thrown value into a `FailureReport`: a RunFailedError yields
|
|
199
|
+
* its own classified report; everything else synthesizes a best-effort
|
|
200
|
+
* generic report (class `"unknown"`, exit {@link EXIT_CODES.generic}) so
|
|
201
|
+
* every terminal surface — compiled bundles' catch wrappers, daemon mains,
|
|
202
|
+
* `crewhaus run` — renders ONE shape regardless of what escaped.
|
|
203
|
+
*/
|
|
204
|
+
export function toFailureReport(err) {
|
|
205
|
+
if (isRunFailedError(err))
|
|
206
|
+
return err.report;
|
|
207
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
208
|
+
// A `ConfigError` (missing env var, unresolvable secret ref — e.g. the
|
|
209
|
+
// thredz boot's THREDZ_API_KEY resolution, §4.4) is a classified failure
|
|
210
|
+
// with its own exit code (21), not the generic catch-all. Duck-typed on
|
|
211
|
+
// the stable `code` field so a realm-split copy of this package still
|
|
212
|
+
// classifies.
|
|
213
|
+
const code = err?.code;
|
|
214
|
+
if (err instanceof Error && code === "config") {
|
|
215
|
+
return {
|
|
216
|
+
class: "config",
|
|
217
|
+
title: "configuration error",
|
|
218
|
+
detail,
|
|
219
|
+
exitCode: EXIT_CODES.config,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
class: "unknown",
|
|
224
|
+
title: "unexpected error",
|
|
225
|
+
detail,
|
|
226
|
+
exitCode: EXIT_CODES.generic,
|
|
227
|
+
};
|
|
228
|
+
}
|