@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.
Files changed (114) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/build-rig-binaries.d.ts +2 -0
  3. package/dist/bin/rig.d.ts +2 -0
  4. package/dist/bin/rig.js +11052 -6668
  5. package/dist/src/app/board.d.ts +23 -0
  6. package/dist/src/app/board.js +1786 -0
  7. package/dist/src/app/drone-ui.d.ts +37 -0
  8. package/dist/src/app/drone-ui.js +294 -0
  9. package/dist/src/app/theme.d.ts +47 -0
  10. package/dist/src/app/theme.js +150 -0
  11. package/dist/src/commands/_async-ui.d.ts +13 -0
  12. package/dist/src/commands/_async-ui.js +223 -0
  13. package/dist/src/commands/_authority-runs.d.ts +22 -0
  14. package/dist/src/commands/_authority-runs.js +2 -3
  15. package/dist/src/commands/_cli-format.d.ts +49 -0
  16. package/dist/src/commands/_cli-format.js +447 -0
  17. package/dist/src/commands/_connection-state.d.ts +44 -0
  18. package/dist/src/commands/_connection-state.js +30 -11
  19. package/dist/src/commands/_doctor-checks.d.ts +52 -0
  20. package/dist/src/commands/_doctor-checks.js +180 -44
  21. package/dist/src/commands/_help-catalog.d.ts +51 -0
  22. package/dist/src/commands/_help-catalog.js +442 -0
  23. package/dist/src/commands/_json-output.d.ts +11 -0
  24. package/dist/src/commands/_json-output.js +56 -0
  25. package/dist/src/commands/_operator-surface.d.ts +34 -0
  26. package/dist/src/commands/_operator-surface.js +220 -0
  27. package/dist/src/commands/_operator-view.d.ts +30 -0
  28. package/dist/src/commands/_operator-view.js +803 -73
  29. package/dist/src/commands/_parsers.d.ts +15 -0
  30. package/dist/src/commands/_parsers.js +18 -11
  31. package/dist/src/commands/_paths.d.ts +11 -0
  32. package/dist/src/commands/_pi-frontend.d.ts +27 -0
  33. package/dist/src/commands/_pi-frontend.js +742 -0
  34. package/dist/src/commands/_pi-install.d.ts +42 -0
  35. package/dist/src/commands/_pi-install.js +5 -4
  36. package/dist/src/commands/_policy.d.ts +8 -0
  37. package/dist/src/commands/_policy.js +12 -5
  38. package/dist/src/commands/_preflight.d.ts +22 -0
  39. package/dist/src/commands/_preflight.js +190 -128
  40. package/dist/src/commands/_probes.d.ts +1 -0
  41. package/dist/src/commands/_run-driver-helpers.d.ts +99 -0
  42. package/dist/src/commands/_run-driver-helpers.js +75 -22
  43. package/dist/src/commands/_run-replay.d.ts +24 -0
  44. package/dist/src/commands/_run-replay.js +142 -0
  45. package/dist/src/commands/_server-client.d.ts +186 -0
  46. package/dist/src/commands/_server-client.js +360 -61
  47. package/dist/src/commands/_snapshot-upload.d.ts +39 -0
  48. package/dist/src/commands/_snapshot-upload.js +163 -39
  49. package/dist/src/commands/_spinner.d.ts +25 -0
  50. package/dist/src/commands/_spinner.js +65 -0
  51. package/dist/src/commands/_task-picker.d.ts +9 -0
  52. package/dist/src/commands/_task-picker.js +172 -19
  53. package/dist/src/commands/agent.d.ts +3 -0
  54. package/dist/src/commands/agent.js +39 -20
  55. package/dist/src/commands/browser.d.ts +65 -0
  56. package/dist/src/commands/browser.js +334 -51
  57. package/dist/src/commands/connect.d.ts +7 -0
  58. package/dist/src/commands/connect.js +272 -33
  59. package/dist/src/commands/dist.d.ts +28 -0
  60. package/dist/src/commands/dist.js +19 -12
  61. package/dist/src/commands/doctor.d.ts +3 -0
  62. package/dist/src/commands/doctor.js +378 -45
  63. package/dist/src/commands/github.d.ts +3 -0
  64. package/dist/src/commands/github.js +375 -53
  65. package/dist/src/commands/inbox.d.ts +30 -0
  66. package/dist/src/commands/inbox.js +760 -70
  67. package/dist/src/commands/init.d.ts +74 -0
  68. package/dist/src/commands/init.js +963 -119
  69. package/dist/src/commands/inspect.d.ts +3 -0
  70. package/dist/src/commands/inspect.js +588 -32
  71. package/dist/src/commands/inspector.d.ts +3 -0
  72. package/dist/src/commands/inspector.js +20 -13
  73. package/dist/src/commands/pi.d.ts +3 -0
  74. package/dist/src/commands/pi.js +177 -0
  75. package/dist/src/commands/plugin.d.ts +16 -0
  76. package/dist/src/commands/plugin.js +95 -27
  77. package/dist/src/commands/profile-and-review.d.ts +4 -0
  78. package/dist/src/commands/profile-and-review.js +26 -19
  79. package/dist/src/commands/queue.d.ts +3 -0
  80. package/dist/src/commands/queue.js +32 -12
  81. package/dist/src/commands/remote.d.ts +3 -0
  82. package/dist/src/commands/remote.js +43 -36
  83. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  84. package/dist/src/commands/repo-git-harness.js +22 -15
  85. package/dist/src/commands/run.d.ts +3 -0
  86. package/dist/src/commands/run.js +1379 -159
  87. package/dist/src/commands/server.d.ts +7 -0
  88. package/dist/src/commands/server.js +502 -57
  89. package/dist/src/commands/setup.d.ts +16 -0
  90. package/dist/src/commands/setup.js +390 -63
  91. package/dist/src/commands/stats.d.ts +12 -0
  92. package/dist/src/commands/stats.js +1051 -0
  93. package/dist/src/commands/task-report-bug.d.ts +19 -0
  94. package/dist/src/commands/task-report-bug.js +260 -62
  95. package/dist/src/commands/task-run-driver.d.ts +132 -0
  96. package/dist/src/commands/task-run-driver.js +886 -130
  97. package/dist/src/commands/task.d.ts +14 -0
  98. package/dist/src/commands/task.js +1644 -314
  99. package/dist/src/commands/test.d.ts +3 -0
  100. package/dist/src/commands/test.js +15 -8
  101. package/dist/src/commands/workspace.d.ts +3 -0
  102. package/dist/src/commands/workspace.js +18 -11
  103. package/dist/src/commands.d.ts +29 -0
  104. package/dist/src/commands.js +10967 -6637
  105. package/dist/src/index.d.ts +4 -0
  106. package/dist/src/index.js +10168 -5787
  107. package/dist/src/launcher.d.ts +61 -0
  108. package/dist/src/launcher.js +77 -13
  109. package/dist/src/report-bug.d.ts +44 -0
  110. package/dist/src/report-bug.js +3 -3
  111. package/dist/src/runner.d.ts +47 -0
  112. package/dist/src/runner.js +16 -22
  113. package/dist/src/withMutedConsole.d.ts +2 -0
  114. 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
- import * as clack2 from "@clack/prompts";
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
- import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
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
- const result = await clack.text({
78
- message,
79
- defaultValue: defaultValue?.trim() ? defaultValue : undefined,
80
- placeholder: options.placeholder,
81
- validate: options.required ? (value) => validateRequiredBugPromptValue(value, message) : undefined
82
- });
83
- return unwrapClackPrompt(result).trim();
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 clack.confirm({
90
- message,
91
- initialValue
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, "bun run rig browser explain");
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 CliError2(`rig browser app: set RIG_BROWSER_APP=<app-slug> to select which project app scripts to invoke.
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 CliError2(`Unknown browser ${command} command: ${subcommand}. Valid modes: ${modes.join(", ")}.
659
+ throw new CliError(`Unknown browser ${command} command: ${subcommand}. Valid modes: ${modes.join(", ")}.
377
660
 
378
661
  ${browserHelpText()}`);
379
662
  }
380
- requireNoExtraArgs(appRest, `bun run rig browser ${command} ${subcommand}`);
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, `bun run rig browser ${command}`);
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 CliError2(`Unknown browser command: ${command}
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, "bun run rig browser demo [--port <n>] [--profile <name>] [--state-dir <path>] [--target-url <url>] [--keep-open] [--no-build]");
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 CliError2("rig browser demo requires an interactive TTY in text mode.");
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 CliError2(`Invalid --port value: ${portResult.value}`);
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
- clack2.intro("rig browser demo");
434
- clack2.note([
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
- clack2.note(formatBrowserDemoRuntime(runtime), "Runtime contract the agent receives");
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 spinner2 = clack2.spinner();
447
- spinner2.start("Preparing browser bundle for the launch command");
729
+ const spinner = droneSpinner();
730
+ spinner.start("Preparing browser bundle for the launch command");
448
731
  try {
449
732
  runBrowserDemoBuild(context.projectRoot);
450
- spinner2.stop("Browser bundle built");
733
+ spinner.stop("Browser bundle built");
451
734
  } catch (error) {
452
- spinner2.error("Browser bundle build failed");
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 = clack2.spinner();
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
- clack2.note([
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 = clack2.spinner();
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
- clack2.outro(keepOpen ? "Demo complete. Browser left open by request." : "Demo complete. Closing browser.");
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 CliError2(`Browser demo build failed.${details ? `
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
- clack2.log.warn(`Expected one of:
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 CliError2("Browser demo cancelled."));
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 CliError2("Browser demo reached CDP but /json/version did not include Browser metadata.");
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 CliError2(`Rig Browser exited before ${label} became ready.`);
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 CliError2(`${label} did not become ready within ${timeoutMs}ms: ${String(lastError)}`);
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>;