@h-rig/cli 0.0.6-alpha.9 → 0.0.6-alpha.90
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 +1 -1
- package/dist/bin/build-rig-binaries.d.ts +2 -0
- package/dist/bin/rig.d.ts +2 -0
- package/dist/bin/rig.js +11052 -6668
- package/dist/src/app/board.d.ts +23 -0
- package/dist/src/app/board.js +1786 -0
- package/dist/src/app/drone-ui.d.ts +37 -0
- package/dist/src/app/drone-ui.js +294 -0
- package/dist/src/app/theme.d.ts +47 -0
- package/dist/src/app/theme.js +150 -0
- package/dist/src/commands/_async-ui.d.ts +13 -0
- package/dist/src/commands/_async-ui.js +223 -0
- package/dist/src/commands/_authority-runs.d.ts +22 -0
- package/dist/src/commands/_authority-runs.js +2 -3
- package/dist/src/commands/_cli-format.d.ts +49 -0
- package/dist/src/commands/_cli-format.js +447 -0
- package/dist/src/commands/_connection-state.d.ts +44 -0
- package/dist/src/commands/_connection-state.js +30 -11
- package/dist/src/commands/_doctor-checks.d.ts +52 -0
- package/dist/src/commands/_doctor-checks.js +180 -44
- package/dist/src/commands/_help-catalog.d.ts +51 -0
- package/dist/src/commands/_help-catalog.js +442 -0
- package/dist/src/commands/_json-output.d.ts +11 -0
- package/dist/src/commands/_json-output.js +56 -0
- package/dist/src/commands/_operator-surface.d.ts +34 -0
- package/dist/src/commands/_operator-surface.js +220 -0
- package/dist/src/commands/_operator-view.d.ts +30 -0
- package/dist/src/commands/_operator-view.js +803 -73
- package/dist/src/commands/_parsers.d.ts +15 -0
- package/dist/src/commands/_parsers.js +18 -11
- package/dist/src/commands/_paths.d.ts +11 -0
- package/dist/src/commands/_pi-frontend.d.ts +27 -0
- package/dist/src/commands/_pi-frontend.js +742 -0
- package/dist/src/commands/_pi-install.d.ts +42 -0
- package/dist/src/commands/_pi-install.js +5 -4
- package/dist/src/commands/_policy.d.ts +8 -0
- package/dist/src/commands/_policy.js +12 -5
- package/dist/src/commands/_preflight.d.ts +22 -0
- package/dist/src/commands/_preflight.js +190 -128
- package/dist/src/commands/_probes.d.ts +1 -0
- package/dist/src/commands/_run-driver-helpers.d.ts +99 -0
- package/dist/src/commands/_run-driver-helpers.js +75 -22
- package/dist/src/commands/_run-replay.d.ts +24 -0
- package/dist/src/commands/_run-replay.js +142 -0
- package/dist/src/commands/_server-client.d.ts +186 -0
- package/dist/src/commands/_server-client.js +360 -61
- package/dist/src/commands/_snapshot-upload.d.ts +39 -0
- package/dist/src/commands/_snapshot-upload.js +163 -39
- package/dist/src/commands/_spinner.d.ts +25 -0
- package/dist/src/commands/_spinner.js +65 -0
- package/dist/src/commands/_task-picker.d.ts +9 -0
- package/dist/src/commands/_task-picker.js +172 -19
- package/dist/src/commands/agent.d.ts +3 -0
- package/dist/src/commands/agent.js +39 -20
- package/dist/src/commands/browser.d.ts +65 -0
- package/dist/src/commands/browser.js +334 -51
- package/dist/src/commands/connect.d.ts +7 -0
- package/dist/src/commands/connect.js +272 -33
- package/dist/src/commands/dist.d.ts +28 -0
- package/dist/src/commands/dist.js +19 -12
- package/dist/src/commands/doctor.d.ts +3 -0
- package/dist/src/commands/doctor.js +378 -45
- package/dist/src/commands/github.d.ts +3 -0
- package/dist/src/commands/github.js +375 -53
- package/dist/src/commands/inbox.d.ts +30 -0
- package/dist/src/commands/inbox.js +760 -70
- package/dist/src/commands/init.d.ts +74 -0
- package/dist/src/commands/init.js +963 -119
- package/dist/src/commands/inspect.d.ts +3 -0
- package/dist/src/commands/inspect.js +588 -32
- package/dist/src/commands/inspector.d.ts +3 -0
- package/dist/src/commands/inspector.js +20 -13
- package/dist/src/commands/pi.d.ts +3 -0
- package/dist/src/commands/pi.js +177 -0
- package/dist/src/commands/plugin.d.ts +16 -0
- package/dist/src/commands/plugin.js +95 -27
- package/dist/src/commands/profile-and-review.d.ts +4 -0
- package/dist/src/commands/profile-and-review.js +26 -19
- package/dist/src/commands/queue.d.ts +3 -0
- package/dist/src/commands/queue.js +32 -12
- package/dist/src/commands/remote.d.ts +3 -0
- package/dist/src/commands/remote.js +43 -36
- package/dist/src/commands/repo-git-harness.d.ts +5 -0
- package/dist/src/commands/repo-git-harness.js +22 -15
- package/dist/src/commands/run.d.ts +3 -0
- package/dist/src/commands/run.js +1379 -159
- package/dist/src/commands/server.d.ts +7 -0
- package/dist/src/commands/server.js +502 -57
- package/dist/src/commands/setup.d.ts +16 -0
- package/dist/src/commands/setup.js +390 -63
- package/dist/src/commands/stats.d.ts +12 -0
- package/dist/src/commands/stats.js +1051 -0
- package/dist/src/commands/task-report-bug.d.ts +19 -0
- package/dist/src/commands/task-report-bug.js +260 -62
- package/dist/src/commands/task-run-driver.d.ts +132 -0
- package/dist/src/commands/task-run-driver.js +886 -130
- package/dist/src/commands/task.d.ts +14 -0
- package/dist/src/commands/task.js +1644 -314
- package/dist/src/commands/test.d.ts +3 -0
- package/dist/src/commands/test.js +15 -8
- package/dist/src/commands/workspace.d.ts +3 -0
- package/dist/src/commands/workspace.js +18 -11
- package/dist/src/commands.d.ts +29 -0
- package/dist/src/commands.js +10967 -6637
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +10168 -5787
- package/dist/src/launcher.d.ts +61 -0
- package/dist/src/launcher.js +77 -13
- package/dist/src/report-bug.d.ts +44 -0
- package/dist/src/report-bug.js +3 -3
- package/dist/src/runner.d.ts +47 -0
- package/dist/src/runner.js +16 -22
- package/dist/src/withMutedConsole.d.ts +2 -0
- package/package.json +13 -6
|
@@ -5,17 +5,299 @@ import { resolve } from "path";
|
|
|
5
5
|
import { spawn } from "child_process";
|
|
6
6
|
import { emitKeypressEvents } from "readline";
|
|
7
7
|
import { pathToFileURL } from "url";
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
// packages/cli/src/app/drone-ui.ts
|
|
10
|
+
import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
|
|
11
|
+
|
|
12
|
+
// packages/cli/src/app/theme.ts
|
|
13
|
+
var RIG_PALETTE = {
|
|
14
|
+
ink: "#f2f3f6",
|
|
15
|
+
ink2: "#aeb0ba",
|
|
16
|
+
ink3: "#6c6e79",
|
|
17
|
+
ink4: "#44464f",
|
|
18
|
+
accent: "#ccff4d",
|
|
19
|
+
accentDim: "#a9d63f",
|
|
20
|
+
cyan: "#56d8ff",
|
|
21
|
+
red: "#ff5d5d",
|
|
22
|
+
yellow: "#ffd24d"
|
|
23
|
+
};
|
|
24
|
+
function hexToRgb(hex) {
|
|
25
|
+
const value = hex.replace("#", "");
|
|
26
|
+
return [
|
|
27
|
+
Number.parseInt(value.slice(0, 2), 16),
|
|
28
|
+
Number.parseInt(value.slice(2, 4), 16),
|
|
29
|
+
Number.parseInt(value.slice(4, 6), 16)
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
function fg(hex) {
|
|
33
|
+
const [r, g, b] = hexToRgb(hex);
|
|
34
|
+
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
35
|
+
}
|
|
36
|
+
var ink = fg(RIG_PALETTE.ink);
|
|
37
|
+
var ink2 = fg(RIG_PALETTE.ink2);
|
|
38
|
+
var ink3 = fg(RIG_PALETTE.ink3);
|
|
39
|
+
var ink4 = fg(RIG_PALETTE.ink4);
|
|
40
|
+
var accent = fg(RIG_PALETTE.accent);
|
|
41
|
+
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
42
|
+
var cyan = fg(RIG_PALETTE.cyan);
|
|
43
|
+
var red = fg(RIG_PALETTE.red);
|
|
44
|
+
var yellow = fg(RIG_PALETTE.yellow);
|
|
45
|
+
function bold(text) {
|
|
46
|
+
return `\x1B[1m${text}\x1B[22m`;
|
|
47
|
+
}
|
|
48
|
+
var DRONE_ART = [
|
|
49
|
+
" .-=-. .-=-. ",
|
|
50
|
+
" ( !!! ) ( !!! ) ",
|
|
51
|
+
" '-=-'._ _.'-=-' ",
|
|
52
|
+
" '._ _.' ",
|
|
53
|
+
" '=$$$$$$$=.' ",
|
|
54
|
+
" =$$$$$$$$$$$= ",
|
|
55
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
56
|
+
" $$$@@ @@$$$ ",
|
|
57
|
+
" $$@ ? @$$$ ",
|
|
58
|
+
" $$$@ '-' @$$$ ",
|
|
59
|
+
" $$$@@ @@$$$ ",
|
|
60
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
61
|
+
" =$$$$$$$$$$$= ",
|
|
62
|
+
" '=$$$$$$$=.' ",
|
|
63
|
+
" _.' '._ ",
|
|
64
|
+
" .-=-.' '.-=-. ",
|
|
65
|
+
" ( !!! ) ( !!! ) ",
|
|
66
|
+
" '-=-' '-=-' "
|
|
67
|
+
];
|
|
68
|
+
var EYE_FRAMES = ["@", "o", "."];
|
|
69
|
+
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
70
|
+
var DRONE_HEIGHT = DRONE_ART.length;
|
|
71
|
+
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
72
|
+
function microDroneFrame(tick) {
|
|
73
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
74
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
75
|
+
return `(${blade})${eye}(${blade})`;
|
|
76
|
+
}
|
|
77
|
+
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
78
|
+
function renderMicroDroneFrame(tick) {
|
|
79
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
80
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
81
|
+
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// packages/cli/src/commands/_spinner.ts
|
|
85
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
86
|
+
function createTtySpinner(input) {
|
|
87
|
+
const output = input.output ?? process.stdout;
|
|
88
|
+
const isTty = output.isTTY === true;
|
|
89
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
90
|
+
let label = input.label;
|
|
91
|
+
let frame = 0;
|
|
92
|
+
let paused = false;
|
|
93
|
+
let stopped = false;
|
|
94
|
+
let lastPrintedLabel = "";
|
|
95
|
+
const render = () => {
|
|
96
|
+
if (stopped || paused)
|
|
97
|
+
return;
|
|
98
|
+
if (!isTty) {
|
|
99
|
+
if (label !== lastPrintedLabel) {
|
|
100
|
+
output.write(`${label}
|
|
101
|
+
`);
|
|
102
|
+
lastPrintedLabel = label;
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
frame = (frame + 1) % frames.length;
|
|
107
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
108
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
109
|
+
};
|
|
110
|
+
const clearLine = () => {
|
|
111
|
+
if (isTty)
|
|
112
|
+
output.write("\r\x1B[2K");
|
|
113
|
+
};
|
|
114
|
+
render();
|
|
115
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
116
|
+
return {
|
|
117
|
+
setLabel(next) {
|
|
118
|
+
label = next;
|
|
119
|
+
render();
|
|
120
|
+
},
|
|
121
|
+
pause() {
|
|
122
|
+
paused = true;
|
|
123
|
+
clearLine();
|
|
124
|
+
},
|
|
125
|
+
resume() {
|
|
126
|
+
if (stopped)
|
|
127
|
+
return;
|
|
128
|
+
paused = false;
|
|
129
|
+
render();
|
|
130
|
+
},
|
|
131
|
+
stop(finalLine) {
|
|
132
|
+
if (stopped)
|
|
133
|
+
return;
|
|
134
|
+
stopped = true;
|
|
135
|
+
if (timer)
|
|
136
|
+
clearInterval(timer);
|
|
137
|
+
clearLine();
|
|
138
|
+
if (finalLine)
|
|
139
|
+
output.write(`${finalLine}
|
|
140
|
+
`);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// packages/cli/src/app/drone-ui.ts
|
|
146
|
+
var isTty = () => Boolean(process.stdout.isTTY);
|
|
147
|
+
function hairline(width = Math.min(process.stdout.columns ?? 80, 100)) {
|
|
148
|
+
return ink4("\u2500".repeat(Math.max(10, width)));
|
|
149
|
+
}
|
|
150
|
+
function droneIntro(title, subtitle) {
|
|
151
|
+
console.log("");
|
|
152
|
+
console.log(` ${accent("\u258D")}${bold(ink(title))}${subtitle ? ink3(` \u2014 ${subtitle}`) : ""}`);
|
|
153
|
+
console.log(hairline());
|
|
154
|
+
}
|
|
155
|
+
function droneOutro(text) {
|
|
156
|
+
console.log(hairline());
|
|
157
|
+
console.log(` ${accent("\u25C6")} ${ink2(text)}`);
|
|
158
|
+
console.log("");
|
|
159
|
+
}
|
|
160
|
+
function droneNote(message, title) {
|
|
161
|
+
if (title)
|
|
162
|
+
console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
|
|
163
|
+
for (const line of message.split(`
|
|
164
|
+
`)) {
|
|
165
|
+
console.log(` ${ink4("\u2502")} ${line}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function droneInfo(text) {
|
|
169
|
+
console.log(` ${cyan("\xB7")} ${ink2(text)}`);
|
|
170
|
+
}
|
|
171
|
+
function droneWarn(text) {
|
|
172
|
+
console.log(` ${yellow("\u25B2")} ${ink2(text)}`);
|
|
173
|
+
}
|
|
174
|
+
function droneCancel(text) {
|
|
175
|
+
console.log(` ${red("\u2716")} ${ink3(text)}`);
|
|
176
|
+
}
|
|
177
|
+
function droneSpinner() {
|
|
178
|
+
let active = null;
|
|
179
|
+
return {
|
|
180
|
+
start(message) {
|
|
181
|
+
active = createTtySpinner({
|
|
182
|
+
label: message,
|
|
183
|
+
frames: MICRO_DRONE_FRAMES,
|
|
184
|
+
styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
stop(message) {
|
|
188
|
+
active?.stop(message ? ` ${accent("\u25C6")} ${ink2(message)}` : undefined);
|
|
189
|
+
active = null;
|
|
190
|
+
},
|
|
191
|
+
error(message) {
|
|
192
|
+
active?.stop(message ? ` ${red("\u2716")} ${ink2(message)}` : undefined);
|
|
193
|
+
active = null;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
var SELECT_THEME = {
|
|
198
|
+
selectedPrefix: (text) => accent(text),
|
|
199
|
+
selectedText: (text) => bold(ink(text)),
|
|
200
|
+
description: (text) => ink3(text),
|
|
201
|
+
scrollInfo: (text) => ink4(text),
|
|
202
|
+
noMatch: (text) => ink3(text)
|
|
203
|
+
};
|
|
204
|
+
async function runMiniTui(build) {
|
|
205
|
+
const terminal = new ProcessTerminal;
|
|
206
|
+
const tui = new TUI(terminal);
|
|
207
|
+
let settled = false;
|
|
208
|
+
return await new Promise((resolve) => {
|
|
209
|
+
const finish = (result) => {
|
|
210
|
+
if (settled)
|
|
211
|
+
return;
|
|
212
|
+
settled = true;
|
|
213
|
+
tui.stop();
|
|
214
|
+
resolve(result);
|
|
215
|
+
};
|
|
216
|
+
build(tui, finish);
|
|
217
|
+
tui.start();
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
async function droneSelect(input) {
|
|
221
|
+
if (!isTty() || input.options.length === 0) {
|
|
222
|
+
return input.initialValue ?? input.options[0]?.value ?? null;
|
|
223
|
+
}
|
|
224
|
+
return runMiniTui((tui, finish) => {
|
|
225
|
+
tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}`));
|
|
226
|
+
const items = input.options.map((option) => ({
|
|
227
|
+
value: option.value,
|
|
228
|
+
label: option.label,
|
|
229
|
+
...option.hint ? { description: option.hint } : {}
|
|
230
|
+
}));
|
|
231
|
+
const list = new SelectList(items, Math.min(items.length, 12), SELECT_THEME);
|
|
232
|
+
const initialIndex = input.initialValue ? items.findIndex((item) => item.value === input.initialValue) : -1;
|
|
233
|
+
if (initialIndex > 0)
|
|
234
|
+
list.setSelectedIndex(initialIndex);
|
|
235
|
+
list.onSelect = (item) => finish(item.value);
|
|
236
|
+
list.onCancel = () => finish(null);
|
|
237
|
+
tui.addChild(list);
|
|
238
|
+
tui.addChild(new Text(ink4(" \u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")));
|
|
239
|
+
tui.setFocus(list);
|
|
240
|
+
tui.addInputListener((data) => {
|
|
241
|
+
if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
|
|
242
|
+
finish(null);
|
|
243
|
+
return { consume: true };
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async function droneText(input) {
|
|
250
|
+
if (!isTty())
|
|
251
|
+
return input.initialValue ?? null;
|
|
252
|
+
return runMiniTui((tui, finish) => {
|
|
253
|
+
tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}${input.placeholder ? ink4(` (${input.placeholder})`) : ""}`));
|
|
254
|
+
const field = new Input;
|
|
255
|
+
if (input.initialValue)
|
|
256
|
+
field.setValue(input.initialValue);
|
|
257
|
+
field.onSubmit = (value) => finish(value);
|
|
258
|
+
field.onEscape = () => finish(null);
|
|
259
|
+
tui.addChild(field);
|
|
260
|
+
tui.addChild(new Text(ink4(" enter submit \xB7 esc cancel")));
|
|
261
|
+
tui.setFocus(field);
|
|
262
|
+
tui.addInputListener((data) => {
|
|
263
|
+
if (matchesKey(data, "ctrl+c")) {
|
|
264
|
+
finish(null);
|
|
265
|
+
return { consume: true };
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
async function droneConfirm(input) {
|
|
272
|
+
const answer = await droneSelect({
|
|
273
|
+
message: input.message,
|
|
274
|
+
options: [
|
|
275
|
+
{ value: "yes", label: "Yes" },
|
|
276
|
+
{ value: "no", label: "No" }
|
|
277
|
+
],
|
|
278
|
+
initialValue: input.initialValue === false ? "no" : "yes"
|
|
279
|
+
});
|
|
280
|
+
return answer === null ? null : answer === "yes";
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// packages/cli/src/commands/browser.ts
|
|
9
284
|
import pc2 from "picocolors";
|
|
10
285
|
|
|
11
286
|
// packages/cli/src/runner.ts
|
|
12
287
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
13
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
288
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
14
289
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
15
|
-
import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
|
|
16
|
-
import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
|
|
17
290
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
18
|
-
|
|
291
|
+
|
|
292
|
+
class CliError extends RuntimeCliError {
|
|
293
|
+
hint;
|
|
294
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
295
|
+
super(message, exitCode);
|
|
296
|
+
if (options.hint?.trim()) {
|
|
297
|
+
this.hint = options.hint.trim();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
19
301
|
function takeFlag(args, flag) {
|
|
20
302
|
const rest = [];
|
|
21
303
|
let value = false;
|
|
@@ -36,7 +318,7 @@ function takeOption(args, option) {
|
|
|
36
318
|
if (current === option) {
|
|
37
319
|
const next = args[index + 1];
|
|
38
320
|
if (!next || next.startsWith("-")) {
|
|
39
|
-
throw new CliError(`Missing value for ${option}`);
|
|
321
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
40
322
|
}
|
|
41
323
|
value = next;
|
|
42
324
|
index += 1;
|
|
@@ -59,7 +341,6 @@ Usage: ${usage}`);
|
|
|
59
341
|
import { runCapture as runCapture2 } from "@rig/runtime/control-plane/native/utils";
|
|
60
342
|
|
|
61
343
|
// packages/cli/src/commands/task-report-bug.ts
|
|
62
|
-
import * as clack from "@clack/prompts";
|
|
63
344
|
import pc from "picocolors";
|
|
64
345
|
import {
|
|
65
346
|
appendJsonlRecord,
|
|
@@ -74,28 +355,30 @@ import { resolveMonorepoRoot } from "@rig/runtime/control-plane/native/utils";
|
|
|
74
355
|
|
|
75
356
|
// packages/cli/src/commands/task-report-bug.ts
|
|
76
357
|
async function promptBugText(message, defaultValue, options = {}) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
358
|
+
for (;; ) {
|
|
359
|
+
const result = await droneText({
|
|
360
|
+
message,
|
|
361
|
+
...options.placeholder ? { placeholder: options.placeholder } : {},
|
|
362
|
+
...defaultValue?.trim() ? { initialValue: defaultValue } : {}
|
|
363
|
+
});
|
|
364
|
+
if (result === null) {
|
|
365
|
+
droneCancel("Bug report cancelled.");
|
|
366
|
+
throw new CliError("Bug report cancelled by user.");
|
|
367
|
+
}
|
|
368
|
+
const invalid = options.required ? validateRequiredBugPromptValue(result, message) : undefined;
|
|
369
|
+
if (!invalid)
|
|
370
|
+
return result.trim();
|
|
371
|
+
droneInfo(invalid);
|
|
372
|
+
}
|
|
84
373
|
}
|
|
85
374
|
function validateRequiredBugPromptValue(value, label) {
|
|
86
375
|
return value?.trim() ? undefined : `${label} is required.`;
|
|
87
376
|
}
|
|
88
377
|
async function promptBugConfirm(message, initialValue) {
|
|
89
|
-
const result = await
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return unwrapClackPrompt(result);
|
|
94
|
-
}
|
|
95
|
-
function unwrapClackPrompt(result) {
|
|
96
|
-
if (clack.isCancel(result)) {
|
|
97
|
-
clack.cancel("Bug report cancelled.");
|
|
98
|
-
throw new CliError2("Bug report cancelled by user.");
|
|
378
|
+
const result = await droneConfirm({ message, initialValue });
|
|
379
|
+
if (result === null) {
|
|
380
|
+
droneCancel("Bug report cancelled.");
|
|
381
|
+
throw new CliError("Bug report cancelled by user.");
|
|
99
382
|
}
|
|
100
383
|
return result;
|
|
101
384
|
}
|
|
@@ -351,7 +634,7 @@ async function executeBrowser(context, args) {
|
|
|
351
634
|
return { ok: true, group: "browser", command: "help" };
|
|
352
635
|
}
|
|
353
636
|
if (command === "explain") {
|
|
354
|
-
requireNoExtraArgs(rest, "
|
|
637
|
+
requireNoExtraArgs(rest, "rig browser explain");
|
|
355
638
|
console.log(browserAgentUsageText());
|
|
356
639
|
return { ok: true, group: "browser", command: "explain" };
|
|
357
640
|
}
|
|
@@ -361,7 +644,7 @@ async function executeBrowser(context, args) {
|
|
|
361
644
|
if (command === "app" || command === "hp-next") {
|
|
362
645
|
const appSlug = command === "hp-next" ? "hp-next" : process.env.RIG_BROWSER_APP?.trim() || "";
|
|
363
646
|
if (!appSlug) {
|
|
364
|
-
throw new
|
|
647
|
+
throw new CliError(`rig browser app: set RIG_BROWSER_APP=<app-slug> to select which project app scripts to invoke.
|
|
365
648
|
` + `Scripts are invoked as 'bun run app:<mode>:browser:<app-slug>'.
|
|
366
649
|
|
|
367
650
|
${browserHelpText()}`);
|
|
@@ -373,11 +656,11 @@ ${browserHelpText()}`);
|
|
|
373
656
|
}
|
|
374
657
|
const modes = ["dev", "start", "check", "e2e", "reset"];
|
|
375
658
|
if (!modes.includes(subcommand)) {
|
|
376
|
-
throw new
|
|
659
|
+
throw new CliError(`Unknown browser ${command} command: ${subcommand}. Valid modes: ${modes.join(", ")}.
|
|
377
660
|
|
|
378
661
|
${browserHelpText()}`);
|
|
379
662
|
}
|
|
380
|
-
requireNoExtraArgs(appRest, `
|
|
663
|
+
requireNoExtraArgs(appRest, `rig browser ${command} ${subcommand}`);
|
|
381
664
|
await context.runCommand(["bun", "run", `app:${subcommand}:browser:${appSlug}`]);
|
|
382
665
|
return { ok: true, group: "browser", command: `${command}-${subcommand}` };
|
|
383
666
|
}
|
|
@@ -389,13 +672,13 @@ ${browserHelpText()}`);
|
|
|
389
672
|
};
|
|
390
673
|
const packageScript = packageScripts[command];
|
|
391
674
|
if (packageScript) {
|
|
392
|
-
requireNoExtraArgs(rest, `
|
|
675
|
+
requireNoExtraArgs(rest, `rig browser ${command}`);
|
|
393
676
|
await context.runCommand(["bun", "run", "--filter=@rig/browser", packageScript]);
|
|
394
677
|
return { ok: true, group: "browser", command };
|
|
395
678
|
}
|
|
396
|
-
throw new
|
|
679
|
+
throw new CliError(`Unknown browser command: ${command}
|
|
397
680
|
|
|
398
|
-
${browserHelpText()}`);
|
|
681
|
+
${browserHelpText()}`, 1, { hint: "Run `rig browser help` for the full browser command reference." });
|
|
399
682
|
}
|
|
400
683
|
async function executeBrowserDemo(context, args) {
|
|
401
684
|
const [maybeHelp] = args;
|
|
@@ -416,13 +699,13 @@ async function executeBrowserDemo(context, args) {
|
|
|
416
699
|
pending = keepOpenFlag.rest;
|
|
417
700
|
const noBuildFlag = takeFlag(pending, "--no-build");
|
|
418
701
|
pending = noBuildFlag.rest;
|
|
419
|
-
requireNoExtraArgs(pending, "
|
|
702
|
+
requireNoExtraArgs(pending, "rig browser demo [--port <n>] [--profile <name>] [--state-dir <path>] [--target-url <url>] [--keep-open] [--no-build]");
|
|
420
703
|
if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
421
|
-
throw new
|
|
704
|
+
throw new CliError("rig browser demo requires an interactive TTY in text mode.", 1, { hint: "Run `rig browser demo` from an interactive terminal (no --json, no piped stdin)." });
|
|
422
705
|
}
|
|
423
706
|
const port = portResult.value ? Number.parseInt(portResult.value, 10) : undefined;
|
|
424
707
|
if (port !== undefined && (!Number.isFinite(port) || port <= 0)) {
|
|
425
|
-
throw new
|
|
708
|
+
throw new CliError(`Invalid --port value: ${portResult.value}`, 1, { hint: "Pass a positive port number, e.g. `--port 9222`." });
|
|
426
709
|
}
|
|
427
710
|
const runtime = buildBrowserDemoRuntime(context.projectRoot, {
|
|
428
711
|
...port !== undefined ? { port } : {},
|
|
@@ -430,26 +713,26 @@ async function executeBrowserDemo(context, args) {
|
|
|
430
713
|
...stateDirResult.value ? { stateDir: stateDirResult.value } : {},
|
|
431
714
|
...targetUrlResult.value ? { targetUrl: targetUrlResult.value } : {}
|
|
432
715
|
});
|
|
433
|
-
|
|
434
|
-
|
|
716
|
+
droneIntro("rig browser demo");
|
|
717
|
+
droneNote([
|
|
435
718
|
"You are now acting as the agent inside a browser-required task run.",
|
|
436
719
|
"Type each simple command when prompted. The CLI will run the real backing action",
|
|
437
720
|
"and print the same kind of output an agent would inspect before the next step."
|
|
438
721
|
].join(`
|
|
439
722
|
`), "Agent task-run walkthrough");
|
|
440
|
-
|
|
723
|
+
droneNote(formatBrowserDemoRuntime(runtime), "Runtime contract the agent receives");
|
|
441
724
|
const agentCommands = buildBrowserDemoAgentCommands(runtime);
|
|
442
725
|
await promptBrowserDemoAgentCommand("Agent command 1/4: print browser attach info", agentCommands.attachInfo);
|
|
443
726
|
printBrowserDemoCommandOutput(agentCommands.attachInfo.primary, formatBrowserDemoAttachInfoOutput(runtime));
|
|
444
727
|
await promptBrowserDemoAgentCommand("Agent command 2/4: launch Rig Browser", agentCommands.launch);
|
|
445
728
|
if (!noBuildFlag.value) {
|
|
446
|
-
const
|
|
447
|
-
|
|
729
|
+
const spinner = droneSpinner();
|
|
730
|
+
spinner.start("Preparing browser bundle for the launch command");
|
|
448
731
|
try {
|
|
449
732
|
runBrowserDemoBuild(context.projectRoot);
|
|
450
|
-
|
|
733
|
+
spinner.stop("Browser bundle built");
|
|
451
734
|
} catch (error) {
|
|
452
|
-
|
|
735
|
+
spinner.error("Browser bundle build failed");
|
|
453
736
|
throw error;
|
|
454
737
|
}
|
|
455
738
|
}
|
|
@@ -458,20 +741,20 @@ async function executeBrowserDemo(context, args) {
|
|
|
458
741
|
try {
|
|
459
742
|
printBrowserDemoCommandOutput(agentCommands.launch.primary, formatBrowserDemoLaunchOutput(runtime, child.pid));
|
|
460
743
|
await promptBrowserDemoAgentCommand("Agent command 3/4: check live browser endpoint", agentCommands.check);
|
|
461
|
-
const readySpinner =
|
|
744
|
+
const readySpinner = droneSpinner();
|
|
462
745
|
readySpinner.start(`Waiting for live CDP endpoint at ${runtime.attachUrl}`);
|
|
463
746
|
const { version, pageTarget, targets } = await waitForBrowserDemoReady(runtime, child);
|
|
464
747
|
readySpinner.stop("Live CDP endpoint is ready");
|
|
465
748
|
printBrowserDemoCommandOutput(agentCommands.check.primary, formatBrowserDemoCheckOutput(runtime, version, pageTarget, targets));
|
|
466
749
|
await promptBugText("Look at the launched browser page, then type ready", undefined, { required: true, placeholder: "ready" });
|
|
467
750
|
await promptBrowserDemoAgentCommand("Agent command 4/4: attach DevTools MCP", agentCommands.attach);
|
|
468
|
-
|
|
751
|
+
droneNote([
|
|
469
752
|
"The attach step evaluates JavaScript inside the live browser page.",
|
|
470
753
|
"It records DOM state before the change, changes #status, #details, and the page background,",
|
|
471
754
|
"then records DOM state and layout again so the transcript proves what changed."
|
|
472
755
|
].join(`
|
|
473
756
|
`), "What mutationEvaluation means");
|
|
474
|
-
const cdpSpinner =
|
|
757
|
+
const cdpSpinner = droneSpinner();
|
|
475
758
|
cdpSpinner.start("Agent attaching over WebSocket CDP");
|
|
476
759
|
const cdpResult = await runBrowserDemoCdpAction(pageTarget.webSocketDebuggerUrl);
|
|
477
760
|
cdpSpinner.stop("Agent CDP action completed");
|
|
@@ -480,7 +763,7 @@ async function executeBrowserDemo(context, args) {
|
|
|
480
763
|
if (!keepOpen) {
|
|
481
764
|
keepOpen = await promptBugConfirm("Keep the demo browser open after this command exits?", false);
|
|
482
765
|
}
|
|
483
|
-
|
|
766
|
+
droneOutro(keepOpen ? "Demo complete. Browser left open by request." : "Demo complete. Closing browser.");
|
|
484
767
|
return {
|
|
485
768
|
ok: true,
|
|
486
769
|
group: "browser",
|
|
@@ -577,7 +860,7 @@ function runBrowserDemoBuild(projectRoot) {
|
|
|
577
860
|
if (result.exitCode !== 0) {
|
|
578
861
|
const details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(`
|
|
579
862
|
`);
|
|
580
|
-
throw new
|
|
863
|
+
throw new CliError(`Browser demo build failed.${details ? `
|
|
581
864
|
${details}` : ""}`, result.exitCode);
|
|
582
865
|
}
|
|
583
866
|
}
|
|
@@ -587,7 +870,7 @@ async function promptBrowserDemoAgentCommand(message, command) {
|
|
|
587
870
|
if (browserDemoCommandMatches(value, command)) {
|
|
588
871
|
return normalizeBrowserDemoCommand(value);
|
|
589
872
|
}
|
|
590
|
-
|
|
873
|
+
droneWarn(`Expected one of:
|
|
591
874
|
${command.accepted.map((accepted) => ` ${accepted}`).join(`
|
|
592
875
|
`)}`);
|
|
593
876
|
}
|
|
@@ -632,7 +915,7 @@ function readBrowserDemoCommandLine(command) {
|
|
|
632
915
|
cleanup();
|
|
633
916
|
stdout.write(`
|
|
634
917
|
`);
|
|
635
|
-
rejectInput(new
|
|
918
|
+
rejectInput(new CliError("Browser demo cancelled."));
|
|
636
919
|
return;
|
|
637
920
|
}
|
|
638
921
|
if (key.name === "return" || key.name === "enter") {
|
|
@@ -698,7 +981,7 @@ async function waitForBrowserDemoReady(runtime, child) {
|
|
|
698
981
|
return { targets: nextTargets, pageTarget: nextPageTarget };
|
|
699
982
|
}, child, "CDP demo page target");
|
|
700
983
|
if (!version.Browser) {
|
|
701
|
-
throw new
|
|
984
|
+
throw new CliError("Browser demo reached CDP but /json/version did not include Browser metadata.");
|
|
702
985
|
}
|
|
703
986
|
return { version, targets, pageTarget };
|
|
704
987
|
}
|
|
@@ -711,14 +994,14 @@ async function waitForBrowserDemo(check, child, label, timeoutMs = 18000) {
|
|
|
711
994
|
let lastError = null;
|
|
712
995
|
for (;; ) {
|
|
713
996
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
714
|
-
throw new
|
|
997
|
+
throw new CliError(`Rig Browser exited before ${label} became ready.`);
|
|
715
998
|
}
|
|
716
999
|
try {
|
|
717
1000
|
return await check();
|
|
718
1001
|
} catch (error) {
|
|
719
1002
|
lastError = error;
|
|
720
1003
|
if (Date.now() - startedAt > timeoutMs) {
|
|
721
|
-
throw new
|
|
1004
|
+
throw new CliError(`${label} did not become ready within ${timeoutMs}ms: ${String(lastError)}`);
|
|
722
1005
|
}
|
|
723
1006
|
await new Promise((resolveDelay) => setTimeout(resolveDelay, 150));
|
|
724
1007
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
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>;
|