@castlemilk/omega 0.1.8 → 0.1.9
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.
- package/dist/cli.js +102 -42
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -85,7 +85,7 @@ import React2 from "react";
|
|
|
85
85
|
|
|
86
86
|
// ../../apps/cli/src/commands/tui.tsx
|
|
87
87
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
88
|
-
import { Box, Text, useApp, useInput } from "ink";
|
|
88
|
+
import { Box, Text, useApp, useInput, useWindowSize } from "ink";
|
|
89
89
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
90
90
|
var API = process.env.HARNESS_API_URL || "http://localhost:4000";
|
|
91
91
|
function formatTime(d) {
|
|
@@ -123,7 +123,7 @@ function useTasks(pollMs = 1e3) {
|
|
|
123
123
|
const addLog = (message, level = "info") => {
|
|
124
124
|
setLogs((prev) => {
|
|
125
125
|
const next = [...prev, { time: formatTime(/* @__PURE__ */ new Date()), message, level }];
|
|
126
|
-
return next.slice(-
|
|
126
|
+
return next.slice(-200);
|
|
127
127
|
});
|
|
128
128
|
};
|
|
129
129
|
useEffect(() => {
|
|
@@ -153,7 +153,7 @@ function useTasks(pollMs = 1e3) {
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
for (const id of Object.keys(previousTasks.current)) {
|
|
156
|
-
if (!current[id]) {
|
|
156
|
+
if (!current[id] && !id.startsWith("__")) {
|
|
157
157
|
addLog(`Task removed: "${previousTasks.current[id].title}"`, "warning");
|
|
158
158
|
}
|
|
159
159
|
}
|
|
@@ -178,8 +178,12 @@ function useTasks(pollMs = 1e3) {
|
|
|
178
178
|
}, [pollMs]);
|
|
179
179
|
return { tasks, logs, connected };
|
|
180
180
|
}
|
|
181
|
+
function truncate(str, max) {
|
|
182
|
+
if (str.length <= max) return str;
|
|
183
|
+
return str.slice(0, max - 1) + "\u2026";
|
|
184
|
+
}
|
|
181
185
|
function Header({ connected }) {
|
|
182
|
-
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", paddingX: 1, children: [
|
|
186
|
+
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", paddingX: 1, height: 3, flexShrink: 0, children: [
|
|
183
187
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Omega Harness Console" }),
|
|
184
188
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
185
189
|
/* @__PURE__ */ jsx(Text, { color: connected ? "green" : "red", children: connected ? "\u25CF connected" : "\u25CF disconnected" }),
|
|
@@ -189,39 +193,6 @@ function Header({ connected }) {
|
|
|
189
193
|
] })
|
|
190
194
|
] });
|
|
191
195
|
}
|
|
192
|
-
function TaskList({ tasks }) {
|
|
193
|
-
const sorted = useMemo(
|
|
194
|
-
() => [...tasks].sort(
|
|
195
|
-
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
|
|
196
|
-
),
|
|
197
|
-
[tasks]
|
|
198
|
-
);
|
|
199
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "single", paddingX: 1, minHeight: 10, children: [
|
|
200
|
-
/* @__PURE__ */ jsxs(Text, { bold: true, underline: true, children: [
|
|
201
|
-
"Tasks (",
|
|
202
|
-
tasks.length,
|
|
203
|
-
")"
|
|
204
|
-
] }),
|
|
205
|
-
sorted.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No tasks yet. Create one in the web UI." }),
|
|
206
|
-
sorted.map((task) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
207
|
-
/* @__PURE__ */ jsx(Text, { color: statusColor(task.status), children: statusSymbol(task.status) }),
|
|
208
|
-
/* @__PURE__ */ jsx(Box, { width: 20, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: formatTime(new Date(task.updatedAt)) }) }),
|
|
209
|
-
/* @__PURE__ */ jsx(Box, { width: 12, children: /* @__PURE__ */ jsx(Text, { color: statusColor(task.status), bold: true, children: task.status.toUpperCase() }) }),
|
|
210
|
-
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: task.provider ? `${task.provider}/${task.model}` : "-" }) }),
|
|
211
|
-
/* @__PURE__ */ jsx(Box, { flexGrow: 1, children: /* @__PURE__ */ jsx(Text, { children: task.title }) })
|
|
212
|
-
] }, task.id))
|
|
213
|
-
] });
|
|
214
|
-
}
|
|
215
|
-
function ConsoleLog({ logs }) {
|
|
216
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "single", paddingX: 1, flexGrow: 1, children: [
|
|
217
|
-
/* @__PURE__ */ jsx(Text, { bold: true, underline: true, children: "Console" }),
|
|
218
|
-
logs.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Waiting for activity..." }),
|
|
219
|
-
logs.map((log, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
220
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: log.time }),
|
|
221
|
-
/* @__PURE__ */ jsx(Text, { color: log.level, children: log.message })
|
|
222
|
-
] }, i))
|
|
223
|
-
] });
|
|
224
|
-
}
|
|
225
196
|
function Stats({ tasks }) {
|
|
226
197
|
const counts = useMemo(() => {
|
|
227
198
|
const total = tasks.length;
|
|
@@ -231,7 +202,7 @@ function Stats({ tasks }) {
|
|
|
231
202
|
const failed = tasks.filter((t) => t.status === "failed").length;
|
|
232
203
|
return { total, todo, inProgress, done, failed };
|
|
233
204
|
}, [tasks]);
|
|
234
|
-
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", paddingX: 1, gap: 2, children: [
|
|
205
|
+
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", paddingX: 1, height: 3, flexShrink: 0, gap: 2, children: [
|
|
235
206
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
236
207
|
"total: ",
|
|
237
208
|
counts.total
|
|
@@ -254,20 +225,109 @@ function Stats({ tasks }) {
|
|
|
254
225
|
] })
|
|
255
226
|
] });
|
|
256
227
|
}
|
|
228
|
+
function TaskList({
|
|
229
|
+
tasks,
|
|
230
|
+
height,
|
|
231
|
+
collapsed,
|
|
232
|
+
toggle,
|
|
233
|
+
columns
|
|
234
|
+
}) {
|
|
235
|
+
const sorted = useMemo(
|
|
236
|
+
() => [...tasks].sort(
|
|
237
|
+
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
|
|
238
|
+
),
|
|
239
|
+
[tasks]
|
|
240
|
+
);
|
|
241
|
+
const header = /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
242
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, underline: true, children: [
|
|
243
|
+
"Tasks (",
|
|
244
|
+
tasks.length,
|
|
245
|
+
")"
|
|
246
|
+
] }),
|
|
247
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
248
|
+
"[t] ",
|
|
249
|
+
collapsed ? "expand" : "collapse"
|
|
250
|
+
] })
|
|
251
|
+
] });
|
|
252
|
+
if (collapsed) {
|
|
253
|
+
return /* @__PURE__ */ jsx(Box, { borderStyle: "single", paddingX: 1, height: 3, flexShrink: 0, children: header });
|
|
254
|
+
}
|
|
255
|
+
const availableLines = Math.max(0, height - 3);
|
|
256
|
+
const visible = sorted.slice(0, availableLines);
|
|
257
|
+
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", paddingX: 1, flexDirection: "column", height, flexShrink: 0, children: [
|
|
258
|
+
header,
|
|
259
|
+
visible.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No tasks yet. Create one in the web UI." }),
|
|
260
|
+
visible.map((task) => {
|
|
261
|
+
const providerText = task.provider ? `${task.provider}/${task.model}` : "-";
|
|
262
|
+
const titleMax = Math.max(10, columns - 50);
|
|
263
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
264
|
+
/* @__PURE__ */ jsx(Text, { color: statusColor(task.status), children: statusSymbol(task.status) }),
|
|
265
|
+
/* @__PURE__ */ jsx(Box, { width: 20, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: formatTime(new Date(task.updatedAt)) }) }),
|
|
266
|
+
/* @__PURE__ */ jsx(Box, { width: 12, children: /* @__PURE__ */ jsx(Text, { color: statusColor(task.status), bold: true, children: task.status.toUpperCase() }) }),
|
|
267
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncate(providerText, 23) }) }),
|
|
268
|
+
/* @__PURE__ */ jsx(Box, { flexGrow: 1, children: /* @__PURE__ */ jsx(Text, { children: truncate(task.title, titleMax) }) })
|
|
269
|
+
] }, task.id);
|
|
270
|
+
})
|
|
271
|
+
] });
|
|
272
|
+
}
|
|
273
|
+
function ConsoleLog({
|
|
274
|
+
logs,
|
|
275
|
+
height,
|
|
276
|
+
columns
|
|
277
|
+
}) {
|
|
278
|
+
const availableLines = Math.max(0, height - 3);
|
|
279
|
+
const visible = logs.slice(-availableLines);
|
|
280
|
+
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", paddingX: 1, flexDirection: "column", height, flexGrow: 1, children: [
|
|
281
|
+
/* @__PURE__ */ jsx(Text, { bold: true, underline: true, children: "Console" }),
|
|
282
|
+
visible.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Waiting for activity..." }),
|
|
283
|
+
visible.map((log, i) => {
|
|
284
|
+
const timeWidth = 10;
|
|
285
|
+
const msgMax = Math.max(10, columns - timeWidth - 4);
|
|
286
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
287
|
+
/* @__PURE__ */ jsx(Box, { width: timeWidth, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: log.time }) }),
|
|
288
|
+
/* @__PURE__ */ jsx(Box, { flexGrow: 1, children: /* @__PURE__ */ jsx(Text, { color: log.level, children: truncate(log.message, msgMax) }) })
|
|
289
|
+
] }, i);
|
|
290
|
+
})
|
|
291
|
+
] });
|
|
292
|
+
}
|
|
257
293
|
function TuiApp() {
|
|
258
294
|
const { exit } = useApp();
|
|
259
295
|
const { tasks, logs, connected } = useTasks();
|
|
296
|
+
const { columns, rows } = useWindowSize();
|
|
297
|
+
const [tasksCollapsed, setTasksCollapsed] = useState(false);
|
|
298
|
+
const [sidebar, setSidebar] = useState(false);
|
|
260
299
|
useInput((input, key) => {
|
|
261
300
|
if (input === "q" || key.escape) {
|
|
262
301
|
exit();
|
|
263
302
|
}
|
|
303
|
+
if (input === "t") {
|
|
304
|
+
setTasksCollapsed((c) => !c);
|
|
305
|
+
}
|
|
306
|
+
if (input === "s") {
|
|
307
|
+
setSidebar((s) => !s);
|
|
308
|
+
}
|
|
264
309
|
});
|
|
265
|
-
|
|
310
|
+
const mainHeight = Math.max(6, rows - 9);
|
|
311
|
+
const taskListWidth = sidebar ? Math.max(30, Math.floor(columns * 0.4)) : void 0;
|
|
312
|
+
const taskListHeight = sidebar ? mainHeight : tasksCollapsed ? 3 : Math.max(3, Math.floor(mainHeight * 0.45));
|
|
313
|
+
const consoleHeight = sidebar ? mainHeight : mainHeight - taskListHeight;
|
|
314
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: rows, width: columns, gap: 1, padding: 1, children: [
|
|
266
315
|
/* @__PURE__ */ jsx(Header, { connected }),
|
|
267
316
|
/* @__PURE__ */ jsx(Stats, { tasks }),
|
|
268
|
-
/* @__PURE__ */
|
|
269
|
-
|
|
270
|
-
|
|
317
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: sidebar ? "row" : "column", gap: 1, flexGrow: 1, children: [
|
|
318
|
+
/* @__PURE__ */ jsx(
|
|
319
|
+
TaskList,
|
|
320
|
+
{
|
|
321
|
+
tasks,
|
|
322
|
+
height: taskListHeight,
|
|
323
|
+
collapsed: tasksCollapsed,
|
|
324
|
+
toggle: () => setTasksCollapsed((c) => !c),
|
|
325
|
+
columns: taskListWidth ?? columns
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
/* @__PURE__ */ jsx(ConsoleLog, { logs, height: consoleHeight, columns })
|
|
329
|
+
] }),
|
|
330
|
+
/* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "q/esc quit \u2022 t toggle tasks \u2022 s toggle sidebar" }) })
|
|
271
331
|
] });
|
|
272
332
|
}
|
|
273
333
|
|