@h-rig/cli 0.0.6-alpha.80 → 0.0.6-alpha.81

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 (105) hide show
  1. package/dist/bin/rig.js +17034 -11249
  2. package/dist/src/app/board.js +32 -3
  3. package/dist/src/app/drone-ui.js +1 -1
  4. package/dist/src/app/theme.js +1 -0
  5. package/dist/src/app-opentui/adapters/common.d.ts +53 -0
  6. package/dist/src/app-opentui/adapters/common.js +149 -0
  7. package/dist/src/app-opentui/adapters/doctor.d.ts +11 -0
  8. package/dist/src/app-opentui/adapters/doctor.js +780 -0
  9. package/dist/src/app-opentui/adapters/fleet.d.ts +16 -0
  10. package/dist/src/app-opentui/adapters/fleet.js +874 -0
  11. package/dist/src/app-opentui/adapters/inbox.d.ts +33 -0
  12. package/dist/src/app-opentui/adapters/inbox.js +1454 -0
  13. package/dist/src/app-opentui/adapters/init.d.ts +13 -0
  14. package/dist/src/app-opentui/adapters/init.js +2357 -0
  15. package/dist/src/app-opentui/adapters/pi-attach.d.ts +16 -0
  16. package/dist/src/app-opentui/adapters/pi-attach.js +1295 -0
  17. package/dist/src/app-opentui/adapters/run-detail.d.ts +20 -0
  18. package/dist/src/app-opentui/adapters/run-detail.js +893 -0
  19. package/dist/src/app-opentui/adapters/server.d.ts +14 -0
  20. package/dist/src/app-opentui/adapters/server.js +798 -0
  21. package/dist/src/app-opentui/adapters/tasks.d.ts +55 -0
  22. package/dist/src/app-opentui/adapters/tasks.js +3472 -0
  23. package/dist/src/app-opentui/bootstrap.d.ts +16 -0
  24. package/dist/src/app-opentui/bootstrap.js +19509 -0
  25. package/dist/src/app-opentui/drone.d.ts +12 -0
  26. package/dist/src/app-opentui/drone.js +227 -0
  27. package/dist/src/app-opentui/events.d.ts +7 -0
  28. package/dist/src/app-opentui/events.js +28 -0
  29. package/dist/src/app-opentui/index.d.ts +8 -0
  30. package/dist/src/app-opentui/index.js +3477 -0
  31. package/dist/src/app-opentui/intent.d.ts +3 -0
  32. package/dist/src/app-opentui/intent.js +211 -0
  33. package/dist/src/app-opentui/layout.d.ts +15 -0
  34. package/dist/src/app-opentui/layout.js +44 -0
  35. package/dist/src/app-opentui/list-search.d.ts +8 -0
  36. package/dist/src/app-opentui/list-search.js +43 -0
  37. package/dist/src/app-opentui/pi-host-child.d.ts +2 -0
  38. package/dist/src/app-opentui/pi-host-child.js +778 -0
  39. package/dist/src/app-opentui/pi-pty-host.d.ts +64 -0
  40. package/dist/src/app-opentui/pi-pty-host.js +384 -0
  41. package/dist/src/app-opentui/registry.d.ts +4 -0
  42. package/dist/src/app-opentui/registry.js +6835 -0
  43. package/dist/src/app-opentui/render/graphics.d.ts +39 -0
  44. package/dist/src/app-opentui/render/graphics.js +537 -0
  45. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +2 -0
  46. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +1480 -0
  47. package/dist/src/app-opentui/render/image-visual-layer-worker.d.ts +1 -0
  48. package/dist/src/app-opentui/render/image-visual-layer-worker.js +1541 -0
  49. package/dist/src/app-opentui/render/image-visual-layer.d.ts +93 -0
  50. package/dist/src/app-opentui/render/image-visual-layer.js +945 -0
  51. package/dist/src/app-opentui/render/panels.d.ts +10 -0
  52. package/dist/src/app-opentui/render/panels.js +201 -0
  53. package/dist/src/app-opentui/render/scene.d.ts +16 -0
  54. package/dist/src/app-opentui/render/scene.js +110 -0
  55. package/dist/src/app-opentui/render/text.d.ts +10 -0
  56. package/dist/src/app-opentui/render/text.js +121 -0
  57. package/dist/src/app-opentui/render/type-bar.d.ts +14 -0
  58. package/dist/src/app-opentui/render/type-bar.js +137 -0
  59. package/dist/src/app-opentui/runtime.d.ts +2 -0
  60. package/dist/src/app-opentui/runtime.js +3406 -0
  61. package/dist/src/app-opentui/scenes/doctor.d.ts +2 -0
  62. package/dist/src/app-opentui/scenes/doctor.js +91 -0
  63. package/dist/src/app-opentui/scenes/error.d.ts +2 -0
  64. package/dist/src/app-opentui/scenes/error.js +190 -0
  65. package/dist/src/app-opentui/scenes/fleet.d.ts +3 -0
  66. package/dist/src/app-opentui/scenes/fleet.js +207 -0
  67. package/dist/src/app-opentui/scenes/handoff.d.ts +2 -0
  68. package/dist/src/app-opentui/scenes/handoff.js +147 -0
  69. package/dist/src/app-opentui/scenes/help.d.ts +3 -0
  70. package/dist/src/app-opentui/scenes/help.js +138 -0
  71. package/dist/src/app-opentui/scenes/inbox.d.ts +2 -0
  72. package/dist/src/app-opentui/scenes/inbox.js +118 -0
  73. package/dist/src/app-opentui/scenes/init.d.ts +2 -0
  74. package/dist/src/app-opentui/scenes/init.js +94 -0
  75. package/dist/src/app-opentui/scenes/main.d.ts +2 -0
  76. package/dist/src/app-opentui/scenes/main.js +96 -0
  77. package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -0
  78. package/dist/src/app-opentui/scenes/run-detail.js +139 -0
  79. package/dist/src/app-opentui/scenes/server.d.ts +2 -0
  80. package/dist/src/app-opentui/scenes/server.js +88 -0
  81. package/dist/src/app-opentui/scenes/tasks.d.ts +3 -0
  82. package/dist/src/app-opentui/scenes/tasks.js +230 -0
  83. package/dist/src/app-opentui/state.d.ts +4 -0
  84. package/dist/src/app-opentui/state.js +286 -0
  85. package/dist/src/app-opentui/theme.d.ts +36 -0
  86. package/dist/src/app-opentui/theme.js +88 -0
  87. package/dist/src/app-opentui/types.d.ts +188 -0
  88. package/dist/src/app-opentui/types.js +1 -0
  89. package/dist/src/commands/_async-ui.js +1 -1
  90. package/dist/src/commands/_operator-view.js +1 -1
  91. package/dist/src/commands/_pi-frontend.js +1 -1
  92. package/dist/src/commands/_spinner.js +1 -1
  93. package/dist/src/commands/browser.js +1 -1
  94. package/dist/src/commands/doctor.js +1 -1
  95. package/dist/src/commands/github.js +1 -1
  96. package/dist/src/commands/inbox.js +1 -1
  97. package/dist/src/commands/init.js +1 -1
  98. package/dist/src/commands/inspect.js +1 -1
  99. package/dist/src/commands/run.js +1 -1
  100. package/dist/src/commands/setup.js +1 -1
  101. package/dist/src/commands/stats.js +1 -1
  102. package/dist/src/commands/task.js +1 -1
  103. package/dist/src/commands.js +33 -4
  104. package/dist/src/index.js +33 -4
  105. package/package.json +11 -8
@@ -50,6 +50,7 @@ function statusColor(status) {
50
50
  case "validating":
51
51
  case "reviewing":
52
52
  case "closing-out":
53
+ case "stopping":
53
54
  return cyan;
54
55
  case "needs-attention":
55
56
  case "needs_attention":
@@ -951,7 +952,7 @@ async function loadTaskRunProjectDefaults(projectRoot) {
951
952
 
952
953
  // packages/cli/src/app/board.ts
953
954
  var BOARD_REFRESH_MS = 5000;
954
- var BOARD_TICK_MS = 250;
955
+ var BOARD_TICK_MS = 16;
955
956
  var BOARD_TASK_PAGE = 20;
956
957
  function oneLine(message) {
957
958
  return message.split(`
@@ -974,6 +975,7 @@ function statusRank(status) {
974
975
  case "pending":
975
976
  case "preparing":
976
977
  case "adopted":
978
+ case "stopping":
977
979
  return 2;
978
980
  case "completed":
979
981
  case "merged":
@@ -1013,6 +1015,10 @@ class RunsList {
1013
1015
  selectedRun() {
1014
1016
  return this.visibleRuns()[this.selected] ?? null;
1015
1017
  }
1018
+ patchRun(runId, patch) {
1019
+ this.runs = this.runs.map((run) => run.runId === runId ? { ...run, ...patch } : run);
1020
+ this.clampSelection();
1021
+ }
1016
1022
  cycleSort() {
1017
1023
  this.sortMode = this.sortMode === "active" ? "recent" : this.sortMode === "recent" ? "status" : "active";
1018
1024
  this.clampSelection();
@@ -1235,6 +1241,14 @@ class InboxView {
1235
1241
  selectedItem() {
1236
1242
  return this.items[this.selected] ?? null;
1237
1243
  }
1244
+ patchItem(requestId, summary) {
1245
+ this.items = this.items.map((item) => item.requestId === requestId ? { ...item, summary } : item);
1246
+ }
1247
+ removeItem(requestId) {
1248
+ const previousIndex = this.selected;
1249
+ this.items = this.items.filter((item) => item.requestId !== requestId);
1250
+ this.selected = Math.max(0, Math.min(previousIndex, Math.max(0, this.items.length - 1)));
1251
+ }
1238
1252
  invalidate() {}
1239
1253
  render(width) {
1240
1254
  return this.renderLines(width).map((line) => truncateToWidth(line, Math.max(10, width - 1)));
@@ -1456,9 +1470,14 @@ async function runOperatorBoard(context, options = {}) {
1456
1470
  tui.stop();
1457
1471
  };
1458
1472
  let refreshInFlight = false;
1459
- const refresh = async () => {
1473
+ const refresh = async (options2 = {}) => {
1460
1474
  if (refreshInFlight)
1461
1475
  return;
1476
+ if (!options2.quiet) {
1477
+ notice = "refreshing fleet\u2026";
1478
+ renderFooter();
1479
+ tui.requestRender();
1480
+ }
1462
1481
  if (!hasRigProject(context.projectRoot)) {
1463
1482
  list.loading = false;
1464
1483
  list.noProject = true;
@@ -1541,6 +1560,7 @@ async function runOperatorBoard(context, options = {}) {
1541
1560
  };
1542
1561
  const resolveApproval = async (item, decision) => {
1543
1562
  notice = `${decision === "approve" ? "approving" : "rejecting"} ${item.requestId.slice(0, 12)}\u2026`;
1563
+ inboxView.patchItem(item.requestId, `${decision === "approve" ? "approving" : "rejecting"}\u2026 ${item.summary}`);
1544
1564
  renderFooter();
1545
1565
  tui.requestRender();
1546
1566
  try {
@@ -1549,8 +1569,10 @@ async function runOperatorBoard(context, options = {}) {
1549
1569
  headers: { "content-type": "application/json" },
1550
1570
  body: JSON.stringify({ runId: item.runId, requestId: item.requestId, decision, note: null })
1551
1571
  });
1572
+ inboxView.removeItem(item.requestId);
1552
1573
  notice = `${decision === "approve" ? "approved" : "rejected"} \u2014 drone resumes`;
1553
1574
  } catch (error) {
1575
+ inboxView.patchItem(item.requestId, item.summary);
1554
1576
  notice = `resolve failed: ${oneLine(error instanceof Error ? error.message : String(error))}`;
1555
1577
  }
1556
1578
  renderFooter();
@@ -1559,6 +1581,7 @@ async function runOperatorBoard(context, options = {}) {
1559
1581
  };
1560
1582
  const answerInput = async (item, text) => {
1561
1583
  notice = `answering ${item.requestId.slice(0, 12)}\u2026`;
1584
+ inboxView.patchItem(item.requestId, `answering\u2026 ${item.summary}`);
1562
1585
  renderFooter();
1563
1586
  tui.requestRender();
1564
1587
  try {
@@ -1571,8 +1594,10 @@ async function runOperatorBoard(context, options = {}) {
1571
1594
  answers: { [item.questionId ?? "response"]: text }
1572
1595
  })
1573
1596
  });
1597
+ inboxView.removeItem(item.requestId);
1574
1598
  notice = "answer sent \u2014 drone resumes";
1575
1599
  } catch (error) {
1600
+ inboxView.patchItem(item.requestId, item.summary);
1576
1601
  notice = `answer failed: ${oneLine(error instanceof Error ? error.message : String(error))}`;
1577
1602
  }
1578
1603
  renderFooter();
@@ -1721,6 +1746,7 @@ async function runOperatorBoard(context, options = {}) {
1721
1746
  const run = list.selectedRun();
1722
1747
  if (run) {
1723
1748
  notice = `stop requested for ${run.runId.slice(0, 8)}\u2026`;
1749
+ list.patchRun(run.runId, { status: "stopping" });
1724
1750
  renderFooter();
1725
1751
  tui.requestRender();
1726
1752
  stopRunViaServer(context, run.runId).then(() => refresh()).catch(() => refresh());
@@ -1728,6 +1754,9 @@ async function runOperatorBoard(context, options = {}) {
1728
1754
  return { consume: true };
1729
1755
  }
1730
1756
  if (data === "r") {
1757
+ notice = "refreshing fleet\u2026";
1758
+ renderFooter();
1759
+ tui.requestRender();
1731
1760
  refresh();
1732
1761
  return { consume: true };
1733
1762
  }
@@ -1757,7 +1786,7 @@ async function runOperatorBoard(context, options = {}) {
1757
1786
  refresh();
1758
1787
  }, BOARD_REFRESH_MS);
1759
1788
  tui.start();
1760
- refresh();
1789
+ refresh({ quiet: true });
1761
1790
  await new Promise((resolve3) => {
1762
1791
  const poll = setInterval(() => {
1763
1792
  if (stopped) {
@@ -105,7 +105,7 @@ function createTtySpinner(input) {
105
105
  output.write("\r\x1B[2K");
106
106
  };
107
107
  render();
108
- const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
108
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 16) : null;
109
109
  return {
110
110
  setLabel(next) {
111
111
  label = next;
@@ -44,6 +44,7 @@ function statusColor(status) {
44
44
  case "validating":
45
45
  case "reviewing":
46
46
  case "closing-out":
47
+ case "stopping":
47
48
  return cyan;
48
49
  case "needs-attention":
49
50
  case "needs_attention":
@@ -0,0 +1,53 @@
1
+ import type { RunnerContext } from "../../runner";
2
+ import type { AppEvent, AppIntent, AppRuntime, AppSceneId } from "../types";
3
+ export type AppStateLike = {
4
+ readonly projectRoot?: string;
5
+ readonly scene?: AppSceneId;
6
+ readonly status?: string;
7
+ readonly tick?: number;
8
+ readonly argv?: readonly string[];
9
+ readonly data?: Record<string, unknown>;
10
+ readonly footer?: Record<string, unknown>;
11
+ readonly [key: string]: unknown;
12
+ };
13
+ export type AppAdapterEvent = AppEvent;
14
+ export type AppRendererHandoff = {
15
+ readonly suspend?: () => void | Promise<void>;
16
+ readonly resume?: () => void | Promise<void>;
17
+ readonly destroy?: () => void | Promise<void>;
18
+ };
19
+ export type AppAdapterContext = {
20
+ readonly projectRoot?: string;
21
+ readonly rig?: Pick<RunnerContext, "projectRoot" | "runId" | "outputMode">;
22
+ readonly renderer?: AppRendererHandoff;
23
+ readonly ensureRuntime?: () => Promise<RunnerContext>;
24
+ emit(event: AppAdapterEvent): void;
25
+ getState(): AppStateLike;
26
+ };
27
+ export declare function adapterContextFromRuntime(runtime: AppRuntime, renderer?: AppRendererHandoff): AppAdapterContext;
28
+ export type NormalizedAppError = {
29
+ readonly message: string;
30
+ readonly hint?: string;
31
+ };
32
+ export type CapturedConsole = {
33
+ readonly result: unknown;
34
+ readonly output: readonly string[];
35
+ };
36
+ export declare function projectRootOf(ctx: AppAdapterContext): string;
37
+ export declare function runtimeOf(ctx: AppAdapterContext): Promise<RunnerContext>;
38
+ export declare function normalizeAppError(error: unknown): NormalizedAppError;
39
+ export declare function emitStarted(ctx: AppAdapterContext, label: string, optimistic?: Record<string, unknown>): void;
40
+ export declare function emitProgress(ctx: AppAdapterContext, label: string, detail?: string, data?: Record<string, unknown>): void;
41
+ export declare function emitCompleted(ctx: AppAdapterContext, label: string, data?: Record<string, unknown>): void;
42
+ export declare function emitFailed(ctx: AppAdapterContext, label: string, error: unknown, data?: Record<string, unknown>): void;
43
+ export declare function patchData(ctx: AppAdapterContext, data: Record<string, unknown>): void;
44
+ export declare function patchFooter(ctx: AppAdapterContext, footer: Record<string, unknown>): void;
45
+ export declare function captureConsole<T>(fn: () => Promise<T> | T): Promise<{
46
+ result: T;
47
+ output: readonly string[];
48
+ }>;
49
+ export declare function releaseRendererForExternalTui(ctx: AppAdapterContext): Promise<void>;
50
+ export declare function arrayFromPayload(value: unknown): Record<string, unknown>[];
51
+ export declare function stringField(record: Record<string, unknown>, keys: readonly string[], fallback?: string): string;
52
+ export declare function compactRecord(record: Record<string, unknown>, keys: readonly string[]): Record<string, unknown>;
53
+ export declare function payloadString(intent: AppIntent, key: string): string | undefined;
@@ -0,0 +1,149 @@
1
+ // @bun
2
+ // packages/cli/src/app-opentui/adapters/common.ts
3
+ function adapterContextFromRuntime(runtime, renderer) {
4
+ return {
5
+ projectRoot: runtime.getState().projectRoot,
6
+ renderer,
7
+ ensureRuntime: () => runtime.getRunnerContext(),
8
+ emit: (event) => runtime.emit(event),
9
+ getState: () => runtime.getState()
10
+ };
11
+ }
12
+ function projectRootOf(ctx) {
13
+ const root = ctx.rig?.projectRoot ?? ctx.projectRoot ?? ctx.getState().projectRoot;
14
+ if (typeof root === "string" && root.trim())
15
+ return root;
16
+ throw new Error("Rig app adapter requires a projectRoot.");
17
+ }
18
+ async function runtimeOf(ctx) {
19
+ if (ctx.rig && "runId" in ctx.rig && ctx.ensureRuntime === undefined) {
20
+ return ctx.rig;
21
+ }
22
+ if (ctx.ensureRuntime)
23
+ return ctx.ensureRuntime();
24
+ throw new Error("Rig app adapter requires ensureRuntime() before this action can run.");
25
+ }
26
+ function normalizeAppError(error) {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ const rawHint = error instanceof Error ? error.hint : undefined;
29
+ return {
30
+ message,
31
+ ...typeof rawHint === "string" && rawHint.trim() ? { hint: rawHint.trim() } : {}
32
+ };
33
+ }
34
+ function emitStarted(ctx, label, optimistic) {
35
+ ctx.emit({ type: "action.started", label, ...optimistic ? { optimistic } : {} });
36
+ }
37
+ function emitProgress(ctx, label, detail, data) {
38
+ ctx.emit({ type: "action.progress", label, ...detail ? { detail } : {}, ...data ? { data } : {} });
39
+ }
40
+ function emitCompleted(ctx, label, data) {
41
+ ctx.emit({ type: "action.completed", label, ...data ? { data } : {} });
42
+ }
43
+ function emitFailed(ctx, label, error, data) {
44
+ if (data)
45
+ patchData(ctx, data);
46
+ const normalized = normalizeAppError(error);
47
+ ctx.emit({
48
+ type: "action.failed",
49
+ label,
50
+ message: normalized.message,
51
+ ...normalized.hint ? { hint: normalized.hint } : {},
52
+ cause: error
53
+ });
54
+ }
55
+ function patchData(ctx, data) {
56
+ ctx.emit({ type: "data.patch", data });
57
+ }
58
+ function patchFooter(ctx, footer) {
59
+ ctx.emit({ type: "footer.patch", footer });
60
+ }
61
+ async function captureConsole(fn) {
62
+ const output = [];
63
+ const original = {
64
+ log: console.log,
65
+ info: console.info,
66
+ warn: console.warn,
67
+ error: console.error
68
+ };
69
+ const capture = (...parts) => {
70
+ output.push(parts.map((part) => typeof part === "string" ? part : JSON.stringify(part)).join(" "));
71
+ };
72
+ console.log = capture;
73
+ console.info = capture;
74
+ console.warn = capture;
75
+ console.error = capture;
76
+ try {
77
+ const result = await fn();
78
+ return { result, output };
79
+ } finally {
80
+ console.log = original.log;
81
+ console.info = original.info;
82
+ console.warn = original.warn;
83
+ console.error = original.error;
84
+ }
85
+ }
86
+ async function releaseRendererForExternalTui(ctx) {
87
+ const renderer = ctx.renderer;
88
+ if (!renderer)
89
+ return;
90
+ if (renderer.suspend) {
91
+ await renderer.suspend();
92
+ return;
93
+ }
94
+ if (renderer.destroy) {
95
+ await renderer.destroy();
96
+ }
97
+ }
98
+ function arrayFromPayload(value) {
99
+ if (Array.isArray(value)) {
100
+ return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
101
+ }
102
+ if (value && typeof value === "object" && !Array.isArray(value)) {
103
+ const entries = value.entries;
104
+ if (Array.isArray(entries))
105
+ return arrayFromPayload(entries);
106
+ }
107
+ return [];
108
+ }
109
+ function stringField(record, keys, fallback = "") {
110
+ for (const key of keys) {
111
+ const value = record[key];
112
+ if (typeof value === "string" && value.trim())
113
+ return value.trim();
114
+ if (typeof value === "number" && Number.isFinite(value))
115
+ return String(value);
116
+ }
117
+ return fallback;
118
+ }
119
+ function compactRecord(record, keys) {
120
+ const out = {};
121
+ for (const key of keys) {
122
+ const value = record[key];
123
+ if (value !== undefined && value !== null && value !== "")
124
+ out[key] = value;
125
+ }
126
+ return out;
127
+ }
128
+ function payloadString(intent, key) {
129
+ const value = intent.action.payload?.[key];
130
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
131
+ }
132
+ export {
133
+ stringField,
134
+ runtimeOf,
135
+ releaseRendererForExternalTui,
136
+ projectRootOf,
137
+ payloadString,
138
+ patchFooter,
139
+ patchData,
140
+ normalizeAppError,
141
+ emitStarted,
142
+ emitProgress,
143
+ emitFailed,
144
+ emitCompleted,
145
+ compactRecord,
146
+ captureConsole,
147
+ arrayFromPayload,
148
+ adapterContextFromRuntime
149
+ };
@@ -0,0 +1,11 @@
1
+ import type { AppAdapter } from "../types";
2
+ import { type AppAdapterContext } from "./common";
3
+ export declare function createDoctorAdapter(): AppAdapter;
4
+ export type AppDoctorCheck = {
5
+ readonly id: string;
6
+ readonly label: string;
7
+ readonly status: "pass" | "warn" | "fail";
8
+ readonly detail?: string;
9
+ readonly remediation?: string;
10
+ };
11
+ export declare function runDoctorChecksForApp(ctx: AppAdapterContext): Promise<AppDoctorCheck[]>;