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

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 (163) hide show
  1. package/dist/bin/rig.js +22085 -14618
  2. package/dist/src/app/board.js +155 -28
  3. package/dist/src/app-opentui/adapters/doctor.d.ts +0 -2
  4. package/dist/src/app-opentui/adapters/doctor.js +1 -25
  5. package/dist/src/app-opentui/adapters/family.d.ts +62 -0
  6. package/dist/src/app-opentui/adapters/family.js +14305 -0
  7. package/dist/src/app-opentui/adapters/fleet.d.ts +0 -2
  8. package/dist/src/app-opentui/adapters/fleet.js +6 -40
  9. package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
  10. package/dist/src/app-opentui/adapters/inbox.js +54 -59
  11. package/dist/src/app-opentui/adapters/init.d.ts +0 -2
  12. package/dist/src/app-opentui/adapters/init.js +0 -26
  13. package/dist/src/app-opentui/adapters/inspect.d.ts +52 -0
  14. package/dist/src/app-opentui/adapters/inspect.js +1024 -0
  15. package/dist/src/app-opentui/adapters/pi-attach.d.ts +15 -6
  16. package/dist/src/app-opentui/adapters/pi-attach.js +348 -93
  17. package/dist/src/app-opentui/adapters/pi.d.ts +23 -0
  18. package/dist/src/app-opentui/adapters/pi.js +363 -0
  19. package/dist/src/app-opentui/adapters/plugin.d.ts +84 -0
  20. package/dist/src/app-opentui/adapters/plugin.js +544 -0
  21. package/dist/src/app-opentui/adapters/repo.d.ts +37 -0
  22. package/dist/src/app-opentui/adapters/repo.js +186 -0
  23. package/dist/src/app-opentui/adapters/run-detail.d.ts +9 -2
  24. package/dist/src/app-opentui/adapters/run-detail.js +97 -44
  25. package/dist/src/app-opentui/adapters/server.d.ts +10 -2
  26. package/dist/src/app-opentui/adapters/server.js +96 -27
  27. package/dist/src/app-opentui/adapters/tasks.d.ts +0 -2
  28. package/dist/src/app-opentui/adapters/tasks.js +437 -105
  29. package/dist/src/app-opentui/adapters/workspace.d.ts +49 -0
  30. package/dist/src/app-opentui/adapters/workspace.js +333 -0
  31. package/dist/src/app-opentui/autocomplete.d.ts +20 -0
  32. package/dist/src/app-opentui/autocomplete.js +576 -0
  33. package/dist/src/app-opentui/bootstrap.js +24296 -16919
  34. package/dist/src/app-opentui/command-palette.d.ts +3 -0
  35. package/dist/src/app-opentui/command-palette.js +1010 -0
  36. package/dist/src/app-opentui/drone.js +8 -6
  37. package/dist/src/app-opentui/fleet-stats.d.ts +32 -0
  38. package/dist/src/app-opentui/fleet-stats.js +114 -0
  39. package/dist/src/app-opentui/index.js +3438 -1724
  40. package/dist/src/app-opentui/intent.js +71 -48
  41. package/dist/src/app-opentui/keymap.d.ts +6 -5
  42. package/dist/src/app-opentui/keymap.js +1064 -23
  43. package/dist/src/app-opentui/layout.d.ts +7 -0
  44. package/dist/src/app-opentui/layout.js +13 -6
  45. package/dist/src/app-opentui/list-search.d.ts +24 -0
  46. package/dist/src/app-opentui/list-search.js +88 -1
  47. package/dist/src/app-opentui/pi-host-child.js +33 -1
  48. package/dist/src/app-opentui/pi-pty-host.d.ts +5 -0
  49. package/dist/src/app-opentui/pi-pty-host.js +21 -3
  50. package/dist/src/app-opentui/react/App.d.ts +9 -0
  51. package/dist/src/app-opentui/react/App.js +5144 -0
  52. package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
  53. package/dist/src/app-opentui/react/Backdrop.js +1834 -0
  54. package/dist/src/app-opentui/react/ChromeHost.d.ts +5 -0
  55. package/dist/src/app-opentui/react/ChromeHost.js +2942 -0
  56. package/dist/src/app-opentui/react/SceneFrameView.d.ts +7 -0
  57. package/dist/src/app-opentui/react/SceneFrameView.js +529 -0
  58. package/dist/src/app-opentui/react/context.d.ts +17 -0
  59. package/dist/src/app-opentui/react/context.js +37 -0
  60. package/dist/src/app-opentui/react/launch.d.ts +2 -0
  61. package/dist/src/app-opentui/react/launch.js +5743 -0
  62. package/dist/src/app-opentui/react/nav.d.ts +18 -0
  63. package/dist/src/app-opentui/react/nav.js +54 -0
  64. package/dist/src/app-opentui/react/scroll.d.ts +12 -0
  65. package/dist/src/app-opentui/react/scroll.js +21 -0
  66. package/dist/src/app-opentui/react/syntax.d.ts +2 -0
  67. package/dist/src/app-opentui/react/syntax.js +64 -0
  68. package/dist/src/app-opentui/registry.js +19923 -5151
  69. package/dist/src/app-opentui/render/constants.d.ts +31 -0
  70. package/dist/src/app-opentui/render/constants.js +66 -0
  71. package/dist/src/app-opentui/render/graphics.d.ts +2 -1
  72. package/dist/src/app-opentui/render/graphics.js +106 -39
  73. package/dist/src/app-opentui/render/image-visual-layer-worker.js +108 -20
  74. package/dist/src/app-opentui/render/image-visual-layer.d.ts +7 -0
  75. package/dist/src/app-opentui/render/image-visual-layer.js +109 -20
  76. package/dist/src/app-opentui/render/native-host.d.ts +37 -0
  77. package/dist/src/app-opentui/render/native-host.js +179 -0
  78. package/dist/src/app-opentui/render/panels.js +18 -11
  79. package/dist/src/app-opentui/render/preloader.js +8 -6
  80. package/dist/src/app-opentui/render/scene.d.ts +50 -1
  81. package/dist/src/app-opentui/render/scene.js +183 -6
  82. package/dist/src/app-opentui/render/text.d.ts +7 -1
  83. package/dist/src/app-opentui/render/text.js +10 -7
  84. package/dist/src/app-opentui/render/type-bar.js +69 -30
  85. package/dist/src/app-opentui/runtime.d.ts +44 -1
  86. package/dist/src/app-opentui/runtime.js +3231 -1363
  87. package/dist/src/app-opentui/scenes/command.js +20 -6
  88. package/dist/src/app-opentui/scenes/doctor.js +176 -11
  89. package/dist/src/app-opentui/scenes/error.js +20 -10
  90. package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +2 -0
  91. package/dist/src/app-opentui/scenes/family-domains/agent.js +348 -0
  92. package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +2 -0
  93. package/dist/src/app-opentui/scenes/family-domains/browser.js +195 -0
  94. package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +2 -0
  95. package/dist/src/app-opentui/scenes/family-domains/dist.js +243 -0
  96. package/dist/src/app-opentui/scenes/family-domains/git.d.ts +2 -0
  97. package/dist/src/app-opentui/scenes/family-domains/git.js +195 -0
  98. package/dist/src/app-opentui/scenes/family-domains/github.d.ts +2 -0
  99. package/dist/src/app-opentui/scenes/family-domains/github.js +274 -0
  100. package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +2 -0
  101. package/dist/src/app-opentui/scenes/family-domains/harness.js +152 -0
  102. package/dist/src/app-opentui/scenes/family-domains/index.d.ts +4 -0
  103. package/dist/src/app-opentui/scenes/family-domains/index.js +1679 -0
  104. package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +76 -0
  105. package/dist/src/app-opentui/scenes/family-domains/kit.js +305 -0
  106. package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +2 -0
  107. package/dist/src/app-opentui/scenes/family-domains/profile.js +212 -0
  108. package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +2 -0
  109. package/dist/src/app-opentui/scenes/family-domains/queue.js +146 -0
  110. package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +2 -0
  111. package/dist/src/app-opentui/scenes/family-domains/remote.js +518 -0
  112. package/dist/src/app-opentui/scenes/family-domains/review.d.ts +2 -0
  113. package/dist/src/app-opentui/scenes/family-domains/review.js +280 -0
  114. package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +2 -0
  115. package/dist/src/app-opentui/scenes/family-domains/setup.js +267 -0
  116. package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +2 -0
  117. package/dist/src/app-opentui/scenes/family-domains/stats.js +370 -0
  118. package/dist/src/app-opentui/scenes/family.d.ts +3 -0
  119. package/dist/src/app-opentui/scenes/family.js +2144 -0
  120. package/dist/src/app-opentui/scenes/fleet.js +521 -31
  121. package/dist/src/app-opentui/scenes/handoff.js +204 -12
  122. package/dist/src/app-opentui/scenes/help.js +609 -40
  123. package/dist/src/app-opentui/scenes/inbox.js +278 -17
  124. package/dist/src/app-opentui/scenes/init.js +84 -39
  125. package/dist/src/app-opentui/scenes/inspect.d.ts +3 -0
  126. package/dist/src/app-opentui/scenes/inspect.js +793 -0
  127. package/dist/src/app-opentui/scenes/main.js +218 -39
  128. package/dist/src/app-opentui/scenes/pi.d.ts +3 -0
  129. package/dist/src/app-opentui/scenes/pi.js +508 -0
  130. package/dist/src/app-opentui/scenes/plugin.d.ts +3 -0
  131. package/dist/src/app-opentui/scenes/plugin.js +486 -0
  132. package/dist/src/app-opentui/scenes/repo.d.ts +3 -0
  133. package/dist/src/app-opentui/scenes/repo.js +424 -0
  134. package/dist/src/app-opentui/scenes/run-detail.js +333 -20
  135. package/dist/src/app-opentui/scenes/server.js +181 -15
  136. package/dist/src/app-opentui/scenes/tasks.js +486 -31
  137. package/dist/src/app-opentui/scenes/workspace.d.ts +3 -0
  138. package/dist/src/app-opentui/scenes/workspace.js +426 -0
  139. package/dist/src/app-opentui/selectable.d.ts +19 -0
  140. package/dist/src/app-opentui/selectable.js +79 -0
  141. package/dist/src/app-opentui/state.js +83 -30
  142. package/dist/src/app-opentui/surface-catalog.d.ts +20 -0
  143. package/dist/src/app-opentui/surface-catalog.js +540 -0
  144. package/dist/src/app-opentui/theme.d.ts +28 -6
  145. package/dist/src/app-opentui/theme.js +61 -8
  146. package/dist/src/app-opentui/types.d.ts +121 -4
  147. package/dist/src/commands/_authority-runs.d.ts +1 -1
  148. package/dist/src/commands/_authority-runs.js +2 -12
  149. package/dist/src/commands/_help-catalog.js +95 -15
  150. package/dist/src/commands/_operator-view.js +34 -2
  151. package/dist/src/commands/_pi-frontend.d.ts +2 -0
  152. package/dist/src/commands/_pi-frontend.js +34 -0
  153. package/dist/src/commands/_server-events.d.ts +26 -0
  154. package/dist/src/commands/_server-events.js +310 -0
  155. package/dist/src/commands/agent.js +2 -12
  156. package/dist/src/commands/run.js +34 -2
  157. package/dist/src/commands/server.js +2 -12
  158. package/dist/src/commands/stats.js +95 -15
  159. package/dist/src/commands/task-run-driver.js +2 -12
  160. package/dist/src/commands/task.js +131 -29
  161. package/dist/src/commands.js +192 -31
  162. package/dist/src/index.js +192 -31
  163. package/package.json +11 -9
@@ -108,7 +108,16 @@ function panelPixelPlacement(layout, panel, size, minPixels = 8) {
108
108
  return width > minPixels && height > minPixels ? { left, top, width, height, leftCells, topCells, widthCells, heightCells } : null;
109
109
  }
110
110
 
111
+ // packages/cli/src/app-opentui/render/constants.ts
112
+ var GLOW_FALLOFF_EXP_IMAGE = 2.4;
113
+
111
114
  // packages/cli/src/app-opentui/render/image-visual-layer.ts
115
+ var PANEL_MASK_RADIUS_MIN = 14;
116
+ var PANEL_MASK_RADIUS_MAX = 34;
117
+ var PANEL_MASK_RADIUS_FACTOR = 0.035;
118
+ var PANEL_BLUR_RADIUS_MIN = 8;
119
+ var PANEL_BLUR_RADIUS_MAX = 28;
120
+ var PANEL_BLUR_RADIUS_FACTOR = 0.018;
112
121
  var BG = [7, 8, 9, 255];
113
122
  var PANEL = [16, 17, 21, 184];
114
123
  var PANEL_HEADER = [16, 17, 21, 190];
@@ -126,6 +135,12 @@ var PANEL_BLUR_SCALE = 1;
126
135
  var PANEL_MASK_CACHE_LIMIT = 16;
127
136
  var ZLIB_LEVEL = 1;
128
137
  var DEFAULT_IMAGE_RESOLUTION_SCALE = 1;
138
+ var LOAD_BUCKETS = 5;
139
+ function loadBucket(load) {
140
+ if (!Number.isFinite(load ?? NaN))
141
+ return 0;
142
+ return Math.max(0, Math.min(LOAD_BUCKETS, Math.round((load ?? 0) * LOAD_BUCKETS)));
143
+ }
129
144
  var panelMaskCache = new Map;
130
145
  var BG_WORD = rgbaWord(BG);
131
146
  function imageTransport() {
@@ -217,17 +232,25 @@ function drawAsciiGlyph(data, width, height, x, y, cellWidth, cellHeight, char,
217
232
  }
218
233
  }
219
234
  }
220
- function drawStaticAsciiFleetBackground(data, width, height, scene, layout) {
235
+ function drawStaticAsciiFleetBackground(data, width, height, scene, layout, load, activeRuns) {
221
236
  const rows = fleetRows(sceneStaticTick(scene), { animate: true });
222
237
  const cellWidth = width / Math.max(1, layout.width);
223
238
  const cellHeight = height / Math.max(1, layout.height);
224
- const leftCells = Math.floor((layout.width - FLEET_GRID_WIDTH) / 2);
239
+ const sideBySide = layout.width >= FLEET_GRID_WIDTH * 1.9;
240
+ const leftCells = sideBySide ? Math.max(1, Math.floor(layout.width * 0.3 - FLEET_GRID_WIDTH / 2)) : Math.floor((layout.width - FLEET_GRID_WIDTH) / 2);
225
241
  const topCells = Math.floor((layout.height - FLEET_GRID_HEIGHT) / 2);
226
242
  const fleetLeft = leftCells * cellWidth;
227
243
  const fleetTop = topCells * cellHeight;
228
- drawGlow(data, width, height, width * 0.5, height * 0.5, Math.min(width, height) * 0.4, LIME, 0.03);
229
- drawGlow(data, width, height, width * 0.18, height * 0.22, Math.min(width, height) * 0.28, CYAN, 0.022);
230
- drawGlow(data, width, height, width * 0.82, height * 0.78, Math.min(width, height) * 0.22, MAGENTA, 0.014);
244
+ drawGlow(data, width, height, width * 0.5, height * 0.5, Math.min(width, height) * 0.4, LIME, 0.022 + load * 0.03);
245
+ drawGlow(data, width, height, width * 0.18, height * 0.22, Math.min(width, height) * 0.28, CYAN, 0.018 + load * 0.012);
246
+ drawGlow(data, width, height, width * 0.82, height * 0.78, Math.min(width, height) * 0.22, MAGENTA, 0.012 + load * 0.008);
247
+ let droneTotal = 0;
248
+ for (const line of rows)
249
+ for (const char of line)
250
+ if (char === "@" || char === "$" || char === "%")
251
+ droneTotal += 1;
252
+ const litTarget = Math.max(0, Math.min(droneTotal, activeRuns));
253
+ let droneIndex = 0;
231
254
  for (let row = 0;row < rows.length; row += 1) {
232
255
  const line = rows[row];
233
256
  for (let col = 0;col < line.length; col += 1) {
@@ -237,26 +260,30 @@ function drawStaticAsciiFleetBackground(data, width, height, scene, layout) {
237
260
  const x = fleetLeft + col * cellWidth;
238
261
  const y = fleetTop + row * cellHeight;
239
262
  const color = charColor(char, row, rows.length);
240
- drawAsciiGlyph(data, width, height, x + cellWidth * 0.07, y + cellHeight * 0.05, cellWidth, cellHeight, char, color, 0.52);
241
- if (char === "@" || char === "$" || char === "%") {
242
- drawGlow(data, width, height, x + cellWidth * 0.5, y + cellHeight * 0.5, Math.max(cellWidth, cellHeight) * 0.95, color, 0.02);
263
+ const isDrone = char === "@" || char === "$" || char === "%";
264
+ const lit = isDrone && droneIndex < litTarget;
265
+ drawAsciiGlyph(data, width, height, x + cellWidth * 0.07, y + cellHeight * 0.05, cellWidth, cellHeight, char, color, lit ? 0.72 : 0.46);
266
+ if (isDrone) {
267
+ droneIndex += 1;
268
+ drawGlow(data, width, height, x + cellWidth * 0.5, y + cellHeight * 0.5, Math.max(cellWidth, cellHeight) * 0.95, color, lit ? 0.044 : 0.014);
243
269
  }
244
270
  }
245
271
  }
246
272
  }
247
- function applyStaticAtmosphere(data, width, height) {
273
+ function applyStaticAtmosphere(data, width, height, load) {
248
274
  const cx = width * 0.5;
249
275
  const cy = height * 0.42;
250
276
  const radius = Math.max(width, height) * 0.78;
277
+ const minVignette = 0.1 - load * 0.02;
251
278
  for (let y = 0;y < height; y += 1) {
252
279
  for (let x = 0;x < width; x += 1) {
253
280
  const distance = Math.hypot(x - cx, y - cy) / radius;
254
- const alpha = Math.max(0.1, Math.min(0.82, 0.12 + Math.pow(distance, 1.65) * 0.62));
281
+ const alpha = Math.max(minVignette, Math.min(0.82, 0.12 + Math.pow(distance, 1.65) * 0.62));
255
282
  blendOver(data, (y * width + x) * 4, BG, alpha);
256
283
  }
257
284
  }
258
- drawGlow(data, width, height, width * 0.82, height * 0.04, Math.min(width, height) * 0.2, LIME, 0.03);
259
- drawGlow(data, width, height, width * 0.12, height * 0.18, Math.min(width, height) * 0.16, CYAN, 0.022);
285
+ drawGlow(data, width, height, width * 0.82, height * 0.04, Math.min(width, height) * 0.2, LIME, 0.024 + load * 0.012);
286
+ drawGlow(data, width, height, width * 0.12, height * 0.18, Math.min(width, height) * 0.16, CYAN, 0.018 + load * 0.008);
260
287
  }
261
288
  function makeCrcTable() {
262
289
  const table = new Uint32Array(256);
@@ -339,6 +366,23 @@ function blendOver(data, index, color, alphaScale = 1) {
339
366
  data[index + 2] = clampByte(color[2] * alpha + data[index + 2] * inv);
340
367
  data[index + 3] = 255;
341
368
  }
369
+ function drawDisc(data, width, height, cx, cy, radius, color, alpha = 1) {
370
+ const minX = Math.max(0, Math.floor(cx - radius));
371
+ const maxX = Math.min(width - 1, Math.ceil(cx + radius));
372
+ const minY = Math.max(0, Math.floor(cy - radius));
373
+ const maxY = Math.min(height - 1, Math.ceil(cy + radius));
374
+ for (let y = minY;y <= maxY; y += 1) {
375
+ for (let x = minX;x <= maxX; x += 1) {
376
+ const dx = x + 0.5 - cx;
377
+ const dy = y + 0.5 - cy;
378
+ const d = Math.sqrt(dx * dx + dy * dy);
379
+ if (d > radius)
380
+ continue;
381
+ const edge = Math.max(0, Math.min(1, radius - d));
382
+ blendOver(data, (y * width + x) * 4, color, alpha * Math.min(1, 0.35 + edge));
383
+ }
384
+ }
385
+ }
342
386
  function drawGlow(data, width, height, cx, cy, radius, color, alpha = 0.18) {
343
387
  const minX = Math.max(0, Math.floor(cx - radius));
344
388
  const maxX = Math.min(width - 1, Math.ceil(cx + radius));
@@ -351,11 +395,20 @@ function drawGlow(data, width, height, cx, cy, radius, color, alpha = 0.18) {
351
395
  const d = Math.sqrt(dx * dx + dy * dy);
352
396
  if (d > radius)
353
397
  continue;
354
- const falloff = Math.pow(1 - d / Math.max(1, radius), 2.4);
398
+ const falloff = Math.pow(1 - d / Math.max(1, radius), GLOW_FALLOFF_EXP_IMAGE);
355
399
  blendOver(data, (y * width + x) * 4, color, alpha * falloff);
356
400
  }
357
401
  }
358
402
  }
403
+ function drawLine(data, width, height, x0, y0, x1, y1, color, alpha = 0.5, thickness = 1.4) {
404
+ const dx = x1 - x0;
405
+ const dy = y1 - y0;
406
+ const steps = Math.max(1, Math.ceil(Math.hypot(dx, dy) * 1.2));
407
+ for (let i = 0;i <= steps; i += 1) {
408
+ const t = i / steps;
409
+ drawDisc(data, width, height, x0 + dx * t, y0 + dy * t, thickness, color, alpha);
410
+ }
411
+ }
359
412
  function roundRectAlpha(px, py, x, y, w, h, r) {
360
413
  const rx = Math.max(x + r, Math.min(px, x + w - r));
361
414
  const ry = Math.max(y + r, Math.min(py, y + h - r));
@@ -459,7 +512,7 @@ function getPanelMask(width, height, rect, headerPx, blurScale) {
459
512
  const cached = panelMaskCache.get(key);
460
513
  if (cached)
461
514
  return cached;
462
- const radius = Math.max(14, Math.min(34, Math.round(Math.min(rect.width, rect.height) * 0.035)));
515
+ const radius = Math.max(PANEL_MASK_RADIUS_MIN, Math.min(PANEL_MASK_RADIUS_MAX, Math.round(Math.min(rect.width, rect.height) * PANEL_MASK_RADIUS_FACTOR)));
463
516
  const sampledWidth = Math.max(1, Math.ceil(rect.width / blurScale));
464
517
  const sampledHeight = Math.max(1, Math.ceil(rect.height / blurScale));
465
518
  const x0 = Math.max(0, rect.left);
@@ -514,7 +567,7 @@ function getPanelMask(width, height, rect, headerPx, blurScale) {
514
567
  function compositePanel(data, width, height, rect, headerPx) {
515
568
  const blurScale = PANEL_BLUR_SCALE;
516
569
  const sampled = downsampleRegion(data, width, height, rect, blurScale);
517
- const blurRadius = Math.max(8, Math.min(28, Math.round(Math.min(rect.width, rect.height) * 0.018)));
570
+ const blurRadius = Math.max(PANEL_BLUR_RADIUS_MIN, Math.min(PANEL_BLUR_RADIUS_MAX, Math.round(Math.min(rect.width, rect.height) * PANEL_BLUR_RADIUS_FACTOR)));
518
571
  const blurred = blurRgb(sampled.pixels, sampled.width, sampled.height, blurRadius);
519
572
  const mask = getPanelMask(width, height, rect, headerPx, blurScale);
520
573
  for (let i = 0;i < mask.indices.length; i += 1) {
@@ -533,16 +586,49 @@ function compositePanel(data, width, height, rect, headerPx) {
533
586
  blendOver(data, mask.dividerIndices[i], PANEL_LINE, 0.28);
534
587
  }
535
588
  }
536
- function drawBackground(data, width, height, _tick, scene, layout) {
589
+ var RIG_GLYPH_STROKES = {
590
+ R: [[0, 0, 0, 1], [0, 0, 0.82, 0], [0.82, 0, 0.82, 0.5], [0, 0.5, 0.82, 0.5], [0.36, 0.5, 0.92, 1]],
591
+ I: [[0.5, 0, 0.5, 1], [0.18, 0, 0.82, 0], [0.18, 1, 0.82, 1]],
592
+ G: [[0.92, 0.08, 0.12, 0], [0.12, 0, 0.12, 1], [0.12, 1, 0.92, 1], [0.92, 0.5, 0.92, 1], [0.5, 0.5, 0.92, 0.5]]
593
+ };
594
+ function drawBigRigWordmark(data, width, height, layout, load) {
595
+ const sideBySide = layout.width >= FLEET_GRID_WIDTH * 1.9;
596
+ if (!sideBySide)
597
+ return;
598
+ const letters = "RIG";
599
+ const min = Math.min(width, height);
600
+ const glyphH = height * 0.42;
601
+ const glyphW = width * 0.13;
602
+ const gap = glyphW * 0.3;
603
+ const totalW = letters.length * glyphW + (letters.length - 1) * gap;
604
+ const centerX = width * 0.71;
605
+ const startX = centerX - totalW / 2;
606
+ const top = (height - glyphH) / 2;
607
+ const stroke = Math.max(2, min * 0.013);
608
+ drawGlow(data, width, height, centerX, top + glyphH / 2, Math.max(glyphW, glyphH) * 0.9, LIME, 0.022 + load * 0.02);
609
+ const strokeAlpha = 0.1 + load * 0.06;
610
+ letters.split("").forEach((letter, index) => {
611
+ const segments = RIG_GLYPH_STROKES[letter];
612
+ if (!segments)
613
+ return;
614
+ const ox = startX + index * (glyphW + gap);
615
+ for (const [x0, y0, x1, y1] of segments) {
616
+ drawLine(data, width, height, ox + x0 * glyphW, top + y0 * glyphH, ox + x1 * glyphW, top + y1 * glyphH, LIME_DIM, strokeAlpha, stroke);
617
+ }
618
+ });
619
+ }
620
+ function drawBackground(data, width, height, _tick, scene, layout, load, activeRuns) {
537
621
  fillRgba(data, BG, BG_WORD);
538
- drawStaticAsciiFleetBackground(data, width, height, scene, layout);
539
- applyStaticAtmosphere(data, width, height);
622
+ drawStaticAsciiFleetBackground(data, width, height, scene, layout, load, activeRuns);
623
+ drawBigRigWordmark(data, width, height, layout, load);
624
+ applyStaticAtmosphere(data, width, height, load);
540
625
  }
541
626
  function imageVisualFrameKey(input) {
542
627
  const width = Math.max(1, Math.floor(input.pixelSize.width));
543
628
  const height = Math.max(1, Math.floor(input.pixelSize.height));
544
629
  const layer = "layer" in input ? input.layer ?? "full" : "full";
545
- return `${layer}:${width}x${height}:${input.layout.width}x${input.layout.height}:${input.scene}:${input.tick}:${input.panels.map((panel) => `${panel.id}:${panel.top}:${panel.height}:${panel.width ?? ""}:${panel.left ?? ""}:${panel.headerHeight ?? ""}`).join("|")}`;
630
+ const load = loadBucket(input.load);
631
+ return `${layer}:${width}x${height}:${input.layout.width}x${input.layout.height}:${input.scene}:${input.tick}:l${load}:${input.panels.map((panel) => `${panel.id}:${panel.top}:${panel.height}:${panel.width ?? ""}:${panel.left ?? ""}:${panel.headerHeight ?? ""}`).join("|")}`;
546
632
  }
547
633
  function encodeKittyFrame(width, height, data, input) {
548
634
  if (input.transport === "png") {
@@ -589,7 +675,9 @@ function renderImageVisualFrame(input) {
589
675
  return null;
590
676
  const layer = input.layer ?? "full";
591
677
  const data = new Uint8ClampedArray(byteCount);
592
- drawBackground(data, width, height, 0, input.scene, input.layout);
678
+ const load = loadBucket(input.load) / LOAD_BUCKETS;
679
+ const activeRuns = Math.max(0, Math.floor(input.activeRuns ?? 0));
680
+ drawBackground(data, width, height, 0, input.scene, input.layout, load, activeRuns);
593
681
  if (layer === "split") {
594
682
  const sequences = [encodeKittyFrame(width, height, data, input)];
595
683
  let panelIndex = 0;
@@ -973,6 +1061,7 @@ function forceModernImageVisuals() {
973
1061
  export {
974
1062
  renderImageVisualFrame,
975
1063
  pixelSizeForRenderer,
1064
+ loadBucket,
976
1065
  imageVisualFrameKey,
977
1066
  forceModernImageVisuals,
978
1067
  ImageVisualLayer
@@ -0,0 +1,37 @@
1
+ import { BoxRenderable, CodeRenderable, DiffRenderable, ScrollBoxRenderable, TextRenderable, TextTableRenderable, type CliRenderer } from "@opentui/core";
2
+ import type { StageLayout } from "../layout";
3
+ export type NativeMountKind = "code" | "diff" | "markdown" | "table";
4
+ /** A scene's request to render native content in a rectangle of its panel. */
5
+ export type NativeMount = {
6
+ readonly kind: NativeMountKind;
7
+ /** Source/markdown/diff text. */
8
+ readonly content: string;
9
+ /** Rows for `kind: "table"` — first row is the header. */
10
+ readonly rows?: readonly (readonly string[])[];
11
+ /** Tree-sitter filetype for `kind: "code"` (e.g. "typescript", "json"). */
12
+ readonly filetype?: string;
13
+ /** Cell rectangle to occupy (defaults to the centered content area). */
14
+ readonly top?: number;
15
+ readonly left?: number;
16
+ readonly width?: number;
17
+ readonly height?: number;
18
+ /** Pin to the bottom (log/diff tails). */
19
+ readonly stickyBottom?: boolean;
20
+ };
21
+ export type NativeHost = {
22
+ readonly scrollBox: ScrollBoxRenderable;
23
+ code: CodeRenderable | null;
24
+ diff: DiffRenderable | null;
25
+ table: TextTableRenderable | null;
26
+ active: NativeMountKind | null;
27
+ lastKey: string;
28
+ };
29
+ export declare function createNativeHost(renderer: CliRenderer): NativeHost | null;
30
+ export declare function hideNativeHost(host: NativeHost | null): void;
31
+ /** Position + populate the native host for a scene's mount request. Returns true
32
+ * if it rendered natively; false means the caller should fall back to lines. */
33
+ export declare function applyNativeHost(host: NativeHost | null, mount: NativeMount, layout: StageLayout): boolean;
34
+ export declare function destroyNativeHost(host: NativeHost | null): void;
35
+ /** A tiny title bar the scene can keep above the native host (line-rendered). */
36
+ export declare function nativeTitleBar(renderer: CliRenderer, id: string): TextRenderable;
37
+ export { BoxRenderable };
@@ -0,0 +1,179 @@
1
+ // @bun
2
+ // packages/cli/src/app-opentui/render/native-host.ts
3
+ import {
4
+ BoxRenderable,
5
+ CodeRenderable,
6
+ DiffRenderable,
7
+ RGBA,
8
+ ScrollBoxRenderable,
9
+ SyntaxStyle,
10
+ TextRenderable,
11
+ TextTableRenderable
12
+ } from "@opentui/core";
13
+
14
+ // packages/cli/src/app-opentui/theme.ts
15
+ import {
16
+ bold as otuiBold,
17
+ dim as otuiDim,
18
+ fg as otuiFg,
19
+ t,
20
+ TextAttributes
21
+ } from "@opentui/core";
22
+ var RIG_UI = {
23
+ bg: "#070809",
24
+ bg2: "#0b0c0e",
25
+ panel: "#101115",
26
+ panel2: "#14161b",
27
+ glass: "#1e2230",
28
+ border: "#2a2e3a",
29
+ ink: "#f4f5f8",
30
+ ink2: "#c7c9d3",
31
+ ink3: "#9aa0ae",
32
+ ink4: "#787b86",
33
+ lime: "#ccff4d",
34
+ limeDim: "#a9d63f",
35
+ cyan: "#56d8ff",
36
+ cyanDim: "#3f9fbd",
37
+ red: "#ff5d5d",
38
+ yellow: "#ffd24d",
39
+ magenta: "#ff79b0"
40
+ };
41
+ var styles = {
42
+ ink: otuiFg(RIG_UI.ink),
43
+ ink2: otuiFg(RIG_UI.ink2),
44
+ ink3: otuiFg(RIG_UI.ink3),
45
+ ink4: otuiFg(RIG_UI.ink4),
46
+ lime: otuiFg(RIG_UI.lime),
47
+ limeDim: otuiFg(RIG_UI.limeDim),
48
+ cyan: otuiFg(RIG_UI.cyan),
49
+ red: otuiFg(RIG_UI.red),
50
+ yellow: otuiFg(RIG_UI.yellow),
51
+ magenta: otuiFg(RIG_UI.magenta)
52
+ };
53
+
54
+ // packages/cli/src/app-opentui/render/native-host.ts
55
+ var syntaxStyle = null;
56
+ function rigSyntaxStyle() {
57
+ if (syntaxStyle)
58
+ return syntaxStyle;
59
+ syntaxStyle = SyntaxStyle.fromStyles({
60
+ keyword: { fg: RGBA.fromHex(RIG_UI.magenta), bold: true },
61
+ string: { fg: RGBA.fromHex(RIG_UI.lime) },
62
+ number: { fg: RGBA.fromHex(RIG_UI.cyan) },
63
+ comment: { fg: RGBA.fromHex(RIG_UI.ink4), italic: true },
64
+ function: { fg: RGBA.fromHex(RIG_UI.cyan) },
65
+ type: { fg: RGBA.fromHex(RIG_UI.limeDim) },
66
+ constant: { fg: RGBA.fromHex(RIG_UI.yellow) },
67
+ default: { fg: RGBA.fromHex(RIG_UI.ink2) }
68
+ });
69
+ return syntaxStyle;
70
+ }
71
+ function tableContent(rows) {
72
+ return rows.map((row, rowIndex) => row.map((cell) => [{ __isChunk: true, text: cell, fg: RGBA.fromHex(rowIndex === 0 ? RIG_UI.ink3 : RIG_UI.ink2) }]));
73
+ }
74
+ function createNativeHost(renderer) {
75
+ try {
76
+ const scrollBox = new ScrollBoxRenderable(renderer, {
77
+ id: "rig-native-scrollbox",
78
+ position: "absolute",
79
+ left: 0,
80
+ top: 0,
81
+ width: 1,
82
+ height: 1,
83
+ scrollY: true,
84
+ zIndex: 9,
85
+ visible: false
86
+ });
87
+ renderer.root.add(scrollBox);
88
+ return { scrollBox, code: null, diff: null, table: null, active: null, lastKey: "" };
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+ function hideAllChildren(host) {
94
+ if (host.code)
95
+ host.code.visible = false;
96
+ if (host.diff)
97
+ host.diff.visible = false;
98
+ if (host.table)
99
+ host.table.visible = false;
100
+ }
101
+ function hideNativeHost(host) {
102
+ if (!host)
103
+ return;
104
+ host.scrollBox.visible = false;
105
+ hideAllChildren(host);
106
+ host.active = null;
107
+ }
108
+ function applyNativeHost(host, mount, layout) {
109
+ if (!host)
110
+ return false;
111
+ try {
112
+ const left = mount.left ?? layout.centerLeft;
113
+ const top = mount.top ?? layout.centerTop;
114
+ const width = Math.max(8, mount.width ?? layout.centerWidth);
115
+ const height = Math.max(3, mount.height ?? layout.centerHeight);
116
+ host.scrollBox.left = left;
117
+ host.scrollBox.top = top;
118
+ host.scrollBox.width = width;
119
+ host.scrollBox.height = height;
120
+ host.scrollBox.visible = true;
121
+ hideAllChildren(host);
122
+ const rowCount = mount.rows?.length ?? 0;
123
+ const key = `${mount.kind}:${width}x${height}:${mount.content.length}:${mount.filetype ?? ""}:${rowCount}`;
124
+ if (mount.kind === "table") {
125
+ if (!host.table) {
126
+ host.table = new TextTableRenderable(host.scrollBox.ctx, { id: "rig-native-table", content: [], width: "100%", showBorders: true, columnWidthMode: "full", borderColor: RIG_UI.ink4 });
127
+ host.scrollBox.add(host.table);
128
+ }
129
+ if (host.lastKey !== key)
130
+ host.table.content = tableContent(mount.rows ?? []);
131
+ host.table.visible = true;
132
+ } else if (mount.kind === "diff") {
133
+ if (!host.diff) {
134
+ host.diff = new DiffRenderable(host.scrollBox.ctx, { id: "rig-native-diff", diff: "", width: "100%" });
135
+ host.scrollBox.add(host.diff);
136
+ }
137
+ if (host.lastKey !== key)
138
+ host.diff.diff = mount.content;
139
+ host.diff.visible = true;
140
+ } else {
141
+ const filetype = mount.kind === "markdown" ? "markdown" : mount.filetype ?? "text";
142
+ if (!host.code) {
143
+ host.code = new CodeRenderable(host.scrollBox.ctx, { id: "rig-native-code", content: "", filetype, syntaxStyle: rigSyntaxStyle(), width: "100%" });
144
+ host.scrollBox.add(host.code);
145
+ }
146
+ if (host.lastKey !== key) {
147
+ host.code.filetype = filetype;
148
+ host.code.content = mount.content;
149
+ }
150
+ host.code.visible = true;
151
+ }
152
+ host.active = mount.kind;
153
+ host.lastKey = key;
154
+ if (mount.stickyBottom)
155
+ host.scrollBox.scrollTo?.({ x: 0, y: Number.MAX_SAFE_INTEGER });
156
+ return true;
157
+ } catch {
158
+ hideNativeHost(host);
159
+ return false;
160
+ }
161
+ }
162
+ function destroyNativeHost(host) {
163
+ if (!host)
164
+ return;
165
+ try {
166
+ host.scrollBox.destroy?.();
167
+ } catch {}
168
+ }
169
+ function nativeTitleBar(renderer, id) {
170
+ return new TextRenderable(renderer, { id, content: "", position: "absolute", left: 0, top: 0, fg: RIG_UI.ink3, zIndex: 10, visible: false });
171
+ }
172
+ export {
173
+ nativeTitleBar,
174
+ hideNativeHost,
175
+ destroyNativeHost,
176
+ createNativeHost,
177
+ applyNativeHost,
178
+ BoxRenderable
179
+ };
@@ -14,15 +14,17 @@ var RIG_UI = {
14
14
  bg: "#070809",
15
15
  bg2: "#0b0c0e",
16
16
  panel: "#101115",
17
- panel2: "#101115",
18
- glass: "#14161b",
19
- ink: "#f2f3f6",
20
- ink2: "#aeb0ba",
21
- ink3: "#6c6e79",
22
- ink4: "#44464f",
17
+ panel2: "#14161b",
18
+ glass: "#1e2230",
19
+ border: "#2a2e3a",
20
+ ink: "#f4f5f8",
21
+ ink2: "#c7c9d3",
22
+ ink3: "#9aa0ae",
23
+ ink4: "#787b86",
23
24
  lime: "#ccff4d",
24
25
  limeDim: "#a9d63f",
25
26
  cyan: "#56d8ff",
27
+ cyanDim: "#3f9fbd",
26
28
  red: "#ff5d5d",
27
29
  yellow: "#ffd24d",
28
30
  magenta: "#ff79b0"
@@ -112,6 +114,8 @@ function applyFlowTextLine(renderable, line, width) {
112
114
  // packages/cli/src/app-opentui/render/panels.ts
113
115
  var TRANSPARENT2 = RGBA2.fromInts(0, 0, 0, 0);
114
116
  var MAX_PANEL_LINES = 420;
117
+ var PANEL_OPAQUE_ALPHA = 255;
118
+ var PANEL_BORDER = hexToRgba(RIG_UI.border, 255);
115
119
  function hexToRgba(hex, alpha) {
116
120
  const clean = hex.replace(/^#/, "");
117
121
  const full = clean.length === 3 ? clean.split("").map((part) => `${part}${part}`).join("") : clean;
@@ -121,10 +125,12 @@ function hexToRgba(hex, alpha) {
121
125
  return RGBA2.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
122
126
  }
123
127
  function panelBackground(panel) {
124
- return hexToRgba(panel.backgroundColor ?? RIG_UI.panel, panel.backgroundAlpha ?? 184);
128
+ return hexToRgba(panel.backgroundColor ?? RIG_UI.panel, PANEL_OPAQUE_ALPHA);
125
129
  }
126
130
  function panelBorder(panel) {
127
- return panel.borderColor ? hexToRgba(panel.borderColor, panel.borderAlpha ?? 54) : TRANSPARENT2;
131
+ if (panel.borderColor)
132
+ return hexToRgba(panel.borderColor, panel.borderAlpha ?? 255);
133
+ return PANEL_BORDER;
128
134
  }
129
135
  function createScrollPanelLayer(renderer, id, onLineMouseDown) {
130
136
  const panel = new ScrollBoxRenderable(renderer, {
@@ -208,9 +214,10 @@ function applyScrollPanels(panels, layout, scenePanels) {
208
214
  renderable.height = height;
209
215
  renderable.zIndex = panel.zIndex ?? 6;
210
216
  renderable.opacity = panel.opacity ?? 1;
211
- renderable.backgroundColor = panel.chrome === "ad-terminal" ? TRANSPARENT2 : panelBackground(panel);
212
- renderable.border = panel.chrome === "ad-terminal" ? false : panel.border ?? false;
213
- renderable.borderColor = panelBorder(panel);
217
+ const adTerminal = panel.chrome === "ad-terminal";
218
+ renderable.backgroundColor = adTerminal ? TRANSPARENT2 : panelBackground(panel);
219
+ renderable.border = adTerminal ? false : true;
220
+ renderable.borderColor = adTerminal ? TRANSPARENT2 : panelBorder(panel);
214
221
  renderable.paddingX = paddingX;
215
222
  renderable.paddingY = paddingY;
216
223
  renderable.stickyScroll = panel.stickyScroll ?? false;
@@ -11,15 +11,17 @@ var RIG_UI = {
11
11
  bg: "#070809",
12
12
  bg2: "#0b0c0e",
13
13
  panel: "#101115",
14
- panel2: "#101115",
15
- glass: "#14161b",
16
- ink: "#f2f3f6",
17
- ink2: "#aeb0ba",
18
- ink3: "#6c6e79",
19
- ink4: "#44464f",
14
+ panel2: "#14161b",
15
+ glass: "#1e2230",
16
+ border: "#2a2e3a",
17
+ ink: "#f4f5f8",
18
+ ink2: "#c7c9d3",
19
+ ink3: "#9aa0ae",
20
+ ink4: "#787b86",
20
21
  lime: "#ccff4d",
21
22
  limeDim: "#a9d63f",
22
23
  cyan: "#56d8ff",
24
+ cyanDim: "#3f9fbd",
23
25
  red: "#ff5d5d",
24
26
  yellow: "#ffd24d",
25
27
  magenta: "#ff79b0"
@@ -1,5 +1,5 @@
1
1
  import { type StageLayout } from "../layout";
2
- import type { AppSceneFrame, AppSceneLine } from "../types";
2
+ import type { AppSceneFrame, AppSceneLine, AppState } from "../types";
3
3
  export declare function line(text: string, options?: Omit<AppSceneLine, "text">): AppSceneLine;
4
4
  export declare function blank(): AppSceneLine;
5
5
  export declare function center(text: string, fg?: string, bold?: boolean): AppSceneLine;
@@ -11,9 +11,58 @@ 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
+ /**
15
+ * The canonical selectable row — the one selection-highlight mechanism for the
16
+ * whole shell (the dense tables already do this; this lifts the pattern out of
17
+ * each scene so they converge). A selected row gets the solid left rule
18
+ * (`SELECTION_MARKER`), lime+bold text, and `RIG_UI.glass` as the row `bg` so it
19
+ * paints a raised bar on the opaque panel ground (render/text.ts plumbs `bg` →
20
+ * RGBA). An idle row keeps a same-width blank marker so labels stay
21
+ * column-aligned whether or not a row is selected. `selectableIndex` makes the
22
+ * row clickable/navigable; pass the list index.
23
+ */
24
+ export declare function selectionLine(input: {
25
+ readonly text: string;
26
+ readonly active: boolean;
27
+ readonly index?: number;
28
+ readonly activateOnClick?: boolean;
29
+ }): AppSceneLine;
30
+ /**
31
+ * A dense-table header row: bold ink heading text on the `RIG_UI.glass` bar, the
32
+ * same raised-bar treatment a selected row gets, so a table's header and its
33
+ * selection share one visual language. Columns are joined with the shared
34
+ * `COLUMN_GUTTER`; pass already-padded column labels.
35
+ */
36
+ export declare function tableHeaderLine(columns: readonly string[]): AppSceneLine;
37
+ /**
38
+ * A `LABEL value` definition row padded to the shared `LABEL_WIDTH`, the
39
+ * canonical width for kv/deck rows across the shell (scenes had diverged on
40
+ * 10/22/26). The label is upper-cased chrome; the value carries the data tone.
41
+ */
42
+ export declare function labeledLine(label: string, value: string, fg?: string): AppSceneLine;
14
43
  export declare function loadingLine(message?: string): AppSceneLine;
15
44
  export declare function emptyLine(message?: string): AppSceneLine;
16
45
  export declare function errorLine(message: string): AppSceneLine;
46
+ /**
47
+ * Per-scene preloader shown while a scene's primary data slice is still absent
48
+ * during a `loading` status (#22). Uses the Rig drone mascot — the animated
49
+ * signal-bus fleet sized for a panel body — with a captioned drone underneath,
50
+ * so a slow fetch reads as a live, branded "fetching" state rather than an empty
51
+ * panel. `tick` (from AppState.tick) drives the animation; pass it from the
52
+ * scene. `compact` swaps the full fleet for a single mini drone in tight panels.
53
+ */
54
+ export declare function loadingRows(label: string, tick?: number, compact?: boolean): AppSceneLine[];
55
+ /**
56
+ * Non-destructive failure banner for a degraded background refresh. Surfaces
57
+ * the error text without wiping the last-known data, and points the operator at
58
+ * the existing refresh/retry deck row below.
59
+ */
60
+ export declare function errorBanner(message: string, hint?: string): AppSceneLine[];
61
+ /**
62
+ * Typed reader for the background-refresh error string the data adapters write
63
+ * onto `state.data.lastRefreshError` (cleared on a successful refresh).
64
+ */
65
+ export declare function lastRefreshError(state: AppState): string | undefined;
17
66
  export declare function fitSceneLine(input: AppSceneLine, layout: StageLayout): AppSceneLine;
18
67
  export declare function fitSceneLines(lines: readonly AppSceneLine[], layout: StageLayout): AppSceneLine[];
19
68
  export declare function makeSceneFrame(input: AppSceneFrame): AppSceneFrame;