@h-rig/cli 0.0.6-alpha.77 → 0.0.6-alpha.79

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 (91) hide show
  1. package/dist/bin/build-rig-binaries.d.ts +2 -0
  2. package/dist/bin/rig.d.ts +2 -0
  3. package/dist/bin/rig.js +10214 -9309
  4. package/dist/src/app/board.d.ts +23 -0
  5. package/dist/src/app/board.js +1786 -0
  6. package/dist/src/app/drone-ui.d.ts +37 -0
  7. package/dist/src/app/drone-ui.js +294 -0
  8. package/dist/src/app/theme.d.ts +47 -0
  9. package/dist/src/{commands/_tui-theme.js → app/theme.js} +16 -1
  10. package/dist/src/commands/_async-ui.d.ts +13 -0
  11. package/dist/src/commands/_async-ui.js +74 -3
  12. package/dist/src/commands/_authority-runs.d.ts +22 -0
  13. package/dist/src/commands/_cli-format.d.ts +49 -0
  14. package/dist/src/commands/_cli-format.js +26 -8
  15. package/dist/src/commands/_connection-state.d.ts +44 -0
  16. package/dist/src/commands/_doctor-checks.d.ts +52 -0
  17. package/dist/src/commands/_doctor-checks.js +3 -1
  18. package/dist/src/commands/_help-catalog.d.ts +51 -0
  19. package/dist/src/commands/_help-catalog.js +9 -70
  20. package/dist/src/commands/_json-output.d.ts +11 -0
  21. package/dist/src/commands/_operator-surface.d.ts +34 -0
  22. package/dist/src/commands/_operator-view.d.ts +30 -0
  23. package/dist/src/commands/_operator-view.js +184 -7
  24. package/dist/src/commands/_parsers.d.ts +15 -0
  25. package/dist/src/commands/_paths.d.ts +11 -0
  26. package/dist/src/commands/_pi-frontend.d.ts +27 -0
  27. package/dist/src/commands/_pi-frontend.js +184 -7
  28. package/dist/src/commands/_pi-install.d.ts +42 -0
  29. package/dist/src/commands/_pi-install.js +1 -1
  30. package/dist/src/commands/_policy.d.ts +8 -0
  31. package/dist/src/commands/_preflight.d.ts +22 -0
  32. package/dist/src/commands/_preflight.js +3 -1
  33. package/dist/src/commands/_probes.d.ts +1 -0
  34. package/dist/src/commands/_run-driver-helpers.d.ts +99 -0
  35. package/dist/src/commands/_run-replay.d.ts +24 -0
  36. package/dist/src/commands/_server-client.d.ts +186 -0
  37. package/dist/src/commands/_server-client.js +3 -1
  38. package/dist/src/commands/_snapshot-upload.d.ts +39 -0
  39. package/dist/src/commands/_snapshot-upload.js +3 -1
  40. package/dist/src/commands/_spinner.d.ts +25 -0
  41. package/dist/src/commands/_task-picker.d.ts +9 -0
  42. package/dist/src/commands/_task-picker.js +132 -7
  43. package/dist/src/commands/agent.d.ts +3 -0
  44. package/dist/src/commands/browser.d.ts +65 -0
  45. package/dist/src/commands/browser.js +306 -30
  46. package/dist/src/commands/connect.d.ts +7 -0
  47. package/dist/src/commands/connect.js +130 -64
  48. package/dist/src/commands/dist.d.ts +28 -0
  49. package/dist/src/commands/doctor.d.ts +3 -0
  50. package/dist/src/commands/doctor.js +77 -4
  51. package/dist/src/commands/github.d.ts +3 -0
  52. package/dist/src/commands/github.js +77 -4
  53. package/dist/src/commands/inbox.d.ts +30 -0
  54. package/dist/src/commands/inbox.js +101 -78
  55. package/dist/src/commands/init.d.ts +74 -0
  56. package/dist/src/commands/init.js +350 -10
  57. package/dist/src/commands/inspect.d.ts +3 -0
  58. package/dist/src/commands/inspect.js +77 -4
  59. package/dist/src/commands/inspector.d.ts +3 -0
  60. package/dist/src/commands/pi.d.ts +3 -0
  61. package/dist/src/commands/plugin.d.ts +16 -0
  62. package/dist/src/commands/profile-and-review.d.ts +4 -0
  63. package/dist/src/commands/queue.d.ts +3 -0
  64. package/dist/src/commands/remote.d.ts +3 -0
  65. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  66. package/dist/src/commands/run.d.ts +3 -0
  67. package/dist/src/commands/run.js +195 -69
  68. package/dist/src/commands/server.d.ts +7 -0
  69. package/dist/src/commands/server.js +133 -65
  70. package/dist/src/commands/setup.d.ts +16 -0
  71. package/dist/src/commands/setup.js +77 -4
  72. package/dist/src/commands/stats.d.ts +12 -0
  73. package/dist/src/commands/stats.js +57 -113
  74. package/dist/src/commands/task-report-bug.d.ts +19 -0
  75. package/dist/src/commands/task-report-bug.js +231 -40
  76. package/dist/src/commands/task-run-driver.d.ts +132 -0
  77. package/dist/src/commands/task-run-driver.js +26 -3
  78. package/dist/src/commands/task.d.ts +14 -0
  79. package/dist/src/commands/task.js +341 -229
  80. package/dist/src/commands/test.d.ts +3 -0
  81. package/dist/src/commands/workspace.d.ts +3 -0
  82. package/dist/src/commands.d.ts +29 -0
  83. package/dist/src/commands.js +10194 -9289
  84. package/dist/src/index.d.ts +4 -0
  85. package/dist/src/index.js +10200 -9295
  86. package/dist/src/launcher.d.ts +61 -0
  87. package/dist/src/report-bug.d.ts +44 -0
  88. package/dist/src/runner.d.ts +47 -0
  89. package/dist/src/withMutedConsole.d.ts +2 -0
  90. package/package.json +10 -9
  91. package/dist/src/commands/_operator-board.js +0 -730
@@ -5,7 +5,282 @@ 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
@@ -66,7 +341,6 @@ Usage: ${usage}`);
66
341
  import { runCapture as runCapture2 } from "@rig/runtime/control-plane/native/utils";
67
342
 
68
343
  // packages/cli/src/commands/task-report-bug.ts
69
- import * as clack from "@clack/prompts";
70
344
  import pc from "picocolors";
71
345
  import {
72
346
  appendJsonlRecord,
@@ -81,27 +355,29 @@ import { resolveMonorepoRoot } from "@rig/runtime/control-plane/native/utils";
81
355
 
82
356
  // packages/cli/src/commands/task-report-bug.ts
83
357
  async function promptBugText(message, defaultValue, options = {}) {
84
- const result = await clack.text({
85
- message,
86
- defaultValue: defaultValue?.trim() ? defaultValue : undefined,
87
- placeholder: options.placeholder,
88
- validate: options.required ? (value) => validateRequiredBugPromptValue(value, message) : undefined
89
- });
90
- 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
+ }
91
373
  }
92
374
  function validateRequiredBugPromptValue(value, label) {
93
375
  return value?.trim() ? undefined : `${label} is required.`;
94
376
  }
95
377
  async function promptBugConfirm(message, initialValue) {
96
- const result = await clack.confirm({
97
- message,
98
- initialValue
99
- });
100
- return unwrapClackPrompt(result);
101
- }
102
- function unwrapClackPrompt(result) {
103
- if (clack.isCancel(result)) {
104
- clack.cancel("Bug report cancelled.");
378
+ const result = await droneConfirm({ message, initialValue });
379
+ if (result === null) {
380
+ droneCancel("Bug report cancelled.");
105
381
  throw new CliError("Bug report cancelled by user.");
106
382
  }
107
383
  return result;
@@ -437,26 +713,26 @@ async function executeBrowserDemo(context, args) {
437
713
  ...stateDirResult.value ? { stateDir: stateDirResult.value } : {},
438
714
  ...targetUrlResult.value ? { targetUrl: targetUrlResult.value } : {}
439
715
  });
440
- clack2.intro("rig browser demo");
441
- clack2.note([
716
+ droneIntro("rig browser demo");
717
+ droneNote([
442
718
  "You are now acting as the agent inside a browser-required task run.",
443
719
  "Type each simple command when prompted. The CLI will run the real backing action",
444
720
  "and print the same kind of output an agent would inspect before the next step."
445
721
  ].join(`
446
722
  `), "Agent task-run walkthrough");
447
- clack2.note(formatBrowserDemoRuntime(runtime), "Runtime contract the agent receives");
723
+ droneNote(formatBrowserDemoRuntime(runtime), "Runtime contract the agent receives");
448
724
  const agentCommands = buildBrowserDemoAgentCommands(runtime);
449
725
  await promptBrowserDemoAgentCommand("Agent command 1/4: print browser attach info", agentCommands.attachInfo);
450
726
  printBrowserDemoCommandOutput(agentCommands.attachInfo.primary, formatBrowserDemoAttachInfoOutput(runtime));
451
727
  await promptBrowserDemoAgentCommand("Agent command 2/4: launch Rig Browser", agentCommands.launch);
452
728
  if (!noBuildFlag.value) {
453
- const spinner2 = clack2.spinner();
454
- spinner2.start("Preparing browser bundle for the launch command");
729
+ const spinner = droneSpinner();
730
+ spinner.start("Preparing browser bundle for the launch command");
455
731
  try {
456
732
  runBrowserDemoBuild(context.projectRoot);
457
- spinner2.stop("Browser bundle built");
733
+ spinner.stop("Browser bundle built");
458
734
  } catch (error) {
459
- spinner2.error("Browser bundle build failed");
735
+ spinner.error("Browser bundle build failed");
460
736
  throw error;
461
737
  }
462
738
  }
@@ -465,20 +741,20 @@ async function executeBrowserDemo(context, args) {
465
741
  try {
466
742
  printBrowserDemoCommandOutput(agentCommands.launch.primary, formatBrowserDemoLaunchOutput(runtime, child.pid));
467
743
  await promptBrowserDemoAgentCommand("Agent command 3/4: check live browser endpoint", agentCommands.check);
468
- const readySpinner = clack2.spinner();
744
+ const readySpinner = droneSpinner();
469
745
  readySpinner.start(`Waiting for live CDP endpoint at ${runtime.attachUrl}`);
470
746
  const { version, pageTarget, targets } = await waitForBrowserDemoReady(runtime, child);
471
747
  readySpinner.stop("Live CDP endpoint is ready");
472
748
  printBrowserDemoCommandOutput(agentCommands.check.primary, formatBrowserDemoCheckOutput(runtime, version, pageTarget, targets));
473
749
  await promptBugText("Look at the launched browser page, then type ready", undefined, { required: true, placeholder: "ready" });
474
750
  await promptBrowserDemoAgentCommand("Agent command 4/4: attach DevTools MCP", agentCommands.attach);
475
- clack2.note([
751
+ droneNote([
476
752
  "The attach step evaluates JavaScript inside the live browser page.",
477
753
  "It records DOM state before the change, changes #status, #details, and the page background,",
478
754
  "then records DOM state and layout again so the transcript proves what changed."
479
755
  ].join(`
480
756
  `), "What mutationEvaluation means");
481
- const cdpSpinner = clack2.spinner();
757
+ const cdpSpinner = droneSpinner();
482
758
  cdpSpinner.start("Agent attaching over WebSocket CDP");
483
759
  const cdpResult = await runBrowserDemoCdpAction(pageTarget.webSocketDebuggerUrl);
484
760
  cdpSpinner.stop("Agent CDP action completed");
@@ -487,7 +763,7 @@ async function executeBrowserDemo(context, args) {
487
763
  if (!keepOpen) {
488
764
  keepOpen = await promptBugConfirm("Keep the demo browser open after this command exits?", false);
489
765
  }
490
- 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.");
491
767
  return {
492
768
  ok: true,
493
769
  group: "browser",
@@ -594,7 +870,7 @@ async function promptBrowserDemoAgentCommand(message, command) {
594
870
  if (browserDemoCommandMatches(value, command)) {
595
871
  return normalizeBrowserDemoCommand(value);
596
872
  }
597
- clack2.log.warn(`Expected one of:
873
+ droneWarn(`Expected one of:
598
874
  ${command.accepted.map((accepted) => ` ${accepted}`).join(`
599
875
  `)}`);
600
876
  }
@@ -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>;
@@ -1,6 +1,131 @@
1
1
  // @bun
2
- // packages/cli/src/commands/connect.ts
3
- import { cancel, isCancel, select } from "@clack/prompts";
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
+ }
4
129
 
5
130
  // packages/cli/src/runner.ts
6
131
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -115,66 +240,7 @@ function writeRepoConnection(projectRoot, state) {
115
240
  }
116
241
 
117
242
  // packages/cli/src/commands/_cli-format.ts
118
- import { log, note } from "@clack/prompts";
119
243
  import pc from "picocolors";
120
-
121
- // packages/cli/src/commands/_tui-theme.ts
122
- var RIG_PALETTE = {
123
- ink: "#f2f3f6",
124
- ink2: "#aeb0ba",
125
- ink3: "#6c6e79",
126
- ink4: "#44464f",
127
- accent: "#ccff4d",
128
- accentDim: "#a9d63f",
129
- cyan: "#56d8ff",
130
- red: "#ff5d5d",
131
- yellow: "#ffd24d"
132
- };
133
- function hexToRgb(hex) {
134
- const value = hex.replace("#", "");
135
- return [
136
- Number.parseInt(value.slice(0, 2), 16),
137
- Number.parseInt(value.slice(2, 4), 16),
138
- Number.parseInt(value.slice(4, 6), 16)
139
- ];
140
- }
141
- function fg(hex) {
142
- const [r, g, b] = hexToRgb(hex);
143
- return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
144
- }
145
- var ink = fg(RIG_PALETTE.ink);
146
- var ink2 = fg(RIG_PALETTE.ink2);
147
- var ink3 = fg(RIG_PALETTE.ink3);
148
- var ink4 = fg(RIG_PALETTE.ink4);
149
- var accent = fg(RIG_PALETTE.accent);
150
- var accentDim = fg(RIG_PALETTE.accentDim);
151
- var cyan = fg(RIG_PALETTE.cyan);
152
- var red = fg(RIG_PALETTE.red);
153
- var yellow = fg(RIG_PALETTE.yellow);
154
- var DRONE_ART = [
155
- " .-=-. .-=-. ",
156
- " ( !!! ) ( !!! ) ",
157
- " '-=-'._ _.'-=-' ",
158
- " '._ _.' ",
159
- " '=$$$$$$$=.' ",
160
- " =$$$$$$$$$$$= ",
161
- " $$$@@@@@@@@@@$$$ ",
162
- " $$$@@ @@$$$ ",
163
- " $$@ ? @$$$ ",
164
- " $$$@ '-' @$$$ ",
165
- " $$$@@ @@$$$ ",
166
- " $$$@@@@@@@@@@$$$ ",
167
- " =$$$$$$$$$$$= ",
168
- " '=$$$$$$$=.' ",
169
- " _.' '._ ",
170
- " .-=-.' '.-=-. ",
171
- " ( !!! ) ( !!! ) ",
172
- " '-=-' '-=-' "
173
- ];
174
- var DRONE_WIDTH = DRONE_ART[0].length;
175
- var DRONE_HEIGHT = DRONE_ART.length;
176
-
177
- // packages/cli/src/commands/_cli-format.ts
178
244
  var themeDim = (value) => ink3(value);
179
245
  var themeFaint = (value) => ink4(value);
180
246
  function truncate(value, width) {
@@ -279,13 +345,13 @@ async function promptForConnectionAlias(context) {
279
345
  hint: connection.kind === "remote" ? connection.baseUrl : "local"
280
346
  }))
281
347
  ].filter((option, index, all) => all.findIndex((candidate) => candidate.value === option.value) === index);
282
- const answer = await select({
348
+ const answer = await droneSelect({
283
349
  message: "Select Rig server for this repo",
284
350
  initialValue: repo?.selected ?? "local",
285
351
  options
286
352
  });
287
- if (isCancel(answer)) {
288
- cancel("No server selected.");
353
+ if (answer === null) {
354
+ droneCancel("No server selected.");
289
355
  throw new CliError("No server selected.", 3);
290
356
  }
291
357
  return String(answer);
@@ -0,0 +1,28 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
3
+ export type DistDoctorDetails = {
4
+ bun: {
5
+ available: boolean;
6
+ path: string | null;
7
+ version: string;
8
+ };
9
+ rig: {
10
+ onPath: boolean;
11
+ path: string | null;
12
+ runnable: boolean;
13
+ };
14
+ userBinDir: string;
15
+ userBinInPath: boolean;
16
+ latestDistBinary: string | null;
17
+ };
18
+ export type BuildTarget = {
19
+ source: string;
20
+ dest: string;
21
+ cwd: string;
22
+ };
23
+ export declare function collectRigValidatorBuildTargets(input: {
24
+ contextProjectRoot: string;
25
+ hostProjectRoot: string;
26
+ imageDir: string;
27
+ }): BuildTarget[];
28
+ export declare function executeDist(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
@@ -0,0 +1,3 @@
1
+ import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
2
+ import { type RunnerContext } from "../runner";
3
+ export declare function executeDoctor(context: RunnerContext, args: string[]): Promise<CommandOutcome>;