@h-rig/cli 0.0.6-alpha.82 → 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 (206) hide show
  1. package/dist/bin/build-rig-binaries.js +40 -8
  2. package/dist/bin/rig.js +23402 -14577
  3. package/dist/src/app/board.js +217 -41
  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.d.ts +0 -2
  8. package/dist/src/app-opentui/adapters/doctor.js +64 -39
  9. package/dist/src/app-opentui/adapters/family.d.ts +62 -0
  10. package/dist/src/app-opentui/adapters/family.js +14305 -0
  11. package/dist/src/app-opentui/adapters/fleet.d.ts +0 -2
  12. package/dist/src/app-opentui/adapters/fleet.js +90 -60
  13. package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
  14. package/dist/src/app-opentui/adapters/inbox.js +137 -78
  15. package/dist/src/app-opentui/adapters/init.d.ts +0 -2
  16. package/dist/src/app-opentui/adapters/init.js +85 -47
  17. package/dist/src/app-opentui/adapters/inspect.d.ts +52 -0
  18. package/dist/src/app-opentui/adapters/inspect.js +1024 -0
  19. package/dist/src/app-opentui/adapters/pi-attach.d.ts +15 -6
  20. package/dist/src/app-opentui/adapters/pi-attach.js +442 -125
  21. package/dist/src/app-opentui/adapters/pi.d.ts +23 -0
  22. package/dist/src/app-opentui/adapters/pi.js +363 -0
  23. package/dist/src/app-opentui/adapters/plugin.d.ts +84 -0
  24. package/dist/src/app-opentui/adapters/plugin.js +544 -0
  25. package/dist/src/app-opentui/adapters/repo.d.ts +37 -0
  26. package/dist/src/app-opentui/adapters/repo.js +186 -0
  27. package/dist/src/app-opentui/adapters/run-detail.d.ts +9 -2
  28. package/dist/src/app-opentui/adapters/run-detail.js +180 -63
  29. package/dist/src/app-opentui/adapters/server.d.ts +10 -2
  30. package/dist/src/app-opentui/adapters/server.js +191 -45
  31. package/dist/src/app-opentui/adapters/tasks.d.ts +11 -2
  32. package/dist/src/app-opentui/adapters/tasks.js +1123 -143
  33. package/dist/src/app-opentui/adapters/workspace.d.ts +49 -0
  34. package/dist/src/app-opentui/adapters/workspace.js +333 -0
  35. package/dist/src/app-opentui/autocomplete.d.ts +20 -0
  36. package/dist/src/app-opentui/autocomplete.js +576 -0
  37. package/dist/src/app-opentui/bootstrap.d.ts +1 -6
  38. package/dist/src/app-opentui/bootstrap.js +25252 -16474
  39. package/dist/src/app-opentui/command-palette.d.ts +3 -0
  40. package/dist/src/app-opentui/command-palette.js +1010 -0
  41. package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
  42. package/dist/src/app-opentui/command-pty-host.js +248 -0
  43. package/dist/src/app-opentui/drone.js +8 -6
  44. package/dist/src/app-opentui/events.js +1 -1
  45. package/dist/src/app-opentui/fleet-stats.d.ts +32 -0
  46. package/dist/src/app-opentui/fleet-stats.js +114 -0
  47. package/dist/src/app-opentui/focus-manager.d.ts +14 -0
  48. package/dist/src/app-opentui/focus-manager.js +24 -0
  49. package/dist/src/app-opentui/index.js +5431 -2797
  50. package/dist/src/app-opentui/intent.js +179 -50
  51. package/dist/src/app-opentui/keymap.d.ts +21 -0
  52. package/dist/src/app-opentui/keymap.js +1748 -0
  53. package/dist/src/app-opentui/launch-routing.d.ts +16 -0
  54. package/dist/src/app-opentui/launch-routing.js +55 -0
  55. package/dist/src/app-opentui/layout.d.ts +7 -0
  56. package/dist/src/app-opentui/layout.js +13 -6
  57. package/dist/src/app-opentui/list-search.d.ts +24 -0
  58. package/dist/src/app-opentui/list-search.js +88 -1
  59. package/dist/src/app-opentui/pi-host-child.js +99 -17
  60. package/dist/src/app-opentui/pi-pty-host.d.ts +14 -0
  61. package/dist/src/app-opentui/pi-pty-host.js +30 -14
  62. package/dist/src/app-opentui/react/App.d.ts +9 -0
  63. package/dist/src/app-opentui/react/App.js +5144 -0
  64. package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
  65. package/dist/src/app-opentui/react/Backdrop.js +1834 -0
  66. package/dist/src/app-opentui/react/ChromeHost.d.ts +5 -0
  67. package/dist/src/app-opentui/react/ChromeHost.js +2942 -0
  68. package/dist/src/app-opentui/react/SceneFrameView.d.ts +7 -0
  69. package/dist/src/app-opentui/react/SceneFrameView.js +529 -0
  70. package/dist/src/app-opentui/react/context.d.ts +17 -0
  71. package/dist/src/app-opentui/react/context.js +37 -0
  72. package/dist/src/app-opentui/react/launch.d.ts +2 -0
  73. package/dist/src/app-opentui/react/launch.js +5743 -0
  74. package/dist/src/app-opentui/react/nav.d.ts +18 -0
  75. package/dist/src/app-opentui/react/nav.js +54 -0
  76. package/dist/src/app-opentui/react/scroll.d.ts +12 -0
  77. package/dist/src/app-opentui/react/scroll.js +21 -0
  78. package/dist/src/app-opentui/react/syntax.d.ts +2 -0
  79. package/dist/src/app-opentui/react/syntax.js +64 -0
  80. package/dist/src/app-opentui/registry.js +20428 -4828
  81. package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
  82. package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
  83. package/dist/src/app-opentui/render/constants.d.ts +31 -0
  84. package/dist/src/app-opentui/render/constants.js +66 -0
  85. package/dist/src/app-opentui/render/graphics.d.ts +2 -1
  86. package/dist/src/app-opentui/render/graphics.js +228 -46
  87. package/dist/src/app-opentui/render/image-visual-layer-worker.js +469 -930
  88. package/dist/src/app-opentui/render/image-visual-layer.d.ts +25 -10
  89. package/dist/src/app-opentui/render/image-visual-layer.js +448 -329
  90. package/dist/src/app-opentui/render/native-host.d.ts +37 -0
  91. package/dist/src/app-opentui/render/native-host.js +179 -0
  92. package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
  93. package/dist/src/app-opentui/render/panel-layout.js +48 -0
  94. package/dist/src/app-opentui/render/panels.d.ts +2 -0
  95. package/dist/src/app-opentui/render/panels.js +78 -38
  96. package/dist/src/app-opentui/render/preloader.d.ts +10 -0
  97. package/dist/src/app-opentui/render/preloader.js +165 -0
  98. package/dist/src/app-opentui/render/scene.d.ts +53 -1
  99. package/dist/src/app-opentui/render/scene.js +195 -6
  100. package/dist/src/app-opentui/render/text.d.ts +7 -1
  101. package/dist/src/app-opentui/render/text.js +15 -8
  102. package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
  103. package/dist/src/app-opentui/render/type-bar.js +113 -39
  104. package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
  105. package/dist/src/app-opentui/runtime-resources.js +62 -0
  106. package/dist/src/app-opentui/runtime.d.ts +44 -1
  107. package/dist/src/app-opentui/runtime.js +5415 -2738
  108. package/dist/src/app-opentui/scenes/command.d.ts +3 -0
  109. package/dist/src/app-opentui/scenes/command.js +117 -0
  110. package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
  111. package/dist/src/app-opentui/scenes/doctor.js +221 -17
  112. package/dist/src/app-opentui/scenes/error.js +60 -20
  113. package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +2 -0
  114. package/dist/src/app-opentui/scenes/family-domains/agent.js +348 -0
  115. package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +2 -0
  116. package/dist/src/app-opentui/scenes/family-domains/browser.js +195 -0
  117. package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +2 -0
  118. package/dist/src/app-opentui/scenes/family-domains/dist.js +243 -0
  119. package/dist/src/app-opentui/scenes/family-domains/git.d.ts +2 -0
  120. package/dist/src/app-opentui/scenes/family-domains/git.js +195 -0
  121. package/dist/src/app-opentui/scenes/family-domains/github.d.ts +2 -0
  122. package/dist/src/app-opentui/scenes/family-domains/github.js +274 -0
  123. package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +2 -0
  124. package/dist/src/app-opentui/scenes/family-domains/harness.js +152 -0
  125. package/dist/src/app-opentui/scenes/family-domains/index.d.ts +4 -0
  126. package/dist/src/app-opentui/scenes/family-domains/index.js +1679 -0
  127. package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +76 -0
  128. package/dist/src/app-opentui/scenes/family-domains/kit.js +305 -0
  129. package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +2 -0
  130. package/dist/src/app-opentui/scenes/family-domains/profile.js +212 -0
  131. package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +2 -0
  132. package/dist/src/app-opentui/scenes/family-domains/queue.js +146 -0
  133. package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +2 -0
  134. package/dist/src/app-opentui/scenes/family-domains/remote.js +518 -0
  135. package/dist/src/app-opentui/scenes/family-domains/review.d.ts +2 -0
  136. package/dist/src/app-opentui/scenes/family-domains/review.js +280 -0
  137. package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +2 -0
  138. package/dist/src/app-opentui/scenes/family-domains/setup.js +267 -0
  139. package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +2 -0
  140. package/dist/src/app-opentui/scenes/family-domains/stats.js +370 -0
  141. package/dist/src/app-opentui/scenes/family.d.ts +3 -0
  142. package/dist/src/app-opentui/scenes/family.js +2144 -0
  143. package/dist/src/app-opentui/scenes/fleet.js +552 -43
  144. package/dist/src/app-opentui/scenes/handoff.js +342 -35
  145. package/dist/src/app-opentui/scenes/help.js +640 -56
  146. package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
  147. package/dist/src/app-opentui/scenes/inbox.js +329 -21
  148. package/dist/src/app-opentui/scenes/init.d.ts +2 -1
  149. package/dist/src/app-opentui/scenes/init.js +120 -34
  150. package/dist/src/app-opentui/scenes/inspect.d.ts +3 -0
  151. package/dist/src/app-opentui/scenes/inspect.js +793 -0
  152. package/dist/src/app-opentui/scenes/main.d.ts +2 -1
  153. package/dist/src/app-opentui/scenes/main.js +264 -29
  154. package/dist/src/app-opentui/scenes/pi.d.ts +3 -0
  155. package/dist/src/app-opentui/scenes/pi.js +508 -0
  156. package/dist/src/app-opentui/scenes/plugin.d.ts +3 -0
  157. package/dist/src/app-opentui/scenes/plugin.js +486 -0
  158. package/dist/src/app-opentui/scenes/repo.d.ts +3 -0
  159. package/dist/src/app-opentui/scenes/repo.js +424 -0
  160. package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
  161. package/dist/src/app-opentui/scenes/run-detail.js +362 -35
  162. package/dist/src/app-opentui/scenes/server.d.ts +2 -1
  163. package/dist/src/app-opentui/scenes/server.js +243 -26
  164. package/dist/src/app-opentui/scenes/tasks.js +518 -41
  165. package/dist/src/app-opentui/scenes/workspace.d.ts +3 -0
  166. package/dist/src/app-opentui/scenes/workspace.js +426 -0
  167. package/dist/src/app-opentui/selectable.d.ts +19 -0
  168. package/dist/src/app-opentui/selectable.js +79 -0
  169. package/dist/src/app-opentui/state.js +129 -36
  170. package/dist/src/app-opentui/surface-catalog.d.ts +20 -0
  171. package/dist/src/app-opentui/surface-catalog.js +540 -0
  172. package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
  173. package/dist/src/app-opentui/terminal-capabilities.js +15 -0
  174. package/dist/src/app-opentui/theme.d.ts +28 -6
  175. package/dist/src/app-opentui/theme.js +61 -8
  176. package/dist/src/app-opentui/types.d.ts +130 -5
  177. package/dist/src/commands/_authority-runs.d.ts +1 -1
  178. package/dist/src/commands/_authority-runs.js +2 -12
  179. package/dist/src/commands/_doctor-checks.js +62 -13
  180. package/dist/src/commands/_help-catalog.js +95 -15
  181. package/dist/src/commands/_operator-view.js +97 -15
  182. package/dist/src/commands/_pi-frontend.d.ts +2 -0
  183. package/dist/src/commands/_pi-frontend.js +97 -13
  184. package/dist/src/commands/_preflight.js +64 -14
  185. package/dist/src/commands/_server-client.js +82 -18
  186. package/dist/src/commands/_server-events.d.ts +26 -0
  187. package/dist/src/commands/_server-events.js +310 -0
  188. package/dist/src/commands/_snapshot-upload.js +62 -13
  189. package/dist/src/commands/agent.js +2 -12
  190. package/dist/src/commands/connect.js +7 -1
  191. package/dist/src/commands/doctor.js +62 -13
  192. package/dist/src/commands/github.js +144 -23
  193. package/dist/src/commands/inbox.js +62 -13
  194. package/dist/src/commands/init.js +82 -18
  195. package/dist/src/commands/inspect.js +62 -13
  196. package/dist/src/commands/run.js +100 -15
  197. package/dist/src/commands/server.js +71 -26
  198. package/dist/src/commands/setup.js +62 -13
  199. package/dist/src/commands/stats.js +157 -28
  200. package/dist/src/commands/task-run-driver.js +64 -25
  201. package/dist/src/commands/task.js +196 -43
  202. package/dist/src/commands.js +419 -123
  203. package/dist/src/index.js +426 -130
  204. package/package.json +11 -10
  205. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
  206. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
@@ -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"
@@ -38,11 +40,11 @@ var styles = {
38
40
  };
39
41
  function statusColor(status) {
40
42
  switch (status) {
41
- case "running":
42
43
  case "success":
43
44
  case "completed":
44
45
  case "merged":
45
46
  return RIG_UI.lime;
47
+ case "running":
46
48
  case "preparing":
47
49
  case "created":
48
50
  case "validating":
@@ -63,6 +65,134 @@ function statusColor(status) {
63
65
  }
64
66
  }
65
67
 
68
+ // packages/cli/src/app-opentui/drone.ts
69
+ import { RGBA, StyledText, TextAttributes as TextAttributes2 } from "@opentui/core";
70
+ var MINI_DRONE = [
71
+ "(!!!) (!!!)",
72
+ " \\%==%/ ",
73
+ " %%?%% ",
74
+ " /%==%\\ ",
75
+ "(!!!) (!!!)"
76
+ ];
77
+ var LEAD_MARK = [
78
+ " .-=-. ",
79
+ "=%%?%%=",
80
+ " '-=-' "
81
+ ];
82
+ var BLADE_FRAMES = ["---", "\\\\\\", "|||", "///"];
83
+ var EYE_FRAMES = ["o", "@", "\u2022", "."];
84
+ var COLOR = {
85
+ body: RGBA.fromHex(RIG_UI.lime),
86
+ mini: RGBA.fromHex(RIG_UI.limeDim),
87
+ rotor: RGBA.fromHex(RIG_UI.cyan),
88
+ path: RGBA.fromHex(RIG_UI.cyan),
89
+ eye: RGBA.fromHex(RIG_UI.ink),
90
+ dim: RGBA.fromHex(RIG_UI.ink4),
91
+ ink: RGBA.fromHex(RIG_UI.ink2)
92
+ };
93
+ function bladeForTick(tick, phase = 0) {
94
+ return BLADE_FRAMES[(Math.floor(tick / 3) + phase) % BLADE_FRAMES.length];
95
+ }
96
+ function eyeForTick(tick, phase = 0) {
97
+ const pulse = Math.sin(tick * 0.09 + phase);
98
+ return pulse > 0.55 ? EYE_FRAMES[1] : pulse > 0.1 ? EYE_FRAMES[0] : pulse > -0.45 ? EYE_FRAMES[2] : EYE_FRAMES[3];
99
+ }
100
+ function chunk(text, fg, bold = false, dim = false) {
101
+ let attributes = TextAttributes2.NONE;
102
+ if (bold)
103
+ attributes |= TextAttributes2.BOLD;
104
+ if (dim)
105
+ attributes |= TextAttributes2.DIM;
106
+ return { __isChunk: true, text, fg, ...attributes !== TextAttributes2.NONE ? { attributes } : {} };
107
+ }
108
+ function styledLine(text, colorFor) {
109
+ const chunks = [];
110
+ let run = "";
111
+ let runColor = null;
112
+ const flush = () => {
113
+ if (!run || !runColor)
114
+ return;
115
+ chunks.push(chunk(run, COLOR[runColor], runColor === "body" || runColor === "eye", runColor === "dim"));
116
+ run = "";
117
+ };
118
+ for (const char of text) {
119
+ const next = colorFor(char);
120
+ if (next !== runColor) {
121
+ flush();
122
+ runColor = next;
123
+ }
124
+ run += char;
125
+ }
126
+ flush();
127
+ return new StyledText(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
128
+ }
129
+ function droneColor(char) {
130
+ if (char === "?" || char === "o" || char === "@" || char === "\u2022")
131
+ return "eye";
132
+ if (char === "%" || char === "=")
133
+ return "mini";
134
+ if (char === "$")
135
+ return "body";
136
+ if (char === "(" || char === ")" || char === "/" || char === "\\" || char === "|" || char === "-")
137
+ return "rotor";
138
+ if (char === "\xB7" || char === "\u2022" || char === "'" || char === ".")
139
+ return "path";
140
+ if (char.trim() === "")
141
+ return "dim";
142
+ return "ink";
143
+ }
144
+ function motionColor(char) {
145
+ if (char === "\u25CF" || char === "\u25C6" || char === "\u25C9")
146
+ return "body";
147
+ if (char === "\u2022" || char === "\xB7" || char === "\u2500" || char === "\u2502" || char === "\u2571" || char === "\u2572" || char === "\u256D" || char === "\u256E" || char === "\u2570" || char === "\u256F")
148
+ return "path";
149
+ if (char === "\u258C" || char === "\u2590" || char === "\u2581" || char === "\u2594")
150
+ return "mini";
151
+ return droneColor(char);
152
+ }
153
+ function materializeDrone(lines, tick, phase = 0) {
154
+ const blade = bladeForTick(tick, phase);
155
+ const eye = eyeForTick(tick, phase);
156
+ return lines.map((line) => line.replaceAll("!!!", blade).replaceAll("?", eye));
157
+ }
158
+ function miniDroneLines(tick, align = "left", phase = 0) {
159
+ return materializeDrone(MINI_DRONE, tick, phase).map((text) => ({
160
+ text,
161
+ styledText: styledLine(text, droneColor),
162
+ fg: RIG_UI.limeDim,
163
+ align
164
+ }));
165
+ }
166
+ function brandFleetLines(tick, align = "center") {
167
+ const left = materializeDrone(MINI_DRONE, tick, 0);
168
+ const right = materializeDrone(MINI_DRONE, tick, 2);
169
+ const lead = materializeDrone(LEAD_MARK, tick, 1);
170
+ const packet = ["\xB7", "\u2022", "\u25CF", "\u2022"][Math.floor(tick / 2) % 4];
171
+ const bridge = [
172
+ ` ${left[0]} ${lead[0]} ${right[0]}`,
173
+ ` ${left[1]} \xB7\u2500\u2500${packet}\u2500\u2500\xB7 ${lead[1]} \xB7\u2500\u2500${packet}\u2500\u2500\xB7 ${right[1]}`,
174
+ ` ${left[2]} \xB7' '${lead[2]}' '\xB7 ${right[2]}`,
175
+ ` ${left[3]} \u2572 signal bus \u2571 ${right[3]}`,
176
+ ` ${left[4]} \xB7\u2500\u2500\u2500${packet}\u2500\u2500\u2500\u2500\u2500\u2500${packet}\u2500\u2500\u2500\xB7 ${right[4]}`
177
+ ];
178
+ return bridge.map((text) => ({
179
+ text,
180
+ styledText: styledLine(text, motionColor),
181
+ fg: RIG_UI.limeDim,
182
+ align
183
+ }));
184
+ }
185
+ function actionDrone(tick, phase = 0) {
186
+ const blade = bladeForTick(tick, phase);
187
+ const eye = eyeForTick(tick, phase);
188
+ return `(${blade})\u2572${eye}\u2571(${blade})`;
189
+ }
190
+ function actionDroneLine(tick, text, fg = RIG_UI.ink2) {
191
+ const prefix = actionDrone(tick);
192
+ const content = `${prefix} ${text}`;
193
+ return { text: content, styledText: styledLine(content, motionColor), fg, align: "center" };
194
+ }
195
+
66
196
  // packages/cli/src/app-opentui/render/scene.ts
67
197
  function line(text, options = {}) {
68
198
  return { text, ...options };
@@ -70,9 +200,6 @@ function line(text, options = {}) {
70
200
  function blank() {
71
201
  return { text: "" };
72
202
  }
73
- function center(text, fg = RIG_UI.ink2, bold = false) {
74
- return { text, fg, bold, align: "center" };
75
- }
76
203
  function deckRow(input) {
77
204
  const prefix = input.active ? "\u25B8" : " ";
78
205
  const label = input.label.toUpperCase().padEnd(10);
@@ -86,11 +213,81 @@ function deckRow(input) {
86
213
  function kv(label, value, fg = RIG_UI.ink2) {
87
214
  return line(` ${label.toUpperCase().padEnd(10)} ${value}`, { fg });
88
215
  }
216
+ function loadingRows(label, tick = 0, compact = false) {
217
+ const mascot = compact ? miniDroneLines(tick, "center") : brandFleetLines(tick, "center");
218
+ return [
219
+ blank(),
220
+ ...mascot,
221
+ blank(),
222
+ { ...actionDroneLine(tick, `loading ${label}\u2026`, RIG_UI.cyan), align: "center" }
223
+ ];
224
+ }
225
+ function errorBanner(message, hint) {
226
+ return [
227
+ line(`\u2717 failed to load \u2014 ${message}`, { fg: RIG_UI.red, bold: true }),
228
+ ...hint ? [line(` ${hint}`, { fg: RIG_UI.ink3 })] : [],
229
+ line(" select refresh/retry below", { fg: RIG_UI.ink4 }),
230
+ line("", { fg: RIG_UI.ink3 })
231
+ ];
232
+ }
233
+ function lastRefreshError(state) {
234
+ const value = state.data.lastRefreshError;
235
+ return typeof value === "string" && value.trim() ? value : undefined;
236
+ }
89
237
  function makeSceneFrame(input) {
90
238
  return input;
91
239
  }
92
240
 
241
+ // packages/cli/src/app-opentui/selectable.ts
242
+ function withSelectable(line2, item) {
243
+ return { ...line2, selectable: item, activateOnClick: true };
244
+ }
245
+
93
246
  // packages/cli/src/app-opentui/scenes/run-detail.ts
247
+ function actionRow(deck, item) {
248
+ const row = deckRow({ ...deck, activateOnClick: true });
249
+ return item ? withSelectable(row, item) : row;
250
+ }
251
+ function isTerminalRunStatus(status) {
252
+ return ["completed", "complete", "done", "failed", "error", "errored", "merged", "cancelled", "canceled", "stopped", "aborted"].includes(status.toLowerCase());
253
+ }
254
+ function runDetailActions(runId, status) {
255
+ const short = runId ? runId.slice(0, 8) : "";
256
+ const attach = {
257
+ label: "pi",
258
+ detail: "attach bundled Pi \u2014 live or finished transcript",
259
+ item: runId ? { id: "attach", label: "attach", intent: { scene: "handoff", argv: ["attach", runId], action: { kind: "run-attach", payload: { runId }, label: `Attach Pi ${short}` } }, message: "attach real bundled Pi" } : null
260
+ };
261
+ const inspect = {
262
+ label: "inspect",
263
+ detail: "logs/timeline/diff/failures",
264
+ item: runId ? { id: "inspect", label: "inspect", data: { selectedRunId: runId }, intent: { scene: "inspect", argv: ["inspect", runId], action: { kind: "refresh", payload: { runId }, label: `Inspect ${short}` } }, message: "logs/timeline/diff/failures" } : null
265
+ };
266
+ const fleet = {
267
+ label: "runs",
268
+ detail: "return to fleet",
269
+ item: { id: "fleet", label: "fleet", intent: { scene: "fleet", argv: ["fleet"], action: { kind: "refresh", label: "Opening fleet" } }, message: "back to fleet" }
270
+ };
271
+ if (runId && isTerminalRunStatus(status)) {
272
+ const rerun = {
273
+ label: "rerun",
274
+ detail: "re-dispatch this run from a clean runtime",
275
+ item: { id: "rerun", label: "rerun", intent: { scene: "command", argv: ["run", "restart", runId], action: { kind: "command-run", payload: { runId }, label: `Rerun ${short}` } }, message: "re-dispatch this run (rig run restart)" }
276
+ };
277
+ return [attach, rerun, inspect, fleet];
278
+ }
279
+ const steer = {
280
+ label: "steer",
281
+ detail: "send an inline steer message",
282
+ item: runId ? { id: "steer", label: "steer", prompt: { label: `steer ${short}`, scene: "run-detail", argv: ["steer", runId], intentKind: "run-steer", payloadBase: { runId }, payloadKey: "message" }, message: "send an inline steer message" } : null
283
+ };
284
+ const stop = {
285
+ label: "stop",
286
+ detail: "request stop",
287
+ item: runId ? { id: "stop", label: "stop", intent: { scene: "run-detail", argv: ["stop", runId], action: { kind: "run-stop", payload: { runId }, label: `Stop ${short}` } }, message: "request stop" } : null
288
+ };
289
+ return [attach, steer, stop, inspect, fleet];
290
+ }
94
291
  function snapshot(state) {
95
292
  const value = state.data.runDetail;
96
293
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -100,37 +297,167 @@ function selectedRunId(state, run) {
100
297
  return run.runId;
101
298
  return typeof state.data.selectedRunId === "string" ? state.data.selectedRunId : undefined;
102
299
  }
103
- function entryText(entry) {
104
- return String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? entry.type ?? "event").replace(/\s+/g, " ").slice(0, 96);
300
+ var ENTRY_ROW_LIMIT = 40;
301
+ function entryField(entry, keys) {
302
+ for (const key of keys) {
303
+ const value = entry[key];
304
+ if (typeof value === "string" && value.trim())
305
+ return value.trim();
306
+ if (typeof value === "number")
307
+ return String(value);
308
+ }
309
+ return "";
310
+ }
311
+ function entryMessage(entry) {
312
+ return String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? entry.type ?? "event").replace(/\s+/g, " ").slice(0, 160);
313
+ }
314
+ function entrySeverityColor(entry, fallback) {
315
+ const token = `${entryField(entry, ["type", "level", "status", "kind"])} ${entryMessage(entry)}`.toLowerCase();
316
+ if (/\b(fail|failed|failure|error|fatal|crash|abort)\b/.test(token))
317
+ return RIG_UI.red;
318
+ if (/\b(warn|warning|attention|degraded|retry)\b/.test(token))
319
+ return RIG_UI.yellow;
320
+ if (/\b(success|succeeded|completed|done|merged|passed)\b/.test(token))
321
+ return RIG_UI.limeDim;
322
+ return fallback;
323
+ }
324
+ function entryRow(entry, fallback) {
325
+ const color = entrySeverityColor(entry, fallback);
326
+ const time = entryField(entry, ["timestamp", "ts", "time", "at"]).replace("T", " ").slice(0, 19);
327
+ const type = entryField(entry, ["type", "level", "kind", "status"]).slice(0, 14);
328
+ const glyph = color === RIG_UI.red ? "\u2717" : color === RIG_UI.yellow ? "\u26A0" : "\xB7";
329
+ const segments = [time, type ? type.toUpperCase() : undefined, entryMessage(entry)].filter((part) => Boolean(part));
330
+ return line(`${glyph} ${segments.join(" \xB7 ")}`, { fg: color, bold: color === RIG_UI.red });
331
+ }
332
+ function entrySection(label, entries, fallback) {
333
+ if (entries.length === 0)
334
+ return [];
335
+ const shown = entries.slice(0, ENTRY_ROW_LIMIT);
336
+ const overflow = entries.length - shown.length;
337
+ return [
338
+ line("", { fg: RIG_UI.ink3 }),
339
+ line(`${label} (${entries.length})`, { fg: RIG_UI.ink3, bold: true }),
340
+ ...shown.map((entry) => entryRow(entry, fallback)),
341
+ ...overflow > 0 ? [line(` (${overflow} more)`, { fg: RIG_UI.ink4 })] : []
342
+ ];
343
+ }
344
+ function primaryError(state) {
345
+ return state.error?.message ?? lastRefreshError(state);
346
+ }
347
+ function optimisticStatus(state, runId) {
348
+ const value = state.data.optimisticRun;
349
+ if (!value || typeof value !== "object" || Array.isArray(value))
350
+ return;
351
+ const record = value;
352
+ if (runId && record.runId !== runId)
353
+ return;
354
+ return typeof record.status === "string" ? record.status : undefined;
355
+ }
356
+ function pendingSteer(state, runId) {
357
+ const value = state.data.pendingRunMessage;
358
+ if (!value || typeof value !== "object" || Array.isArray(value))
359
+ return null;
360
+ const record = value;
361
+ if (runId && record.runId !== runId)
362
+ return null;
363
+ if (typeof record.text !== "string")
364
+ return null;
365
+ return {
366
+ text: record.text,
367
+ status: typeof record.status === "string" ? record.status : "queued",
368
+ ...typeof record.result === "string" && record.result.trim() ? { result: record.result.trim() } : {}
369
+ };
370
+ }
371
+ function steerBlock(pending) {
372
+ const failed = pending.status === "failed";
373
+ const sent = pending.status === "sent" || pending.status === "delivered";
374
+ const glyph = failed ? "\u2717" : sent ? "\u2713" : "\u27F3";
375
+ const color = failed ? RIG_UI.red : sent ? RIG_UI.lime : RIG_UI.cyan;
376
+ const echoed = pending.text.length > 84 ? `${pending.text.slice(0, 83)}\u2026` : pending.text;
377
+ return [
378
+ line("", { fg: RIG_UI.ink3 }),
379
+ line(`${glyph} STEER \xB7 ${pending.status}`, { fg: color, bold: true }),
380
+ line(` "${echoed}"`, { fg: RIG_UI.ink2 }),
381
+ ...pending.result ? [line(` ${failed ? "error" : "result"}: ${pending.result.replace(/\s+/g, " ").slice(0, 120)}`, { fg: failed ? RIG_UI.red : RIG_UI.ink3 })] : []
382
+ ];
105
383
  }
106
- function renderRunDetailScene(state) {
384
+ function timelineCountLabel(snapshot2) {
385
+ const shown = snapshot2.timeline.length;
386
+ const total = snapshot2.timelineTotal;
387
+ return total !== undefined && total > shown ? `showing ${shown} of ${total}` : `${shown} loaded`;
388
+ }
389
+ function loadMoreItem(runId, cursor) {
390
+ return {
391
+ id: "timeline-load-more",
392
+ label: "load more timeline",
393
+ data: { runDetailLoadMore: { runId, cursor } },
394
+ intent: { scene: "run-detail", argv: ["run", "status", runId], action: { kind: "refresh", payload: { runId }, label: "Load more timeline" } },
395
+ message: "fetch the next page of timeline events"
396
+ };
397
+ }
398
+ function panelWidth(layout) {
399
+ return layout?.centerWidth ?? 100;
400
+ }
401
+ function panelHeight(layout) {
402
+ return Math.max(10, (layout?.centerHeight ?? 24) - 1);
403
+ }
404
+ function renderRunDetailScene(state, layout) {
107
405
  const run = snapshot(state);
108
406
  const runId = selectedRunId(state, run);
109
- const selected = Math.max(0, Math.min(2, state.selection.index));
110
- const timeline = run?.timeline.slice(-5).map((entry) => entryText(entry)) ?? [];
111
- const logs = run?.logs.slice(-3).map((entry) => entryText(entry)) ?? [];
112
- const status = run?.status ?? "loading";
113
- const lines = [
114
- center(run ? run.title : "run", RIG_UI.ink, true),
115
- center(runId ? `${runId.slice(0, 8)} \xB7 ${status}` : "loading run", run ? statusColor(status) : RIG_UI.ink3),
116
- blank(),
117
- ...runId ? [
118
- deckRow({ label: "pi", detail: "attach bundled Pi", index: 0, active: selected === 0, activateOnClick: true }),
119
- deckRow({ label: "stop", detail: "request stop", index: 1, active: selected === 1, activateOnClick: true }),
120
- deckRow({ label: "runs", detail: "return to list", index: 2, active: selected === 2, activateOnClick: true }),
121
- blank(),
122
- kv("status", status, statusColor(status)),
123
- kv("run", runId, RIG_UI.ink2)
124
- ] : [line("loading run telemetry", { fg: RIG_UI.ink3, align: "center" })],
125
- ...timeline.length > 0 ? [blank(), line(" timeline", { fg: RIG_UI.ink4, bold: true }), ...timeline.map((entry) => line(` \xB7 ${entry}`, { fg: RIG_UI.ink2 }))] : [],
126
- ...logs.length > 0 ? [blank(), line(" logs", { fg: RIG_UI.ink4, bold: true }), ...logs.map((entry) => line(` \xB7 ${entry}`, { fg: RIG_UI.ink4 }))] : []
127
- ];
407
+ const status = optimisticStatus(state, runId) ?? run?.status ?? "loading";
408
+ const actions = runDetailActions(runId, status);
409
+ const actionCount = actions.length;
410
+ const canLoadMore = Boolean(run?.timelineCursor && runId);
411
+ const loadMoreIndex = actionCount;
412
+ const maxIndex = canLoadMore ? loadMoreIndex : Math.max(0, actionCount - 1);
413
+ const selected = Math.max(0, Math.min(maxIndex, state.selection.index));
414
+ const timeline = run?.timeline ?? [];
415
+ const logs = run?.logs ?? [];
416
+ const pending = pendingSteer(state, runId);
417
+ const loading = state.status === "loading" && !run;
418
+ const errorText = primaryError(state);
419
+ const timelineSection = run ? [
420
+ line("", { fg: RIG_UI.ink3 }),
421
+ line(`TIMELINE \xB7 ${timelineCountLabel(run)}`, { fg: RIG_UI.ink3, bold: true }),
422
+ ...timeline.slice(0, ENTRY_ROW_LIMIT).map((entry) => entryRow(entry, RIG_UI.ink2)),
423
+ ...canLoadMore && runId ? [withSelectable(deckRow({ label: "load more", detail: `next page \xB7 ${timelineCountLabel(run)}`, index: loadMoreIndex, active: selected === loadMoreIndex, activateOnClick: true }), loadMoreItem(runId, run.timelineCursor))] : []
424
+ ] : [];
128
425
  return makeSceneFrame({
129
426
  scene: "run-detail",
130
427
  title: "Run",
131
- lines,
132
- footer: { run: runId ? `${runId.slice(0, 8)} ${status}` : undefined },
133
- typeBarPlaceholder: runId ? `attach ${runId.slice(0, 8)} \xB7 stop ${runId.slice(0, 8)} \xB7 runs` : "runs \xB7 tasks",
428
+ lines: [
429
+ line("", { fg: RIG_UI.ink4 }),
430
+ line(` run \xB7 ${runId ? `${runId.slice(0, 8)} \xB7 ${status}` : "loading"}`, { fg: run ? statusColor(status) : RIG_UI.ink3 })
431
+ ],
432
+ panels: [{
433
+ id: "run-detail",
434
+ top: 0,
435
+ width: panelWidth(layout),
436
+ height: panelHeight(layout),
437
+ lines: [
438
+ ...errorText ? errorBanner(errorText, "select inspect/runs below, or retry the action") : [],
439
+ line(run ? run.title : "Run telemetry", { fg: RIG_UI.ink, bold: true }),
440
+ ...loading ? loadingRows("run telemetry", state.tick) : runId ? [kv("run", runId, RIG_UI.ink2), kv("status", status, statusColor(status))] : [line("loading run telemetry", { fg: RIG_UI.ink3 })],
441
+ ...pending ? steerBlock(pending) : [],
442
+ line("", { fg: RIG_UI.ink3 }),
443
+ line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
444
+ ...actions.map((action, index) => actionRow({ label: action.label, detail: action.detail, index, active: selected === index }, action.item)),
445
+ ...timelineSection,
446
+ ...entrySection("LOGS", logs, RIG_UI.ink3)
447
+ ],
448
+ backgroundColor: RIG_UI.panel,
449
+ backgroundAlpha: 184,
450
+ opacity: 1,
451
+ border: false,
452
+ stickyScroll: true,
453
+ stickyStart: "bottom",
454
+ chrome: "ad-terminal",
455
+ headerText: runId ? `run ${runId.slice(0, 8)}` : "run",
456
+ headerHeight: 3,
457
+ paddingX: layout?.compact ? 2 : 3,
458
+ paddingY: 1
459
+ }],
460
+ footer: { run: runId ? `${runId.slice(0, 8)} ${status}` : undefined, message: "enter/click action" },
134
461
  live: state.status === "action" || !run
135
462
  });
136
463
  }
@@ -1,2 +1,3 @@
1
1
  import type { AppSceneFrame, AppState } from "../types";
2
- export declare function renderServerScene(state: AppState): AppSceneFrame;
2
+ import type { StageLayout } from "../layout";
3
+ export declare function renderServerScene(state: AppState, layout?: StageLayout): AppSceneFrame;