@elaraai/e3-ui-cli 1.0.72 → 1.0.74

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 (220) hide show
  1. package/README.md +46 -21
  2. package/bin/e3-ui.mjs +6 -0
  3. package/dist/app/assets/{engine-BKZbmXkC-DmcCFcnb.js → engine-Bm-cIDd_-DwUdGcTZ.js} +1 -1
  4. package/dist/app/assets/{index-BJNWHnRv.js → index-mj-YVVN1.js} +91 -91
  5. package/dist/app/index.html +1 -1
  6. package/dist/cli.js +36 -5
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/tui.d.ts +84 -0
  9. package/dist/commands/tui.d.ts.map +1 -0
  10. package/dist/commands/tui.js +89 -0
  11. package/dist/commands/tui.js.map +1 -0
  12. package/dist/tui/api.d.ts +108 -0
  13. package/dist/tui/api.d.ts.map +1 -0
  14. package/dist/tui/api.js +130 -0
  15. package/dist/tui/api.js.map +1 -0
  16. package/dist/tui/app.d.ts +23 -0
  17. package/dist/tui/app.d.ts.map +1 -0
  18. package/dist/tui/app.js +244 -0
  19. package/dist/tui/app.js.map +1 -0
  20. package/dist/tui/controller.d.ts +116 -0
  21. package/dist/tui/controller.d.ts.map +1 -0
  22. package/dist/tui/controller.js +644 -0
  23. package/dist/tui/controller.js.map +1 -0
  24. package/dist/tui/data/dataflow.d.ts +68 -0
  25. package/dist/tui/data/dataflow.d.ts.map +1 -0
  26. package/dist/tui/data/dataflow.js +137 -0
  27. package/dist/tui/data/dataflow.js.map +1 -0
  28. package/dist/tui/data/dataset.d.ts +80 -0
  29. package/dist/tui/data/dataset.d.ts.map +1 -0
  30. package/dist/tui/data/dataset.js +297 -0
  31. package/dist/tui/data/dataset.js.map +1 -0
  32. package/dist/tui/data/edit-buffer.d.ts +74 -0
  33. package/dist/tui/data/edit-buffer.d.ts.map +1 -0
  34. package/dist/tui/data/edit-buffer.js +120 -0
  35. package/dist/tui/data/edit-buffer.js.map +1 -0
  36. package/dist/tui/data/feeds.d.ts +45 -0
  37. package/dist/tui/data/feeds.d.ts.map +1 -0
  38. package/dist/tui/data/feeds.js +318 -0
  39. package/dist/tui/data/feeds.js.map +1 -0
  40. package/dist/tui/data/logs.d.ts +68 -0
  41. package/dist/tui/data/logs.d.ts.map +1 -0
  42. package/dist/tui/data/logs.js +134 -0
  43. package/dist/tui/data/logs.js.map +1 -0
  44. package/dist/tui/input/commands.d.ts +159 -0
  45. package/dist/tui/input/commands.d.ts.map +1 -0
  46. package/dist/tui/input/commands.js +259 -0
  47. package/dist/tui/input/commands.js.map +1 -0
  48. package/dist/tui/input/completion.d.ts +63 -0
  49. package/dist/tui/input/completion.d.ts.map +1 -0
  50. package/dist/tui/input/completion.js +128 -0
  51. package/dist/tui/input/completion.js.map +1 -0
  52. package/dist/tui/input/keymap.d.ts +153 -0
  53. package/dist/tui/input/keymap.d.ts.map +1 -0
  54. package/dist/tui/input/keymap.js +206 -0
  55. package/dist/tui/input/keymap.js.map +1 -0
  56. package/dist/tui/input/mouse.d.ts +52 -0
  57. package/dist/tui/input/mouse.d.ts.map +1 -0
  58. package/dist/tui/input/mouse.js +55 -0
  59. package/dist/tui/input/mouse.js.map +1 -0
  60. package/dist/tui/lifecycle.d.ts +61 -0
  61. package/dist/tui/lifecycle.d.ts.map +1 -0
  62. package/dist/tui/lifecycle.js +99 -0
  63. package/dist/tui/lifecycle.js.map +1 -0
  64. package/dist/tui/model/catalogue.d.ts +28 -0
  65. package/dist/tui/model/catalogue.d.ts.map +1 -0
  66. package/dist/tui/model/catalogue.js +94 -0
  67. package/dist/tui/model/catalogue.js.map +1 -0
  68. package/dist/tui/model/help.d.ts +37 -0
  69. package/dist/tui/model/help.d.ts.map +1 -0
  70. package/dist/tui/model/help.js +210 -0
  71. package/dist/tui/model/help.js.map +1 -0
  72. package/dist/tui/model/index.d.ts +42 -0
  73. package/dist/tui/model/index.d.ts.map +1 -0
  74. package/dist/tui/model/index.js +50 -0
  75. package/dist/tui/model/index.js.map +1 -0
  76. package/dist/tui/model/status.d.ts +88 -0
  77. package/dist/tui/model/status.d.ts.map +1 -0
  78. package/dist/tui/model/status.js +137 -0
  79. package/dist/tui/model/status.js.map +1 -0
  80. package/dist/tui/model/tree.d.ts +126 -0
  81. package/dist/tui/model/tree.d.ts.map +1 -0
  82. package/dist/tui/model/tree.js +217 -0
  83. package/dist/tui/model/tree.js.map +1 -0
  84. package/dist/tui/model/types.d.ts +21 -0
  85. package/dist/tui/model/types.d.ts.map +1 -0
  86. package/dist/tui/model/types.js +46 -0
  87. package/dist/tui/model/types.js.map +1 -0
  88. package/dist/tui/render/glyphs.d.ts +122 -0
  89. package/dist/tui/render/glyphs.d.ts.map +1 -0
  90. package/dist/tui/render/glyphs.js +122 -0
  91. package/dist/tui/render/glyphs.js.map +1 -0
  92. package/dist/tui/render/layout.d.ts +145 -0
  93. package/dist/tui/render/layout.d.ts.map +1 -0
  94. package/dist/tui/render/layout.js +209 -0
  95. package/dist/tui/render/layout.js.map +1 -0
  96. package/dist/tui/render/text.d.ts +153 -0
  97. package/dist/tui/render/text.d.ts.map +1 -0
  98. package/dist/tui/render/text.js +320 -0
  99. package/dist/tui/render/text.js.map +1 -0
  100. package/dist/tui/render/theme.d.ts +88 -0
  101. package/dist/tui/render/theme.d.ts.map +1 -0
  102. package/dist/tui/render/theme.js +145 -0
  103. package/dist/tui/render/theme.js.map +1 -0
  104. package/dist/tui/session.d.ts +78 -0
  105. package/dist/tui/session.d.ts.map +1 -0
  106. package/dist/tui/session.js +237 -0
  107. package/dist/tui/session.js.map +1 -0
  108. package/dist/tui/state/actions.d.ts +584 -0
  109. package/dist/tui/state/actions.d.ts.map +1 -0
  110. package/dist/tui/state/actions.js +62 -0
  111. package/dist/tui/state/actions.js.map +1 -0
  112. package/dist/tui/state/persist.d.ts +114 -0
  113. package/dist/tui/state/persist.d.ts.map +1 -0
  114. package/dist/tui/state/persist.js +187 -0
  115. package/dist/tui/state/persist.js.map +1 -0
  116. package/dist/tui/state/poll.d.ts +99 -0
  117. package/dist/tui/state/poll.d.ts.map +1 -0
  118. package/dist/tui/state/poll.js +160 -0
  119. package/dist/tui/state/poll.js.map +1 -0
  120. package/dist/tui/state/reducer.d.ts +16 -0
  121. package/dist/tui/state/reducer.d.ts.map +1 -0
  122. package/dist/tui/state/reducer.js +363 -0
  123. package/dist/tui/state/reducer.js.map +1 -0
  124. package/dist/tui/state/store.d.ts +37 -0
  125. package/dist/tui/state/store.d.ts.map +1 -0
  126. package/dist/tui/state/store.js +84 -0
  127. package/dist/tui/state/store.js.map +1 -0
  128. package/dist/tui/suspend.d.ts +17 -0
  129. package/dist/tui/suspend.d.ts.map +1 -0
  130. package/dist/tui/suspend.js +33 -0
  131. package/dist/tui/suspend.js.map +1 -0
  132. package/dist/tui/ui/App.d.ts +44 -0
  133. package/dist/tui/ui/App.d.ts.map +1 -0
  134. package/dist/tui/ui/App.js +105 -0
  135. package/dist/tui/ui/App.js.map +1 -0
  136. package/dist/tui/ui/frame.d.ts +86 -0
  137. package/dist/tui/ui/frame.d.ts.map +1 -0
  138. package/dist/tui/ui/frame.js +42 -0
  139. package/dist/tui/ui/frame.js.map +1 -0
  140. package/dist/tui/ui/lines.d.ts +92 -0
  141. package/dist/tui/ui/lines.d.ts.map +1 -0
  142. package/dist/tui/ui/lines.js +94 -0
  143. package/dist/tui/ui/lines.js.map +1 -0
  144. package/dist/tui/ui/shell/chrome.d.ts +61 -0
  145. package/dist/tui/ui/shell/chrome.d.ts.map +1 -0
  146. package/dist/tui/ui/shell/chrome.js +272 -0
  147. package/dist/tui/ui/shell/chrome.js.map +1 -0
  148. package/dist/tui/ui/shell/widgets.d.ts +116 -0
  149. package/dist/tui/ui/shell/widgets.d.ts.map +1 -0
  150. package/dist/tui/ui/shell/widgets.js +183 -0
  151. package/dist/tui/ui/shell/widgets.js.map +1 -0
  152. package/dist/tui/ui/views/about.d.ts +20 -0
  153. package/dist/tui/ui/views/about.d.ts.map +1 -0
  154. package/dist/tui/ui/views/about.js +40 -0
  155. package/dist/tui/ui/views/about.js.map +1 -0
  156. package/dist/tui/ui/views/all.d.ts +17 -0
  157. package/dist/tui/ui/views/all.d.ts.map +1 -0
  158. package/dist/tui/ui/views/all.js +17 -0
  159. package/dist/tui/ui/views/all.js.map +1 -0
  160. package/dist/tui/ui/views/dashboard.d.ts +211 -0
  161. package/dist/tui/ui/views/dashboard.d.ts.map +1 -0
  162. package/dist/tui/ui/views/dashboard.js +651 -0
  163. package/dist/tui/ui/views/dashboard.js.map +1 -0
  164. package/dist/tui/ui/views/help.d.ts +17 -0
  165. package/dist/tui/ui/views/help.d.ts.map +1 -0
  166. package/dist/tui/ui/views/help.js +65 -0
  167. package/dist/tui/ui/views/help.js.map +1 -0
  168. package/dist/tui/ui/views/index.d.ts +42 -0
  169. package/dist/tui/ui/views/index.d.ts.map +1 -0
  170. package/dist/tui/ui/views/index.js +42 -0
  171. package/dist/tui/ui/views/index.js.map +1 -0
  172. package/dist/tui/ui/views/input.d.ts +6 -0
  173. package/dist/tui/ui/views/input.d.ts.map +1 -0
  174. package/dist/tui/ui/views/input.js +494 -0
  175. package/dist/tui/ui/views/input.js.map +1 -0
  176. package/dist/tui/ui/views/launch.d.ts +16 -0
  177. package/dist/tui/ui/views/launch.d.ts.map +1 -0
  178. package/dist/tui/ui/views/launch.js +43 -0
  179. package/dist/tui/ui/views/launch.js.map +1 -0
  180. package/dist/tui/ui/views/refusal.d.ts +20 -0
  181. package/dist/tui/ui/views/refusal.d.ts.map +1 -0
  182. package/dist/tui/ui/views/refusal.js +47 -0
  183. package/dist/tui/ui/views/refusal.js.map +1 -0
  184. package/dist/tui/ui/views/repos.d.ts +10 -0
  185. package/dist/tui/ui/views/repos.d.ts.map +1 -0
  186. package/dist/tui/ui/views/repos.js +93 -0
  187. package/dist/tui/ui/views/repos.js.map +1 -0
  188. package/dist/tui/ui/views/task.d.ts +17 -0
  189. package/dist/tui/ui/views/task.d.ts.map +1 -0
  190. package/dist/tui/ui/views/task.js +309 -0
  191. package/dist/tui/ui/views/task.js.map +1 -0
  192. package/dist/tui/ui/views/wordmark.d.ts +15 -0
  193. package/dist/tui/ui/views/wordmark.d.ts.map +1 -0
  194. package/dist/tui/ui/views/wordmark.js +50 -0
  195. package/dist/tui/ui/views/wordmark.js.map +1 -0
  196. package/dist/tui/ui/views/workspaces.d.ts +17 -0
  197. package/dist/tui/ui/views/workspaces.d.ts.map +1 -0
  198. package/dist/tui/ui/views/workspaces.js +127 -0
  199. package/dist/tui/ui/views/workspaces.js.map +1 -0
  200. package/dist/tui/ui/widgets/leaf-editor.d.ts +58 -0
  201. package/dist/tui/ui/widgets/leaf-editor.d.ts.map +1 -0
  202. package/dist/tui/ui/widgets/leaf-editor.js +119 -0
  203. package/dist/tui/ui/widgets/leaf-editor.js.map +1 -0
  204. package/dist/tui/ui/widgets/logs.d.ts +99 -0
  205. package/dist/tui/ui/widgets/logs.d.ts.map +1 -0
  206. package/dist/tui/ui/widgets/logs.js +291 -0
  207. package/dist/tui/ui/widgets/logs.js.map +1 -0
  208. package/dist/tui/ui/widgets/reads.d.ts +62 -0
  209. package/dist/tui/ui/widgets/reads.d.ts.map +1 -0
  210. package/dist/tui/ui/widgets/reads.js +122 -0
  211. package/dist/tui/ui/widgets/reads.js.map +1 -0
  212. package/dist/tui/ui/widgets/runs.d.ts +51 -0
  213. package/dist/tui/ui/widgets/runs.d.ts.map +1 -0
  214. package/dist/tui/ui/widgets/runs.js +86 -0
  215. package/dist/tui/ui/widgets/runs.js.map +1 -0
  216. package/dist/tui/ui/widgets/tree.d.ts +149 -0
  217. package/dist/tui/ui/widgets/tree.d.ts.map +1 -0
  218. package/dist/tui/ui/widgets/tree.js +584 -0
  219. package/dist/tui/ui/widgets/tree.js.map +1 -0
  220. package/package.json +22 -12
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The log view — one stream's lines with numbers under a status line
7
+ * (`1,215 lines · 96 KB · ● live · following`), the scrollbar and the
8
+ * footer; follow-tail that pauses on scroll-up and resumes on `F`; the
9
+ * Stdout and Stderr tabs each keep their own scroll, follow and match;
10
+ * `/find` substring matches with `n` / `N` and a held highlight; `s` saves
11
+ * `<ws>.<task>.<stream>.log`; `c` copies through OSC 52.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ import * as fs from 'node:fs';
16
+ import * as path from 'node:path';
17
+ import { emptyLogs, findInLines, logLines } from '../../data/logs.js';
18
+ import { isRunLive } from '../../data/dataflow.js';
19
+ import { layoutOf } from '../../model/index.js';
20
+ import { formatInt, formatSize, padEnd, padStart } from '../../render/text.js';
21
+ import { isLogTab } from '../../state/actions.js';
22
+ import { b, d, t, lrLine } from '../lines.js';
23
+ import { withScrollbar } from '../shell/widgets.js';
24
+ /** Rows the header lines, the dashed rule, the stream line and the footer take. */
25
+ export const LOGS_CHROME_ROWS = 5;
26
+ /** Bytes copied through OSC 52 at most (terminals cap the sequence). */
27
+ export const COPY_LIMIT = 100 * 1024;
28
+ /**
29
+ * The logs context of the current view (a task view on its Stdout or Stderr tab).
30
+ *
31
+ * @param state - The store state
32
+ * @returns The context, or null
33
+ */
34
+ export function logsContext(state) {
35
+ const v = state.view;
36
+ if (v.kind !== 'task' || !isLogTab(v.tab))
37
+ return null;
38
+ const stream = v.tab;
39
+ const data = state.data.logs[v.ws]?.[v.task]?.[stream] ?? emptyLogs();
40
+ return { ws: v.ws, task: v.task, stream, ui: v.logs[stream], data, lines: logLines(data.text), visible: Math.max(1, layoutOf(state).bodyRows - LOGS_CHROME_ROWS) };
41
+ }
42
+ /** The window's top: the tail while following, else the scrolled top (clamped). */
43
+ export function logsTop(ctx) {
44
+ const max = Math.max(0, ctx.lines.length - ctx.visible);
45
+ return ctx.ui.follow ? max : Math.max(0, Math.min(ctx.ui.top, max));
46
+ }
47
+ /** The matching line indices of the held search. */
48
+ export function logsMatches(ctx) {
49
+ return ctx.ui.match === null ? [] : findInLines(ctx.lines, ctx.ui.match.text);
50
+ }
51
+ /**
52
+ * The status line: ` 1,215 lines · 96 KB · ● live · following` (then
53
+ * `capped at 10 MB` and the last fetch error, when there is one).
54
+ *
55
+ * @param ctx - The logs context
56
+ * @param state - The store state
57
+ * @param width - The row width
58
+ * @param g - The glyph set
59
+ * @returns The line
60
+ */
61
+ export function streamLine(ctx, state, width, g) {
62
+ const live = isRunLive(state, ctx.ws) || state.data.status[ctx.ws]?.result.tasks.find(x => x.name === ctx.task)?.status.type === 'in-progress';
63
+ const parts = [`${formatInt(ctx.lines.length)} line${ctx.lines.length === 1 ? '' : 's'}`, formatSize(ctx.data.totalSize)];
64
+ const line = [t(' '), d(parts.join(` ${g.sep} `))];
65
+ if (live)
66
+ line.push(d(` ${g.sep} `), b(`${g.dot} live`, 'pos'));
67
+ if (ctx.ui.follow)
68
+ line.push(d(` ${g.sep} following`));
69
+ if (ctx.data.capped)
70
+ line.push(d(` ${g.sep} `), b('capped at 10 MB', 'warn'));
71
+ if (ctx.data.error !== null && ctx.data.error !== 'no run yet')
72
+ line.push(d(` ${g.sep} `), b(ctx.data.error, 'neg'));
73
+ return lrLine(line, [t(' ')], width);
74
+ }
75
+ /**
76
+ * The visible lines with numbers and the scrollbar.
77
+ *
78
+ * @param ctx - The logs context
79
+ * @param width - The row width including the scrollbar column
80
+ * @param g - The glyph set
81
+ * @returns The lines
82
+ */
83
+ export function renderLogLines(ctx, width, g) {
84
+ const top = logsTop(ctx);
85
+ const matches = new Set(logsMatches(ctx));
86
+ const active = ctx.ui.match === null ? -1 : (logsMatches(ctx)[ctx.ui.match.index] ?? -1);
87
+ const out = [];
88
+ const digits = Math.max(4, String(ctx.lines.length).length);
89
+ for (let i = top; i < top + ctx.visible; i++) {
90
+ const text = ctx.lines[i];
91
+ if (text === undefined) {
92
+ out.push([t(' '.repeat(width - 1))]);
93
+ continue;
94
+ }
95
+ const number = padStart(String(i + 1), digits + 2);
96
+ const body = padEnd(text.replace(/\t/g, ' '), Math.max(1, width - 1 - digits - 4));
97
+ if (i === active)
98
+ out.push([b(number, 'brand'), t(' '), b(body, 'brand')]);
99
+ else if (matches.has(i))
100
+ out.push([d(number), t(' '), b(body)]);
101
+ else
102
+ out.push([d(number), t(' '), t(body)]);
103
+ }
104
+ if (ctx.lines.length === 0) {
105
+ out[0] = [t(' '), d(ctx.data.error === 'no run yet' ? `no ${ctx.stream} yet — the task has not run` : ctx.data.error ?? (ctx.data.complete ? `${ctx.stream} is empty` : 'loading…'))];
106
+ }
107
+ return withScrollbar(out, width, ctx.lines.length, ctx.visible, top, g);
108
+ }
109
+ /**
110
+ * The footer: ` lines a–b of N · at end` with the follow hint flush right.
111
+ *
112
+ * @param ctx - The logs context
113
+ * @param width - The row width
114
+ * @param g - The glyph set
115
+ * @returns The line
116
+ */
117
+ export function logsFooter(ctx, width, g) {
118
+ const total = ctx.lines.length;
119
+ const top = logsTop(ctx);
120
+ const first = total === 0 ? 0 : top + 1;
121
+ const last = Math.min(total, top + ctx.visible);
122
+ const parts = [`lines ${formatInt(first)}–${formatInt(last)} of ${formatInt(total)}`];
123
+ if (last >= total)
124
+ parts.push('at end');
125
+ if (ctx.ui.match !== null) {
126
+ const n = logsMatches(ctx).length;
127
+ parts.push(n === 0 ? `no match for ${ctx.ui.match.text}` : `match ${ctx.ui.match.index + 1} of ${n} ${g.sep} held until esc`);
128
+ }
129
+ const right = ctx.ui.follow ? `${g.up} scroll up pauses follow ${g.sep} F resumes` : 'F follow';
130
+ return lrLine([d(` ${parts.join(` ${g.sep} `)}`)], [d(right), t(' ')], width);
131
+ }
132
+ /** Writes a scrolled top, pausing follow. */
133
+ function scrollTo(controller, ctx, top) {
134
+ const max = Math.max(0, ctx.lines.length - ctx.visible);
135
+ const clamped = Math.max(0, Math.min(top, max));
136
+ if (ctx.ui.follow && clamped < max)
137
+ controller.dispatch({ type: 'logs/follow', follow: false });
138
+ controller.dispatch({ type: 'logs/scroll', top: clamped });
139
+ if (clamped >= max && !ctx.ui.follow)
140
+ controller.dispatch({ type: 'logs/follow', follow: true });
141
+ }
142
+ /**
143
+ * Scrolls the log by lines (the wheel) or to a line (a thumb drag).
144
+ *
145
+ * @param state - The store state
146
+ * @param controller - The controller
147
+ * @param to - `{ delta }` lines, or `{ top }` absolute
148
+ */
149
+ export function scrollLogs(state, controller, to) {
150
+ const ctx = logsContext(state);
151
+ if (ctx === null)
152
+ return;
153
+ scrollTo(controller, ctx, 'delta' in to ? logsTop(ctx) + to.delta : to.top);
154
+ }
155
+ /** Scrolls a match into view (two lines of context above). */
156
+ function showMatch(controller, ctx, index) {
157
+ const matches = logsMatches(ctx);
158
+ if (matches.length === 0)
159
+ return;
160
+ const i = ((index % matches.length) + matches.length) % matches.length;
161
+ const line = matches[i];
162
+ if (ctx.ui.match !== null)
163
+ controller.dispatch({ type: 'logs/match', match: { text: ctx.ui.match.text, index: i } });
164
+ controller.dispatch({ type: 'logs/follow', follow: false });
165
+ controller.dispatch({ type: 'logs/scroll', top: Math.max(0, Math.min(line - 2, Math.max(0, ctx.lines.length - ctx.visible))) });
166
+ }
167
+ /**
168
+ * Handles a key action on the logs.
169
+ *
170
+ * @param action - The action
171
+ * @param state - The store state
172
+ * @param controller - The controller
173
+ * @returns `true` when handled
174
+ */
175
+ export function logsKey(action, state, controller) {
176
+ const ctx = logsContext(state);
177
+ if (ctx === null)
178
+ return false;
179
+ const top = logsTop(ctx);
180
+ const page = Math.max(1, ctx.visible - 1);
181
+ switch (action.kind) {
182
+ case 'move': {
183
+ switch (action.op) {
184
+ case 'up':
185
+ scrollTo(controller, ctx, top - 1);
186
+ return true;
187
+ case 'down':
188
+ scrollTo(controller, ctx, top + 1);
189
+ return true;
190
+ case 'pageUp':
191
+ scrollTo(controller, ctx, top - page);
192
+ return true;
193
+ case 'pageDown':
194
+ scrollTo(controller, ctx, top + page);
195
+ return true;
196
+ case 'home':
197
+ scrollTo(controller, ctx, 0);
198
+ return true;
199
+ case 'end':
200
+ controller.dispatch({ type: 'logs/follow', follow: true });
201
+ return true;
202
+ }
203
+ return true;
204
+ }
205
+ case 'follow':
206
+ controller.dispatch({ type: 'logs/follow', follow: !ctx.ui.follow });
207
+ return true;
208
+ case 'save':
209
+ void controller.execute('/save');
210
+ return true;
211
+ case 'copy': {
212
+ if (ctx.data.text === '') {
213
+ controller.toast('nothing to copy yet', 'warn');
214
+ return true;
215
+ }
216
+ const text = ctx.data.text.length > COPY_LIMIT ? ctx.data.text.slice(-COPY_LIMIT) : ctx.data.text;
217
+ const note = ctx.data.text.length > COPY_LIMIT ? ` (the last ${formatSize(COPY_LIMIT)} of ${formatSize(ctx.data.text.length)})` : '';
218
+ if (controller.deps.copy(text))
219
+ controller.toast(`copied ${formatSize(text.length)} to the clipboard via OSC 52${note} — if it did not arrive, /save writes the file`, 'pos');
220
+ else
221
+ controller.toast('copy needs a terminal that accepts OSC 52 — /save writes the file', 'warn');
222
+ return true;
223
+ }
224
+ case 'next':
225
+ case 'prev': {
226
+ if (ctx.ui.match === null) {
227
+ controller.toast('no match held — /find <text> first', 'warn');
228
+ return true;
229
+ }
230
+ showMatch(controller, ctx, ctx.ui.match.index + (action.kind === 'next' ? 1 : -1));
231
+ return true;
232
+ }
233
+ case 'back':
234
+ if (ctx.ui.match === null)
235
+ return false;
236
+ controller.dispatch({ type: 'logs/match', match: null });
237
+ return true;
238
+ default:
239
+ return false;
240
+ }
241
+ }
242
+ /** The `/save` target: `<ws>.<task>.<stream>.log` in the working directory unless a file is given. */
243
+ export function logsSaveTarget(ctx, file) {
244
+ return path.resolve(file ?? `${ctx.ws}.${ctx.task}.${ctx.stream}.log`);
245
+ }
246
+ /**
247
+ * Handles `/find` and `/save` on the logs.
248
+ *
249
+ * @param command - The parsed command
250
+ * @param state - The store state
251
+ * @param controller - The controller
252
+ * @returns `true` when handled
253
+ */
254
+ export async function logsCommand(command, state, controller) {
255
+ const ctx = logsContext(state);
256
+ if (ctx === null)
257
+ return false;
258
+ switch (command.name) {
259
+ case 'find': {
260
+ const matches = findInLines(ctx.lines, command.query);
261
+ controller.dispatch({ type: 'logs/match', match: { text: command.query, index: 0 } });
262
+ if (matches.length === 0) {
263
+ controller.toast(`no match for ${command.query} in ${ctx.stream}`, 'warn');
264
+ return true;
265
+ }
266
+ const after = logsContext(controller.state());
267
+ if (after !== null)
268
+ showMatch(controller, after, 0);
269
+ controller.toast(`${formatInt(matches.length)} match${matches.length === 1 ? '' : 'es'} ${controller.deps.glyphs.sep} n N next/prev ${controller.deps.glyphs.sep} esc`, 'info');
270
+ return true;
271
+ }
272
+ case 'save': {
273
+ const target = logsSaveTarget(ctx, command.file);
274
+ if (fs.existsSync(target) && !command.force) {
275
+ controller.dispatch({ type: 'command/confirm', confirm: { question: `overwrite ${target}?`, command: `/save "${target}" --force` } });
276
+ return true;
277
+ }
278
+ if (ctx.data.text === '') {
279
+ controller.toast(`nothing to save — ${ctx.stream} is empty`, 'warn');
280
+ return true;
281
+ }
282
+ fs.mkdirSync(path.dirname(target), { recursive: true });
283
+ fs.writeFileSync(target, ctx.data.text);
284
+ controller.toast(`saved ${formatSize(ctx.data.text.length)} to ${target}`, 'pos');
285
+ return true;
286
+ }
287
+ default:
288
+ return false;
289
+ }
290
+ }
291
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../../../src/tui/ui/widgets/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The Reads tab of a `ui` task — its data manifest (`decodeManifest` from
7
+ * `@elaraai/e3-ui/internal`): the dataset paths it reads (each `⏎` opens
8
+ * as a dataset), the paths it reads by window, the package functions it
9
+ * calls and the records it binds.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import { type DataManifest } from '@elaraai/e3-ui/internal';
14
+ import type { TaskDetails } from '@elaraai/e3-api-client';
15
+ import type { Controller } from '../../controller.js';
16
+ import type { Glyphs } from '../../render/glyphs.js';
17
+ import type { TuiState } from '../../state/actions.js';
18
+ import { type Line } from '../lines.js';
19
+ /** One row of the Reads tab. */
20
+ export interface ReadRow {
21
+ kind: 'path' | 'page' | 'function' | 'record';
22
+ text: string;
23
+ /** The dataset path a `path` / `page` row opens. */
24
+ path: string | null;
25
+ }
26
+ /**
27
+ * The manifest of a task's details, if it carries one.
28
+ *
29
+ * @param details - The task details
30
+ * @returns The manifest, or null (no metadata, or not a manifest)
31
+ */
32
+ export declare function manifestOf(details: TaskDetails | undefined): DataManifest | null;
33
+ /** `manifest: 3 reads · 1 function` for the title line. */
34
+ export declare function manifestSummary(manifest: DataManifest, g: Glyphs): string;
35
+ /** The rows of the Reads tab (sections separated by their headings). */
36
+ export declare function readRows(manifest: DataManifest): ReadRow[];
37
+ /**
38
+ * Renders the Reads tab: headed sections, the selection bar on the
39
+ * selected row, a scrollbar when they overflow.
40
+ *
41
+ * @param manifest - The manifest (null when the task has none)
42
+ * @param sel - The selected row
43
+ * @param top - The first visible line
44
+ * @param visible - Visible lines
45
+ * @param width - The row width including the scrollbar column
46
+ * @param g - The glyph set
47
+ * @returns The lines
48
+ */
49
+ export declare function renderReads(manifest: DataManifest | null, sel: number, top: number, visible: number, width: number, g: Glyphs): {
50
+ lines: Line[];
51
+ rowLines: number[];
52
+ top: number;
53
+ total: number;
54
+ };
55
+ /**
56
+ * `⏎` on a Reads row opens the dataset.
57
+ *
58
+ * @param state - The store state
59
+ * @param controller - The controller
60
+ */
61
+ export declare function openRead(state: TuiState, controller: Controller): void;
62
+ //# sourceMappingURL=reads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../../../../src/tui/ui/widgets/reads.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAW,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAGjD,gCAAgC;AAChC,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAOhF;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMzE;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,CAO1D;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA0BjM;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,CAWtE"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The Reads tab of a `ui` task — its data manifest (`decodeManifest` from
7
+ * `@elaraai/e3-ui/internal`): the dataset paths it reads (each `⏎` opens
8
+ * as a dataset), the paths it reads by window, the package functions it
9
+ * calls and the records it binds.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import { decodeManifest } from '@elaraai/e3-ui/internal';
14
+ import { dottedPath } from '../../api.js';
15
+ import { b, d, t } from '../lines.js';
16
+ import { withScrollbar } from '../shell/widgets.js';
17
+ /**
18
+ * The manifest of a task's details, if it carries one.
19
+ *
20
+ * @param details - The task details
21
+ * @returns The manifest, or null (no metadata, or not a manifest)
22
+ */
23
+ export function manifestOf(details) {
24
+ if (details === undefined || details.metadata.type !== 'some')
25
+ return null;
26
+ try {
27
+ return decodeManifest(details.metadata.value);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ /** `manifest: 3 reads · 1 function` for the title line. */
34
+ export function manifestSummary(manifest, g) {
35
+ const parts = [`${manifest.paths.length} read${manifest.paths.length === 1 ? '' : 's'}`];
36
+ if (manifest.pages.length > 0)
37
+ parts.push(`${manifest.pages.length} paged`);
38
+ if (manifest.functions.length > 0)
39
+ parts.push(`${manifest.functions.length} function${manifest.functions.length === 1 ? '' : 's'}`);
40
+ if (manifest.records.length > 0)
41
+ parts.push(`${manifest.records.length} record${manifest.records.length === 1 ? '' : 's'}`);
42
+ return parts.join(` ${g.sep} `);
43
+ }
44
+ /** The rows of the Reads tab (sections separated by their headings). */
45
+ export function readRows(manifest) {
46
+ const rows = [];
47
+ for (const p of manifest.paths)
48
+ rows.push({ kind: 'path', text: dottedPath(p), path: dottedPath(p) });
49
+ for (const p of manifest.pages)
50
+ rows.push({ kind: 'page', text: dottedPath(p), path: dottedPath(p) });
51
+ for (const f of manifest.functions)
52
+ rows.push({ kind: 'function', text: f, path: null });
53
+ for (const r of manifest.records)
54
+ rows.push({ kind: 'record', text: r, path: null });
55
+ return rows;
56
+ }
57
+ /** The section heading of a row kind. */
58
+ const HEADINGS = { path: 'READS', page: 'READS BY WINDOW', function: 'FUNCTIONS', record: 'RECORDS' };
59
+ /**
60
+ * Renders the Reads tab: headed sections, the selection bar on the
61
+ * selected row, a scrollbar when they overflow.
62
+ *
63
+ * @param manifest - The manifest (null when the task has none)
64
+ * @param sel - The selected row
65
+ * @param top - The first visible line
66
+ * @param visible - Visible lines
67
+ * @param width - The row width including the scrollbar column
68
+ * @param g - The glyph set
69
+ * @returns The lines
70
+ */
71
+ export function renderReads(manifest, sel, top, visible, width, g) {
72
+ if (manifest === null) {
73
+ const out = [[t(' '), d('this task carries no data manifest — a ui() task declares its reads through Data.bind / Func.bind / Record.bind')]];
74
+ while (out.length < visible)
75
+ out.push([t(' '.repeat(width))]);
76
+ return { lines: out, rowLines: [], top: 0, total: 1 };
77
+ }
78
+ const rows = readRows(manifest);
79
+ const lines = [];
80
+ const rowLines = [];
81
+ let lastKind = null;
82
+ rows.forEach((row, i) => {
83
+ if (row.kind !== lastKind) {
84
+ if (lastKind !== null)
85
+ lines.push([t(' ')]);
86
+ lines.push([t(' '), b(HEADINGS[row.kind])]);
87
+ lastKind = row.kind;
88
+ }
89
+ const selected = i === sel;
90
+ const opens = row.path !== null;
91
+ rowLines.push(lines.length);
92
+ lines.push([t(' '), selected ? b(g.sel, 'brand') : t(' '), selected ? b(row.text) : t(row.text), d(opens ? ` ${g.enter} open` : '')]);
93
+ });
94
+ if (rows.length === 0)
95
+ lines.push([t(' '), d('the manifest is empty')]);
96
+ const clampedTop = Math.max(0, Math.min(top, Math.max(0, lines.length - visible)));
97
+ const window = lines.slice(clampedTop, clampedTop + visible);
98
+ while (window.length < visible)
99
+ window.push([t(' '.repeat(width - 1))]);
100
+ return { lines: withScrollbar(window, width, lines.length, visible, clampedTop, g), rowLines, top: clampedTop, total: lines.length };
101
+ }
102
+ /**
103
+ * `⏎` on a Reads row opens the dataset.
104
+ *
105
+ * @param state - The store state
106
+ * @param controller - The controller
107
+ */
108
+ export function openRead(state, controller) {
109
+ const v = state.view;
110
+ if (v.kind !== 'task' || v.tab !== 'reads')
111
+ return;
112
+ const manifest = manifestOf(state.data.taskDetails[v.ws]?.[v.task]);
113
+ const row = manifest === null ? undefined : readRows(manifest)[v.reads.sel];
114
+ if (row === undefined)
115
+ return;
116
+ if (row.path === null) {
117
+ controller.toast(`${row.kind === 'function' ? 'a package function' : 'a record'} has no view here`, 'warn');
118
+ return;
119
+ }
120
+ void controller.execute(`/dataset ${row.path}`);
121
+ }
122
+ //# sourceMappingURL=reads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reads.js","sourceRoot":"","sources":["../../../../src/tui/ui/widgets/reads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The Runs tab — `taskExecutionList` (every attempt, `all=true`) newest
7
+ * first: status, started, duration, exit code, the inputs hash (`← current`
8
+ * on the newest when the task is up to date); `⏎` expands the selected
9
+ * run's input hashes, paired with the task's input paths. A retry after a
10
+ * failure and a forced re-run each add a row under the same inputs hash.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ import type { ExecutionListItem } from '@elaraai/e3-api-client';
15
+ import type { Glyphs } from '../../render/glyphs.js';
16
+ import type { TuiState } from '../../state/actions.js';
17
+ import { type Line } from '../lines.js';
18
+ import { type TableRow } from '../shell/widgets.js';
19
+ /** Rows the header lines, the dashed rule and the table header take. */
20
+ export declare const RUNS_CHROME_ROWS = 4;
21
+ /**
22
+ * The runs of a task, newest first.
23
+ *
24
+ * @param state - The store state
25
+ * @param ws - The workspace
26
+ * @param task - The task
27
+ * @returns The runs
28
+ */
29
+ export declare function runsOf(state: TuiState, ws: string, task: string): ExecutionListItem[];
30
+ /**
31
+ * The table rows.
32
+ *
33
+ * @param runs - The runs, newest first
34
+ * @param current - Whether the newest run is the task's current output
35
+ * @param g - The glyph set
36
+ * @returns The rows
37
+ */
38
+ export declare function runRows(runs: readonly ExecutionListItem[], current: boolean, g: Glyphs): TableRow[];
39
+ /**
40
+ * Renders the Runs tab: the table, then the expanded run's input hashes.
41
+ *
42
+ * @param state - The store state
43
+ * @param ws - The workspace
44
+ * @param task - The task
45
+ * @param visible - Rows under the table header
46
+ * @param width - The row width including the scrollbar column
47
+ * @param g - The glyph set
48
+ * @returns The lines (the table header first)
49
+ */
50
+ export declare function renderRuns(state: TuiState, ws: string, task: string, visible: number, width: number, g: Glyphs): Line[];
51
+ //# sourceMappingURL=runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../../../src/tui/ui/widgets/runs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAIhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAW,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEhF,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAErF;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,iBAAiB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE,CAcnG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAyBvH"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import { dottedPath } from '../../api.js';
6
+ import { breakpoint, columnPlan } from '../../render/layout.js';
7
+ import { formatDuration, formatStamp, hashMid, hashTiny } from '../../render/text.js';
8
+ import { historyStatusCell } from '../../model/status.js';
9
+ import { b, d, t } from '../lines.js';
10
+ import { renderTable, withScrollbar } from '../shell/widgets.js';
11
+ /** Rows the header lines, the dashed rule and the table header take. */
12
+ export const RUNS_CHROME_ROWS = 4;
13
+ /**
14
+ * The runs of a task, newest first.
15
+ *
16
+ * @param state - The store state
17
+ * @param ws - The workspace
18
+ * @param task - The task
19
+ * @returns The runs
20
+ */
21
+ export function runsOf(state, ws, task) {
22
+ return [...(state.data.executions[ws]?.[task] ?? [])].sort((a, c) => (a.startedAt < c.startedAt ? 1 : a.startedAt > c.startedAt ? -1 : 0));
23
+ }
24
+ /**
25
+ * The table rows.
26
+ *
27
+ * @param runs - The runs, newest first
28
+ * @param current - Whether the newest run is the task's current output
29
+ * @param g - The glyph set
30
+ * @returns The rows
31
+ */
32
+ export function runRows(runs, current, g) {
33
+ return runs.map((run, i) => {
34
+ const cell = historyStatusCell(run.status.type, g);
35
+ return {
36
+ cells: {
37
+ status: { text: `${cell.glyph} ${cell.word}`, tone: cell.tone },
38
+ started: formatStamp(run.startedAt),
39
+ duration: run.duration.type === 'some' ? formatDuration(Number(run.duration.value)) : '—',
40
+ exit: run.exitCode.type === 'some' ? String(run.exitCode.value) : '—',
41
+ inputs: hashMid(run.inputsHash),
42
+ note: i === 0 && current ? `${g.left} current` : '',
43
+ },
44
+ };
45
+ });
46
+ }
47
+ /**
48
+ * Renders the Runs tab: the table, then the expanded run's input hashes.
49
+ *
50
+ * @param state - The store state
51
+ * @param ws - The workspace
52
+ * @param task - The task
53
+ * @param visible - Rows under the table header
54
+ * @param width - The row width including the scrollbar column
55
+ * @param g - The glyph set
56
+ * @returns The lines (the table header first)
57
+ */
58
+ export function renderRuns(state, ws, task, visible, width, g) {
59
+ const v = state.view;
60
+ const ui = v.kind === 'task' ? v.runs : { sel: 0, top: 0, expanded: false };
61
+ const runs = runsOf(state, ws, task);
62
+ const status = state.data.status[ws]?.result.tasks.find(x => x.name === task)?.status.type;
63
+ const rows = runRows(runs, status === 'up-to-date', g);
64
+ const table = renderTable(columnPlan('runs', breakpoint(state.size)), rows, ui.sel, ui.top, visible, width - 1, g);
65
+ const header = table[0];
66
+ const body = table.slice(1);
67
+ if (runs.length === 0)
68
+ body.push([t(' '), d(state.data.executions[ws]?.[task] === undefined ? 'loading…' : 'no runs yet — r runs the dataflow')]);
69
+ if (ui.expanded) {
70
+ const run = runs[ui.sel];
71
+ if (run !== undefined) {
72
+ const inputs = state.data.taskDetails[ws]?.[task]?.inputs ?? [];
73
+ const pairs = run.inputHashes.map((h, i) => {
74
+ const p = inputs[i];
75
+ const name = p === undefined ? `#${i + 1}` : dottedPath(p).replace(/^\.inputs\./, '').replace(/^\.tasks\./, '.tasks.');
76
+ return `${name} ${hashTiny(h)}`;
77
+ });
78
+ body.push([t(' ')]);
79
+ body.push([t(' '), b(g.bullet, 'brand'), t(` ${hashMid(run.inputsHash)} = sha256 of the inputs (${pairs.join(', ')}) `), d(`${g.sep} ${g.enter} collapses`)]);
80
+ }
81
+ }
82
+ while (body.length < visible)
83
+ body.push([t(' '.repeat(width - 1))]);
84
+ return [header, ...withScrollbar(body.slice(0, visible), width, runs.length, visible, ui.top, g)];
85
+ }
86
+ //# sourceMappingURL=runs.js.map