@h-rig/cli 0.0.6-alpha.77 → 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.
@@ -342,7 +342,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
342
342
  })() : null;
343
343
  if (!response.ok) {
344
344
  const diagnostics = diagnosticMessage(payload);
345
- const detail = diagnostics ?? (text || response.statusText);
345
+ const rawDetail = diagnostics ?? (text || response.statusText);
346
+ const detail = diagnostics ? rawDetail : rawDetail.split(`
347
+ `).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
346
348
  const failure = await buildServerFailureContext(context.projectRoot, server);
347
349
  throw new CliError(`Rig server request failed (${response.status}): ${detail}
348
350
  ${failure.contextLine}`, 1, { hint: failure.hint });
@@ -361,11 +363,10 @@ var RESUMABLE_RUN_STATUSES = new Set([
361
363
  "needs_attention"
362
364
  ]);
363
365
 
364
- // packages/cli/src/commands/_cli-format.ts
365
- import { log, note } from "@clack/prompts";
366
- import pc from "picocolors";
366
+ // packages/cli/src/app/drone-ui.ts
367
+ import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
367
368
 
368
- // packages/cli/src/commands/_tui-theme.ts
369
+ // packages/cli/src/app/theme.ts
369
370
  var RIG_PALETTE = {
370
371
  ink: "#f2f3f6",
371
372
  ink2: "#aeb0ba",
@@ -398,6 +399,9 @@ var accentDim = fg(RIG_PALETTE.accentDim);
398
399
  var cyan = fg(RIG_PALETTE.cyan);
399
400
  var red = fg(RIG_PALETTE.red);
400
401
  var yellow = fg(RIG_PALETTE.yellow);
402
+ function bold(text) {
403
+ return `\x1B[1m${text}\x1B[22m`;
404
+ }
401
405
  var DRONE_ART = [
402
406
  " .-=-. .-=-. ",
403
407
  " ( !!! ) ( !!! ) ",
@@ -418,36 +422,22 @@ var DRONE_ART = [
418
422
  " ( !!! ) ( !!! ) ",
419
423
  " '-=-' '-=-' "
420
424
  ];
425
+ var EYE_FRAMES = ["@", "o", "."];
421
426
  var DRONE_WIDTH = DRONE_ART[0].length;
422
427
  var DRONE_HEIGHT = DRONE_ART.length;
423
-
424
- // packages/cli/src/commands/_cli-format.ts
425
- var themeDim = (value) => ink3(value);
426
- function shouldUseClackOutput() {
427
- return Boolean(process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
428
- }
429
- function printFormattedOutput(message, options = {}) {
430
- if (!shouldUseClackOutput()) {
431
- console.log(message);
432
- return;
433
- }
434
- if (options.title)
435
- note(message, options.title);
436
- else
437
- log.message(message);
428
+ var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
429
+ function microDroneFrame(tick) {
430
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
431
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
432
+ return `(${blade})${eye}(${blade})`;
438
433
  }
439
- function formatSection(title, subtitle) {
440
- return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
441
- }
442
- function formatNextSteps(steps) {
443
- if (steps.length === 0)
444
- return [];
445
- return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
434
+ var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
435
+ function renderMicroDroneFrame(tick) {
436
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
437
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
438
+ return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
446
439
  }
447
440
 
448
- // packages/cli/src/commands/_async-ui.ts
449
- import pc2 from "picocolors";
450
-
451
441
  // packages/cli/src/commands/_spinner.ts
452
442
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
453
443
  function createTtySpinner(input) {
@@ -509,8 +499,40 @@ function createTtySpinner(input) {
509
499
  };
510
500
  }
511
501
 
502
+ // packages/cli/src/app/drone-ui.ts
503
+ function droneNote(message, title) {
504
+ if (title)
505
+ console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
506
+ for (const line of message.split(`
507
+ `)) {
508
+ console.log(` ${ink4("\u2502")} ${line}`);
509
+ }
510
+ }
511
+
512
+ // packages/cli/src/commands/_cli-format.ts
513
+ import pc from "picocolors";
514
+ var themeDim = (value) => ink3(value);
515
+ function shouldUseClackOutput() {
516
+ return Boolean(process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
517
+ }
518
+ function printFormattedOutput(message, options = {}) {
519
+ if (!shouldUseClackOutput()) {
520
+ console.log(message);
521
+ return;
522
+ }
523
+ droneNote(message, options.title);
524
+ }
525
+ function formatSection(title, subtitle) {
526
+ return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
527
+ }
528
+ function formatNextSteps(steps) {
529
+ if (steps.length === 0)
530
+ return [];
531
+ return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
532
+ }
533
+
512
534
  // packages/cli/src/commands/_async-ui.ts
513
- var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
535
+ import pc2 from "picocolors";
514
536
  var DONE_SYMBOL = pc2.green("\u25C7");
515
537
  var FAIL_SYMBOL = pc2.red("\u25A0");
516
538
  var activeUpdate = null;
@@ -544,8 +566,8 @@ async function withSpinner(label, work, options = {}) {
544
566
  const spinner = createTtySpinner({
545
567
  label,
546
568
  output,
547
- frames: CLACK_SPINNER_FRAMES,
548
- styleFrame: (frame) => pc2.magenta(frame)
569
+ frames: MICRO_DRONE_FRAMES,
570
+ styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
549
571
  });
550
572
  const update = (next) => {
551
573
  lastLabel = next;
@@ -567,7 +589,6 @@ async function withSpinner(label, work, options = {}) {
567
589
  }
568
590
 
569
591
  // packages/cli/src/commands/_help-catalog.ts
570
- import { intro, log as log2, note as note2, outro } from "@clack/prompts";
571
592
  import pc3 from "picocolors";
572
593
  var TOP_LEVEL_SECTIONS = [
573
594
  {
@@ -870,25 +891,6 @@ var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
870
891
  function heading(title) {
871
892
  return pc3.bold(pc3.cyan(title));
872
893
  }
873
- function renderRigBanner(version) {
874
- const m = (s) => pc3.bold(pc3.magenta(s));
875
- const c = (s) => pc3.bold(pc3.cyan(s));
876
- const y = (s) => pc3.yellow(s);
877
- const d = (s) => pc3.dim(s);
878
- const lines = [
879
- m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
880
- m(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ") + d("\u2593\u2592\u2591"),
881
- c(" \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557") + d(" \u2591\u2592"),
882
- c(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551") + d(" \u2588\u2593\u2591"),
883
- y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
884
- y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
885
- "",
886
- ` ${c("\u25E2\u25E4")} ${pc3.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
887
- version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
888
- ];
889
- return lines.join(`
890
- `);
891
- }
892
894
  function commandLine(command, description) {
893
895
  const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
894
896
  return `${pc3.dim("\u2502")} ${pc3.bold(commandColumn)} ${description}`;
@@ -942,67 +944,8 @@ function renderGroupHelp(groupName) {
942
944
  const group = ALL_GROUPS.find((candidate) => candidate.name === groupName);
943
945
  return group ? renderGroup(group) : null;
944
946
  }
945
- function shouldUseClackOutput2() {
946
- return Boolean(process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
947
- }
948
- function printTopLevelHelp(state = {}) {
949
- if (!shouldUseClackOutput2()) {
950
- console.log(renderTopLevelHelp());
951
- return;
952
- }
953
- console.log(renderRigBanner(state.version));
954
- console.log("");
955
- if (state.projectInitialized === false) {
956
- intro("no rig project in this directory");
957
- note2([
958
- commandLine("rig init", "Set this repo up: config, GitHub auth, task source, server, Pi."),
959
- commandLine("rig init --yes", "Same, non-interactive, sensible defaults."),
960
- commandLine("rig doctor", "Already initialized somewhere else? Check the wiring.")
961
- ].join(`
962
- `), "Get started");
963
- outro("After init: rig task run --next puts an agent on your next task.");
964
- return;
965
- }
966
- intro(state.selectedServer ? `server: ${state.selectedServer}` : "rig");
967
- for (const section of TOP_LEVEL_SECTIONS) {
968
- note2(renderCommandBlock(section.commands), `${section.title} \u2014 ${section.subtitle}`);
969
- }
970
- log2.info("More: rig help --advanced \xB7 rig <group> --help \xB7 rig --version");
971
- note2([
972
- commandLine("--project <path>", "Use a project root instead of auto-discovery."),
973
- commandLine("--json", "Emit structured output for scripts/agents."),
974
- commandLine("--dry-run", "Print the command plan without mutating state.")
975
- ].join(`
976
- `), "Global options");
977
- outro("init \u2192 task run \u2192 attach (Pi console: watch + steer live) \u2192 inbox \u2192 merged.");
978
- }
979
947
  function printGroupHelpDocument(groupName) {
980
- const rendered = renderGroupHelp(groupName) ?? renderTopLevelHelp();
981
- if (!shouldUseClackOutput2()) {
982
- console.log(rendered);
983
- return;
984
- }
985
- const group = ALL_GROUPS.find((candidate) => candidate.name === groupName);
986
- if (!group) {
987
- printTopLevelHelp();
988
- return;
989
- }
990
- intro(`rig ${group.name}`);
991
- note2(group.summary, "Purpose");
992
- note2(group.usage.join(`
993
- `), "Usage");
994
- note2(group.commands.map((entry) => commandLine(entry.command, entry.description)).join(`
995
- `), "Commands");
996
- if (group.examples?.length)
997
- note2(group.examples.map((line) => `$ ${line}`).join(`
998
- `), "Examples");
999
- if (group.next?.length)
1000
- note2(group.next.map((line) => `\u203A ${line}`).join(`
1001
- `), "Next steps");
1002
- if (group.advanced?.length)
1003
- log2.info(group.advanced.join(`
1004
- `));
1005
- outro("Run with --json when scripts need structured output.");
948
+ console.log(renderGroupHelp(groupName) ?? renderTopLevelHelp());
1006
949
  }
1007
950
 
1008
951
  // packages/cli/src/commands/stats.ts
@@ -2,7 +2,196 @@
2
2
  // packages/cli/src/commands/task-report-bug.ts
3
3
  import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
4
4
  import { resolve as resolve3 } from "path";
5
- import * as clack from "@clack/prompts";
5
+
6
+ // packages/cli/src/app/drone-ui.ts
7
+ import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
8
+
9
+ // packages/cli/src/app/theme.ts
10
+ var RIG_PALETTE = {
11
+ ink: "#f2f3f6",
12
+ ink2: "#aeb0ba",
13
+ ink3: "#6c6e79",
14
+ ink4: "#44464f",
15
+ accent: "#ccff4d",
16
+ accentDim: "#a9d63f",
17
+ cyan: "#56d8ff",
18
+ red: "#ff5d5d",
19
+ yellow: "#ffd24d"
20
+ };
21
+ function hexToRgb(hex) {
22
+ const value = hex.replace("#", "");
23
+ return [
24
+ Number.parseInt(value.slice(0, 2), 16),
25
+ Number.parseInt(value.slice(2, 4), 16),
26
+ Number.parseInt(value.slice(4, 6), 16)
27
+ ];
28
+ }
29
+ function fg(hex) {
30
+ const [r, g, b] = hexToRgb(hex);
31
+ return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
32
+ }
33
+ var ink = fg(RIG_PALETTE.ink);
34
+ var ink2 = fg(RIG_PALETTE.ink2);
35
+ var ink3 = fg(RIG_PALETTE.ink3);
36
+ var ink4 = fg(RIG_PALETTE.ink4);
37
+ var accent = fg(RIG_PALETTE.accent);
38
+ var accentDim = fg(RIG_PALETTE.accentDim);
39
+ var cyan = fg(RIG_PALETTE.cyan);
40
+ var red = fg(RIG_PALETTE.red);
41
+ var yellow = fg(RIG_PALETTE.yellow);
42
+ function bold(text) {
43
+ return `\x1B[1m${text}\x1B[22m`;
44
+ }
45
+ var DRONE_ART = [
46
+ " .-=-. .-=-. ",
47
+ " ( !!! ) ( !!! ) ",
48
+ " '-=-'._ _.'-=-' ",
49
+ " '._ _.' ",
50
+ " '=$$$$$$$=.' ",
51
+ " =$$$$$$$$$$$= ",
52
+ " $$$@@@@@@@@@@$$$ ",
53
+ " $$$@@ @@$$$ ",
54
+ " $$@ ? @$$$ ",
55
+ " $$$@ '-' @$$$ ",
56
+ " $$$@@ @@$$$ ",
57
+ " $$$@@@@@@@@@@$$$ ",
58
+ " =$$$$$$$$$$$= ",
59
+ " '=$$$$$$$=.' ",
60
+ " _.' '._ ",
61
+ " .-=-.' '.-=-. ",
62
+ " ( !!! ) ( !!! ) ",
63
+ " '-=-' '-=-' "
64
+ ];
65
+ var EYE_FRAMES = ["@", "o", "."];
66
+ var DRONE_WIDTH = DRONE_ART[0].length;
67
+ var DRONE_HEIGHT = DRONE_ART.length;
68
+ var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
69
+ function microDroneFrame(tick) {
70
+ const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
71
+ const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
72
+ return `(${blade})${eye}(${blade})`;
73
+ }
74
+ var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
75
+
76
+ // packages/cli/src/app/drone-ui.ts
77
+ var isTty = () => Boolean(process.stdout.isTTY);
78
+ function hairline(width = Math.min(process.stdout.columns ?? 80, 100)) {
79
+ return ink4("\u2500".repeat(Math.max(10, width)));
80
+ }
81
+ function droneIntro(title, subtitle) {
82
+ console.log("");
83
+ console.log(` ${accent("\u258D")}${bold(ink(title))}${subtitle ? ink3(` \u2014 ${subtitle}`) : ""}`);
84
+ console.log(hairline());
85
+ }
86
+ function droneOutro(text) {
87
+ console.log(hairline());
88
+ console.log(` ${accent("\u25C6")} ${ink2(text)}`);
89
+ console.log("");
90
+ }
91
+ function droneNote(message, title) {
92
+ if (title)
93
+ console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
94
+ for (const line of message.split(`
95
+ `)) {
96
+ console.log(` ${ink4("\u2502")} ${line}`);
97
+ }
98
+ }
99
+ function droneStep(text) {
100
+ console.log(` ${accent("\u203A")} ${ink(text)}`);
101
+ }
102
+ function droneInfo(text) {
103
+ console.log(` ${cyan("\xB7")} ${ink2(text)}`);
104
+ }
105
+ function droneCancel(text) {
106
+ console.log(` ${red("\u2716")} ${ink3(text)}`);
107
+ }
108
+ var SELECT_THEME = {
109
+ selectedPrefix: (text) => accent(text),
110
+ selectedText: (text) => bold(ink(text)),
111
+ description: (text) => ink3(text),
112
+ scrollInfo: (text) => ink4(text),
113
+ noMatch: (text) => ink3(text)
114
+ };
115
+ async function runMiniTui(build) {
116
+ const terminal = new ProcessTerminal;
117
+ const tui = new TUI(terminal);
118
+ let settled = false;
119
+ return await new Promise((resolve) => {
120
+ const finish = (result) => {
121
+ if (settled)
122
+ return;
123
+ settled = true;
124
+ tui.stop();
125
+ resolve(result);
126
+ };
127
+ build(tui, finish);
128
+ tui.start();
129
+ });
130
+ }
131
+ async function droneSelect(input) {
132
+ if (!isTty() || input.options.length === 0) {
133
+ return input.initialValue ?? input.options[0]?.value ?? null;
134
+ }
135
+ return runMiniTui((tui, finish) => {
136
+ tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}`));
137
+ const items = input.options.map((option) => ({
138
+ value: option.value,
139
+ label: option.label,
140
+ ...option.hint ? { description: option.hint } : {}
141
+ }));
142
+ const list = new SelectList(items, Math.min(items.length, 12), SELECT_THEME);
143
+ const initialIndex = input.initialValue ? items.findIndex((item) => item.value === input.initialValue) : -1;
144
+ if (initialIndex > 0)
145
+ list.setSelectedIndex(initialIndex);
146
+ list.onSelect = (item) => finish(item.value);
147
+ list.onCancel = () => finish(null);
148
+ tui.addChild(list);
149
+ tui.addChild(new Text(ink4(" \u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")));
150
+ tui.setFocus(list);
151
+ tui.addInputListener((data) => {
152
+ if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
153
+ finish(null);
154
+ return { consume: true };
155
+ }
156
+ return;
157
+ });
158
+ });
159
+ }
160
+ async function droneText(input) {
161
+ if (!isTty())
162
+ return input.initialValue ?? null;
163
+ return runMiniTui((tui, finish) => {
164
+ tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}${input.placeholder ? ink4(` (${input.placeholder})`) : ""}`));
165
+ const field = new Input;
166
+ if (input.initialValue)
167
+ field.setValue(input.initialValue);
168
+ field.onSubmit = (value) => finish(value);
169
+ field.onEscape = () => finish(null);
170
+ tui.addChild(field);
171
+ tui.addChild(new Text(ink4(" enter submit \xB7 esc cancel")));
172
+ tui.setFocus(field);
173
+ tui.addInputListener((data) => {
174
+ if (matchesKey(data, "ctrl+c")) {
175
+ finish(null);
176
+ return { consume: true };
177
+ }
178
+ return;
179
+ });
180
+ });
181
+ }
182
+ async function droneConfirm(input) {
183
+ const answer = await droneSelect({
184
+ message: input.message,
185
+ options: [
186
+ { value: "yes", label: "Yes" },
187
+ { value: "no", label: "No" }
188
+ ],
189
+ initialValue: input.initialValue === false ? "no" : "yes"
190
+ });
191
+ return answer === null ? null : answer === "yes";
192
+ }
193
+
194
+ // packages/cli/src/commands/task-report-bug.ts
6
195
  import pc from "picocolors";
7
196
 
8
197
  // packages/cli/src/runner.ts
@@ -804,14 +993,14 @@ ${result.stdout.trim() || String(error)}`
804
993
  }
805
994
  }
806
995
  async function promptForBugReportDetails(initial) {
807
- clack.intro("rig report-bug");
808
- clack.note([
996
+ droneIntro("rig report-bug");
997
+ droneNote([
809
998
  "Creates an agent-ready issue with copied evidence files.",
810
999
  "When prompted for assets, drag screenshots/videos into the terminal and press Enter."
811
1000
  ].join(`
812
1001
  `), "Bug report wizard");
813
- clack.log.step("1/5 Incident");
814
- clack.note(bugPromptExampleText("incident"), "Input examples");
1002
+ droneStep("1/5 Incident");
1003
+ droneNote(bugPromptExampleText("incident"), "Input examples");
815
1004
  const title = await promptBugText("Bug title", initial.title, {
816
1005
  required: true,
817
1006
  placeholder: "Login page never leaves loading"
@@ -832,8 +1021,8 @@ async function promptForBugReportDetails(initial) {
832
1021
  const summary = await promptBugText("Short summary", initial.summary, {
833
1022
  placeholder: "Email field never appears after navigating from credentials."
834
1023
  });
835
- clack.log.step("2/5 Reproduction");
836
- clack.note(bugPromptExampleText("reproduction"), "Input examples");
1024
+ droneStep("2/5 Reproduction");
1025
+ droneNote(bugPromptExampleText("reproduction"), "Input examples");
837
1026
  const steps = splitPromptList(await promptBugText("Repro steps (semicolon-separated)", initial.steps.join("; "), {
838
1027
  placeholder: "Open /login; Enter qa@example.com; Press Continue"
839
1028
  }));
@@ -843,14 +1032,14 @@ async function promptForBugReportDetails(initial) {
843
1032
  const actual = await promptBugText("Actual behavior", initial.actual, {
844
1033
  placeholder: "Loading shell stays forever."
845
1034
  });
846
- clack.log.step("3/5 Evidence");
847
- clack.note(bugPromptExampleText("evidence"), "Input examples");
1035
+ droneStep("3/5 Evidence");
1036
+ droneNote(bugPromptExampleText("evidence"), "Input examples");
848
1037
  const evidence = splitPromptList(await promptBugText("Evidence notes (console/network/API; semicolon-separated)", initial.evidence.join("; "), {
849
1038
  placeholder: "Console: ChunkLoadError for credentials route; Network: /assets/app.js 404"
850
1039
  }));
851
1040
  const assets = splitDroppedAssetList(await promptBugText("Drag screenshots/videos here (Enter to skip)", initial.assets.map(formatDroppedAssetDefault).join(" "), { placeholder: "/Users/me/Desktop/login-loading.png /Users/me/Desktop/otp-flow.webm" }));
852
- clack.log.step("4/5 Routing");
853
- clack.note(bugPromptExampleText("routing"), "Input examples");
1041
+ droneStep("4/5 Routing");
1042
+ droneNote(bugPromptExampleText("routing"), "Input examples");
854
1043
  const priority = await promptBugSelect("Priority", [
855
1044
  { value: "P0", label: "P0", hint: "urgent / blocking" },
856
1045
  { value: "P1", label: "P1", hint: "high" },
@@ -864,13 +1053,13 @@ async function promptForBugReportDetails(initial) {
864
1053
  const parent = await promptBugText("Parent task or epic id (optional)", initial.parent, {
865
1054
  placeholder: "bd-auth-epic-123"
866
1055
  });
867
- clack.log.step("5/5 Browser");
868
- clack.note(bugPromptExampleText("browser"), "Input examples");
1056
+ droneStep("5/5 Browser");
1057
+ droneNote(bugPromptExampleText("browser"), "Input examples");
869
1058
  const browserRequired = await promptBugConfirm("Does this task need Rig Browser wiring?", initial.browserRequired);
870
1059
  let viewport = initial.viewport || "1440x900";
871
1060
  let profile = initial.profile;
872
1061
  if (browserRequired) {
873
- clack.note([
1062
+ droneNote([
874
1063
  "A profile is the browser state bucket: cookies, localStorage, auth session, and cache.",
875
1064
  "Use a bug-specific profile for clean login/OTP runs; use a shared profile only when saved auth matters."
876
1065
  ].join(`
@@ -878,11 +1067,11 @@ async function promptForBugReportDetails(initial) {
878
1067
  viewport = await promptBugText("Viewport", viewport, { placeholder: "1440x900" });
879
1068
  profile = await promptBugText("Rig Browser profile", initial.profile || (title ? defaultBrowserBugProfile(title) : undefined), { placeholder: "hp-next-login-loading-clean" });
880
1069
  } else {
881
- clack.log.info("Browser wiring skipped. The task will keep assets and steps, but no browser block or browser validation.");
1070
+ droneInfo("Browser wiring skipped. The task will keep assets and steps, but no browser block or browser validation.");
882
1071
  }
883
1072
  const outputRoot = initial.createBeadsTask ? initial.outputRoot : await promptBugText("Output directory", initial.outputRoot || "docs/bug-reports");
884
1073
  const overwrite = await promptBugConfirm("Overwrite if report exists?", initial.overwrite);
885
- clack.outro("Bug report input captured.");
1074
+ droneOutro("Bug report input captured.");
886
1075
  return {
887
1076
  ...initial,
888
1077
  outputRoot,
@@ -909,13 +1098,21 @@ async function promptForBugReportDetails(initial) {
909
1098
  };
910
1099
  }
911
1100
  async function promptBugText(message, defaultValue, options = {}) {
912
- const result = await clack.text({
913
- message,
914
- defaultValue: defaultValue?.trim() ? defaultValue : undefined,
915
- placeholder: options.placeholder,
916
- validate: options.required ? (value) => validateRequiredBugPromptValue(value, message) : undefined
917
- });
918
- return unwrapClackPrompt(result).trim();
1101
+ for (;; ) {
1102
+ const result = await droneText({
1103
+ message,
1104
+ ...options.placeholder ? { placeholder: options.placeholder } : {},
1105
+ ...defaultValue?.trim() ? { initialValue: defaultValue } : {}
1106
+ });
1107
+ if (result === null) {
1108
+ droneCancel("Bug report cancelled.");
1109
+ throw new CliError("Bug report cancelled by user.");
1110
+ }
1111
+ const invalid = options.required ? validateRequiredBugPromptValue(result, message) : undefined;
1112
+ if (!invalid)
1113
+ return result.trim();
1114
+ droneInfo(invalid);
1115
+ }
919
1116
  }
920
1117
  function validateRequiredBugPromptValue(value, label) {
921
1118
  return value?.trim() ? undefined : `${label} is required.`;
@@ -924,7 +1121,7 @@ function bugPromptExampleText(section, options = {}) {
924
1121
  const c = pc.createColors(options.color ?? shouldColorizeCliOutput());
925
1122
  const label = (value) => c.bold(c.cyan(value));
926
1123
  const example = (value) => c.green(value);
927
- const note2 = (value) => c.dim(value);
1124
+ const note = (value) => c.dim(value);
928
1125
  const rows = {
929
1126
  incident: [
930
1127
  ["Bug title", "Login page never leaves loading", "short user-visible failure"],
@@ -953,29 +1150,23 @@ function bugPromptExampleText(section, options = {}) {
953
1150
  ]
954
1151
  };
955
1152
  return rows[section].map(([name, value, detail]) => {
956
- const suffix = detail ? ` ${note2(`(${detail})`)}` : "";
1153
+ const suffix = detail ? ` ${note(`(${detail})`)}` : "";
957
1154
  return `${label(name)}: ${example(value)}${suffix}`;
958
1155
  }).join(`
959
1156
  `);
960
1157
  }
961
1158
  async function promptBugConfirm(message, initialValue) {
962
- const result = await clack.confirm({
963
- message,
964
- initialValue
965
- });
966
- return unwrapClackPrompt(result);
1159
+ const result = await droneConfirm({ message, initialValue });
1160
+ if (result === null) {
1161
+ droneCancel("Bug report cancelled.");
1162
+ throw new CliError("Bug report cancelled by user.");
1163
+ }
1164
+ return result;
967
1165
  }
968
1166
  async function promptBugSelect(message, options, initialValue) {
969
- const result = await clack.select({
970
- message,
971
- options,
972
- initialValue
973
- });
974
- return unwrapClackPrompt(result);
975
- }
976
- function unwrapClackPrompt(result) {
977
- if (clack.isCancel(result)) {
978
- clack.cancel("Bug report cancelled.");
1167
+ const result = await droneSelect({ message, options, initialValue });
1168
+ if (result === null) {
1169
+ droneCancel("Bug report cancelled.");
979
1170
  throw new CliError("Bug report cancelled by user.");
980
1171
  }
981
1172
  return result;
@@ -728,7 +728,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
728
728
  })() : null;
729
729
  if (!response.ok) {
730
730
  const diagnostics = diagnosticMessage(payload);
731
- const detail = diagnostics ?? (text || response.statusText);
731
+ const rawDetail = diagnostics ?? (text || response.statusText);
732
+ const detail = diagnostics ? rawDetail : rawDetail.split(`
733
+ `).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
732
734
  const failure = await buildServerFailureContext(context.projectRoot, server);
733
735
  throw new CliError(`Rig server request failed (${response.status}): ${detail}
734
736
  ${failure.contextLine}`, 1, { hint: failure.hint });