@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
@@ -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 });