@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
@@ -0,0 +1,19 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
3
+ type BugPromptStyleOptions = {
4
+ color?: boolean;
5
+ };
6
+ export declare function executeTaskReportBug(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
7
+ export declare function promptBugText(message: string, defaultValue: string | undefined, options?: {
8
+ placeholder?: string;
9
+ required?: boolean;
10
+ }): Promise<string>;
11
+ export declare function validateRequiredBugPromptValue(value: string | undefined, label: string): string | undefined;
12
+ type BugPromptExampleSection = "incident" | "reproduction" | "evidence" | "routing" | "browser";
13
+ export declare function bugPromptExampleText(section: BugPromptExampleSection, options?: BugPromptStyleOptions): string;
14
+ export declare function promptBugConfirm(message: string, initialValue: boolean): Promise<boolean>;
15
+ export declare function formatDroppedAssetDefault(value: string): string;
16
+ export declare function splitDroppedAssetList(value: string | undefined, options?: {
17
+ splitWhitespace?: boolean;
18
+ }): string[];
19
+ export {};
@@ -2,17 +2,213 @@
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
9
198
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
10
- import { CliError } from "@rig/runtime/control-plane/errors";
199
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
11
200
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
12
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
13
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
14
201
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
15
- import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
202
+
203
+ class CliError extends RuntimeCliError {
204
+ hint;
205
+ constructor(message, exitCode = 1, options = {}) {
206
+ super(message, exitCode);
207
+ if (options.hint?.trim()) {
208
+ this.hint = options.hint.trim();
209
+ }
210
+ }
211
+ }
16
212
  function formatCommand(parts) {
17
213
  return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
18
214
  }
@@ -36,7 +232,7 @@ function takeOption(args, option) {
36
232
  if (current === option) {
37
233
  const next = args[index + 1];
38
234
  if (!next || next.startsWith("-")) {
39
- throw new CliError(`Missing value for ${option}`);
235
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
40
236
  }
41
237
  value = next;
42
238
  index += 1;
@@ -241,15 +437,15 @@ function buildBugReportMarkdown(input, browser, screenshots, assets) {
241
437
  ...input.issueId ? [
242
438
  `- Canonical task assets live under \`artifacts/${input.issueId}/bug-report/\`.`,
243
439
  `- Start with \`artifacts/${input.issueId}/bug-report/task.md\` and the files in \`artifacts/${input.issueId}/bug-report/assets/\`.`,
244
- browserRequired ? `- Run \`bun run rig task info --task ${input.issueId}\` to confirm browser wiring before debugging.` : `- Run \`bun run rig task info --task ${input.issueId}\` to confirm scope and artifact links before debugging.`
440
+ browserRequired ? `- Run \`rig task info --task ${input.issueId}\` to confirm browser wiring before debugging.` : `- Run \`rig task info --task ${input.issueId}\` to confirm scope and artifact links before debugging.`
245
441
  ] : [
246
- "- Draft-only report: convert this into a beads task before assigning it to an agent run."
442
+ "- Draft-only report: convert this into a Rig task before assigning it to an agent run."
247
443
  ],
248
444
  "",
249
445
  "## Validation",
250
446
  "",
251
447
  "```bash",
252
- ...input.issueId ? [`bun run rig task validate --task ${input.issueId}`] : [],
448
+ ...input.issueId ? [`rig task validate --task ${input.issueId}`] : [],
253
449
  ...browserRequired ? [
254
450
  "bun run app:check:browser:hp-next",
255
451
  "bun run app:e2e:browser:hp-next"
@@ -344,7 +540,7 @@ async function executeTaskReportBug(context, args) {
344
540
  const noBrowserFlag = takeFlag(pending, "--no-browser");
345
541
  pending = noBrowserFlag.rest;
346
542
  if (browserFlag.value && noBrowserFlag.value) {
347
- throw new CliError2("Pass only one of --browser or --no-browser.");
543
+ throw new CliError("Pass only one of --browser or --no-browser.", 1, { hint: "Re-run `rig task report-bug` with just one of the flags." });
348
544
  }
349
545
  const overwriteFlag = takeFlag(pending, "--overwrite");
350
546
  pending = overwriteFlag.rest;
@@ -396,7 +592,7 @@ async function executeTaskReportBug(context, args) {
396
592
  pending = outputRootResult.rest;
397
593
  const slugResult = takeOption(pending, "--slug");
398
594
  pending = slugResult.rest;
399
- requireNoExtraArgs(pending, "bun run rig report-bug [--no-prompt] [--no-beads] [--browser|--no-browser] --title <text> --url <url> [--asset <dragged-file>]");
595
+ requireNoExtraArgs(pending, "rig report-bug [--no-prompt] [--no-beads] [--browser|--no-browser] --title <text> --url <url> [--asset <dragged-file>]");
400
596
  let draft = {
401
597
  outputRoot: outputRootResult.value || "",
402
598
  title: titleResult.value,
@@ -428,7 +624,7 @@ async function executeTaskReportBug(context, args) {
428
624
  const shouldPrompt = !noPromptFlag.value;
429
625
  if (shouldPrompt) {
430
626
  if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
431
- throw new CliError2("Interactive bug reporting requires a TTY in text mode. Pass --no-prompt with flags for automation.");
627
+ throw new CliError("Interactive bug reporting requires a TTY in text mode. Pass --no-prompt with flags for automation.");
432
628
  }
433
629
  draft = await promptForBugReportDetails(draft);
434
630
  }
@@ -501,7 +697,7 @@ async function executeTaskReportBug(context, args) {
501
697
  console.log(`Evidence assets: ${result.assetDir}`);
502
698
  if (taskConfigPath) {
503
699
  console.log(`Task config: ${taskConfigPath}`);
504
- console.log(`Run: bun run rig task info --task ${issueId}`);
700
+ console.log(`Run: rig task info --task ${issueId}`);
505
701
  }
506
702
  }
507
703
  return {
@@ -532,7 +728,7 @@ function validateBugReportInputFiles(input) {
532
728
  for (const { path, label } of files.map((item) => ({ ...item, path: item.path.trim() })).filter((item) => item.path)) {
533
729
  const source = resolve3(input.projectRoot, path);
534
730
  if (!existsSync2(source)) {
535
- throw new CliError2(`${label} does not exist: ${source}`);
731
+ throw new CliError(`${label} does not exist: ${source}`, 1, { hint: "Check the path and re-run `rig task report-bug` with an existing file." });
536
732
  }
537
733
  }
538
734
  }
@@ -572,7 +768,7 @@ function createBugReportBeadsTask(monorepoRoot, input, draft) {
572
768
  const issue = tryRunBrJson(monorepoRoot, command);
573
769
  if (!issue.ok) {
574
770
  if (!isRecoverableBeadsJsonlFailure(issue.error)) {
575
- throw new CliError2(issue.error);
771
+ throw new CliError(issue.error);
576
772
  }
577
773
  return {
578
774
  issueId: generateBugReportIssueId(monorepoRoot, input.title),
@@ -583,7 +779,7 @@ function createBugReportBeadsTask(monorepoRoot, input, draft) {
583
779
  }
584
780
  const issueId = issue.value.id?.trim();
585
781
  if (!issueId) {
586
- throw new CliError2("br create did not return an issue id.");
782
+ throw new CliError("br create did not return an issue id.", 1, { hint: "Re-run `rig task report-bug`; if it persists, file the bug via your task source directly." });
587
783
  }
588
784
  return {
589
785
  issueId,
@@ -690,12 +886,12 @@ ${serializedEntry}
690
886
  }
691
887
  const insertAt = raw.lastIndexOf("}");
692
888
  if (insertAt < 0) {
693
- throw new CliError2(`Invalid task config JSON object: ${taskConfigPath}`);
889
+ throw new CliError(`Invalid task config JSON object: ${taskConfigPath}`, 1, { hint: "Fix or reset that file (it must be a JSON object), then re-run `rig task report-bug`." });
694
890
  }
695
891
  const before = raw.slice(0, insertAt).replace(/\s*$/, "");
696
892
  const after = raw.slice(insertAt + 1).trim();
697
893
  if (after) {
698
- throw new CliError2(`Invalid trailing content in task config: ${taskConfigPath}`);
894
+ throw new CliError(`Invalid trailing content in task config: ${taskConfigPath}`, 1, { hint: "Remove the trailing content so the file is a single JSON object, then retry." });
699
895
  }
700
896
  const comma = before.trim() === "{" ? "" : ",";
701
897
  writeFileSync2(taskConfigPath, `${before}${comma}
@@ -763,7 +959,7 @@ function generateBugReportIssueId(monorepoRoot, title) {
763
959
  return id;
764
960
  }
765
961
  }
766
- throw new CliError2("Could not generate a unique bug task id.");
962
+ throw new CliError("Could not generate a unique bug task id.", 1, { hint: "Re-run `rig task report-bug`; pass an explicit title to vary the generated id." });
767
963
  }
768
964
  function isRecoverableBeadsJsonlFailure(message) {
769
965
  return /Invalid JSON|missing field|JSONL is newer than DB|stale database/i.test(message);
@@ -771,7 +967,7 @@ function isRecoverableBeadsJsonlFailure(message) {
771
967
  function runBrJson(cwd, command) {
772
968
  const result = tryRunBrJson(cwd, command);
773
969
  if (!result.ok) {
774
- throw new CliError2(result.error);
970
+ throw new CliError(result.error);
775
971
  }
776
972
  return result.value;
777
973
  }
@@ -797,14 +993,14 @@ ${result.stdout.trim() || String(error)}`
797
993
  }
798
994
  }
799
995
  async function promptForBugReportDetails(initial) {
800
- clack.intro("rig report-bug");
801
- clack.note([
996
+ droneIntro("rig report-bug");
997
+ droneNote([
802
998
  "Creates an agent-ready issue with copied evidence files.",
803
999
  "When prompted for assets, drag screenshots/videos into the terminal and press Enter."
804
1000
  ].join(`
805
1001
  `), "Bug report wizard");
806
- clack.log.step("1/5 Incident");
807
- clack.note(bugPromptExampleText("incident"), "Input examples");
1002
+ droneStep("1/5 Incident");
1003
+ droneNote(bugPromptExampleText("incident"), "Input examples");
808
1004
  const title = await promptBugText("Bug title", initial.title, {
809
1005
  required: true,
810
1006
  placeholder: "Login page never leaves loading"
@@ -825,8 +1021,8 @@ async function promptForBugReportDetails(initial) {
825
1021
  const summary = await promptBugText("Short summary", initial.summary, {
826
1022
  placeholder: "Email field never appears after navigating from credentials."
827
1023
  });
828
- clack.log.step("2/5 Reproduction");
829
- clack.note(bugPromptExampleText("reproduction"), "Input examples");
1024
+ droneStep("2/5 Reproduction");
1025
+ droneNote(bugPromptExampleText("reproduction"), "Input examples");
830
1026
  const steps = splitPromptList(await promptBugText("Repro steps (semicolon-separated)", initial.steps.join("; "), {
831
1027
  placeholder: "Open /login; Enter qa@example.com; Press Continue"
832
1028
  }));
@@ -836,14 +1032,14 @@ async function promptForBugReportDetails(initial) {
836
1032
  const actual = await promptBugText("Actual behavior", initial.actual, {
837
1033
  placeholder: "Loading shell stays forever."
838
1034
  });
839
- clack.log.step("3/5 Evidence");
840
- clack.note(bugPromptExampleText("evidence"), "Input examples");
1035
+ droneStep("3/5 Evidence");
1036
+ droneNote(bugPromptExampleText("evidence"), "Input examples");
841
1037
  const evidence = splitPromptList(await promptBugText("Evidence notes (console/network/API; semicolon-separated)", initial.evidence.join("; "), {
842
1038
  placeholder: "Console: ChunkLoadError for credentials route; Network: /assets/app.js 404"
843
1039
  }));
844
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" }));
845
- clack.log.step("4/5 Routing");
846
- clack.note(bugPromptExampleText("routing"), "Input examples");
1041
+ droneStep("4/5 Routing");
1042
+ droneNote(bugPromptExampleText("routing"), "Input examples");
847
1043
  const priority = await promptBugSelect("Priority", [
848
1044
  { value: "P0", label: "P0", hint: "urgent / blocking" },
849
1045
  { value: "P1", label: "P1", hint: "high" },
@@ -857,13 +1053,13 @@ async function promptForBugReportDetails(initial) {
857
1053
  const parent = await promptBugText("Parent task or epic id (optional)", initial.parent, {
858
1054
  placeholder: "bd-auth-epic-123"
859
1055
  });
860
- clack.log.step("5/5 Browser");
861
- clack.note(bugPromptExampleText("browser"), "Input examples");
1056
+ droneStep("5/5 Browser");
1057
+ droneNote(bugPromptExampleText("browser"), "Input examples");
862
1058
  const browserRequired = await promptBugConfirm("Does this task need Rig Browser wiring?", initial.browserRequired);
863
1059
  let viewport = initial.viewport || "1440x900";
864
1060
  let profile = initial.profile;
865
1061
  if (browserRequired) {
866
- clack.note([
1062
+ droneNote([
867
1063
  "A profile is the browser state bucket: cookies, localStorage, auth session, and cache.",
868
1064
  "Use a bug-specific profile for clean login/OTP runs; use a shared profile only when saved auth matters."
869
1065
  ].join(`
@@ -871,11 +1067,11 @@ async function promptForBugReportDetails(initial) {
871
1067
  viewport = await promptBugText("Viewport", viewport, { placeholder: "1440x900" });
872
1068
  profile = await promptBugText("Rig Browser profile", initial.profile || (title ? defaultBrowserBugProfile(title) : undefined), { placeholder: "hp-next-login-loading-clean" });
873
1069
  } else {
874
- 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.");
875
1071
  }
876
1072
  const outputRoot = initial.createBeadsTask ? initial.outputRoot : await promptBugText("Output directory", initial.outputRoot || "docs/bug-reports");
877
1073
  const overwrite = await promptBugConfirm("Overwrite if report exists?", initial.overwrite);
878
- clack.outro("Bug report input captured.");
1074
+ droneOutro("Bug report input captured.");
879
1075
  return {
880
1076
  ...initial,
881
1077
  outputRoot,
@@ -902,13 +1098,21 @@ async function promptForBugReportDetails(initial) {
902
1098
  };
903
1099
  }
904
1100
  async function promptBugText(message, defaultValue, options = {}) {
905
- const result = await clack.text({
906
- message,
907
- defaultValue: defaultValue?.trim() ? defaultValue : undefined,
908
- placeholder: options.placeholder,
909
- validate: options.required ? (value) => validateRequiredBugPromptValue(value, message) : undefined
910
- });
911
- 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
+ }
912
1116
  }
913
1117
  function validateRequiredBugPromptValue(value, label) {
914
1118
  return value?.trim() ? undefined : `${label} is required.`;
@@ -917,7 +1121,7 @@ function bugPromptExampleText(section, options = {}) {
917
1121
  const c = pc.createColors(options.color ?? shouldColorizeCliOutput());
918
1122
  const label = (value) => c.bold(c.cyan(value));
919
1123
  const example = (value) => c.green(value);
920
- const note2 = (value) => c.dim(value);
1124
+ const note = (value) => c.dim(value);
921
1125
  const rows = {
922
1126
  incident: [
923
1127
  ["Bug title", "Login page never leaves loading", "short user-visible failure"],
@@ -946,30 +1150,24 @@ function bugPromptExampleText(section, options = {}) {
946
1150
  ]
947
1151
  };
948
1152
  return rows[section].map(([name, value, detail]) => {
949
- const suffix = detail ? ` ${note2(`(${detail})`)}` : "";
1153
+ const suffix = detail ? ` ${note(`(${detail})`)}` : "";
950
1154
  return `${label(name)}: ${example(value)}${suffix}`;
951
1155
  }).join(`
952
1156
  `);
953
1157
  }
954
1158
  async function promptBugConfirm(message, initialValue) {
955
- const result = await clack.confirm({
956
- message,
957
- initialValue
958
- });
959
- 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;
960
1165
  }
961
1166
  async function promptBugSelect(message, options, initialValue) {
962
- const result = await clack.select({
963
- message,
964
- options,
965
- initialValue
966
- });
967
- return unwrapClackPrompt(result);
968
- }
969
- function unwrapClackPrompt(result) {
970
- if (clack.isCancel(result)) {
971
- clack.cancel("Bug report cancelled.");
972
- throw new CliError2("Bug report cancelled by user.");
1167
+ const result = await droneSelect({ message, options, initialValue });
1168
+ if (result === null) {
1169
+ droneCancel("Bug report cancelled.");
1170
+ throw new CliError("Bug report cancelled by user.");
973
1171
  }
974
1172
  return result;
975
1173
  }
@@ -979,7 +1177,7 @@ function normalizeBugEnvironmentChoice(environment) {
979
1177
  function requireReportBugValue(value, option) {
980
1178
  const normalized = value?.trim();
981
1179
  if (!normalized) {
982
- throw new CliError2(`Missing ${option}. Run interactively or pass ${option} <value>.`);
1180
+ throw new CliError(`Missing ${option}. Run interactively or pass ${option} <value>.`);
983
1181
  }
984
1182
  return normalized;
985
1183
  }
@@ -1060,7 +1258,7 @@ function takeRepeatedOption(args, option) {
1060
1258
  if (current === option) {
1061
1259
  const next = args[index + 1];
1062
1260
  if (!next || next.startsWith("-")) {
1063
- throw new CliError2(`Missing value for ${option}`);
1261
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
1064
1262
  }
1065
1263
  values.push(next);
1066
1264
  index += 1;
@@ -0,0 +1,132 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import { updateConfiguredTaskSourceTask } from "@rig/runtime/control-plane/tasks/source-lifecycle";
3
+ import { runPrAutomation, type GitCommandRunner, type GitHubCommandRunner, type PrAutomationResult, type RigAutomationConfig } from "@rig/runtime/control-plane/native/pr-automation";
4
+ import { type SourceTaskContract } from "./_run-driver-helpers";
5
+ export type TaskRunReviewState = {
6
+ approved?: boolean;
7
+ provider?: string;
8
+ mode?: string;
9
+ verdict?: string;
10
+ local_reasons?: string[];
11
+ ai_reasons?: string[];
12
+ ai_warnings?: string[];
13
+ };
14
+ declare const PI_CANONICAL_RUN_STAGES: readonly ["Connect", "GitHub/task sync", "Prepare workspace", "Launch Pi", "Plan", "Implement", "Validate", "Commit", "Open PR", "Review/CI", "Merge", "Complete"];
15
+ export declare function canonicalPiRunStages(): string[];
16
+ export declare function buildPiRigBridgeEnv(input: {
17
+ readonly projectRoot: string;
18
+ readonly runId: string;
19
+ readonly taskId: string;
20
+ readonly serverUrl?: string | null;
21
+ readonly authToken?: string | null;
22
+ readonly githubToken?: string | null;
23
+ }): Record<string, string>;
24
+ export declare function applyDirtyBaselineSnapshot(input: {
25
+ readonly sourceRoot: string;
26
+ readonly targetRoot: string;
27
+ }): {
28
+ applied: boolean;
29
+ copiedUntracked: number;
30
+ detail: string;
31
+ };
32
+ export declare function buildTaskRunReviewEnv(config?: TaskRunAutomationConfig | null): Record<string, string>;
33
+ export declare function buildDirtyBaselineHandshakeEnv(input: {
34
+ readonly projectRoot: string;
35
+ readonly runId: string;
36
+ readonly baselineMode?: "head" | "dirty-snapshot";
37
+ }): Record<string, string>;
38
+ type TaskRunAutomationConfig = RigAutomationConfig & {
39
+ readonly github?: {
40
+ readonly issueUpdates?: "lifecycle" | "minimal" | "off";
41
+ };
42
+ readonly planning?: {
43
+ readonly mode?: "auto" | "always" | "off";
44
+ readonly requireForLabels?: readonly string[];
45
+ readonly skipForLabels?: readonly string[];
46
+ };
47
+ };
48
+ export declare function resolveTaskRunAutomationLimits(config?: TaskRunAutomationConfig | null, env?: Record<string, string | undefined>): {
49
+ maxValidationAttempts: number;
50
+ maxPrFixIterations: number;
51
+ };
52
+ export type PlanningClassification = {
53
+ readonly planningRequired: boolean;
54
+ readonly size: "small" | "medium" | "large";
55
+ readonly risk: "low" | "medium" | "high";
56
+ readonly reason: string;
57
+ readonly policy: "always" | "off" | "auto";
58
+ };
59
+ export declare function classifyPlanningNeed(input: {
60
+ readonly config?: TaskRunAutomationConfig | null;
61
+ readonly sourceTask?: SourceTaskContract | null;
62
+ }): PlanningClassification;
63
+ export declare function buildPiValidationRetrySteeringPrompt(input: {
64
+ taskId: string;
65
+ attempt: number;
66
+ maxAttempts: number;
67
+ failureDetail: string;
68
+ validationOutput?: string | null;
69
+ }): string;
70
+ export declare function classifyValidationRetryOutcome(input: {
71
+ attempt: number;
72
+ maxAttempts: number;
73
+ failureDetail: string;
74
+ }): {
75
+ stage: "Validate failed";
76
+ status: "retry" | "needs_attention";
77
+ failureDetail: string;
78
+ };
79
+ export type TaskRunStageName = typeof PI_CANONICAL_RUN_STAGES[number] | "Needs attention" | "Failed";
80
+ export declare function taskRunStageLogId(runId: string, stage: TaskRunStageName): string;
81
+ export type TaskRunPostValidationLifecycleResult = {
82
+ readonly status: "completed" | "skipped" | "needs_attention";
83
+ readonly pr?: PrAutomationResult;
84
+ };
85
+ export declare function runTaskRunPostValidationLifecycle(input: {
86
+ readonly projectRoot: string;
87
+ readonly runId: string;
88
+ readonly taskId?: string;
89
+ readonly runtimeTaskId: string;
90
+ readonly runtimeWorkspace?: string | null;
91
+ readonly branch?: string | null;
92
+ readonly config?: TaskRunAutomationConfig | null;
93
+ readonly sourceTask: SourceTaskContract | null;
94
+ readonly uploadedSnapshot?: boolean;
95
+ readonly appendStage?: (stage: TaskRunStageName, detail?: string | null, status?: string, tone?: "info" | "tool" | "error") => void;
96
+ readonly ghCommand?: GitHubCommandRunner;
97
+ readonly gitCommand?: GitCommandRunner;
98
+ readonly prAutomation?: typeof runPrAutomation;
99
+ readonly steerPi?: (message: string) => Promise<void>;
100
+ readonly updateTaskSource?: typeof updateConfiguredTaskSourceTask;
101
+ }): Promise<TaskRunPostValidationLifecycleResult>;
102
+ export declare function classifyCompletionVerificationLine(line: string): {
103
+ isCompletionLine: boolean;
104
+ isVerifierReview: boolean;
105
+ };
106
+ export declare function createRunLogIdFactory(runId: string): () => string;
107
+ export declare function summarizeTaskRunProcessFailure(input: {
108
+ exitCode: number | null;
109
+ signal: string | null;
110
+ stderrLines?: readonly string[];
111
+ }): string;
112
+ export declare function readTaskRunAcceptedArtifactState(input: {
113
+ taskId: string | null;
114
+ workspaceDir: string | null;
115
+ artifactNotBeforeMs?: number;
116
+ }): {
117
+ accepted: boolean;
118
+ reason: string | null;
119
+ };
120
+ export declare function executeRigOwnedTaskRun(context: RunnerContext, input: {
121
+ runId: string;
122
+ taskId?: string;
123
+ title?: string;
124
+ runtimeAdapter: "claude-code" | "codex" | "pi";
125
+ model?: string;
126
+ runtimeMode: string;
127
+ interactionMode: string;
128
+ initialPrompt?: string;
129
+ baselineMode?: "head" | "dirty-snapshot";
130
+ prMode?: "auto" | "ask" | "off";
131
+ }): Promise<void>;
132
+ export {};