@h-rig/cli 0.0.6-alpha.76 → 0.0.6-alpha.78

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 (32) hide show
  1. package/dist/bin/rig.js +10130 -9246
  2. package/dist/src/app/board.js +1783 -0
  3. package/dist/src/app/drone-ui.js +294 -0
  4. package/dist/src/{commands/_tui-theme.js → app/theme.js} +16 -1
  5. package/dist/src/commands/_async-ui.js +74 -3
  6. package/dist/src/commands/_cli-format.js +107 -29
  7. package/dist/src/commands/_doctor-checks.js +3 -1
  8. package/dist/src/commands/_help-catalog.js +8 -70
  9. package/dist/src/commands/_operator-view.js +184 -7
  10. package/dist/src/commands/_pi-frontend.js +184 -7
  11. package/dist/src/commands/_preflight.js +3 -1
  12. package/dist/src/commands/_server-client.js +3 -1
  13. package/dist/src/commands/_snapshot-upload.js +3 -1
  14. package/dist/src/commands/_task-picker.js +132 -7
  15. package/dist/src/commands/browser.js +306 -30
  16. package/dist/src/commands/connect.js +146 -20
  17. package/dist/src/commands/doctor.js +77 -4
  18. package/dist/src/commands/github.js +77 -4
  19. package/dist/src/commands/inbox.js +171 -88
  20. package/dist/src/commands/init.js +349 -9
  21. package/dist/src/commands/inspect.js +77 -4
  22. package/dist/src/commands/run.js +214 -28
  23. package/dist/src/commands/server.js +149 -21
  24. package/dist/src/commands/setup.js +77 -4
  25. package/dist/src/commands/stats.js +109 -107
  26. package/dist/src/commands/task-report-bug.js +231 -40
  27. package/dist/src/commands/task-run-driver.js +3 -1
  28. package/dist/src/commands/task.js +355 -184
  29. package/dist/src/commands.js +10126 -9242
  30. package/dist/src/index.js +10131 -9247
  31. package/package.json +8 -9
  32. package/dist/src/commands/_operator-board.js +0 -730
@@ -0,0 +1,294 @@
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
+ function renderMicroDroneFrame(tick) {
72
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
73
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
74
+ return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
75
+ }
76
+
77
+ // packages/cli/src/commands/_spinner.ts
78
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
79
+ function createTtySpinner(input) {
80
+ const output = input.output ?? process.stdout;
81
+ const isTty = output.isTTY === true;
82
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
83
+ let label = input.label;
84
+ let frame = 0;
85
+ let paused = false;
86
+ let stopped = false;
87
+ let lastPrintedLabel = "";
88
+ const render = () => {
89
+ if (stopped || paused)
90
+ return;
91
+ if (!isTty) {
92
+ if (label !== lastPrintedLabel) {
93
+ output.write(`${label}
94
+ `);
95
+ lastPrintedLabel = label;
96
+ }
97
+ return;
98
+ }
99
+ frame = (frame + 1) % frames.length;
100
+ const glyph = frames[frame] ?? frames[0] ?? "";
101
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
102
+ };
103
+ const clearLine = () => {
104
+ if (isTty)
105
+ output.write("\r\x1B[2K");
106
+ };
107
+ render();
108
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
109
+ return {
110
+ setLabel(next) {
111
+ label = next;
112
+ render();
113
+ },
114
+ pause() {
115
+ paused = true;
116
+ clearLine();
117
+ },
118
+ resume() {
119
+ if (stopped)
120
+ return;
121
+ paused = false;
122
+ render();
123
+ },
124
+ stop(finalLine) {
125
+ if (stopped)
126
+ return;
127
+ stopped = true;
128
+ if (timer)
129
+ clearInterval(timer);
130
+ clearLine();
131
+ if (finalLine)
132
+ output.write(`${finalLine}
133
+ `);
134
+ }
135
+ };
136
+ }
137
+
138
+ // packages/cli/src/app/drone-ui.ts
139
+ var isTty = () => Boolean(process.stdout.isTTY);
140
+ function hairline(width = Math.min(process.stdout.columns ?? 80, 100)) {
141
+ return ink4("\u2500".repeat(Math.max(10, width)));
142
+ }
143
+ function droneIntro(title, subtitle) {
144
+ console.log("");
145
+ console.log(` ${accent("\u258D")}${bold(ink(title))}${subtitle ? ink3(` \u2014 ${subtitle}`) : ""}`);
146
+ console.log(hairline());
147
+ }
148
+ function droneOutro(text) {
149
+ console.log(hairline());
150
+ console.log(` ${accent("\u25C6")} ${ink2(text)}`);
151
+ console.log("");
152
+ }
153
+ function droneNote(message, title) {
154
+ if (title)
155
+ console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
156
+ for (const line of message.split(`
157
+ `)) {
158
+ console.log(` ${ink4("\u2502")} ${line}`);
159
+ }
160
+ }
161
+ function droneStep(text) {
162
+ console.log(` ${accent("\u203A")} ${ink(text)}`);
163
+ }
164
+ function droneInfo(text) {
165
+ console.log(` ${cyan("\xB7")} ${ink2(text)}`);
166
+ }
167
+ function droneWarn(text) {
168
+ console.log(` ${yellow("\u25B2")} ${ink2(text)}`);
169
+ }
170
+ function droneError(text) {
171
+ console.log(` ${red("\u2716")} ${ink2(text)}`);
172
+ }
173
+ function droneCancel(text) {
174
+ console.log(` ${red("\u2716")} ${ink3(text)}`);
175
+ }
176
+ function droneSpinner() {
177
+ let active = null;
178
+ return {
179
+ start(message) {
180
+ active = createTtySpinner({
181
+ label: message,
182
+ frames: MICRO_DRONE_FRAMES,
183
+ styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
184
+ });
185
+ },
186
+ stop(message) {
187
+ active?.stop(message ? ` ${accent("\u25C6")} ${ink2(message)}` : undefined);
188
+ active = null;
189
+ },
190
+ error(message) {
191
+ active?.stop(message ? ` ${red("\u2716")} ${ink2(message)}` : undefined);
192
+ active = null;
193
+ }
194
+ };
195
+ }
196
+ var SELECT_THEME = {
197
+ selectedPrefix: (text) => accent(text),
198
+ selectedText: (text) => bold(ink(text)),
199
+ description: (text) => ink3(text),
200
+ scrollInfo: (text) => ink4(text),
201
+ noMatch: (text) => ink3(text)
202
+ };
203
+ async function runMiniTui(build) {
204
+ const terminal = new ProcessTerminal;
205
+ const tui = new TUI(terminal);
206
+ let settled = false;
207
+ return await new Promise((resolve) => {
208
+ const finish = (result) => {
209
+ if (settled)
210
+ return;
211
+ settled = true;
212
+ tui.stop();
213
+ resolve(result);
214
+ };
215
+ build(tui, finish);
216
+ tui.start();
217
+ });
218
+ }
219
+ async function droneSelect(input) {
220
+ if (!isTty() || input.options.length === 0) {
221
+ return input.initialValue ?? input.options[0]?.value ?? null;
222
+ }
223
+ return runMiniTui((tui, finish) => {
224
+ tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}`));
225
+ const items = input.options.map((option) => ({
226
+ value: option.value,
227
+ label: option.label,
228
+ ...option.hint ? { description: option.hint } : {}
229
+ }));
230
+ const list = new SelectList(items, Math.min(items.length, 12), SELECT_THEME);
231
+ const initialIndex = input.initialValue ? items.findIndex((item) => item.value === input.initialValue) : -1;
232
+ if (initialIndex > 0)
233
+ list.setSelectedIndex(initialIndex);
234
+ list.onSelect = (item) => finish(item.value);
235
+ list.onCancel = () => finish(null);
236
+ tui.addChild(list);
237
+ tui.addChild(new Text(ink4(" \u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")));
238
+ tui.setFocus(list);
239
+ tui.addInputListener((data) => {
240
+ if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
241
+ finish(null);
242
+ return { consume: true };
243
+ }
244
+ return;
245
+ });
246
+ });
247
+ }
248
+ async function droneText(input) {
249
+ if (!isTty())
250
+ return input.initialValue ?? null;
251
+ return runMiniTui((tui, finish) => {
252
+ tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}${input.placeholder ? ink4(` (${input.placeholder})`) : ""}`));
253
+ const field = new Input;
254
+ if (input.initialValue)
255
+ field.setValue(input.initialValue);
256
+ field.onSubmit = (value) => finish(value);
257
+ field.onEscape = () => finish(null);
258
+ tui.addChild(field);
259
+ tui.addChild(new Text(ink4(" enter submit \xB7 esc cancel")));
260
+ tui.setFocus(field);
261
+ tui.addInputListener((data) => {
262
+ if (matchesKey(data, "ctrl+c")) {
263
+ finish(null);
264
+ return { consume: true };
265
+ }
266
+ return;
267
+ });
268
+ });
269
+ }
270
+ async function droneConfirm(input) {
271
+ const answer = await droneSelect({
272
+ message: input.message,
273
+ options: [
274
+ { value: "yes", label: "Yes" },
275
+ { value: "no", label: "No" }
276
+ ],
277
+ initialValue: input.initialValue === false ? "no" : "yes"
278
+ });
279
+ return answer === null ? null : answer === "yes";
280
+ }
281
+ export {
282
+ droneWarn,
283
+ droneText,
284
+ droneStep,
285
+ droneSpinner,
286
+ droneSelect,
287
+ droneOutro,
288
+ droneNote,
289
+ droneIntro,
290
+ droneInfo,
291
+ droneError,
292
+ droneConfirm,
293
+ droneCancel
294
+ };
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- // packages/cli/src/commands/_tui-theme.ts
2
+ // packages/cli/src/app/theme.ts
3
3
  var RIG_PALETTE = {
4
4
  ink: "#f2f3f6",
5
5
  ink2: "#aeb0ba",
@@ -114,11 +114,25 @@ function renderDroneFrame(tick) {
114
114
  }
115
115
  var DRONE_WIDTH = DRONE_ART[0].length;
116
116
  var DRONE_HEIGHT = DRONE_ART.length;
117
+ var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
118
+ function microDroneFrame(tick) {
119
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
120
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
121
+ return `(${blade})${eye}(${blade})`;
122
+ }
123
+ var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
124
+ function renderMicroDroneFrame(tick) {
125
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
126
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
127
+ return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
128
+ }
117
129
  export {
118
130
  yellow,
119
131
  statusColor,
132
+ renderMicroDroneFrame,
120
133
  renderDroneFrame,
121
134
  red,
135
+ microDroneFrame,
122
136
  ink4,
123
137
  ink3,
124
138
  ink2,
@@ -130,6 +144,7 @@ export {
130
144
  accent,
131
145
  RIG_SPINNER_FRAMES,
132
146
  RIG_PALETTE,
147
+ MICRO_DRONE_FRAMES,
133
148
  DRONE_WIDTH,
134
149
  DRONE_HEIGHT
135
150
  };
@@ -91,8 +91,79 @@ var RESUMABLE_RUN_STATUSES = new Set([
91
91
  "needs_attention"
92
92
  ]);
93
93
 
94
+ // packages/cli/src/app/theme.ts
95
+ var RIG_PALETTE = {
96
+ ink: "#f2f3f6",
97
+ ink2: "#aeb0ba",
98
+ ink3: "#6c6e79",
99
+ ink4: "#44464f",
100
+ accent: "#ccff4d",
101
+ accentDim: "#a9d63f",
102
+ cyan: "#56d8ff",
103
+ red: "#ff5d5d",
104
+ yellow: "#ffd24d"
105
+ };
106
+ function hexToRgb(hex) {
107
+ const value = hex.replace("#", "");
108
+ return [
109
+ Number.parseInt(value.slice(0, 2), 16),
110
+ Number.parseInt(value.slice(2, 4), 16),
111
+ Number.parseInt(value.slice(4, 6), 16)
112
+ ];
113
+ }
114
+ function fg(hex) {
115
+ const [r, g, b] = hexToRgb(hex);
116
+ return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
117
+ }
118
+ var ink = fg(RIG_PALETTE.ink);
119
+ var ink2 = fg(RIG_PALETTE.ink2);
120
+ var ink3 = fg(RIG_PALETTE.ink3);
121
+ var ink4 = fg(RIG_PALETTE.ink4);
122
+ var accent = fg(RIG_PALETTE.accent);
123
+ var accentDim = fg(RIG_PALETTE.accentDim);
124
+ var cyan = fg(RIG_PALETTE.cyan);
125
+ var red = fg(RIG_PALETTE.red);
126
+ var yellow = fg(RIG_PALETTE.yellow);
127
+ function bold(text) {
128
+ return `\x1B[1m${text}\x1B[22m`;
129
+ }
130
+ var DRONE_ART = [
131
+ " .-=-. .-=-. ",
132
+ " ( !!! ) ( !!! ) ",
133
+ " '-=-'._ _.'-=-' ",
134
+ " '._ _.' ",
135
+ " '=$$$$$$$=.' ",
136
+ " =$$$$$$$$$$$= ",
137
+ " $$$@@@@@@@@@@$$$ ",
138
+ " $$$@@ @@$$$ ",
139
+ " $$@ ? @$$$ ",
140
+ " $$$@ '-' @$$$ ",
141
+ " $$$@@ @@$$$ ",
142
+ " $$$@@@@@@@@@@$$$ ",
143
+ " =$$$$$$$$$$$= ",
144
+ " '=$$$$$$$=.' ",
145
+ " _.' '._ ",
146
+ " .-=-.' '.-=-. ",
147
+ " ( !!! ) ( !!! ) ",
148
+ " '-=-' '-=-' "
149
+ ];
150
+ var EYE_FRAMES = ["@", "o", "."];
151
+ var DRONE_WIDTH = DRONE_ART[0].length;
152
+ var DRONE_HEIGHT = DRONE_ART.length;
153
+ var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
154
+ function microDroneFrame(tick) {
155
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
156
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
157
+ return `(${blade})${eye}(${blade})`;
158
+ }
159
+ var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
160
+ function renderMicroDroneFrame(tick) {
161
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
162
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
163
+ return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
164
+ }
165
+
94
166
  // packages/cli/src/commands/_async-ui.ts
95
- var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
96
167
  var DONE_SYMBOL = pc.green("\u25C7");
97
168
  var FAIL_SYMBOL = pc.red("\u25A0");
98
169
  var activeUpdate = null;
@@ -126,8 +197,8 @@ async function withSpinner(label, work, options = {}) {
126
197
  const spinner = createTtySpinner({
127
198
  label,
128
199
  output,
129
- frames: CLACK_SPINNER_FRAMES,
130
- styleFrame: (frame) => pc.magenta(frame)
200
+ frames: MICRO_DRONE_FRAMES,
201
+ styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
131
202
  });
132
203
  const update = (next) => {
133
204
  lastLabel = next;
@@ -1,7 +1,88 @@
1
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
+ function droneNote(message, title) {
74
+ if (title)
75
+ console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
76
+ for (const line of message.split(`
77
+ `)) {
78
+ console.log(` ${ink4("\u2502")} ${line}`);
79
+ }
80
+ }
81
+
2
82
  // packages/cli/src/commands/_cli-format.ts
3
- import { log, note } from "@clack/prompts";
4
83
  import pc from "picocolors";
84
+ var themeDim = (value) => ink3(value);
85
+ var themeFaint = (value) => ink4(value);
5
86
  function stringField(record, key, fallback = "") {
6
87
  const value = record[key];
7
88
  return typeof value === "string" && value.trim() ? value.trim() : fallback;
@@ -30,15 +111,15 @@ function pad(value, width) {
30
111
  }
31
112
  function statusColor(status) {
32
113
  const normalized = status.toLowerCase();
33
- if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
34
- return pc.green;
114
+ if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved", "running"].includes(normalized))
115
+ return accent;
35
116
  if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
36
- return pc.red;
37
- if (["running", "reviewing", "validating", "in_progress", "in-progress", "remote"].includes(normalized))
38
- return pc.cyan;
39
- if (["ready", "open", "queued", "created", "preparing", "local", "pending"].includes(normalized))
40
- return pc.yellow;
41
- return pc.dim;
117
+ return red;
118
+ if (["reviewing", "validating", "in_progress", "in-progress", "remote", "preparing", "closing-out"].includes(normalized))
119
+ return cyan;
120
+ if (["ready", "open", "queued", "created", "local", "pending"].includes(normalized))
121
+ return yellow;
122
+ return themeDim;
42
123
  }
43
124
  function compactDate(value) {
44
125
  if (!value.trim())
@@ -87,27 +168,24 @@ function printFormattedOutput(message, options = {}) {
87
168
  console.log(message);
88
169
  return;
89
170
  }
90
- if (options.title)
91
- note(message, options.title);
92
- else
93
- log.message(message);
171
+ droneNote(message, options.title);
94
172
  }
95
173
  function formatStatusPill(status) {
96
174
  const label = status || "unknown";
97
175
  return statusColor(label)(`\u25CF ${label}`);
98
176
  }
99
177
  function formatSection(title, subtitle) {
100
- return `${pc.bold(pc.cyan("\u25C6"))} ${pc.bold(title)}${subtitle ? pc.dim(` \u2014 ${subtitle}`) : ""}`;
178
+ return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
101
179
  }
102
180
  function formatSuccessCard(title, rows = []) {
103
- const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${pc.dim("\u2502")} ${pc.dim(key.padEnd(12))} ${value}`);
181
+ const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${themeFaint("\u2502")} ${themeDim(key.padEnd(12))} ${value}`);
104
182
  return [formatSection(title), ...body].join(`
105
183
  `);
106
184
  }
107
185
  function formatNextSteps(steps) {
108
186
  if (steps.length === 0)
109
187
  return [];
110
- return [pc.bold("Next"), ...steps.map((step) => `${pc.dim("\u203A")} ${step}`)];
188
+ return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
111
189
  }
112
190
  function formatTaskList(tasks, options = {}) {
113
191
  if (options.raw)
@@ -129,8 +207,8 @@ function formatTaskList(tasks, options = {}) {
129
207
  const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
130
208
  const header = `${pc.bold(pad("TASK", idWidth))} ${pc.bold(pad("STATUS", statusWidth))} ${pc.bold("TITLE")}`;
131
209
  const body = rows.map((row) => {
132
- const labels = row.labels.length > 0 ? pc.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
133
- const source = row.source ? pc.dim(` ${row.source}`) : "";
210
+ const labels = row.labels.length > 0 ? themeDim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
211
+ const source = row.source ? themeDim(` ${row.source}`) : "";
134
212
  return [
135
213
  pc.bold(pad(truncate(row.id, idWidth), idWidth)),
136
214
  statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
@@ -178,7 +256,7 @@ function formatRunList(runs, options = {}) {
178
256
  if (runs.length === 0) {
179
257
  return [
180
258
  formatSection("Runs", "none recorded"),
181
- options.source === "server" ? pc.dim("No runs recorded on the selected Rig server.") : pc.dim("No runs recorded in .rig/runs."),
259
+ options.source === "server" ? themeDim("No runs recorded on the selected Rig server.") : themeDim("No runs recorded in .rig/runs."),
182
260
  "",
183
261
  ...formatNextSteps(["Start one: `rig task run --next`", "Check server: `rig server status`"])
184
262
  ].join(`
@@ -198,7 +276,7 @@ function formatRunList(runs, options = {}) {
198
276
  const body = rows.map((row) => [
199
277
  pc.bold(pad(truncate(row.runId, idWidth), idWidth)),
200
278
  statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
201
- `${row.title}${row.runtime ? pc.dim(` ${row.runtime}`) : ""}`
279
+ `${row.title}${row.runtime ? themeDim(` ${row.runtime}`) : ""}`
202
280
  ].join(" "));
203
281
  return [formatSection("Runs", options.source === "server" ? "selected server" : "local state"), header, ...body, "", ...formatNextSteps(["Follow live: `rig run attach <run-id> --follow`", "Details: `rig run show <run-id>`"])].join(`
204
282
  `);
@@ -272,7 +350,7 @@ function formatRunStatus(summary, options = {}) {
272
350
  const lines = [formatSection("Run status", options.source === "server" ? "selected server" : "local state")];
273
351
  lines.push("", pc.bold(`Active runs (${activeRuns.length})`));
274
352
  if (activeRuns.length === 0) {
275
- lines.push(pc.dim("No active runs."));
353
+ lines.push(themeDim("No active runs."));
276
354
  } else {
277
355
  for (const run of activeRuns) {
278
356
  lines.push(formatRunSummaryLine(run));
@@ -280,7 +358,7 @@ function formatRunStatus(summary, options = {}) {
280
358
  }
281
359
  lines.push("", pc.bold(`Recent runs (${recentRuns.length})`));
282
360
  if (recentRuns.length === 0) {
283
- lines.push(pc.dim("No recent terminal runs."));
361
+ lines.push(themeDim("No recent terminal runs."));
284
362
  } else {
285
363
  for (const run of recentRuns.slice(0, 10)) {
286
364
  lines.push(formatRunSummaryLine(run));
@@ -298,14 +376,14 @@ function formatRunSummaryLine(run) {
298
376
  const title = runTitleOf(record);
299
377
  const runtime = firstString(record, ["runtimeAdapter", "runtime", "adapter"]);
300
378
  const descriptor = [taskId, title].filter(Boolean).join(" \xB7 ");
301
- return `${pc.dim("\u2502")} ${pc.bold(runId)} ${formatStatusPill(status)} ${descriptor}${runtime ? pc.dim(` ${runtime}`) : ""}`;
379
+ return `${themeFaint("\u2502")} ${pc.bold(runId)} ${formatStatusPill(status)} ${descriptor}${runtime ? themeDim(` ${runtime}`) : ""}`;
302
380
  }
303
381
  function formatInboxList(kind, entries) {
304
382
  const title = kind === "approvals" ? "Approval inbox" : "Input inbox";
305
383
  if (entries.length === 0) {
306
384
  return [
307
385
  formatSection(title, "empty"),
308
- pc.dim(kind === "approvals" ? "No pending approvals." : "No pending user-input requests."),
386
+ themeDim(kind === "approvals" ? "No pending approvals." : "No pending user-input requests."),
309
387
  "",
310
388
  ...formatNextSteps(["Check runs: `rig run status`", "Start work: `rig task run --next`"])
311
389
  ].join(`
@@ -319,8 +397,8 @@ function formatInboxList(kind, entries) {
319
397
  const requestId = requestIdOf(record);
320
398
  const status = firstString(record, ["status", "state"], "pending");
321
399
  const prompt = firstString(record, ["prompt", "message", "reason", "title", "summary"], kind === "approvals" ? "Approval requested" : "Input requested");
322
- lines.push(`${pc.dim("\u2502")} ${pc.bold(requestId)} ${formatStatusPill(status)} ${prompt}`);
323
- lines.push(`${pc.dim("\u2502")} ${pc.dim("run ")} ${runId || "(unknown-run)"}${taskId ? pc.dim(` task ${taskId}`) : ""}`);
400
+ lines.push(`${themeFaint("\u2502")} ${pc.bold(requestId)} ${formatStatusPill(status)} ${prompt}`);
401
+ lines.push(`${themeFaint("\u2502")} ${themeDim("run ")} ${runId || "(unknown-run)"}${taskId ? themeDim(` task ${taskId}`) : ""}`);
324
402
  }
325
403
  lines.push("", ...formatNextSteps(kind === "approvals" ? ["Resolve: `rig inbox approve --run <run-id> --request <request-id> --decision approve|reject`", "Rejoin: `rig run attach <run-id> --follow`"] : ["Respond: `rig inbox respond --run <run-id> --request <request-id> --answer key=value`", "Rejoin: `rig run attach <run-id> --follow`"]));
326
404
  return lines.join(`
@@ -342,9 +420,9 @@ function formatConnectionStatus(selected, connections) {
342
420
  const target = !connection ? "not configured" : connection.kind === "remote" ? connection.baseUrl : "local";
343
421
  return [
344
422
  formatSection("Rig server", "selected for this repo"),
345
- `${pc.dim("\u2502")} ${pc.dim("selected ")} ${pc.bold(selected)}`,
346
- `${pc.dim("\u2502")} ${pc.dim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
347
- `${pc.dim("\u2502")} ${pc.dim("target ")} ${target ?? "not configured"}`,
423
+ `${themeFaint("\u2502")} ${themeDim("selected ")} ${pc.bold(selected)}`,
424
+ `${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
425
+ `${themeFaint("\u2502")} ${themeDim("target ")} ${target ?? "not configured"}`,
348
426
  "",
349
427
  ...formatNextSteps(["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
350
428
  ].join(`
@@ -311,7 +311,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
311
311
  })() : null;
312
312
  if (!response.ok) {
313
313
  const diagnostics = diagnosticMessage(payload);
314
- const detail = diagnostics ?? (text || response.statusText);
314
+ const rawDetail = diagnostics ?? (text || response.statusText);
315
+ const detail = diagnostics ? rawDetail : rawDetail.split(`
316
+ `).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
315
317
  const failure = await buildServerFailureContext(context.projectRoot, server);
316
318
  throw new CliError(`Rig server request failed (${response.status}): ${detail}
317
319
  ${failure.contextLine}`, 1, { hint: failure.hint });