@indigoai-us/hq-cli 5.345.173 → 5.345.175
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/CHANGELOG.md +14 -0
- package/dist/command-catalog.generated.d.ts +130 -0
- package/dist/command-catalog.generated.js +159 -0
- package/dist/commands/bot.js +3 -0
- package/dist/commands/channels.js +90 -0
- package/dist/commands/deploy-domains.d.ts +20 -0
- package/dist/commands/deploy-domains.js +237 -0
- package/dist/commands/dm.d.ts +7 -0
- package/dist/commands/dm.js +16 -4
- package/dist/lib/bot/fleet-local.d.ts +2 -0
- package/dist/lib/bot/fleet-local.js +75 -10
- package/dist/lib/bot/run.d.ts +2 -0
- package/dist/lib/bot/run.js +47 -13
- package/dist/lib/bot/runtime/index.js +18 -2
- package/dist/lib/bot/runtime/types.d.ts +13 -0
- package/dist/lib/bot/runtime/types.js +13 -0
- package/dist/lib/bot/runtime-failure.d.ts +17 -6
- package/dist/lib/bot/runtime-failure.js +54 -9
- package/dist/lib/bot/status.d.ts +10 -0
- package/package.json +7 -7
|
@@ -19,6 +19,14 @@ export class RuntimeError extends Error {
|
|
|
19
19
|
* must never decide what went wrong; only the message may.
|
|
20
20
|
*/
|
|
21
21
|
excerptIsOutputTail;
|
|
22
|
+
/** How long the runtime process lived, in ms, when known. */
|
|
23
|
+
durationMs;
|
|
24
|
+
/** True when stdout carried at least one stream event (`system`, `assistant`, `result`): the turn started. */
|
|
25
|
+
sawStreamEvent;
|
|
26
|
+
/** Crash evidence for the bot log: the binary spawned, full stderr and the head of stdout (bounded). */
|
|
27
|
+
binaryPath;
|
|
28
|
+
stderrFull;
|
|
29
|
+
stdoutHead;
|
|
22
30
|
constructor(message, stderrExcerpt, exitCode, opts = {}) {
|
|
23
31
|
super(message);
|
|
24
32
|
this.stderrExcerpt = stderrExcerpt;
|
|
@@ -27,6 +35,11 @@ export class RuntimeError extends Error {
|
|
|
27
35
|
this.started = opts.started ?? true;
|
|
28
36
|
this.aborted = opts.aborted ?? false;
|
|
29
37
|
this.excerptIsOutputTail = opts.excerptIsOutputTail ?? false;
|
|
38
|
+
this.durationMs = opts.durationMs;
|
|
39
|
+
this.sawStreamEvent = opts.sawStreamEvent ?? false;
|
|
40
|
+
this.binaryPath = opts.binaryPath;
|
|
41
|
+
this.stderrFull = opts.stderrFull;
|
|
42
|
+
this.stdoutHead = opts.stdoutHead;
|
|
30
43
|
}
|
|
31
44
|
}
|
|
32
45
|
/**
|
|
@@ -27,16 +27,27 @@ export type RuntimeFailureClass =
|
|
|
27
27
|
| "transient"
|
|
28
28
|
/** The tool is not installed (or not on PATH) on this computer. */
|
|
29
29
|
| "not-installed"
|
|
30
|
+
/** The tool's process exited before the turn started (e.g. Bun's "error: ... (Unexpected)"). A restart heals it. */
|
|
31
|
+
| "runtime-crashed"
|
|
30
32
|
/** Anything else. Neutral copy; never blames the sign-in. */
|
|
31
33
|
| "unknown";
|
|
32
|
-
/** The
|
|
33
|
-
export type RuntimeRepairClass = Extract<RuntimeFailureClass, "signed-out" | "cli-outdated" | "model-unsupported" | "transient">;
|
|
34
|
+
/** The classes that get a repair card in the DM. */
|
|
35
|
+
export type RuntimeRepairClass = Extract<RuntimeFailureClass, "signed-out" | "cli-outdated" | "model-unsupported" | "transient" | "runtime-crashed">;
|
|
34
36
|
/** The one thing the person can do about it. The desktop maps each to a button. */
|
|
35
|
-
export type RuntimeRepairAction = "signIn" | "update" | "switchModel" | "tryAgain";
|
|
37
|
+
export type RuntimeRepairAction = "signIn" | "update" | "switchModel" | "tryAgain" | "restart";
|
|
36
38
|
export declare const RUNTIME_REPAIR_ACTIONS: Record<RuntimeRepairClass, RuntimeRepairAction>;
|
|
37
39
|
export declare function isRuntimeRepairClass(cls: RuntimeFailureClass): cls is RuntimeRepairClass;
|
|
38
40
|
/** Sort a runtime's failure text into one class. Order matters: most specific first. */
|
|
39
41
|
export declare function classifyRuntimeFailure(text: string | undefined | null): RuntimeFailureClass;
|
|
42
|
+
export declare function isBunProcessError(text: string | undefined | null): boolean;
|
|
43
|
+
/** A process that exits non-zero this soon, with no stream event, never started its turn. */
|
|
44
|
+
export declare const RUNTIME_CRASH_MAX_MS = 5000;
|
|
45
|
+
/**
|
|
46
|
+
* True when the coding tool's process exited before the turn started: a
|
|
47
|
+
* non-zero exit code, not stopped by the owner, no stream event on stdout,
|
|
48
|
+
* and either Bun's process error shape on stderr or a life under 5 s.
|
|
49
|
+
*/
|
|
50
|
+
export declare function isRuntimeCrash(err: unknown): boolean;
|
|
40
51
|
/**
|
|
41
52
|
* Class of a failed turn's error. A RuntimeError's excerpt (the runtime's own
|
|
42
53
|
* reported error: failureReason, turn.failed, stderr) is the better evidence;
|
|
@@ -57,11 +68,11 @@ export type RuntimeFailureContext = "kickoff" | "message";
|
|
|
57
68
|
*/
|
|
58
69
|
export declare function runtimeFailureReason(cls: RuntimeFailureClass, runtime: BotRuntimeId | string): string;
|
|
59
70
|
/** The one next step, as a full sentence. */
|
|
60
|
-
export declare function runtimeFailureNextStep(cls: RuntimeFailureClass, runtime: BotRuntimeId | string, context?: RuntimeFailureContext): string;
|
|
71
|
+
export declare function runtimeFailureNextStep(cls: RuntimeFailureClass, runtime: BotRuntimeId | string, context?: RuntimeFailureContext, botName?: string): string;
|
|
61
72
|
/** "My Codex app is out of date. Update Codex, then send me any message." */
|
|
62
|
-
export declare function runtimeFailureText(cls: RuntimeFailureClass, runtime: BotRuntimeId | string, context?: RuntimeFailureContext): string;
|
|
73
|
+
export declare function runtimeFailureText(cls: RuntimeFailureClass, runtime: BotRuntimeId | string, context?: RuntimeFailureContext, botName?: string): string;
|
|
63
74
|
/** A failure after the model started (and maybe posted part of the answer). */
|
|
64
|
-
export declare function runtimeDidNotFinishText(cls: RuntimeFailureClass, runtime: BotRuntimeId | string, progressPosted: boolean): string;
|
|
75
|
+
export declare function runtimeDidNotFinishText(cls: RuntimeFailureClass, runtime: BotRuntimeId | string, progressPosted: boolean, botName?: string): string;
|
|
65
76
|
/**
|
|
66
77
|
* The machine-readable repair payload a failure DM carries. The DM transport
|
|
67
78
|
* (POST /v1/notify/dm) stores structured data only in `richContent`
|
|
@@ -21,6 +21,7 @@ export const RUNTIME_REPAIR_ACTIONS = {
|
|
|
21
21
|
"cli-outdated": "update",
|
|
22
22
|
"model-unsupported": "switchModel",
|
|
23
23
|
transient: "tryAgain",
|
|
24
|
+
"runtime-crashed": "restart",
|
|
24
25
|
};
|
|
25
26
|
export function isRuntimeRepairClass(cls) {
|
|
26
27
|
return cls in RUNTIME_REPAIR_ACTIONS;
|
|
@@ -61,6 +62,38 @@ export function classifyRuntimeFailure(text) {
|
|
|
61
62
|
return "transient";
|
|
62
63
|
return "unknown";
|
|
63
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Bun's process-level error line (Claude Code is a Bun-compiled binary):
|
|
67
|
+
* "error: An unknown error occurred (Unexpected)". The excerpt joins stderr
|
|
68
|
+
* lines with " | ", so each segment is checked on its own.
|
|
69
|
+
*/
|
|
70
|
+
const BUN_PROCESS_ERROR = /^error: .+ \((?:Unexpected|[A-Z][A-Za-z]+)\)\s*$/m;
|
|
71
|
+
export function isBunProcessError(text) {
|
|
72
|
+
return (text ?? "")
|
|
73
|
+
.split(/\n| \| /)
|
|
74
|
+
.some((segment) => BUN_PROCESS_ERROR.test(segment.trim()));
|
|
75
|
+
}
|
|
76
|
+
/** A process that exits non-zero this soon, with no stream event, never started its turn. */
|
|
77
|
+
export const RUNTIME_CRASH_MAX_MS = 5_000;
|
|
78
|
+
function bunShaped(e) {
|
|
79
|
+
return (isBunProcessError(typeof e.stderrExcerpt === "string" ? e.stderrExcerpt : "") ||
|
|
80
|
+
isBunProcessError(typeof e.stderrFull === "string" ? e.stderrFull : ""));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* True when the coding tool's process exited before the turn started: a
|
|
84
|
+
* non-zero exit code, not stopped by the owner, no stream event on stdout,
|
|
85
|
+
* and either Bun's process error shape on stderr or a life under 5 s.
|
|
86
|
+
*/
|
|
87
|
+
export function isRuntimeCrash(err) {
|
|
88
|
+
if (!err || typeof err !== "object" || !("stderrExcerpt" in err))
|
|
89
|
+
return false;
|
|
90
|
+
const e = err;
|
|
91
|
+
if (typeof e.exitCode !== "number" || e.exitCode === 0)
|
|
92
|
+
return false;
|
|
93
|
+
if (e.aborted === true || e.sawStreamEvent === true)
|
|
94
|
+
return false;
|
|
95
|
+
return bunShaped(e) || (typeof e.durationMs === "number" && e.durationMs < RUNTIME_CRASH_MAX_MS);
|
|
96
|
+
}
|
|
64
97
|
/**
|
|
65
98
|
* Class of a failed turn's error. A RuntimeError's excerpt (the runtime's own
|
|
66
99
|
* reported error: failureReason, turn.failed, stderr) is the better evidence;
|
|
@@ -73,12 +106,20 @@ export function classifyRuntimeError(err) {
|
|
|
73
106
|
if (err && typeof err === "object" && "stderrExcerpt" in err) {
|
|
74
107
|
const e = err;
|
|
75
108
|
const message = typeof e.message === "string" ? e.message : "";
|
|
76
|
-
|
|
77
|
-
|
|
109
|
+
const crashed = isRuntimeCrash(err);
|
|
110
|
+
// Bun's own process error is the most specific evidence there is.
|
|
111
|
+
if (crashed && bunShaped(err))
|
|
112
|
+
return "runtime-crashed";
|
|
113
|
+
if (e.excerptIsOutputTail === true) {
|
|
114
|
+
const fromTailMessage = classifyRuntimeFailure(message);
|
|
115
|
+
return fromTailMessage === "unknown" && crashed ? "runtime-crashed" : fromTailMessage;
|
|
116
|
+
}
|
|
78
117
|
const fromExcerpt = classifyRuntimeFailure(typeof e.stderrExcerpt === "string" ? e.stderrExcerpt : "");
|
|
79
118
|
if (fromExcerpt !== "unknown")
|
|
80
119
|
return fromExcerpt;
|
|
81
|
-
|
|
120
|
+
const fromMessage = classifyRuntimeFailure(message);
|
|
121
|
+
// A quick exit with no known cause: the process died before the turn.
|
|
122
|
+
return fromMessage === "unknown" && crashed ? "runtime-crashed" : fromMessage;
|
|
82
123
|
}
|
|
83
124
|
return classifyRuntimeFailure(err instanceof Error ? err.message : String(err ?? ""));
|
|
84
125
|
}
|
|
@@ -106,14 +147,18 @@ export function runtimeFailureReason(cls, runtime) {
|
|
|
106
147
|
return `${tool} is busy or out of reach right now`;
|
|
107
148
|
case "not-installed":
|
|
108
149
|
return `${tool} isn't installed on this computer`;
|
|
150
|
+
case "runtime-crashed":
|
|
151
|
+
return `my ${tool} process could not start`;
|
|
109
152
|
default:
|
|
110
153
|
return `${tool} stopped with an error`;
|
|
111
154
|
}
|
|
112
155
|
}
|
|
113
156
|
/** The one next step, as a full sentence. */
|
|
114
|
-
export function runtimeFailureNextStep(cls, runtime, context = "message") {
|
|
157
|
+
export function runtimeFailureNextStep(cls, runtime, context = "message", botName) {
|
|
115
158
|
const tool = runtimeDisplayName(runtime);
|
|
116
159
|
switch (cls) {
|
|
160
|
+
case "runtime-crashed":
|
|
161
|
+
return `Press "Heal bot" in HQ, or run: hq bot restart ${botName ?? "<bot>"}`;
|
|
117
162
|
case "signed-out":
|
|
118
163
|
return `Use "Sign in to ${tool}" in HQ, then send me any message.`;
|
|
119
164
|
case "cli-outdated":
|
|
@@ -136,12 +181,12 @@ function capitalize(s) {
|
|
|
136
181
|
return s ? s[0].toUpperCase() + s.slice(1) : s;
|
|
137
182
|
}
|
|
138
183
|
/** "My Codex app is out of date. Update Codex, then send me any message." */
|
|
139
|
-
export function runtimeFailureText(cls, runtime, context = "message") {
|
|
140
|
-
return `${capitalize(runtimeFailureReason(cls, runtime))}. ${runtimeFailureNextStep(cls, runtime, context)}`;
|
|
184
|
+
export function runtimeFailureText(cls, runtime, context = "message", botName) {
|
|
185
|
+
return `${capitalize(runtimeFailureReason(cls, runtime))}. ${runtimeFailureNextStep(cls, runtime, context, botName)}`;
|
|
141
186
|
}
|
|
142
187
|
/** A failure after the model started (and maybe posted part of the answer). */
|
|
143
|
-
export function runtimeDidNotFinishText(cls, runtime, progressPosted) {
|
|
144
|
-
return `I didn't finish that. ${runtimeFailureText(cls, runtime)}${progressPosted ? " The messages above show how far I got." : ""}`;
|
|
188
|
+
export function runtimeDidNotFinishText(cls, runtime, progressPosted, botName) {
|
|
189
|
+
return `I didn't finish that. ${runtimeFailureText(cls, runtime, "message", botName)}${progressPosted ? " The messages above show how far I got." : ""}`;
|
|
145
190
|
}
|
|
146
191
|
export function runtimeRepairBlock(args) {
|
|
147
192
|
return {
|
|
@@ -177,7 +222,7 @@ export function withRetrySuggestion(text) {
|
|
|
177
222
|
* press.
|
|
178
223
|
*/
|
|
179
224
|
export function runtimeRepairNotice(args) {
|
|
180
|
-
const text = args.text ?? runtimeFailureText(args.cls, args.runtime, args.context);
|
|
225
|
+
const text = args.text ?? runtimeFailureText(args.cls, args.runtime, args.context, args.botName);
|
|
181
226
|
if (!isRuntimeRepairClass(args.cls))
|
|
182
227
|
return { cls: args.cls, text };
|
|
183
228
|
return {
|
package/dist/lib/bot/status.d.ts
CHANGED
|
@@ -55,6 +55,16 @@ export interface BotStatusFile {
|
|
|
55
55
|
to: string;
|
|
56
56
|
at: string;
|
|
57
57
|
} | null;
|
|
58
|
+
/**
|
|
59
|
+
* The last time the coding tool's process exited before its turn started
|
|
60
|
+
* (runtime-crashed): when, exit code, how long it lived, and its stderr.
|
|
61
|
+
*/
|
|
62
|
+
lastCrash?: {
|
|
63
|
+
at: string;
|
|
64
|
+
code: number | null;
|
|
65
|
+
durationMs?: number;
|
|
66
|
+
stderr: string;
|
|
67
|
+
};
|
|
58
68
|
/**
|
|
59
69
|
* Set while the bot holds its model turns after FAILURE_LIMIT failures in a
|
|
60
70
|
* window (it used to exit instead, and a bot that exited could neither load
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indigoai-us/hq-cli",
|
|
3
|
-
"version": "5.345.
|
|
3
|
+
"version": "5.345.175",
|
|
4
4
|
"description": "HQ by Indigo management CLI — modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -114,11 +114,11 @@
|
|
|
114
114
|
"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}": "eslint --cache --no-error-on-unmatched-pattern"
|
|
115
115
|
},
|
|
116
116
|
"optionalDependencies": {
|
|
117
|
-
"@indigoai-us/hq-hook-win32-x64": "5.345.
|
|
118
|
-
"@indigoai-us/hq-hook-win32-arm64": "5.345.
|
|
119
|
-
"@indigoai-us/hq-hook-darwin-x64": "5.345.
|
|
120
|
-
"@indigoai-us/hq-hook-darwin-arm64": "5.345.
|
|
121
|
-
"@indigoai-us/hq-hook-linux-x64": "5.345.
|
|
122
|
-
"@indigoai-us/hq-hook-linux-arm64": "5.345.
|
|
117
|
+
"@indigoai-us/hq-hook-win32-x64": "5.345.175",
|
|
118
|
+
"@indigoai-us/hq-hook-win32-arm64": "5.345.175",
|
|
119
|
+
"@indigoai-us/hq-hook-darwin-x64": "5.345.175",
|
|
120
|
+
"@indigoai-us/hq-hook-darwin-arm64": "5.345.175",
|
|
121
|
+
"@indigoai-us/hq-hook-linux-x64": "5.345.175",
|
|
122
|
+
"@indigoai-us/hq-hook-linux-arm64": "5.345.175"
|
|
123
123
|
}
|
|
124
124
|
}
|