@h-rig/cli 0.0.6-alpha.90 → 0.0.6-alpha.91
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/README.md +18 -19
- package/dist/bin/build-rig-binaries.js +22 -10
- package/dist/bin/rig.d.ts +71 -1
- package/dist/bin/rig.js +15078 -11169
- package/dist/config/rig-default-config.yml +5 -0
- package/dist/src/app/drone-ui.d.ts +11 -14
- package/dist/src/app/drone-ui.js +70 -86
- package/dist/src/commands/_async-ui.d.ts +1 -4
- package/dist/src/commands/_async-ui.js +9 -111
- package/dist/src/commands/_cli-format.d.ts +16 -9
- package/dist/src/commands/_cli-format.js +167 -295
- package/dist/src/commands/_connection-state.d.ts +11 -1
- package/dist/src/commands/_connection-state.js +50 -5
- package/dist/src/commands/_doctor-checks.d.ts +0 -6
- package/dist/src/commands/_doctor-checks.js +79 -382
- package/dist/src/commands/_help-catalog.d.ts +1 -1
- package/dist/src/commands/_help-catalog.js +217 -157
- package/dist/src/commands/_inprocess-services.d.ts +33 -0
- package/dist/src/commands/_inprocess-services.js +102 -0
- package/dist/src/commands/_json-output.js +4 -0
- package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
- package/dist/src/commands/_lazy-reconcile.js +102 -0
- package/dist/src/commands/_paths.js +1 -1
- package/dist/src/commands/_pi-frontend.d.ts +18 -10
- package/dist/src/commands/_pi-frontend.js +37 -715
- package/dist/src/commands/_pi-install.js +18 -36
- package/dist/src/commands/_policy.d.ts +1 -1
- package/dist/src/commands/_policy.js +56 -15
- package/dist/src/commands/_run-bridge.d.ts +114 -0
- package/dist/src/commands/_run-bridge.js +387 -0
- package/dist/src/commands/_run-diagnostics.d.ts +9 -0
- package/dist/src/commands/_run-diagnostics.js +51 -0
- package/dist/src/commands/_run-driver-helpers.d.ts +8 -81
- package/dist/src/commands/_run-driver-helpers.js +79 -283
- package/dist/src/commands/_run-projection.d.ts +50 -0
- package/dist/src/commands/_run-projection.js +349 -0
- package/dist/src/commands/_run-subcommands.d.ts +3 -0
- package/dist/src/commands/_run-subcommands.js +31 -0
- package/dist/src/commands/_spinner.js +1 -1
- package/dist/src/commands/agent.d.ts +1 -1
- package/dist/src/commands/agent.js +8559 -239
- package/dist/src/commands/dist.d.ts +1 -1
- package/dist/src/commands/dist.js +27 -19
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +93 -475
- package/dist/src/commands/github.d.ts +1 -1
- package/dist/src/commands/github.js +113 -387
- package/dist/src/commands/inbox.d.ts +22 -24
- package/dist/src/commands/inbox.js +420 -691
- package/dist/src/commands/init.d.ts +6 -16
- package/dist/src/commands/init.js +334 -971
- package/dist/src/commands/inspect.d.ts +19 -2
- package/dist/src/commands/inspect.js +644 -610
- package/dist/src/commands/pi.d.ts +1 -1
- package/dist/src/commands/plugin.d.ts +1 -1
- package/dist/src/commands/plugin.js +486 -7
- package/dist/src/commands/profile-and-review.d.ts +1 -1
- package/dist/src/commands/profile-and-review.js +94 -56
- package/dist/src/commands/queue.js +1 -21
- package/dist/src/commands/remote.d.ts +1 -1
- package/dist/src/commands/remote.js +837 -14
- package/dist/src/commands/repo-git-harness.d.ts +1 -1
- package/dist/src/commands/repo-git-harness.js +57 -14
- package/dist/src/commands/run.d.ts +20 -2
- package/dist/src/commands/run.js +17579 -1759
- package/dist/src/commands/server.d.ts +2 -6
- package/dist/src/commands/server.js +141 -723
- package/dist/src/commands/setup.d.ts +1 -1
- package/dist/src/commands/setup.js +102 -484
- package/dist/src/commands/stats.d.ts +13 -10
- package/dist/src/commands/stats.js +689 -761
- package/dist/src/commands/task-run-driver.d.ts +50 -88
- package/dist/src/commands/task-run-driver.js +116 -2717
- package/dist/src/commands/task.d.ts +34 -13
- package/dist/src/commands/task.js +668 -2523
- package/dist/src/commands/test.d.ts +1 -1
- package/dist/src/commands/triage.d.ts +11 -0
- package/dist/src/commands/triage.js +227 -0
- package/dist/src/commands/workspace.d.ts +1 -1
- package/dist/src/commands.d.ts +0 -16
- package/dist/src/commands.js +16657 -12250
- package/dist/src/index.js +16528 -12497
- package/dist/src/launcher.js +4 -0
- package/dist/src/operator-cli.d.ts +2 -0
- package/dist/src/operator-cli.js +17837 -0
- package/dist/src/operator-entry.d.ts +1 -0
- package/dist/src/operator-entry.js +3 -0
- package/package.json +18 -12
- package/dist/src/app/board.d.ts +0 -23
- package/dist/src/app/board.js +0 -1786
- package/dist/src/app/theme.d.ts +0 -47
- package/dist/src/app/theme.js +0 -150
- package/dist/src/commands/_authority-runs.d.ts +0 -22
- package/dist/src/commands/_authority-runs.js +0 -110
- package/dist/src/commands/_operator-surface.d.ts +0 -34
- package/dist/src/commands/_operator-surface.js +0 -220
- package/dist/src/commands/_operator-view.d.ts +0 -30
- package/dist/src/commands/_operator-view.js +0 -1070
- package/dist/src/commands/_preflight.d.ts +0 -22
- package/dist/src/commands/_preflight.js +0 -540
- package/dist/src/commands/_run-replay.d.ts +0 -24
- package/dist/src/commands/_run-replay.js +0 -142
- package/dist/src/commands/_server-client.d.ts +0 -186
- package/dist/src/commands/_server-client.js +0 -681
- package/dist/src/commands/_snapshot-upload.d.ts +0 -39
- package/dist/src/commands/_snapshot-upload.js +0 -455
- package/dist/src/commands/_task-picker.d.ts +0 -9
- package/dist/src/commands/_task-picker.js +0 -201
- package/dist/src/commands/browser.d.ts +0 -65
- package/dist/src/commands/browser.js +0 -1173
- package/dist/src/commands/connect.d.ts +0 -7
- package/dist/src/commands/connect.js +0 -419
- package/dist/src/commands/inspector.d.ts +0 -3
- package/dist/src/commands/inspector.js +0 -263
- package/dist/src/commands/task-report-bug.d.ts +0 -19
- package/dist/src/commands/task-report-bug.js +0 -1281
- package/dist/src/report-bug.d.ts +0 -44
- package/dist/src/report-bug.js +0 -260
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type RunnerContext } from "../runner";
|
|
2
|
-
import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
|
|
3
|
-
export type ConnectionCommandOptions = {
|
|
4
|
-
group: "server";
|
|
5
|
-
interactiveUse?: boolean;
|
|
6
|
-
};
|
|
7
|
-
export declare function executeConnectionCommand(context: RunnerContext, args: string[], options: ConnectionCommandOptions): Promise<CommandOutcome>;
|
|
@@ -1,419 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/app/drone-ui.ts
|
|
3
|
-
import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
|
|
4
|
-
|
|
5
|
-
// packages/cli/src/app/theme.ts
|
|
6
|
-
var RIG_PALETTE = {
|
|
7
|
-
ink: "#f2f3f6",
|
|
8
|
-
ink2: "#aeb0ba",
|
|
9
|
-
ink3: "#6c6e79",
|
|
10
|
-
ink4: "#44464f",
|
|
11
|
-
accent: "#ccff4d",
|
|
12
|
-
accentDim: "#a9d63f",
|
|
13
|
-
cyan: "#56d8ff",
|
|
14
|
-
red: "#ff5d5d",
|
|
15
|
-
yellow: "#ffd24d"
|
|
16
|
-
};
|
|
17
|
-
function hexToRgb(hex) {
|
|
18
|
-
const value = hex.replace("#", "");
|
|
19
|
-
return [
|
|
20
|
-
Number.parseInt(value.slice(0, 2), 16),
|
|
21
|
-
Number.parseInt(value.slice(2, 4), 16),
|
|
22
|
-
Number.parseInt(value.slice(4, 6), 16)
|
|
23
|
-
];
|
|
24
|
-
}
|
|
25
|
-
function fg(hex) {
|
|
26
|
-
const [r, g, b] = hexToRgb(hex);
|
|
27
|
-
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
28
|
-
}
|
|
29
|
-
var ink = fg(RIG_PALETTE.ink);
|
|
30
|
-
var ink2 = fg(RIG_PALETTE.ink2);
|
|
31
|
-
var ink3 = fg(RIG_PALETTE.ink3);
|
|
32
|
-
var ink4 = fg(RIG_PALETTE.ink4);
|
|
33
|
-
var accent = fg(RIG_PALETTE.accent);
|
|
34
|
-
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
35
|
-
var cyan = fg(RIG_PALETTE.cyan);
|
|
36
|
-
var red = fg(RIG_PALETTE.red);
|
|
37
|
-
var yellow = fg(RIG_PALETTE.yellow);
|
|
38
|
-
function bold(text) {
|
|
39
|
-
return `\x1B[1m${text}\x1B[22m`;
|
|
40
|
-
}
|
|
41
|
-
var DRONE_ART = [
|
|
42
|
-
" .-=-. .-=-. ",
|
|
43
|
-
" ( !!! ) ( !!! ) ",
|
|
44
|
-
" '-=-'._ _.'-=-' ",
|
|
45
|
-
" '._ _.' ",
|
|
46
|
-
" '=$$$$$$$=.' ",
|
|
47
|
-
" =$$$$$$$$$$$= ",
|
|
48
|
-
" $$$@@@@@@@@@@$$$ ",
|
|
49
|
-
" $$$@@ @@$$$ ",
|
|
50
|
-
" $$@ ? @$$$ ",
|
|
51
|
-
" $$$@ '-' @$$$ ",
|
|
52
|
-
" $$$@@ @@$$$ ",
|
|
53
|
-
" $$$@@@@@@@@@@$$$ ",
|
|
54
|
-
" =$$$$$$$$$$$= ",
|
|
55
|
-
" '=$$$$$$$=.' ",
|
|
56
|
-
" _.' '._ ",
|
|
57
|
-
" .-=-.' '.-=-. ",
|
|
58
|
-
" ( !!! ) ( !!! ) ",
|
|
59
|
-
" '-=-' '-=-' "
|
|
60
|
-
];
|
|
61
|
-
var EYE_FRAMES = ["@", "o", "."];
|
|
62
|
-
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
63
|
-
var DRONE_HEIGHT = DRONE_ART.length;
|
|
64
|
-
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
65
|
-
function microDroneFrame(tick) {
|
|
66
|
-
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
67
|
-
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
68
|
-
return `(${blade})${eye}(${blade})`;
|
|
69
|
-
}
|
|
70
|
-
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
71
|
-
|
|
72
|
-
// packages/cli/src/app/drone-ui.ts
|
|
73
|
-
var isTty = () => Boolean(process.stdout.isTTY);
|
|
74
|
-
function droneCancel(text) {
|
|
75
|
-
console.log(` ${red("\u2716")} ${ink3(text)}`);
|
|
76
|
-
}
|
|
77
|
-
var SELECT_THEME = {
|
|
78
|
-
selectedPrefix: (text) => accent(text),
|
|
79
|
-
selectedText: (text) => bold(ink(text)),
|
|
80
|
-
description: (text) => ink3(text),
|
|
81
|
-
scrollInfo: (text) => ink4(text),
|
|
82
|
-
noMatch: (text) => ink3(text)
|
|
83
|
-
};
|
|
84
|
-
async function runMiniTui(build) {
|
|
85
|
-
const terminal = new ProcessTerminal;
|
|
86
|
-
const tui = new TUI(terminal);
|
|
87
|
-
let settled = false;
|
|
88
|
-
return await new Promise((resolve) => {
|
|
89
|
-
const finish = (result) => {
|
|
90
|
-
if (settled)
|
|
91
|
-
return;
|
|
92
|
-
settled = true;
|
|
93
|
-
tui.stop();
|
|
94
|
-
resolve(result);
|
|
95
|
-
};
|
|
96
|
-
build(tui, finish);
|
|
97
|
-
tui.start();
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
async function droneSelect(input) {
|
|
101
|
-
if (!isTty() || input.options.length === 0) {
|
|
102
|
-
return input.initialValue ?? input.options[0]?.value ?? null;
|
|
103
|
-
}
|
|
104
|
-
return runMiniTui((tui, finish) => {
|
|
105
|
-
tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}`));
|
|
106
|
-
const items = input.options.map((option) => ({
|
|
107
|
-
value: option.value,
|
|
108
|
-
label: option.label,
|
|
109
|
-
...option.hint ? { description: option.hint } : {}
|
|
110
|
-
}));
|
|
111
|
-
const list = new SelectList(items, Math.min(items.length, 12), SELECT_THEME);
|
|
112
|
-
const initialIndex = input.initialValue ? items.findIndex((item) => item.value === input.initialValue) : -1;
|
|
113
|
-
if (initialIndex > 0)
|
|
114
|
-
list.setSelectedIndex(initialIndex);
|
|
115
|
-
list.onSelect = (item) => finish(item.value);
|
|
116
|
-
list.onCancel = () => finish(null);
|
|
117
|
-
tui.addChild(list);
|
|
118
|
-
tui.addChild(new Text(ink4(" \u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")));
|
|
119
|
-
tui.setFocus(list);
|
|
120
|
-
tui.addInputListener((data) => {
|
|
121
|
-
if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
|
|
122
|
-
finish(null);
|
|
123
|
-
return { consume: true };
|
|
124
|
-
}
|
|
125
|
-
return;
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// packages/cli/src/runner.ts
|
|
131
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
132
|
-
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
133
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
134
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
135
|
-
|
|
136
|
-
class CliError extends RuntimeCliError {
|
|
137
|
-
hint;
|
|
138
|
-
constructor(message, exitCode = 1, options = {}) {
|
|
139
|
-
super(message, exitCode);
|
|
140
|
-
if (options.hint?.trim()) {
|
|
141
|
-
this.hint = options.hint.trim();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
function requireNoExtraArgs(args, usage) {
|
|
146
|
-
if (args.length > 0) {
|
|
147
|
-
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
148
|
-
Usage: ${usage}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// packages/cli/src/commands/_connection-state.ts
|
|
153
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
154
|
-
import { homedir } from "os";
|
|
155
|
-
import { dirname, resolve } from "path";
|
|
156
|
-
function resolveGlobalConnectionsPath(env = process.env) {
|
|
157
|
-
const explicit = env.RIG_CONNECTIONS_FILE?.trim();
|
|
158
|
-
if (explicit)
|
|
159
|
-
return resolve(explicit);
|
|
160
|
-
const stateDir = env.RIG_GLOBAL_STATE_DIR?.trim();
|
|
161
|
-
if (stateDir)
|
|
162
|
-
return resolve(stateDir, "connections.json");
|
|
163
|
-
return resolve(homedir(), ".rig", "connections.json");
|
|
164
|
-
}
|
|
165
|
-
function resolveRepoConnectionPath(projectRoot) {
|
|
166
|
-
return resolve(projectRoot, ".rig", "state", "connection.json");
|
|
167
|
-
}
|
|
168
|
-
function readJsonFile(path) {
|
|
169
|
-
if (!existsSync(path))
|
|
170
|
-
return null;
|
|
171
|
-
try {
|
|
172
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
173
|
-
} catch (error) {
|
|
174
|
-
throw new CliError(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1, { hint: "Fix or delete that file, then re-select a server with `rig server use <alias|local>`." });
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function writeJsonFile(path, value) {
|
|
178
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
179
|
-
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
180
|
-
`, "utf8");
|
|
181
|
-
}
|
|
182
|
-
function normalizeConnection(value) {
|
|
183
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
184
|
-
return null;
|
|
185
|
-
const record = value;
|
|
186
|
-
if (record.kind === "local")
|
|
187
|
-
return { kind: "local", mode: "auto" };
|
|
188
|
-
if (record.kind === "remote" && typeof record.baseUrl === "string" && record.baseUrl.trim()) {
|
|
189
|
-
const baseUrl = record.baseUrl.trim().replace(/\/+$/, "");
|
|
190
|
-
return { kind: "remote", baseUrl };
|
|
191
|
-
}
|
|
192
|
-
return null;
|
|
193
|
-
}
|
|
194
|
-
function readGlobalConnections(options = {}) {
|
|
195
|
-
const path = resolveGlobalConnectionsPath(options.env ?? process.env);
|
|
196
|
-
const payload = readJsonFile(path);
|
|
197
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
198
|
-
return { connections: {} };
|
|
199
|
-
}
|
|
200
|
-
const rawConnections = payload.connections;
|
|
201
|
-
const connections = {};
|
|
202
|
-
if (rawConnections && typeof rawConnections === "object" && !Array.isArray(rawConnections)) {
|
|
203
|
-
for (const [alias, raw] of Object.entries(rawConnections)) {
|
|
204
|
-
const connection = normalizeConnection(raw);
|
|
205
|
-
if (connection)
|
|
206
|
-
connections[alias] = connection;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return { connections };
|
|
210
|
-
}
|
|
211
|
-
function writeGlobalConnections(state, options = {}) {
|
|
212
|
-
writeJsonFile(resolveGlobalConnectionsPath(options.env ?? process.env), state);
|
|
213
|
-
}
|
|
214
|
-
function upsertGlobalConnection(alias, connection, options = {}) {
|
|
215
|
-
const cleanAlias = alias.trim();
|
|
216
|
-
if (!cleanAlias)
|
|
217
|
-
throw new CliError("Connection alias is required.", 1, { hint: "Save a server with `rig server add <alias> <url>`." });
|
|
218
|
-
const state = readGlobalConnections(options);
|
|
219
|
-
state.connections[cleanAlias] = connection;
|
|
220
|
-
writeGlobalConnections(state, options);
|
|
221
|
-
return state;
|
|
222
|
-
}
|
|
223
|
-
function readRepoConnection(projectRoot) {
|
|
224
|
-
const payload = readJsonFile(resolveRepoConnectionPath(projectRoot));
|
|
225
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
226
|
-
return null;
|
|
227
|
-
const record = payload;
|
|
228
|
-
const selected = typeof record.selected === "string" ? record.selected.trim() : "";
|
|
229
|
-
if (!selected)
|
|
230
|
-
return null;
|
|
231
|
-
return {
|
|
232
|
-
selected,
|
|
233
|
-
project: typeof record.project === "string" ? record.project : undefined,
|
|
234
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
235
|
-
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
function writeRepoConnection(projectRoot, state) {
|
|
239
|
-
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// packages/cli/src/commands/_cli-format.ts
|
|
243
|
-
import pc from "picocolors";
|
|
244
|
-
var themeDim = (value) => ink3(value);
|
|
245
|
-
var themeFaint = (value) => ink4(value);
|
|
246
|
-
function truncate(value, width) {
|
|
247
|
-
if (value.length <= width)
|
|
248
|
-
return value;
|
|
249
|
-
if (width <= 1)
|
|
250
|
-
return "\u2026";
|
|
251
|
-
return `${value.slice(0, width - 1)}\u2026`;
|
|
252
|
-
}
|
|
253
|
-
function pad(value, width) {
|
|
254
|
-
return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
|
|
255
|
-
}
|
|
256
|
-
function statusColor(status) {
|
|
257
|
-
const normalized = status.toLowerCase();
|
|
258
|
-
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved", "running"].includes(normalized))
|
|
259
|
-
return accent;
|
|
260
|
-
if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
|
|
261
|
-
return red;
|
|
262
|
-
if (["reviewing", "validating", "in_progress", "in-progress", "remote", "preparing", "closing-out"].includes(normalized))
|
|
263
|
-
return cyan;
|
|
264
|
-
if (["ready", "open", "queued", "created", "local", "pending"].includes(normalized))
|
|
265
|
-
return yellow;
|
|
266
|
-
return themeDim;
|
|
267
|
-
}
|
|
268
|
-
function formatStatusPill(status) {
|
|
269
|
-
const label = status || "unknown";
|
|
270
|
-
return statusColor(label)(`\u25CF ${label}`);
|
|
271
|
-
}
|
|
272
|
-
function formatSection(title, subtitle) {
|
|
273
|
-
return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
|
|
274
|
-
}
|
|
275
|
-
function formatSuccessCard(title, rows = []) {
|
|
276
|
-
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${themeFaint("\u2502")} ${themeDim(key.padEnd(12))} ${value}`);
|
|
277
|
-
return [formatSection(title), ...body].join(`
|
|
278
|
-
`);
|
|
279
|
-
}
|
|
280
|
-
function formatNextSteps(steps) {
|
|
281
|
-
if (steps.length === 0)
|
|
282
|
-
return [];
|
|
283
|
-
return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
|
|
284
|
-
}
|
|
285
|
-
function formatConnectionList(connections) {
|
|
286
|
-
const rows = [["local", { kind: "local", mode: "auto" }], ...Object.entries(connections)];
|
|
287
|
-
const aliasWidth = Math.min(24, Math.max(5, ...rows.map(([alias]) => alias.length)));
|
|
288
|
-
const lines = rows.map(([alias, connection]) => [
|
|
289
|
-
pc.bold(pad(truncate(alias, aliasWidth), aliasWidth)),
|
|
290
|
-
formatStatusPill(connection.kind),
|
|
291
|
-
connection.kind === "remote" ? connection.baseUrl ?? "" : connection.mode ?? "local"
|
|
292
|
-
].join(" "));
|
|
293
|
-
return [formatSection("Rig servers", `${rows.length} available`), `${pc.bold(pad("ALIAS", aliasWidth))} ${pc.bold("KIND")} ${pc.bold("TARGET")}`, ...lines, "", ...formatNextSteps(["Select one: `rig server use <alias|local>`"])].join(`
|
|
294
|
-
`);
|
|
295
|
-
}
|
|
296
|
-
function formatConnectionStatus(selected, connections) {
|
|
297
|
-
const connection = selected === "local" ? { kind: "local", mode: "auto" } : connections[selected];
|
|
298
|
-
const target = !connection ? "not configured" : connection.kind === "remote" ? connection.baseUrl : "local";
|
|
299
|
-
return [
|
|
300
|
-
formatSection("Rig server", "selected for this repo"),
|
|
301
|
-
`${themeFaint("\u2502")} ${themeDim("selected ")} ${pc.bold(selected)}`,
|
|
302
|
-
`${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
|
|
303
|
-
`${themeFaint("\u2502")} ${themeDim("target ")} ${target ?? "not configured"}`,
|
|
304
|
-
"",
|
|
305
|
-
...formatNextSteps(["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
|
|
306
|
-
].join(`
|
|
307
|
-
`);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// packages/cli/src/commands/connect.ts
|
|
311
|
-
function usageName(options) {
|
|
312
|
-
return `rig ${options.group}`;
|
|
313
|
-
}
|
|
314
|
-
function parseConnection(alias, value, options) {
|
|
315
|
-
if (alias === "local" && !value)
|
|
316
|
-
return { kind: "local", mode: "auto" };
|
|
317
|
-
if (!value)
|
|
318
|
-
throw new CliError(`Missing remote server URL. Usage: ${usageName(options)} add <alias> <url>`, 1);
|
|
319
|
-
let parsed;
|
|
320
|
-
try {
|
|
321
|
-
parsed = new URL(value);
|
|
322
|
-
} catch {
|
|
323
|
-
throw new CliError(`Invalid Rig server URL: ${value}`, 1, { hint: "Pass a full http(s) URL, e.g. `rig server add prod https://rig.example.com`." });
|
|
324
|
-
}
|
|
325
|
-
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
326
|
-
throw new CliError("Rig remote server URL must be http(s).", 1, { hint: "Use an http:// or https:// URL, e.g. `rig server add prod https://rig.example.com`." });
|
|
327
|
-
}
|
|
328
|
-
return { kind: "remote", baseUrl: parsed.toString().replace(/\/+$/, "") };
|
|
329
|
-
}
|
|
330
|
-
function printJsonOrText(context, payload, text) {
|
|
331
|
-
if (context.outputMode === "json") {
|
|
332
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
333
|
-
} else {
|
|
334
|
-
console.log(text);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
async function promptForConnectionAlias(context) {
|
|
338
|
-
const state = readGlobalConnections();
|
|
339
|
-
const repo = readRepoConnection(context.projectRoot);
|
|
340
|
-
const options = [
|
|
341
|
-
{ value: "local", label: "local", hint: "Use/start a local Rig server" },
|
|
342
|
-
...Object.entries(state.connections).map(([alias, connection]) => ({
|
|
343
|
-
value: alias,
|
|
344
|
-
label: alias,
|
|
345
|
-
hint: connection.kind === "remote" ? connection.baseUrl : "local"
|
|
346
|
-
}))
|
|
347
|
-
].filter((option, index, all) => all.findIndex((candidate) => candidate.value === option.value) === index);
|
|
348
|
-
const answer = await droneSelect({
|
|
349
|
-
message: "Select Rig server for this repo",
|
|
350
|
-
initialValue: repo?.selected ?? "local",
|
|
351
|
-
options
|
|
352
|
-
});
|
|
353
|
-
if (answer === null) {
|
|
354
|
-
droneCancel("No server selected.");
|
|
355
|
-
throw new CliError("No server selected.", 3);
|
|
356
|
-
}
|
|
357
|
-
return String(answer);
|
|
358
|
-
}
|
|
359
|
-
async function executeConnectionCommand(context, args, options) {
|
|
360
|
-
const [command, ...rest] = args;
|
|
361
|
-
switch (command ?? "status") {
|
|
362
|
-
case "list": {
|
|
363
|
-
requireNoExtraArgs(rest, `${usageName(options)} list`);
|
|
364
|
-
const state = readGlobalConnections();
|
|
365
|
-
printJsonOrText(context, state, formatConnectionList(state.connections));
|
|
366
|
-
return { ok: true, group: options.group, command: "list", details: state };
|
|
367
|
-
}
|
|
368
|
-
case "add": {
|
|
369
|
-
const [alias, url, ...extra] = rest;
|
|
370
|
-
if (!alias)
|
|
371
|
-
throw new CliError(`Missing alias. Usage: ${usageName(options)} add <alias> <url>`, 1);
|
|
372
|
-
requireNoExtraArgs(extra, `${usageName(options)} add <alias> <url>`);
|
|
373
|
-
const connection = parseConnection(alias, url, options);
|
|
374
|
-
const state = upsertGlobalConnection(alias, connection);
|
|
375
|
-
printJsonOrText(context, { alias, connection }, formatSuccessCard("Rig server saved", [
|
|
376
|
-
["alias", alias],
|
|
377
|
-
["target", connection.kind === "remote" ? connection.baseUrl : "local"],
|
|
378
|
-
["next", `${usageName(options)} use ${alias}`]
|
|
379
|
-
]));
|
|
380
|
-
return { ok: true, group: options.group, command: "add", details: { alias, connection, count: Object.keys(state.connections).length } };
|
|
381
|
-
}
|
|
382
|
-
case "use": {
|
|
383
|
-
let [alias, ...extra] = rest;
|
|
384
|
-
requireNoExtraArgs(extra, `${usageName(options)} use <alias|local>`);
|
|
385
|
-
if (!alias && options.interactiveUse && context.outputMode === "text" && process.stdin.isTTY) {
|
|
386
|
-
alias = await promptForConnectionAlias(context);
|
|
387
|
-
}
|
|
388
|
-
if (!alias)
|
|
389
|
-
throw new CliError(`Missing alias. Usage: ${usageName(options)} use <alias|local>`, 1);
|
|
390
|
-
if (alias !== "local") {
|
|
391
|
-
const state = readGlobalConnections();
|
|
392
|
-
if (!state.connections[alias])
|
|
393
|
-
throw new CliError(`Unknown Rig server: ${alias}`, 1, { hint: "Run `rig server list` to see saved aliases, or save one with `rig server add <alias> <url>`." });
|
|
394
|
-
}
|
|
395
|
-
const repoState = { selected: alias, linkedAt: new Date().toISOString() };
|
|
396
|
-
writeRepoConnection(context.projectRoot, repoState);
|
|
397
|
-
printJsonOrText(context, repoState, formatSuccessCard("Rig server selected", [
|
|
398
|
-
["selected", alias],
|
|
399
|
-
["scope", "this repo"],
|
|
400
|
-
["next", "rig task list"]
|
|
401
|
-
]));
|
|
402
|
-
return { ok: true, group: options.group, command: "use", details: repoState };
|
|
403
|
-
}
|
|
404
|
-
case "status": {
|
|
405
|
-
requireNoExtraArgs(rest, `${usageName(options)} status`);
|
|
406
|
-
const repo = readRepoConnection(context.projectRoot);
|
|
407
|
-
const global = readGlobalConnections();
|
|
408
|
-
const details = { selected: repo?.selected ?? "local", repo, connections: global.connections };
|
|
409
|
-
printJsonOrText(context, details, formatConnectionStatus(details.selected, global.connections));
|
|
410
|
-
return { ok: true, group: options.group, command: "status", details };
|
|
411
|
-
}
|
|
412
|
-
default:
|
|
413
|
-
throw new CliError(`Unknown ${options.group} command: ${String(command)}
|
|
414
|
-
Usage: ${usageName(options)} <list|add|use|status>`, 1);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
export {
|
|
418
|
-
executeConnectionCommand
|
|
419
|
-
};
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/inspector.ts
|
|
3
|
-
import { iterateServerSentEvents } from "@rig/client";
|
|
4
|
-
|
|
5
|
-
// packages/cli/src/runner.ts
|
|
6
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
7
|
-
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
8
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
9
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
10
|
-
|
|
11
|
-
class CliError extends RuntimeCliError {
|
|
12
|
-
hint;
|
|
13
|
-
constructor(message, exitCode = 1, options = {}) {
|
|
14
|
-
super(message, exitCode);
|
|
15
|
-
if (options.hint?.trim()) {
|
|
16
|
-
this.hint = options.hint.trim();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function takeFlag(args, flag) {
|
|
21
|
-
const rest = [];
|
|
22
|
-
let value = false;
|
|
23
|
-
for (const arg of args) {
|
|
24
|
-
if (arg === flag) {
|
|
25
|
-
value = true;
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
rest.push(arg);
|
|
29
|
-
}
|
|
30
|
-
return { value, rest };
|
|
31
|
-
}
|
|
32
|
-
function takeOption(args, option) {
|
|
33
|
-
const rest = [];
|
|
34
|
-
let value;
|
|
35
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
36
|
-
const current = args[index];
|
|
37
|
-
if (current === option) {
|
|
38
|
-
const next = args[index + 1];
|
|
39
|
-
if (!next || next.startsWith("-")) {
|
|
40
|
-
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
41
|
-
}
|
|
42
|
-
value = next;
|
|
43
|
-
index += 1;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (current !== undefined) {
|
|
47
|
-
rest.push(current);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return { value, rest };
|
|
51
|
-
}
|
|
52
|
-
function requireNoExtraArgs(args, usage) {
|
|
53
|
-
if (args.length > 0) {
|
|
54
|
-
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
55
|
-
Usage: ${usage}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// packages/cli/src/commands/inspector.ts
|
|
60
|
-
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
61
|
-
|
|
62
|
-
// packages/cli/src/commands/_parsers.ts
|
|
63
|
-
function parseRequiredPositiveInt(value, option) {
|
|
64
|
-
if (!value) {
|
|
65
|
-
throw new CliError(`Missing value for ${option}.`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} 10\`.` });
|
|
66
|
-
}
|
|
67
|
-
const parsed = Number.parseInt(value, 10);
|
|
68
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
69
|
-
throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
|
|
70
|
-
}
|
|
71
|
-
return parsed;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// packages/cli/src/commands/inspector.ts
|
|
75
|
-
function formatInspectorStreamLine(payload) {
|
|
76
|
-
const emittedAt = payload.emittedAt ?? new Date().toISOString();
|
|
77
|
-
const agentStatus = String(payload.agent?.status ?? "unknown");
|
|
78
|
-
const queueDepth = Number(payload.agent?.queueDepth ?? 0);
|
|
79
|
-
const activeRuns = Array.isArray(payload.snapshot?.activeRuns) ? payload.snapshot?.activeRuns.length : 0;
|
|
80
|
-
const lines = [
|
|
81
|
-
`[${emittedAt}] seq=${String(payload.sequence ?? "?")} agent=${agentStatus} queue=${queueDepth} activeRuns=${activeRuns}`
|
|
82
|
-
];
|
|
83
|
-
const lastAssistantMessage = payload.agent?.lastAssistantMessage?.trim();
|
|
84
|
-
if (lastAssistantMessage) {
|
|
85
|
-
lines.push(` assistant: ${lastAssistantMessage.split(`
|
|
86
|
-
`)[0].slice(0, 240)}`);
|
|
87
|
-
}
|
|
88
|
-
const recentProtocol = payload.agent?.recentProtocolEvents;
|
|
89
|
-
const latestProtocol = Array.isArray(recentProtocol) && recentProtocol.length > 0 ? recentProtocol[recentProtocol.length - 1] : null;
|
|
90
|
-
if (latestProtocol?.method) {
|
|
91
|
-
lines.push(` protocol: ${String(latestProtocol.direction ?? "recv")} ${String(latestProtocol.kind ?? "notification")} ${latestProtocol.method}`);
|
|
92
|
-
}
|
|
93
|
-
const finding = Array.isArray(payload.journal?.recentFindings) && payload.journal?.recentFindings.length > 0 ? payload.journal?.recentFindings[0] : null;
|
|
94
|
-
if (finding?.summary) {
|
|
95
|
-
lines.push(` finding: ${String(finding.source ?? "journal")} \xB7 ${finding.summary}`);
|
|
96
|
-
}
|
|
97
|
-
const action = Array.isArray(payload.journal?.recentActions) && payload.journal?.recentActions.length > 0 ? payload.journal?.recentActions[0] : null;
|
|
98
|
-
if (action?.actionType) {
|
|
99
|
-
lines.push(` action: ${action.actionType} (${String(action.status ?? "unknown")})${action.target ? ` -> ${action.target}` : ""}`);
|
|
100
|
-
}
|
|
101
|
-
return lines;
|
|
102
|
-
}
|
|
103
|
-
async function executeInspector(context, args) {
|
|
104
|
-
const [command = "stream", ...rest] = args;
|
|
105
|
-
switch (command) {
|
|
106
|
-
case "stream": {
|
|
107
|
-
let pending = rest;
|
|
108
|
-
const onceResult = takeFlag(pending, "--once");
|
|
109
|
-
pending = onceResult.rest;
|
|
110
|
-
const secondsResult = takeOption(pending, "--seconds");
|
|
111
|
-
pending = secondsResult.rest;
|
|
112
|
-
const pollMsResult = takeOption(pending, "--poll-ms");
|
|
113
|
-
pending = pollMsResult.rest;
|
|
114
|
-
requireNoExtraArgs(pending, "rig inspector stream [--once] [--seconds <n>] [--poll-ms <n>]");
|
|
115
|
-
const seconds = secondsResult.value ? parseRequiredPositiveInt(secondsResult.value, "--seconds") : null;
|
|
116
|
-
const pollMs = pollMsResult.value ? parseRequiredPositiveInt(pollMsResult.value, "--poll-ms") : null;
|
|
117
|
-
if (context.outputMode === "json" && !onceResult.value && !seconds) {
|
|
118
|
-
throw new CliError("--json inspector stream requires --once or --seconds <n>.", 2, { hint: "Re-run as `rig inspector stream --once --json` or `rig inspector stream --seconds 10 --json`." });
|
|
119
|
-
}
|
|
120
|
-
const connection = await ensureLocalRigServerConnection(context.projectRoot);
|
|
121
|
-
const streamUrl = new URL("/api/inspector/stream", connection.baseUrl);
|
|
122
|
-
if (onceResult.value) {
|
|
123
|
-
streamUrl.searchParams.set("once", "1");
|
|
124
|
-
}
|
|
125
|
-
if (pollMs) {
|
|
126
|
-
streamUrl.searchParams.set("pollMs", String(pollMs));
|
|
127
|
-
}
|
|
128
|
-
const controller = new AbortController;
|
|
129
|
-
const deadline = seconds ? setTimeout(() => controller.abort(), seconds * 1000) : null;
|
|
130
|
-
let interrupted = false;
|
|
131
|
-
const onSignal = () => {
|
|
132
|
-
interrupted = true;
|
|
133
|
-
controller.abort();
|
|
134
|
-
};
|
|
135
|
-
if (!onceResult.value) {
|
|
136
|
-
process.once("SIGINT", onSignal);
|
|
137
|
-
process.once("SIGTERM", onSignal);
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
const response = await fetch(streamUrl, {
|
|
141
|
-
headers: connection.authToken ? { authorization: `Bearer ${connection.authToken}` } : undefined,
|
|
142
|
-
signal: controller.signal
|
|
143
|
-
});
|
|
144
|
-
if (!response.ok) {
|
|
145
|
-
throw new CliError(`Inspector stream request failed (${response.status}).`, response.status);
|
|
146
|
-
}
|
|
147
|
-
let received = 0;
|
|
148
|
-
let lastEvent = null;
|
|
149
|
-
for await (const event of iterateServerSentEvents(response)) {
|
|
150
|
-
const payload = JSON.parse(event.data);
|
|
151
|
-
lastEvent = { event: event.event, payload };
|
|
152
|
-
received += 1;
|
|
153
|
-
if (context.outputMode === "text" && event.event === "snapshot") {
|
|
154
|
-
for (const line of formatInspectorStreamLine(payload)) {
|
|
155
|
-
console.log(line);
|
|
156
|
-
}
|
|
157
|
-
} else if (context.outputMode === "text") {
|
|
158
|
-
console.log(`[inspector:${event.event}] ${event.data}`);
|
|
159
|
-
}
|
|
160
|
-
if (onceResult.value) {
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return {
|
|
165
|
-
ok: true,
|
|
166
|
-
group: "inspector",
|
|
167
|
-
command,
|
|
168
|
-
details: {
|
|
169
|
-
streamUrl: streamUrl.toString(),
|
|
170
|
-
received,
|
|
171
|
-
interrupted,
|
|
172
|
-
once: onceResult.value,
|
|
173
|
-
seconds,
|
|
174
|
-
lastEvent
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
} catch (error) {
|
|
178
|
-
if (controller.signal.aborted && !onceResult.value) {
|
|
179
|
-
return {
|
|
180
|
-
ok: true,
|
|
181
|
-
group: "inspector",
|
|
182
|
-
command,
|
|
183
|
-
details: {
|
|
184
|
-
streamUrl: streamUrl.toString(),
|
|
185
|
-
received: 0,
|
|
186
|
-
interrupted: true,
|
|
187
|
-
once: onceResult.value,
|
|
188
|
-
seconds,
|
|
189
|
-
lastEvent: null
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
throw error;
|
|
194
|
-
} finally {
|
|
195
|
-
if (deadline) {
|
|
196
|
-
clearTimeout(deadline);
|
|
197
|
-
}
|
|
198
|
-
if (!onceResult.value) {
|
|
199
|
-
process.off("SIGINT", onSignal);
|
|
200
|
-
process.off("SIGTERM", onSignal);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
case "scan-upstream-drift": {
|
|
205
|
-
let pending = rest;
|
|
206
|
-
const scanIdResult = takeOption(pending, "--scan-id");
|
|
207
|
-
pending = scanIdResult.rest;
|
|
208
|
-
requireNoExtraArgs(pending, "rig inspector scan-upstream-drift [--scan-id <id>]");
|
|
209
|
-
const connection = await ensureLocalRigServerConnection(context.projectRoot);
|
|
210
|
-
const response = await fetch(new URL("/api/inspector/tools/invoke", connection.baseUrl), {
|
|
211
|
-
method: "POST",
|
|
212
|
-
headers: {
|
|
213
|
-
"content-type": "application/json",
|
|
214
|
-
...connection.authToken ? { authorization: `Bearer ${connection.authToken}` } : {}
|
|
215
|
-
},
|
|
216
|
-
body: JSON.stringify({
|
|
217
|
-
name: "scan_upstream_drift",
|
|
218
|
-
input: scanIdResult.value ? { scanId: scanIdResult.value } : {}
|
|
219
|
-
})
|
|
220
|
-
});
|
|
221
|
-
if (!response.ok) {
|
|
222
|
-
throw new CliError(`Upstream drift scan request failed (${response.status}).`, response.status);
|
|
223
|
-
}
|
|
224
|
-
const result = await response.json();
|
|
225
|
-
if (context.outputMode === "text") {
|
|
226
|
-
console.log(String(result.summary ?? "Upstream drift scan completed"));
|
|
227
|
-
const details = result.details;
|
|
228
|
-
if (details && typeof details === "object" && !Array.isArray(details)) {
|
|
229
|
-
const record = details;
|
|
230
|
-
if (typeof record.scannedCommitCount === "number") {
|
|
231
|
-
console.log(` scanned commits: ${record.scannedCommitCount}`);
|
|
232
|
-
}
|
|
233
|
-
if (typeof record.ignoredCommitCount === "number") {
|
|
234
|
-
console.log(` ignored commits: ${record.ignoredCommitCount}`);
|
|
235
|
-
}
|
|
236
|
-
if (typeof record.followupCount === "number") {
|
|
237
|
-
console.log(` follow-up tasks: ${record.followupCount}`);
|
|
238
|
-
}
|
|
239
|
-
if (Array.isArray(record.createdTaskIds) && record.createdTaskIds.length > 0) {
|
|
240
|
-
console.log(` created tasks: ${record.createdTaskIds.join(", ")}`);
|
|
241
|
-
}
|
|
242
|
-
if (typeof record.latestHeadSha === "string" && record.latestHeadSha.length > 0) {
|
|
243
|
-
console.log(` latest upstream head: ${record.latestHeadSha}`);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return {
|
|
248
|
-
ok: true,
|
|
249
|
-
group: "inspector",
|
|
250
|
-
command,
|
|
251
|
-
details: {
|
|
252
|
-
scanId: scanIdResult.value ?? null,
|
|
253
|
-
result
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
default:
|
|
258
|
-
throw new CliError(`Unknown inspector command: ${command}`, 1, { hint: "Run `rig inspector --help` \u2014 commands are stream|scan-upstream-drift." });
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
export {
|
|
262
|
-
executeInspector
|
|
263
|
-
};
|