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

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 (100) hide show
  1. package/dist/bin/build-rig-binaries.js +40 -8
  2. package/dist/bin/rig.js +2807 -1443
  3. package/dist/src/app/board.js +62 -13
  4. package/dist/src/app-opentui/adapters/command.d.ts +2 -0
  5. package/dist/src/app-opentui/adapters/command.js +329 -0
  6. package/dist/src/app-opentui/adapters/common.js +2 -2
  7. package/dist/src/app-opentui/adapters/doctor.js +63 -14
  8. package/dist/src/app-opentui/adapters/fleet.js +84 -20
  9. package/dist/src/app-opentui/adapters/inbox.js +83 -19
  10. package/dist/src/app-opentui/adapters/init.js +87 -23
  11. package/dist/src/app-opentui/adapters/pi-attach.js +102 -36
  12. package/dist/src/app-opentui/adapters/run-detail.js +83 -19
  13. package/dist/src/app-opentui/adapters/server.js +100 -23
  14. package/dist/src/app-opentui/adapters/tasks.d.ts +11 -0
  15. package/dist/src/app-opentui/adapters/tasks.js +742 -94
  16. package/dist/src/app-opentui/bootstrap.d.ts +1 -6
  17. package/dist/src/app-opentui/bootstrap.js +13776 -12369
  18. package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
  19. package/dist/src/app-opentui/command-pty-host.js +248 -0
  20. package/dist/src/app-opentui/events.js +1 -1
  21. package/dist/src/app-opentui/focus-manager.d.ts +14 -0
  22. package/dist/src/app-opentui/focus-manager.js +24 -0
  23. package/dist/src/app-opentui/index.js +3806 -2878
  24. package/dist/src/app-opentui/intent.js +154 -48
  25. package/dist/src/app-opentui/keymap.d.ts +20 -0
  26. package/dist/src/app-opentui/keymap.js +707 -0
  27. package/dist/src/app-opentui/launch-routing.d.ts +16 -0
  28. package/dist/src/app-opentui/launch-routing.js +55 -0
  29. package/dist/src/app-opentui/layout.js +2 -2
  30. package/dist/src/app-opentui/pi-host-child.js +66 -16
  31. package/dist/src/app-opentui/pi-pty-host.d.ts +9 -0
  32. package/dist/src/app-opentui/pi-pty-host.js +15 -13
  33. package/dist/src/app-opentui/registry.js +3228 -2396
  34. package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
  35. package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
  36. package/dist/src/app-opentui/render/graphics.d.ts +1 -1
  37. package/dist/src/app-opentui/render/graphics.js +131 -16
  38. package/dist/src/app-opentui/render/image-visual-layer-worker.js +413 -958
  39. package/dist/src/app-opentui/render/image-visual-layer.d.ts +19 -10
  40. package/dist/src/app-opentui/render/image-visual-layer.js +391 -357
  41. package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
  42. package/dist/src/app-opentui/render/panel-layout.js +48 -0
  43. package/dist/src/app-opentui/render/panels.d.ts +2 -0
  44. package/dist/src/app-opentui/render/panels.js +62 -29
  45. package/dist/src/app-opentui/render/preloader.d.ts +10 -0
  46. package/dist/src/app-opentui/render/preloader.js +163 -0
  47. package/dist/src/app-opentui/render/scene.d.ts +3 -0
  48. package/dist/src/app-opentui/render/scene.js +12 -0
  49. package/dist/src/app-opentui/render/text.js +5 -1
  50. package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
  51. package/dist/src/app-opentui/render/type-bar.js +51 -16
  52. package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
  53. package/dist/src/app-opentui/runtime-resources.js +62 -0
  54. package/dist/src/app-opentui/runtime.js +2329 -1512
  55. package/dist/src/app-opentui/scenes/command.d.ts +3 -0
  56. package/dist/src/app-opentui/scenes/command.js +103 -0
  57. package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
  58. package/dist/src/app-opentui/scenes/doctor.js +53 -14
  59. package/dist/src/app-opentui/scenes/error.js +44 -14
  60. package/dist/src/app-opentui/scenes/fleet.js +40 -21
  61. package/dist/src/app-opentui/scenes/handoff.js +142 -27
  62. package/dist/src/app-opentui/scenes/help.js +63 -48
  63. package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
  64. package/dist/src/app-opentui/scenes/inbox.js +64 -17
  65. package/dist/src/app-opentui/scenes/init.d.ts +2 -1
  66. package/dist/src/app-opentui/scenes/init.js +62 -21
  67. package/dist/src/app-opentui/scenes/main.d.ts +2 -1
  68. package/dist/src/app-opentui/scenes/main.js +80 -24
  69. package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
  70. package/dist/src/app-opentui/scenes/run-detail.js +39 -25
  71. package/dist/src/app-opentui/scenes/server.d.ts +2 -1
  72. package/dist/src/app-opentui/scenes/server.js +71 -20
  73. package/dist/src/app-opentui/scenes/tasks.js +44 -22
  74. package/dist/src/app-opentui/state.js +70 -30
  75. package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
  76. package/dist/src/app-opentui/terminal-capabilities.js +15 -0
  77. package/dist/src/app-opentui/types.d.ts +10 -2
  78. package/dist/src/commands/_doctor-checks.js +62 -13
  79. package/dist/src/commands/_operator-view.js +63 -13
  80. package/dist/src/commands/_pi-frontend.js +63 -13
  81. package/dist/src/commands/_preflight.js +64 -14
  82. package/dist/src/commands/_server-client.js +82 -18
  83. package/dist/src/commands/_snapshot-upload.js +62 -13
  84. package/dist/src/commands/connect.js +7 -1
  85. package/dist/src/commands/doctor.js +62 -13
  86. package/dist/src/commands/github.js +144 -23
  87. package/dist/src/commands/inbox.js +62 -13
  88. package/dist/src/commands/init.js +82 -18
  89. package/dist/src/commands/inspect.js +62 -13
  90. package/dist/src/commands/run.js +66 -13
  91. package/dist/src/commands/server.js +69 -14
  92. package/dist/src/commands/setup.js +62 -13
  93. package/dist/src/commands/stats.js +62 -13
  94. package/dist/src/commands/task-run-driver.js +62 -13
  95. package/dist/src/commands/task.js +65 -14
  96. package/dist/src/commands.js +227 -92
  97. package/dist/src/index.js +234 -99
  98. package/package.json +8 -9
  99. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
  100. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1480
@@ -0,0 +1,38 @@
1
+ import type { StageLayout } from "../layout";
2
+ import type { AppScenePanel } from "../types";
3
+ export type PanelCellRect = {
4
+ readonly left: number;
5
+ readonly top: number;
6
+ readonly width: number;
7
+ readonly height: number;
8
+ readonly right: number;
9
+ readonly bottom: number;
10
+ readonly headerHeight: number;
11
+ readonly dividerY: number;
12
+ };
13
+ export type PanelContentRect = {
14
+ readonly left: number;
15
+ readonly top: number;
16
+ readonly width: number;
17
+ readonly height: number;
18
+ readonly paddingX: number;
19
+ readonly paddingY: number;
20
+ readonly contentWidth: number;
21
+ };
22
+ export type PanelPixelSize = {
23
+ readonly width: number;
24
+ readonly height: number;
25
+ };
26
+ export type PanelPixelPlacement = {
27
+ readonly left: number;
28
+ readonly top: number;
29
+ readonly width: number;
30
+ readonly height: number;
31
+ readonly leftCells: number;
32
+ readonly topCells: number;
33
+ readonly widthCells: number;
34
+ readonly heightCells: number;
35
+ };
36
+ export declare function panelCellRect(layout: StageLayout, panel: AppScenePanel): PanelCellRect | null;
37
+ export declare function panelContentRect(layout: StageLayout, panel: AppScenePanel): PanelContentRect | null;
38
+ export declare function panelPixelPlacement(layout: StageLayout, panel: AppScenePanel, size: PanelPixelSize, minPixels?: number): PanelPixelPlacement | null;
@@ -0,0 +1,48 @@
1
+ // @bun
2
+ // packages/cli/src/app-opentui/render/panel-layout.ts
3
+ function panelCellRect(layout, panel) {
4
+ const left = Math.max(0, Math.min(layout.width - 1, layout.centerLeft + (panel.left ?? 0)));
5
+ const desiredWidth = panel.width ?? layout.centerWidth;
6
+ const width = Math.max(1, Math.min(layout.width - left, desiredWidth));
7
+ const top = Math.max(0, Math.min(layout.height - 1, layout.centerTop + panel.top));
8
+ const height = Math.max(1, Math.min(layout.height - top, panel.height));
9
+ if (width <= 3 || height <= 3)
10
+ return null;
11
+ const right = left + width - 1;
12
+ const bottom = top + height - 1;
13
+ const headerHeight = panel.chrome === "ad-terminal" ? Math.max(3, Math.min(height - 2, panel.headerHeight ?? 3)) : 0;
14
+ const dividerY = headerHeight ? Math.min(bottom - 1, top + headerHeight) : top;
15
+ return { left, top, width, height, right, bottom, headerHeight, dividerY };
16
+ }
17
+ function panelContentRect(layout, panel) {
18
+ const rect = panelCellRect(layout, panel);
19
+ if (!rect)
20
+ return null;
21
+ const chromeInset = panel.chrome === "ad-terminal" ? 1 : 0;
22
+ const left = rect.left + chromeInset;
23
+ const top = rect.top + rect.headerHeight + chromeInset;
24
+ const width = Math.max(1, Math.min(layout.width - left, rect.width - chromeInset * 2));
25
+ const height = Math.max(1, Math.min(layout.height - top, rect.height - rect.headerHeight - chromeInset * 2));
26
+ const paddingX = panel.paddingX ?? (panel.chrome === "ad-terminal" ? 5 : 2);
27
+ const paddingY = panel.paddingY ?? (panel.chrome === "ad-terminal" ? 2 : 1);
28
+ const contentWidth = Math.max(1, width - paddingX * 2 - 1);
29
+ return { left, top, width, height, paddingX, paddingY, contentWidth };
30
+ }
31
+ function panelPixelPlacement(layout, panel, size, minPixels = 8) {
32
+ const cellW = size.width / layout.width;
33
+ const cellH = size.height / layout.height;
34
+ const leftCells = layout.centerLeft + (panel.left ?? 0);
35
+ const topCells = layout.centerTop + panel.top;
36
+ const widthCells = panel.width ?? layout.centerWidth;
37
+ const heightCells = panel.height;
38
+ const left = Math.round(leftCells * cellW);
39
+ const top = Math.round(topCells * cellH);
40
+ const width = Math.round(widthCells * cellW);
41
+ const height = Math.round(heightCells * cellH);
42
+ return width > minPixels && height > minPixels ? { left, top, width, height, leftCells, topCells, widthCells, heightCells } : null;
43
+ }
44
+ export {
45
+ panelPixelPlacement,
46
+ panelContentRect,
47
+ panelCellRect
48
+ };
@@ -4,6 +4,8 @@ import type { AppSceneLine, AppScenePanel } from "../types";
4
4
  import { type TextLineRenderable } from "./text";
5
5
  export type ScrollPanelRenderable = ScrollBoxRenderable & {
6
6
  __rigTextLines: TextLineRenderable[];
7
+ __rigRenderer: CliRenderer;
8
+ __rigOnLineMouseDown?: (line: AppSceneLine, event: MouseEvent) => void;
7
9
  __rigPanelId?: string;
8
10
  };
9
11
  export declare function createScrollPanelLayer(renderer: CliRenderer, id: string, onLineMouseDown?: (line: AppSceneLine, event: MouseEvent) => void): ScrollPanelRenderable;
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/cli/src/app-opentui/render/panels.ts
3
- import { RGBA, ScrollBoxRenderable } from "@opentui/core";
3
+ import { RGBA as RGBA2, ScrollBoxRenderable } from "@opentui/core";
4
4
 
5
5
  // packages/cli/src/app-opentui/theme.ts
6
6
  import {
@@ -40,8 +40,39 @@ var styles = {
40
40
  magenta: otuiFg(RIG_UI.magenta)
41
41
  };
42
42
 
43
+ // packages/cli/src/app-opentui/render/panel-layout.ts
44
+ function panelCellRect(layout, panel) {
45
+ const left = Math.max(0, Math.min(layout.width - 1, layout.centerLeft + (panel.left ?? 0)));
46
+ const desiredWidth = panel.width ?? layout.centerWidth;
47
+ const width = Math.max(1, Math.min(layout.width - left, desiredWidth));
48
+ const top = Math.max(0, Math.min(layout.height - 1, layout.centerTop + panel.top));
49
+ const height = Math.max(1, Math.min(layout.height - top, panel.height));
50
+ if (width <= 3 || height <= 3)
51
+ return null;
52
+ const right = left + width - 1;
53
+ const bottom = top + height - 1;
54
+ const headerHeight = panel.chrome === "ad-terminal" ? Math.max(3, Math.min(height - 2, panel.headerHeight ?? 3)) : 0;
55
+ const dividerY = headerHeight ? Math.min(bottom - 1, top + headerHeight) : top;
56
+ return { left, top, width, height, right, bottom, headerHeight, dividerY };
57
+ }
58
+ function panelContentRect(layout, panel) {
59
+ const rect = panelCellRect(layout, panel);
60
+ if (!rect)
61
+ return null;
62
+ const chromeInset = panel.chrome === "ad-terminal" ? 1 : 0;
63
+ const left = rect.left + chromeInset;
64
+ const top = rect.top + rect.headerHeight + chromeInset;
65
+ const width = Math.max(1, Math.min(layout.width - left, rect.width - chromeInset * 2));
66
+ const height = Math.max(1, Math.min(layout.height - top, rect.height - rect.headerHeight - chromeInset * 2));
67
+ const paddingX = panel.paddingX ?? (panel.chrome === "ad-terminal" ? 5 : 2);
68
+ const paddingY = panel.paddingY ?? (panel.chrome === "ad-terminal" ? 2 : 1);
69
+ const contentWidth = Math.max(1, width - paddingX * 2 - 1);
70
+ return { left, top, width, height, paddingX, paddingY, contentWidth };
71
+ }
72
+
43
73
  // packages/cli/src/app-opentui/render/text.ts
44
- import { TextAttributes as TextAttributes2, TextRenderable } from "@opentui/core";
74
+ import { RGBA, TextAttributes as TextAttributes2, TextRenderable } from "@opentui/core";
75
+ var TRANSPARENT = RGBA.fromInts(0, 0, 0, 0);
45
76
  function selectableMouseHandler(currentLineRef, onLineMouseDown) {
46
77
  return (event) => {
47
78
  const currentLine = currentLineRef();
@@ -74,25 +105,26 @@ function applyFlowTextLine(renderable, line, width) {
74
105
  renderable.width = Math.max(1, width);
75
106
  renderable.content = line?.styledText ?? line?.text ?? "";
76
107
  renderable.fg = line?.fg ?? RIG_UI.ink2;
108
+ renderable.bg = line?.bg ?? TRANSPARENT;
77
109
  renderable.attributes = line?.bold ? TextAttributes2.BOLD : line?.dim ? TextAttributes2.DIM : 0;
78
110
  }
79
111
 
80
112
  // packages/cli/src/app-opentui/render/panels.ts
81
- var TRANSPARENT = RGBA.fromInts(0, 0, 0, 0);
113
+ var TRANSPARENT2 = RGBA2.fromInts(0, 0, 0, 0);
82
114
  var MAX_PANEL_LINES = 420;
83
115
  function hexToRgba(hex, alpha) {
84
116
  const clean = hex.replace(/^#/, "");
85
117
  const full = clean.length === 3 ? clean.split("").map((part) => `${part}${part}`).join("") : clean;
86
118
  const value = Number.parseInt(full, 16);
87
119
  if (!Number.isFinite(value))
88
- return RGBA.fromInts(14, 15, 17, alpha);
89
- return RGBA.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
120
+ return RGBA2.fromInts(14, 15, 17, alpha);
121
+ return RGBA2.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
90
122
  }
91
123
  function panelBackground(panel) {
92
124
  return hexToRgba(panel.backgroundColor ?? RIG_UI.panel, panel.backgroundAlpha ?? 184);
93
125
  }
94
126
  function panelBorder(panel) {
95
- return panel.borderColor ? hexToRgba(panel.borderColor, panel.borderAlpha ?? 54) : TRANSPARENT;
127
+ return panel.borderColor ? hexToRgba(panel.borderColor, panel.borderAlpha ?? 54) : TRANSPARENT2;
96
128
  }
97
129
  function createScrollPanelLayer(renderer, id, onLineMouseDown) {
98
130
  const panel = new ScrollBoxRenderable(renderer, {
@@ -102,7 +134,7 @@ function createScrollPanelLayer(renderer, id, onLineMouseDown) {
102
134
  top: -2,
103
135
  width: 1,
104
136
  height: 1,
105
- backgroundColor: TRANSPARENT,
137
+ backgroundColor: TRANSPARENT2,
106
138
  border: false,
107
139
  shouldFill: true,
108
140
  opacity: 1,
@@ -118,7 +150,7 @@ function createScrollPanelLayer(renderer, id, onLineMouseDown) {
118
150
  visible: false,
119
151
  width: 1,
120
152
  trackOptions: {
121
- backgroundColor: TRANSPARENT,
153
+ backgroundColor: TRANSPARENT2,
122
154
  foregroundColor: hexToRgba(RIG_UI.ink4, 84)
123
155
  }
124
156
  },
@@ -126,18 +158,24 @@ function createScrollPanelLayer(renderer, id, onLineMouseDown) {
126
158
  height: 0,
127
159
  visible: false,
128
160
  trackOptions: {
129
- backgroundColor: TRANSPARENT,
130
- foregroundColor: TRANSPARENT
161
+ backgroundColor: TRANSPARENT2,
162
+ foregroundColor: TRANSPARENT2
131
163
  }
132
164
  }
133
165
  });
134
166
  panel.__rigTextLines = [];
135
- for (let index = 0;index < MAX_PANEL_LINES; index += 1) {
136
- const line = createFlowTextLine(renderer, `${id}-line-${index}`, onLineMouseDown);
167
+ panel.__rigRenderer = renderer;
168
+ panel.__rigOnLineMouseDown = onLineMouseDown;
169
+ return panel;
170
+ }
171
+ function ensurePanelLineCount(panel, desiredCount) {
172
+ const target = Math.min(MAX_PANEL_LINES, Math.max(0, desiredCount));
173
+ while (panel.__rigTextLines.length < target) {
174
+ const index = panel.__rigTextLines.length;
175
+ const line = createFlowTextLine(panel.__rigRenderer, `${panel.id}-line-${index}`, panel.__rigOnLineMouseDown);
137
176
  panel.__rigTextLines.push(line);
138
177
  panel.add(line);
139
178
  }
140
- return panel;
141
179
  }
142
180
  function hidePanel(panel) {
143
181
  panel.visible = false;
@@ -145,7 +183,7 @@ function hidePanel(panel) {
145
183
  panel.left = 0;
146
184
  panel.width = 1;
147
185
  panel.height = 1;
148
- panel.backgroundColor = TRANSPARENT;
186
+ panel.backgroundColor = TRANSPARENT2;
149
187
  panel.border = false;
150
188
  panel.__rigPanelId = undefined;
151
189
  panel.__rigTextLines.forEach((line) => applyFlowTextLine(line, undefined, 1));
@@ -157,19 +195,12 @@ function applyScrollPanels(panels, layout, scenePanels) {
157
195
  hidePanel(renderable);
158
196
  return;
159
197
  }
160
- const cardLeft = Math.max(0, Math.min(layout.width - 1, layout.centerLeft + (panel.left ?? 0)));
161
- const desiredWidth = panel.width ?? layout.centerWidth;
162
- const cardWidth = Math.max(1, Math.min(layout.width - cardLeft, desiredWidth));
163
- const cardTop = Math.max(0, Math.min(layout.height - 1, layout.centerTop + panel.top));
164
- const cardHeight = Math.max(1, Math.min(layout.height - cardTop, panel.height));
165
- const headerHeight = panel.chrome === "ad-terminal" ? Math.max(3, Math.min(cardHeight - 2, panel.headerHeight ?? 3)) : 0;
166
- const left = cardLeft + (panel.chrome === "ad-terminal" ? 1 : 0);
167
- const top = cardTop + headerHeight + (panel.chrome === "ad-terminal" ? 1 : 0);
168
- const width = Math.max(1, Math.min(layout.width - left, cardWidth - (panel.chrome === "ad-terminal" ? 2 : 0)));
169
- const height = Math.max(1, Math.min(layout.height - top, cardHeight - headerHeight - (panel.chrome === "ad-terminal" ? 2 : 0)));
170
- const paddingX = panel.paddingX ?? (panel.chrome === "ad-terminal" ? 5 : 2);
171
- const paddingY = panel.paddingY ?? (panel.chrome === "ad-terminal" ? 2 : 1);
172
- const contentWidth = Math.max(1, width - paddingX * 2 - 1);
198
+ const contentRect = panelContentRect(layout, panel);
199
+ if (!contentRect) {
200
+ hidePanel(renderable);
201
+ return;
202
+ }
203
+ const { left, top, width, height, paddingX, paddingY, contentWidth } = contentRect;
173
204
  renderable.visible = true;
174
205
  renderable.left = left;
175
206
  renderable.top = top;
@@ -177,7 +208,7 @@ function applyScrollPanels(panels, layout, scenePanels) {
177
208
  renderable.height = height;
178
209
  renderable.zIndex = panel.zIndex ?? 6;
179
210
  renderable.opacity = panel.opacity ?? 1;
180
- renderable.backgroundColor = panel.chrome === "ad-terminal" ? TRANSPARENT : panelBackground(panel);
211
+ renderable.backgroundColor = panel.chrome === "ad-terminal" ? TRANSPARENT2 : panelBackground(panel);
181
212
  renderable.border = panel.chrome === "ad-terminal" ? false : panel.border ?? false;
182
213
  renderable.borderColor = panelBorder(panel);
183
214
  renderable.paddingX = paddingX;
@@ -190,8 +221,10 @@ function applyScrollPanels(panels, layout, scenePanels) {
190
221
  renderable.__rigPanelId = panel.id;
191
222
  renderable.scrollTo(0);
192
223
  }
224
+ const lineCount = Math.min(panel.lines.length, MAX_PANEL_LINES);
225
+ ensurePanelLineCount(renderable, lineCount);
193
226
  renderable.__rigTextLines.forEach((line, lineIndex) => {
194
- applyFlowTextLine(line, panel.lines[lineIndex], contentWidth);
227
+ applyFlowTextLine(line, lineIndex < lineCount ? panel.lines[lineIndex] : undefined, contentWidth);
195
228
  });
196
229
  });
197
230
  }
@@ -0,0 +1,10 @@
1
+ import type { StageLayout } from "../layout";
2
+ import type { AppSceneFrame, AppSceneId } from "../types";
3
+ export type PreloaderTransitionState = {
4
+ scene: AppSceneId | null;
5
+ startedAtMs: number;
6
+ minUntilMs: number;
7
+ };
8
+ export declare function maybeStartPreloaderTransition(transition: PreloaderTransitionState, scene: AppSceneId, now?: number): void;
9
+ export declare function isPreloaderActive(transition: PreloaderTransitionState, targetReady: boolean, now?: number): boolean;
10
+ export declare function renderAsciiPreloaderFrame(scene: AppSceneId, layout: StageLayout, tick: number): AppSceneFrame;
@@ -0,0 +1,163 @@
1
+ // @bun
2
+ // packages/cli/src/app-opentui/theme.ts
3
+ import {
4
+ bold as otuiBold,
5
+ dim as otuiDim,
6
+ fg as otuiFg,
7
+ t,
8
+ TextAttributes
9
+ } from "@opentui/core";
10
+ var RIG_UI = {
11
+ bg: "#070809",
12
+ bg2: "#0b0c0e",
13
+ panel: "#101115",
14
+ panel2: "#101115",
15
+ glass: "#14161b",
16
+ ink: "#f2f3f6",
17
+ ink2: "#aeb0ba",
18
+ ink3: "#6c6e79",
19
+ ink4: "#44464f",
20
+ lime: "#ccff4d",
21
+ limeDim: "#a9d63f",
22
+ cyan: "#56d8ff",
23
+ red: "#ff5d5d",
24
+ yellow: "#ffd24d",
25
+ magenta: "#ff79b0"
26
+ };
27
+ var styles = {
28
+ ink: otuiFg(RIG_UI.ink),
29
+ ink2: otuiFg(RIG_UI.ink2),
30
+ ink3: otuiFg(RIG_UI.ink3),
31
+ ink4: otuiFg(RIG_UI.ink4),
32
+ lime: otuiFg(RIG_UI.lime),
33
+ limeDim: otuiFg(RIG_UI.limeDim),
34
+ cyan: otuiFg(RIG_UI.cyan),
35
+ red: otuiFg(RIG_UI.red),
36
+ yellow: otuiFg(RIG_UI.yellow),
37
+ magenta: otuiFg(RIG_UI.magenta)
38
+ };
39
+
40
+ // packages/cli/src/app-opentui/render/ascii-fleet.ts
41
+ var LEAD_DRONE = [
42
+ " .-=-. .-=-. ",
43
+ " ( !!! ) ( !!! ) ",
44
+ " '-=-'._ _.'-=-' ",
45
+ " '._ _.' ",
46
+ " '=$$$$$$$=.' ",
47
+ " =$$$$$$$$$$$= ",
48
+ " $$$@@@@@@@@@@$$$ ",
49
+ " $$$@@ @@$$$ ",
50
+ " $$@ ? @$$$ ",
51
+ " $$$@ '-' @$$$ ",
52
+ " $$$@@ @@$$$ ",
53
+ " $$$@@@@@@@@@@$$$ ",
54
+ " =$$$$$$$$$$$= ",
55
+ " '=$$$$$$$=.' ",
56
+ " _.' '._ ",
57
+ " .-=-.' '.-=-. ",
58
+ " ( !!! ) ( !!! ) ",
59
+ " '-=-' '-=-' "
60
+ ];
61
+ var MINI_DRONE = [
62
+ "(!!!) (!!!)",
63
+ " \\%==%/ ",
64
+ " %%?%% ",
65
+ " /%==%\\ ",
66
+ "(!!!) (!!!)"
67
+ ];
68
+ var ROTORS = ["---", "\\\\\\", "|||", "///"];
69
+ var FLEET_GRID_WIDTH = 52;
70
+ var FLEET_GRID_HEIGHT = 27;
71
+ var FLEET = [
72
+ { art: MINI_DRONE, x: 0, y: 2, amp: 1, speed: 0.05, phase: 0, dx: 1, driftSpeed: 0.02 },
73
+ { art: MINI_DRONE, x: 39, y: 2, amp: 1, speed: 0.044, phase: 2.1, dx: 1, driftSpeed: 0.017 },
74
+ { art: MINI_DRONE, x: 1, y: 20, amp: 1, speed: 0.048, phase: 4.2, dx: 1, driftSpeed: 0.023 },
75
+ { art: MINI_DRONE, x: 38, y: 20, amp: 1, speed: 0.041, phase: 1.3, dx: 1, driftSpeed: 0.015 },
76
+ { art: LEAD_DRONE, x: 10, y: 5, amp: 2, speed: 0.04, phase: 0, dx: 0, driftSpeed: 0.011 }
77
+ ];
78
+ function fleetRows(tick, options = {}) {
79
+ const animate = options.animate ?? true;
80
+ const t2 = animate ? tick : 0;
81
+ const blade = ROTORS[Math.floor(t2 / 4) % ROTORS.length];
82
+ const pulse = Math.sin(t2 * 0.07);
83
+ const eye = pulse > 0.45 ? "@" : pulse > -0.1 ? "o" : ".";
84
+ const grid = Array.from({ length: FLEET_GRID_HEIGHT }, () => Array.from({ length: FLEET_GRID_WIDTH }, () => " "));
85
+ for (const drone of FLEET) {
86
+ const yOffset = drone.y + Math.round(drone.amp * Math.sin(t2 * drone.speed + drone.phase));
87
+ const xOffset = drone.x + Math.round(drone.dx * Math.sin(t2 * drone.driftSpeed + drone.phase));
88
+ for (let row = 0;row < drone.art.length; row += 1) {
89
+ const source = drone.art[row];
90
+ const targetY = yOffset + row;
91
+ if (targetY < 0 || targetY >= FLEET_GRID_HEIGHT)
92
+ continue;
93
+ for (let col = 0;col < source.length; col += 1) {
94
+ let char = source[col];
95
+ if (char === " ")
96
+ continue;
97
+ const targetX = xOffset + col;
98
+ if (targetX < 0 || targetX >= FLEET_GRID_WIDTH)
99
+ continue;
100
+ if (source.slice(col, col + 3) === "!!!") {
101
+ for (let rotorIndex = 0;rotorIndex < 3; rotorIndex += 1) {
102
+ if (targetX + rotorIndex < FLEET_GRID_WIDTH)
103
+ grid[targetY][targetX + rotorIndex] = blade[rotorIndex];
104
+ }
105
+ col += 2;
106
+ continue;
107
+ }
108
+ if (char === "?")
109
+ char = eye;
110
+ grid[targetY][targetX] = char;
111
+ }
112
+ }
113
+ }
114
+ return grid.map((row) => row.join("").replace(/\s+$/, ""));
115
+ }
116
+
117
+ // packages/cli/src/app-opentui/render/preloader.ts
118
+ var PRELOADER_MIN_DURATION_MS = 520;
119
+ var PRELOADER_MAX_DURATION_MS = 5000;
120
+ function maybeStartPreloaderTransition(transition, scene, now = Date.now()) {
121
+ if (transition.scene === scene)
122
+ return;
123
+ transition.scene = scene;
124
+ transition.startedAtMs = now;
125
+ transition.minUntilMs = now + PRELOADER_MIN_DURATION_MS;
126
+ }
127
+ function isPreloaderActive(transition, targetReady, now = Date.now()) {
128
+ if (now < transition.minUntilMs)
129
+ return true;
130
+ if (!targetReady && now - transition.startedAtMs < PRELOADER_MAX_DURATION_MS)
131
+ return true;
132
+ return false;
133
+ }
134
+ function preloaderLine(line, options = {}) {
135
+ return { text: line, bg: RIG_UI.bg, ...options };
136
+ }
137
+ function blockLine(text, leftPad, fg) {
138
+ return preloaderLine(`${" ".repeat(Math.max(0, leftPad))}${text.padEnd(FLEET_GRID_WIDTH)}`, { fg });
139
+ }
140
+ function renderAsciiPreloaderFrame(scene, layout, tick) {
141
+ const sprite = fleetRows(tick);
142
+ const leftPad = Math.max(0, Math.floor((layout.width - FLEET_GRID_WIDTH) / 2));
143
+ const blank = () => preloaderLine("");
144
+ const body = [
145
+ ...sprite.map((text, index) => blockLine(text, leftPad, index >= 7 && index <= 18 ? RIG_UI.lime : RIG_UI.limeDim))
146
+ ];
147
+ const topPadding = Math.max(0, Math.floor((layout.height - body.length) / 2));
148
+ const bottomPadding = Math.max(0, layout.height - body.length - topPadding);
149
+ return {
150
+ scene,
151
+ title: "Preloader",
152
+ lines: [...Array.from({ length: topPadding }, blank), ...body, ...Array.from({ length: bottomPadding }, blank)],
153
+ live: true,
154
+ fullScreen: true,
155
+ hideTypeBar: true,
156
+ footer: { message: "" }
157
+ };
158
+ }
159
+ export {
160
+ renderAsciiPreloaderFrame,
161
+ maybeStartPreloaderTransition,
162
+ isPreloaderActive
163
+ };
@@ -11,6 +11,9 @@ export declare function deckRow(input: {
11
11
  readonly activateOnClick?: boolean;
12
12
  }): AppSceneLine;
13
13
  export declare function kv(label: string, value: string, fg?: string): AppSceneLine;
14
+ export declare function loadingLine(message?: string): AppSceneLine;
15
+ export declare function emptyLine(message?: string): AppSceneLine;
16
+ export declare function errorLine(message: string): AppSceneLine;
14
17
  export declare function fitSceneLine(input: AppSceneLine, layout: StageLayout): AppSceneLine;
15
18
  export declare function fitSceneLines(lines: readonly AppSceneLine[], layout: StageLayout): AppSceneLine[];
16
19
  export declare function makeSceneFrame(input: AppSceneFrame): AppSceneFrame;
@@ -85,6 +85,15 @@ function deckRow(input) {
85
85
  function kv(label, value, fg = RIG_UI.ink2) {
86
86
  return line(` ${label.toUpperCase().padEnd(10)} ${value}`, { fg });
87
87
  }
88
+ function loadingLine(message = "loading") {
89
+ return line(` \u27F2 ${message}`, { fg: RIG_UI.limeDim });
90
+ }
91
+ function emptyLine(message = "nothing here yet") {
92
+ return line(` ${message}`, { fg: RIG_UI.ink4 });
93
+ }
94
+ function errorLine(message) {
95
+ return line(` ! ${message}`, { fg: RIG_UI.magenta, bold: true });
96
+ }
88
97
  function fitSceneLine(input, layout) {
89
98
  const fitted = truncateText(input.text, layout.centerWidth);
90
99
  return {
@@ -100,10 +109,13 @@ function makeSceneFrame(input) {
100
109
  }
101
110
  export {
102
111
  makeSceneFrame,
112
+ loadingLine,
103
113
  line,
104
114
  kv,
105
115
  fitSceneLines,
106
116
  fitSceneLine,
117
+ errorLine,
118
+ emptyLine,
107
119
  deckRow,
108
120
  center,
109
121
  blank
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/cli/src/app-opentui/render/text.ts
3
- import { TextAttributes as TextAttributes2, TextRenderable } from "@opentui/core";
3
+ import { RGBA, TextAttributes as TextAttributes2, TextRenderable } from "@opentui/core";
4
4
 
5
5
  // packages/cli/src/app-opentui/theme.ts
6
6
  import {
@@ -41,6 +41,7 @@ var styles = {
41
41
  };
42
42
 
43
43
  // packages/cli/src/app-opentui/render/text.ts
44
+ var TRANSPARENT = RGBA.fromInts(0, 0, 0, 0);
44
45
  function selectableMouseHandler(currentLineRef, onLineMouseDown) {
45
46
  return (event) => {
46
47
  const currentLine = currentLineRef();
@@ -91,6 +92,7 @@ function applyTextLine(renderable, line, top, left, width) {
91
92
  renderable.width = width;
92
93
  renderable.content = line?.styledText ?? line?.text ?? "";
93
94
  renderable.fg = line?.fg ?? RIG_UI.ink2;
95
+ renderable.bg = line?.bg ?? TRANSPARENT;
94
96
  renderable.attributes = line?.bold ? TextAttributes2.BOLD : line?.dim ? TextAttributes2.DIM : 0;
95
97
  }
96
98
  function applyFlowTextLine(renderable, line, width) {
@@ -100,6 +102,7 @@ function applyFlowTextLine(renderable, line, width) {
100
102
  renderable.width = Math.max(1, width);
101
103
  renderable.content = line?.styledText ?? line?.text ?? "";
102
104
  renderable.fg = line?.fg ?? RIG_UI.ink2;
105
+ renderable.bg = line?.bg ?? TRANSPARENT;
103
106
  renderable.attributes = line?.bold ? TextAttributes2.BOLD : line?.dim ? TextAttributes2.DIM : 0;
104
107
  }
105
108
  function clearTextLines(renderables, from = 0) {
@@ -110,6 +113,7 @@ function clearTextLines(renderables, from = 0) {
110
113
  renderable.top = -1;
111
114
  renderable.left = 0;
112
115
  renderable.width = 1;
116
+ renderable.bg = TRANSPARENT;
113
117
  }
114
118
  }
115
119
  export {
@@ -1,6 +1,7 @@
1
- import { InputRenderable, TextRenderable, type CliRenderer } from "@opentui/core";
1
+ import { BoxRenderable, InputRenderable, TextRenderable, type CliRenderer } from "@opentui/core";
2
2
  import type { AppFooterState, AppTypeBarState } from "../types";
3
3
  export type TypeBarRenderables = {
4
+ readonly background: BoxRenderable;
4
5
  readonly input: InputRenderable;
5
6
  readonly prefix: TextRenderable;
6
7
  readonly footer: TextRenderable;
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/cli/src/app-opentui/render/type-bar.ts
3
- import { InputRenderable, InputRenderableEvents, TextRenderable } from "@opentui/core";
3
+ import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA, TextRenderable } from "@opentui/core";
4
4
 
5
5
  // packages/cli/src/app-opentui/theme.ts
6
6
  import {
@@ -53,48 +53,72 @@ function truncateText(text, width) {
53
53
  }
54
54
 
55
55
  // packages/cli/src/app-opentui/render/type-bar.ts
56
+ var TYPEBAR_BG = RGBA.fromInts(20, 25, 14, 224);
57
+ var TYPEBAR_BORDER = RGBA.fromInts(204, 255, 77, 92);
56
58
  function createTypeBar(renderer) {
57
- const prefix = new TextRenderable(renderer, {
58
- id: "rig-typebar-prefix",
59
- content: " rig \u203A",
59
+ const background = new BoxRenderable(renderer, {
60
+ id: "typebar-card",
60
61
  position: "absolute",
61
62
  left: 0,
62
63
  top: 0,
64
+ width: 1,
65
+ height: 1,
66
+ backgroundColor: TYPEBAR_BG,
67
+ border: true,
68
+ borderColor: TYPEBAR_BORDER,
69
+ zIndex: 4
70
+ });
71
+ const prefix = new TextRenderable(renderer, {
72
+ id: "typebar-prefix",
73
+ content: " \u203A",
74
+ position: "absolute",
75
+ left: 1,
76
+ top: 0,
63
77
  fg: RIG_UI.lime,
78
+ zIndex: 7,
64
79
  selectable: true
65
80
  });
66
81
  const input = new InputRenderable(renderer, {
67
- id: "rig-typebar-input",
82
+ id: "typebar-input",
68
83
  position: "absolute",
69
- left: 7,
84
+ left: 4,
70
85
  top: 0,
71
86
  width: 40,
72
- placeholder: "fleet \xB7 tasks \xB7 run next \xB7 help",
87
+ placeholder: "runs \xB7 tasks \xB7 run next \xB7 help",
73
88
  textColor: RIG_UI.ink,
74
89
  cursorColor: RIG_UI.lime,
75
90
  cursorStyle: { style: "block", blinking: false },
76
91
  showCursor: true,
92
+ zIndex: 7,
77
93
  selectable: true
78
94
  });
79
95
  const footer = new TextRenderable(renderer, {
80
- id: "rig-footer",
96
+ id: "footer",
81
97
  content: "",
82
98
  position: "absolute",
83
99
  left: 0,
84
100
  top: 1,
85
101
  width: "100%",
86
102
  fg: RIG_UI.ink4,
103
+ zIndex: 7,
87
104
  selectable: true
88
105
  });
89
106
  input.focus();
90
- return { input, prefix, footer };
107
+ return { background, input, prefix, footer };
91
108
  }
92
109
  function positionTypeBar(renderables, input, footer, width, typeBarTop, footerTop) {
93
- renderables.prefix.content = " rig \u203A";
110
+ renderables.background.visible = true;
111
+ const cardTop = Math.max(0, typeBarTop - 1);
112
+ renderables.background.left = 0;
113
+ renderables.background.top = cardTop;
114
+ renderables.background.width = width;
115
+ renderables.background.height = Math.max(3, footerTop - cardTop + 1);
116
+ renderables.prefix.content = " \u203A";
117
+ renderables.prefix.left = 2;
94
118
  renderables.prefix.top = typeBarTop;
95
119
  renderables.input.top = typeBarTop;
96
- renderables.input.left = 7;
97
- renderables.input.width = Math.max(10, width - 9);
120
+ renderables.input.left = 5;
121
+ renderables.input.width = Math.max(10, width - 8);
98
122
  renderables.input.placeholder = input.placeholder;
99
123
  renderables.input.showCursor = true;
100
124
  renderables.footer.top = footerTop;
@@ -104,6 +128,8 @@ function positionTypeBar(renderables, input, footer, width, typeBarTop, footerTo
104
128
  renderables.input.focus();
105
129
  }
106
130
  function hideTypeBar(renderables, height) {
131
+ renderables.background.visible = false;
132
+ renderables.background.top = height + 1;
107
133
  renderables.prefix.content = "";
108
134
  renderables.prefix.top = height + 1;
109
135
  renderables.input.value = "";
@@ -119,13 +145,22 @@ function bindTypeBar(renderables, handlers) {
119
145
  renderables.input.on(InputRenderableEvents.INPUT, (value) => handlers.onInput(value));
120
146
  renderables.input.on(InputRenderableEvents.ENTER, (value) => handlers.onEnter(value));
121
147
  }
148
+ function safeFooterMessage(message) {
149
+ const trimmed = message?.trim();
150
+ if (!trimmed)
151
+ return null;
152
+ if (/https?:|\b[a-z0-9-]+\.[a-z]{2,}\b|\brig\b/i.test(trimmed))
153
+ return null;
154
+ return trimmed;
155
+ }
122
156
  function formatFooter(footer, width) {
157
+ const safeMessage = safeFooterMessage(footer.message);
123
158
  const parts = [
124
- footer.project ? `project ${footer.project}` : null,
125
- footer.server ? `server ${footer.server}` : null,
126
- footer.auth ? `auth ${footer.auth}` : null,
159
+ footer.project ? "workspace" : null,
160
+ footer.server ? "server selected" : null,
161
+ footer.auth ? "auth ready" : null,
127
162
  footer.run ? `run ${footer.run}` : null,
128
- footer.message ?? null
163
+ safeMessage
129
164
  ].filter((part) => Boolean(part));
130
165
  return ` ${truncateText(parts.join(" \xB7 "), Math.max(8, width - 2))}`;
131
166
  }