@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
@@ -36,19 +36,25 @@ var RIG_UI = {
36
36
  bg: "#070809",
37
37
  bg2: "#0b0c0e",
38
38
  panel: "#101115",
39
- panel2: "#101115",
40
- glass: "#14161b",
41
- ink: "#f2f3f6",
42
- ink2: "#aeb0ba",
43
- ink3: "#6c6e79",
44
- ink4: "#44464f",
39
+ panel2: "#14161b",
40
+ glass: "#1e2230",
41
+ border: "#2a2e3a",
42
+ ink: "#f4f5f8",
43
+ ink2: "#c7c9d3",
44
+ ink3: "#9aa0ae",
45
+ ink4: "#787b86",
45
46
  lime: "#ccff4d",
46
47
  limeDim: "#a9d63f",
47
48
  cyan: "#56d8ff",
49
+ cyanDim: "#3f9fbd",
48
50
  red: "#ff5d5d",
49
51
  yellow: "#ffd24d",
50
52
  magenta: "#ff79b0"
51
53
  };
54
+ var SELECTION_MARKER = "\u258C";
55
+ var SELECTION_MARKER_IDLE = " ";
56
+ var LABEL_WIDTH = 14;
57
+ var COLUMN_GUTTER = " ";
52
58
  var styles = {
53
59
  ink: otuiFg(RIG_UI.ink),
54
60
  ink2: otuiFg(RIG_UI.ink2),
@@ -62,6 +68,134 @@ var styles = {
62
68
  magenta: otuiFg(RIG_UI.magenta)
63
69
  };
64
70
 
71
+ // packages/cli/src/app-opentui/drone.ts
72
+ import { RGBA, StyledText, TextAttributes as TextAttributes2 } from "@opentui/core";
73
+ var MINI_DRONE = [
74
+ "(!!!) (!!!)",
75
+ " \\%==%/ ",
76
+ " %%?%% ",
77
+ " /%==%\\ ",
78
+ "(!!!) (!!!)"
79
+ ];
80
+ var LEAD_MARK = [
81
+ " .-=-. ",
82
+ "=%%?%%=",
83
+ " '-=-' "
84
+ ];
85
+ var BLADE_FRAMES = ["---", "\\\\\\", "|||", "///"];
86
+ var EYE_FRAMES = ["o", "@", "\u2022", "."];
87
+ var COLOR = {
88
+ body: RGBA.fromHex(RIG_UI.lime),
89
+ mini: RGBA.fromHex(RIG_UI.limeDim),
90
+ rotor: RGBA.fromHex(RIG_UI.cyan),
91
+ path: RGBA.fromHex(RIG_UI.cyan),
92
+ eye: RGBA.fromHex(RIG_UI.ink),
93
+ dim: RGBA.fromHex(RIG_UI.ink4),
94
+ ink: RGBA.fromHex(RIG_UI.ink2)
95
+ };
96
+ function bladeForTick(tick, phase = 0) {
97
+ return BLADE_FRAMES[(Math.floor(tick / 3) + phase) % BLADE_FRAMES.length];
98
+ }
99
+ function eyeForTick(tick, phase = 0) {
100
+ const pulse = Math.sin(tick * 0.09 + phase);
101
+ return pulse > 0.55 ? EYE_FRAMES[1] : pulse > 0.1 ? EYE_FRAMES[0] : pulse > -0.45 ? EYE_FRAMES[2] : EYE_FRAMES[3];
102
+ }
103
+ function chunk(text, fg, bold = false, dim = false) {
104
+ let attributes = TextAttributes2.NONE;
105
+ if (bold)
106
+ attributes |= TextAttributes2.BOLD;
107
+ if (dim)
108
+ attributes |= TextAttributes2.DIM;
109
+ return { __isChunk: true, text, fg, ...attributes !== TextAttributes2.NONE ? { attributes } : {} };
110
+ }
111
+ function styledLine(text, colorFor) {
112
+ const chunks = [];
113
+ let run = "";
114
+ let runColor = null;
115
+ const flush = () => {
116
+ if (!run || !runColor)
117
+ return;
118
+ chunks.push(chunk(run, COLOR[runColor], runColor === "body" || runColor === "eye", runColor === "dim"));
119
+ run = "";
120
+ };
121
+ for (const char of text) {
122
+ const next = colorFor(char);
123
+ if (next !== runColor) {
124
+ flush();
125
+ runColor = next;
126
+ }
127
+ run += char;
128
+ }
129
+ flush();
130
+ return new StyledText(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
131
+ }
132
+ function droneColor(char) {
133
+ if (char === "?" || char === "o" || char === "@" || char === "\u2022")
134
+ return "eye";
135
+ if (char === "%" || char === "=")
136
+ return "mini";
137
+ if (char === "$")
138
+ return "body";
139
+ if (char === "(" || char === ")" || char === "/" || char === "\\" || char === "|" || char === "-")
140
+ return "rotor";
141
+ if (char === "\xB7" || char === "\u2022" || char === "'" || char === ".")
142
+ return "path";
143
+ if (char.trim() === "")
144
+ return "dim";
145
+ return "ink";
146
+ }
147
+ function motionColor(char) {
148
+ if (char === "\u25CF" || char === "\u25C6" || char === "\u25C9")
149
+ return "body";
150
+ if (char === "\u2022" || char === "\xB7" || char === "\u2500" || char === "\u2502" || char === "\u2571" || char === "\u2572" || char === "\u256D" || char === "\u256E" || char === "\u2570" || char === "\u256F")
151
+ return "path";
152
+ if (char === "\u258C" || char === "\u2590" || char === "\u2581" || char === "\u2594")
153
+ return "mini";
154
+ return droneColor(char);
155
+ }
156
+ function materializeDrone(lines, tick, phase = 0) {
157
+ const blade = bladeForTick(tick, phase);
158
+ const eye = eyeForTick(tick, phase);
159
+ return lines.map((line) => line.replaceAll("!!!", blade).replaceAll("?", eye));
160
+ }
161
+ function miniDroneLines(tick, align = "left", phase = 0) {
162
+ return materializeDrone(MINI_DRONE, tick, phase).map((text) => ({
163
+ text,
164
+ styledText: styledLine(text, droneColor),
165
+ fg: RIG_UI.limeDim,
166
+ align
167
+ }));
168
+ }
169
+ function brandFleetLines(tick, align = "center") {
170
+ const left = materializeDrone(MINI_DRONE, tick, 0);
171
+ const right = materializeDrone(MINI_DRONE, tick, 2);
172
+ const lead = materializeDrone(LEAD_MARK, tick, 1);
173
+ const packet = ["\xB7", "\u2022", "\u25CF", "\u2022"][Math.floor(tick / 2) % 4];
174
+ const bridge = [
175
+ ` ${left[0]} ${lead[0]} ${right[0]}`,
176
+ ` ${left[1]} \xB7\u2500\u2500${packet}\u2500\u2500\xB7 ${lead[1]} \xB7\u2500\u2500${packet}\u2500\u2500\xB7 ${right[1]}`,
177
+ ` ${left[2]} \xB7' '${lead[2]}' '\xB7 ${right[2]}`,
178
+ ` ${left[3]} \u2572 signal bus \u2571 ${right[3]}`,
179
+ ` ${left[4]} \xB7\u2500\u2500\u2500${packet}\u2500\u2500\u2500\u2500\u2500\u2500${packet}\u2500\u2500\u2500\xB7 ${right[4]}`
180
+ ];
181
+ return bridge.map((text) => ({
182
+ text,
183
+ styledText: styledLine(text, motionColor),
184
+ fg: RIG_UI.limeDim,
185
+ align
186
+ }));
187
+ }
188
+ function actionDrone(tick, phase = 0) {
189
+ const blade = bladeForTick(tick, phase);
190
+ const eye = eyeForTick(tick, phase);
191
+ return `(${blade})\u2572${eye}\u2571(${blade})`;
192
+ }
193
+ function actionDroneLine(tick, text, fg = RIG_UI.ink2) {
194
+ const prefix = actionDrone(tick);
195
+ const content = `${prefix} ${text}`;
196
+ return { text: content, styledText: styledLine(content, motionColor), fg, align: "center" };
197
+ }
198
+
65
199
  // packages/cli/src/app-opentui/render/scene.ts
66
200
  function line(text, options = {}) {
67
201
  return { text, ...options };
@@ -85,6 +219,22 @@ function deckRow(input) {
85
219
  function kv(label, value, fg = RIG_UI.ink2) {
86
220
  return line(` ${label.toUpperCase().padEnd(10)} ${value}`, { fg });
87
221
  }
222
+ function selectionLine(input) {
223
+ const marker = input.active ? SELECTION_MARKER : SELECTION_MARKER_IDLE;
224
+ return line(`${marker} ${input.text}`, {
225
+ fg: input.active ? RIG_UI.lime : RIG_UI.ink2,
226
+ bold: input.active,
227
+ bg: input.active ? RIG_UI.glass : undefined,
228
+ selectableIndex: input.index,
229
+ activateOnClick: input.activateOnClick
230
+ });
231
+ }
232
+ function tableHeaderLine(columns) {
233
+ return line(columns.join(COLUMN_GUTTER), { fg: RIG_UI.ink, bold: true, bg: RIG_UI.glass });
234
+ }
235
+ function labeledLine(label, value, fg = RIG_UI.ink2) {
236
+ return line(`${COLUMN_GUTTER}${label.toUpperCase().padEnd(LABEL_WIDTH)}${COLUMN_GUTTER}${value}`, { fg });
237
+ }
88
238
  function loadingLine(message = "loading") {
89
239
  return line(` \u27F2 ${message}`, { fg: RIG_UI.limeDim });
90
240
  }
@@ -94,6 +244,27 @@ function emptyLine(message = "nothing here yet") {
94
244
  function errorLine(message) {
95
245
  return line(` ! ${message}`, { fg: RIG_UI.magenta, bold: true });
96
246
  }
247
+ function loadingRows(label, tick = 0, compact = false) {
248
+ const mascot = compact ? miniDroneLines(tick, "center") : brandFleetLines(tick, "center");
249
+ return [
250
+ blank(),
251
+ ...mascot,
252
+ blank(),
253
+ { ...actionDroneLine(tick, `loading ${label}\u2026`, RIG_UI.cyan), align: "center" }
254
+ ];
255
+ }
256
+ function errorBanner(message, hint) {
257
+ return [
258
+ line(`\u2717 failed to load \u2014 ${message}`, { fg: RIG_UI.red, bold: true }),
259
+ ...hint ? [line(` ${hint}`, { fg: RIG_UI.ink3 })] : [],
260
+ line(" select refresh/retry below", { fg: RIG_UI.ink4 }),
261
+ line("", { fg: RIG_UI.ink3 })
262
+ ];
263
+ }
264
+ function lastRefreshError(state) {
265
+ const value = state.data.lastRefreshError;
266
+ return typeof value === "string" && value.trim() ? value : undefined;
267
+ }
97
268
  function fitSceneLine(input, layout) {
98
269
  const fitted = truncateText(input.text, layout.centerWidth);
99
270
  return {
@@ -108,13 +279,19 @@ function makeSceneFrame(input) {
108
279
  return input;
109
280
  }
110
281
  export {
282
+ tableHeaderLine,
283
+ selectionLine,
111
284
  makeSceneFrame,
285
+ loadingRows,
112
286
  loadingLine,
113
287
  line,
288
+ lastRefreshError,
289
+ labeledLine,
114
290
  kv,
115
291
  fitSceneLines,
116
292
  fitSceneLine,
117
293
  errorLine,
294
+ errorBanner,
118
295
  emptyLine,
119
296
  deckRow,
120
297
  center,
@@ -1,5 +1,11 @@
1
- import { TextRenderable, type CliRenderer, type MouseEvent } from "@opentui/core";
1
+ import { RGBA, TextRenderable, type CliRenderer, type MouseEvent } from "@opentui/core";
2
2
  import type { AppSceneLine } from "../types";
3
+ /** The "no background" sentinel: a line with no `bg` paints nothing and lets the
4
+ * opaque panel ground (render/panels.ts) show through. A line WITH a `bg` (e.g.
5
+ * a selected row, set via RIG_UI.glass) paints a raised bar on that ground —
6
+ * this is the one selection-highlight mechanism, plumbed end-to-end here so
7
+ * scenes only set `bg` on the AppSceneLine and never touch RGBA. */
8
+ export declare const TRANSPARENT: RGBA;
3
9
  export type TextLineRenderable = TextRenderable & {
4
10
  setRigSceneLine?(line: AppSceneLine | undefined): void;
5
11
  };
@@ -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"
@@ -121,5 +123,6 @@ export {
121
123
  createFlowTextLine,
122
124
  clearTextLines,
123
125
  applyTextLine,
124
- applyFlowTextLine
126
+ applyFlowTextLine,
127
+ TRANSPARENT
125
128
  };
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/cli/src/app-opentui/render/type-bar.ts
3
- import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA, TextRenderable } from "@opentui/core";
3
+ import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA, StyledText, TextRenderable } from "@opentui/core";
4
4
 
5
5
  // packages/cli/src/app-opentui/theme.ts
6
6
  import {
@@ -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"
@@ -44,13 +46,6 @@ var styles = {
44
46
  function visibleWidth(text) {
45
47
  return [...text].length;
46
48
  }
47
- function truncateText(text, width) {
48
- if (visibleWidth(text) <= width)
49
- return text;
50
- if (width <= 1)
51
- return "\u2026";
52
- return `${[...text].slice(0, Math.max(0, width - 1)).join("")}\u2026`;
53
- }
54
49
 
55
50
  // packages/cli/src/app-opentui/render/type-bar.ts
56
51
  var TYPEBAR_BG = RGBA.fromInts(20, 25, 14, 224);
@@ -99,33 +94,49 @@ function createTypeBar(renderer) {
99
94
  left: 0,
100
95
  top: 1,
101
96
  width: "100%",
102
- fg: RIG_UI.ink4,
97
+ fg: RIG_UI.ink3,
103
98
  zIndex: 7,
104
99
  selectable: true
105
100
  });
106
- input.focus();
107
101
  return { background, input, prefix, footer };
108
102
  }
103
+ function modePrefix(mode) {
104
+ switch (mode) {
105
+ case "search":
106
+ return { glyph: " /", color: RIG_UI.cyan };
107
+ case "command":
108
+ return { glyph: " /", color: RIG_UI.lime };
109
+ case "prompt":
110
+ return { glyph: " ?", color: RIG_UI.yellow };
111
+ default:
112
+ return { glyph: " \u203A", color: RIG_UI.ink3 };
113
+ }
114
+ }
109
115
  function positionTypeBar(renderables, input, footer, width, typeBarTop, footerTop) {
116
+ const mode = input.mode ?? "nav";
117
+ const editing = mode !== "nav";
118
+ const { glyph, color } = modePrefix(mode);
110
119
  renderables.background.visible = true;
111
120
  const cardTop = Math.max(0, typeBarTop - 1);
112
121
  renderables.background.left = 0;
113
122
  renderables.background.top = cardTop;
114
123
  renderables.background.width = width;
115
124
  renderables.background.height = Math.max(3, footerTop - cardTop + 1);
116
- renderables.prefix.content = " \u203A";
125
+ renderables.prefix.content = glyph;
126
+ renderables.prefix.fg = color;
117
127
  renderables.prefix.left = 2;
118
128
  renderables.prefix.top = typeBarTop;
119
129
  renderables.input.top = typeBarTop;
120
130
  renderables.input.left = 5;
121
131
  renderables.input.width = Math.max(10, width - 8);
122
- renderables.input.placeholder = input.placeholder;
123
- renderables.input.showCursor = true;
132
+ renderables.input.value = editing ? input.value : "";
133
+ renderables.input.placeholder = editing ? mode === "prompt" ? input.prompt?.label ?? "type a value" : mode === "command" ? "rig \u2026" : "filter\u2026" : input.placeholder;
134
+ renderables.input.showCursor = editing;
135
+ if (renderables.input.focused)
136
+ renderables.input.blur();
124
137
  renderables.footer.top = footerTop;
125
138
  renderables.footer.width = "100%";
126
139
  renderables.footer.content = formatFooter(footer, width);
127
- if (!renderables.input.focused)
128
- renderables.input.focus();
129
140
  }
130
141
  function hideTypeBar(renderables, height) {
131
142
  renderables.background.visible = false;
@@ -153,16 +164,44 @@ function safeFooterMessage(message) {
153
164
  return null;
154
165
  return trimmed;
155
166
  }
156
- function formatFooter(footer, width) {
167
+ function liveCell(live) {
168
+ const connected = live.trimStart().startsWith("\u25CF");
169
+ return { text: live, style: connected ? styles.cyan : styles.ink3 };
170
+ }
171
+ function footerCells(footer) {
157
172
  const safeMessage = safeFooterMessage(footer.message);
158
- const parts = [
159
- footer.project ? "workspace" : null,
160
- footer.server ? "server selected" : null,
161
- footer.auth ? "auth ready" : null,
162
- footer.run ? `run ${footer.run}` : null,
163
- safeMessage
164
- ].filter((part) => Boolean(part));
165
- return ` ${truncateText(parts.join(" \xB7 "), Math.max(8, width - 2))}`;
173
+ const cells = [
174
+ footer.section ? { text: `\u25B8 ${footer.section}`, style: (s) => otuiBold(styles.ink2(s)) } : null,
175
+ footer.live ? liveCell(footer.live) : null,
176
+ footer.project ? { text: "workspace", style: styles.ink3 } : null,
177
+ footer.server ? { text: "server selected", style: styles.ink3 } : null,
178
+ footer.auth ? { text: "auth ready", style: styles.ink3 } : null,
179
+ footer.run ? { text: `run ${footer.run}`, style: styles.ink3 } : null,
180
+ safeMessage ? { text: safeMessage, style: styles.ink2 } : null,
181
+ footer.updated ? { text: footer.updated, style: styles.ink3 } : null
182
+ ];
183
+ return cells.filter((cell) => cell !== null);
184
+ }
185
+ var FOOTER_SEPARATOR = " \xB7 ";
186
+ function formatFooter(footer, width) {
187
+ const budget = Math.max(8, width - 2);
188
+ const chunks = [styles.ink3(" ")];
189
+ let used = 1;
190
+ footerCells(footer).forEach((cell, index) => {
191
+ const sep = index === 0 ? "" : FOOTER_SEPARATOR;
192
+ const remaining = budget - used - visibleWidth(sep);
193
+ if (remaining <= 0)
194
+ return;
195
+ if (sep) {
196
+ chunks.push(styles.ink4(sep));
197
+ used += visibleWidth(sep);
198
+ }
199
+ const fits = visibleWidth(cell.text) <= remaining;
200
+ const text = fits ? cell.text : remaining <= 1 ? "\u2026" : `${[...cell.text].slice(0, Math.max(0, remaining - 1)).join("")}\u2026`;
201
+ chunks.push(cell.style(text));
202
+ used += visibleWidth(text);
203
+ });
204
+ return new StyledText(chunks);
166
205
  }
167
206
  export {
168
207
  positionTypeBar,
@@ -1,2 +1,45 @@
1
- import type { AppLaunchOptions } from "./types";
1
+ import { StyledText, type CliRenderer } from "@opentui/core";
2
+ import { createAppStore } from "./state";
3
+ import type { AppIntent, AppLaunchOptions, AppRuntime, AppSceneId, AppSelectableItem, AppState } from "./types";
4
+ import { type NativeHost } from "./render/native-host";
5
+ /** Total per-scene entry intent for back-navigation (#13). Every AppSceneId
6
+ * resolves to an intent that re-enters THAT scene with its real data refresh —
7
+ * so popping the back-stack restores the exact prior scene, never dumping home
8
+ * from an unrelated origin. Transient PTY scenes (command/handoff) can't be
9
+ * "restored" from a closed terminal, so they re-enter their owning section. */
10
+ export declare function entryIntentForScene(scene: AppSceneId): AppIntent;
11
+ /** Readable section name for the persistent footer breadcrumb. */
12
+ export declare function sceneSectionLabel(scene: AppSceneId): string;
13
+ /** Footer freshness indicator (#6): push-connected vs polling fallback, so the
14
+ * UI never silently lies about whether it is live. */
15
+ export declare function liveLinkLabel(status: "connecting" | "connected" | "disconnected"): string;
16
+ /** Build the persistent top-nav strip as styled text: every section label with
17
+ * the ACTIVE one highlighted (lime + bold), Inbox carrying a live pending-count
18
+ * badge. Rendered on every scene so the operator always sees the sections and
19
+ * where they are (#2). Returns a StyledText for a single absolute TextRenderable. */
20
+ export declare function buildNavStrip(state: AppState): StyledText;
21
+ /** Test-only: the id of the nav section that should light up for a scene (#2). */
22
+ export declare function __activeNavSectionIdForTest(scene: AppSceneId): string;
23
+ /** Test-only: the intent esc/back resolves to given a back-stack — proving back
24
+ * restores the ACTUAL prior scene, never dumping home from an unrelated origin
25
+ * (#13). Mirrors runtime.goBack's resolution (pop → entryIntentForScene). */
26
+ export declare function __backTargetIntentForTest(history: readonly AppSceneId[]): AppIntent;
27
+ /** Test-only: whether a scene resolves to a REAL renderer (false ⇒ it would hit
28
+ * the redirect stub). Asserts the stub is unreachable for every real scene (#3). */
29
+ export declare function __sceneHasRendererForTest(scene: AppSceneId, sceneRenderers?: AppLaunchOptions["sceneRenderers"]): boolean;
30
+ export declare function selectIndex(store: ReturnType<typeof createAppStore>, index: number, renderedItems?: readonly AppSelectableItem[]): boolean;
31
+ export declare function moveSelection(store: ReturnType<typeof createAppStore>, delta: number, renderedItems?: readonly AppSelectableItem[]): boolean;
32
+ /** Select the item with this stable id (#12). Clicks resolve by id so a render
33
+ * between mouse-down and the click callback can't misfire on a shifted row. */
34
+ export declare function selectById(store: ReturnType<typeof createAppStore>, id: string, renderedItems?: readonly AppSelectableItem[]): boolean;
35
+ export declare function activateSelection(runtime: AppRuntime, renderedItems?: readonly AppSelectableItem[]): Promise<boolean>;
36
+ /** Test-only: render a single scene's state to a renderer headlessly so the
37
+ * FULL scene render path (scene renderer → panels + lines + native mounts) can
38
+ * be snapshot-verified via @opentui/core's createTestRenderer + captureCharFrame,
39
+ * without launching the live app. Mirrors the renderable pool the live app
40
+ * builds, then calls the real `renderNow`. Returns the derived selectable list. */
41
+ export declare function __renderSceneForTest(renderer: CliRenderer, state: AppState, sceneRenderers?: AppLaunchOptions["sceneRenderers"]): {
42
+ readonly selectables: readonly AppSelectableItem[];
43
+ readonly nativeHost: NativeHost | null;
44
+ };
2
45
  export declare function launchRigOpenTuiApp(options: AppLaunchOptions): Promise<void>;