@h-rig/omp-extension-plugin 0.0.6-alpha.190 → 0.0.6-alpha.192
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/src/cockpit/board-views.d.ts +10 -0
- package/dist/src/cockpit/board-views.js +110 -27
- package/dist/src/cockpit/extension.d.ts +1 -1
- package/dist/src/cockpit/extension.js +362 -128
- package/dist/src/cockpit/plugin.js +361 -128
- package/dist/src/cockpit/screen-catalog.js +2 -2
- package/dist/src/plugin.js +361 -128
- package/package.json +4 -4
|
@@ -21,7 +21,7 @@ import { DOCTOR } from "@rig/contracts";
|
|
|
21
21
|
import { RIG_COCKPIT_PANEL_SLOT } from "@rig/contracts";
|
|
22
22
|
import { defineCapability } from "@rig/core/capability";
|
|
23
23
|
import { loadCapabilityForRoot, requireCapabilityForRoot } from "@rig/core/capability-loaders";
|
|
24
|
-
import { isKeyRelease, matchesKey } from "@oh-my-pi/pi-tui";
|
|
24
|
+
import { isKeyRelease, matchesKey, parseSgrMouse } from "@oh-my-pi/pi-tui";
|
|
25
25
|
import { Duration, Effect, Fiber, Stream } from "effect";
|
|
26
26
|
|
|
27
27
|
// packages/omp-extension-plugin/src/cockpit/board-views.ts
|
|
@@ -29,6 +29,7 @@ import { truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
|
29
29
|
import {
|
|
30
30
|
accent,
|
|
31
31
|
accentDim,
|
|
32
|
+
bgPanel,
|
|
32
33
|
bold,
|
|
33
34
|
cyan,
|
|
34
35
|
ink,
|
|
@@ -36,10 +37,6 @@ import {
|
|
|
36
37
|
ink3,
|
|
37
38
|
ink4,
|
|
38
39
|
red,
|
|
39
|
-
DRONE_WIDTH,
|
|
40
|
-
renderDroneFrame,
|
|
41
|
-
renderMicroDroneFrame,
|
|
42
|
-
RIG_SPINNER_FRAMES,
|
|
43
40
|
screenGlyph,
|
|
44
41
|
sectionDivider,
|
|
45
42
|
statusColor,
|
|
@@ -51,11 +48,13 @@ import {
|
|
|
51
48
|
function hairline(width) {
|
|
52
49
|
return ink4("\u2500".repeat(Math.max(0, width)));
|
|
53
50
|
}
|
|
51
|
+
|
|
54
52
|
class BoardSettingsList {
|
|
55
53
|
items = [];
|
|
56
54
|
selected = 0;
|
|
57
55
|
title = "";
|
|
58
56
|
emptyMessage = "nothing to show";
|
|
57
|
+
#rowToIndex = new Map;
|
|
59
58
|
setItems(items) {
|
|
60
59
|
this.items = [...items];
|
|
61
60
|
if (!this.selectableAt(this.selected))
|
|
@@ -86,44 +85,77 @@ class BoardSettingsList {
|
|
|
86
85
|
selectedItem() {
|
|
87
86
|
return this.selectableAt(this.selected) ? this.items[this.selected] : null;
|
|
88
87
|
}
|
|
88
|
+
hitTest(line) {
|
|
89
|
+
const index = this.#rowToIndex.get(line);
|
|
90
|
+
return index !== undefined && this.selectableAt(index) ? index : undefined;
|
|
91
|
+
}
|
|
92
|
+
selectIndex(index) {
|
|
93
|
+
if (!this.selectableAt(index))
|
|
94
|
+
return false;
|
|
95
|
+
const moved = this.selected !== index;
|
|
96
|
+
this.selected = index;
|
|
97
|
+
return moved;
|
|
98
|
+
}
|
|
89
99
|
invalidate() {}
|
|
90
100
|
render(width) {
|
|
91
101
|
return this.renderLines(width).map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
92
102
|
}
|
|
93
103
|
renderLines(width) {
|
|
104
|
+
this.#rowToIndex.clear();
|
|
94
105
|
if (this.items.length === 0) {
|
|
95
106
|
return ["", ` ${ink2(this.emptyMessage)}`, ""];
|
|
96
107
|
}
|
|
97
|
-
const maxVisible = Math.max(8, Math.min(
|
|
108
|
+
const maxVisible = Math.max(8, Math.min(18, (process.stdout.rows ?? 30) - 10));
|
|
98
109
|
const start = Math.max(0, Math.min(this.selected - Math.floor(maxVisible / 2), this.items.length - maxVisible));
|
|
99
110
|
const window = this.items.slice(start, start + maxVisible);
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
const labelWidth = Math.min(28, Math.max(10, ...window.map((item) => {
|
|
112
|
+
const navGlyph = item.id.startsWith("to:") ? 2 : 0;
|
|
113
|
+
return item.label.length + navGlyph;
|
|
114
|
+
})));
|
|
115
|
+
const actionWidth = Math.max(0, ...window.map((item) => item.values?.[0] && item.values[0] !== item.currentValue ? item.values[0].length + 2 : 0));
|
|
116
|
+
const valueWidth = Math.max(12, width - labelWidth - actionWidth - 8);
|
|
117
|
+
const lines = [""];
|
|
118
|
+
for (let index = 0;index < window.length; index += 1) {
|
|
119
|
+
const item = window[index];
|
|
103
120
|
const absolute = start + index;
|
|
104
121
|
const isSelected = absolute === this.selected;
|
|
105
|
-
|
|
122
|
+
if (item.id === "title") {
|
|
123
|
+
lines.push(` ${accent("\u258D")}${bold(ink(item.label))}${item.currentValue ? ` ${ink3(item.currentValue)}` : ""}`);
|
|
124
|
+
if (item.description)
|
|
125
|
+
lines.push(` ${ink4(truncateToWidth(item.description, Math.max(12, width - 4)))}`);
|
|
126
|
+
lines.push("");
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (item.heading && !item.currentValue) {
|
|
130
|
+
lines.push(sectionDivider(item.label.toLowerCase(), width));
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
106
133
|
const navGlyph = item.id.startsWith("to:") ? `${screenGlyph(item.id.slice(3))} ` : "";
|
|
107
|
-
const
|
|
108
|
-
const isTitle = item.id === "title";
|
|
134
|
+
const labelPlain = truncateToWidth(`${navGlyph}${item.label}`, labelWidth).padEnd(labelWidth);
|
|
109
135
|
const isStatus = item.id.endsWith(":status");
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
136
|
+
const valuePlain = truncateToWidth(item.currentValue ?? "", valueWidth).padEnd(valueWidth);
|
|
137
|
+
const label = isSelected ? ink(labelPlain) : item.heading ? ink3(labelPlain) : ink2(labelPlain);
|
|
138
|
+
const value = !item.currentValue ? ink4(valuePlain) : isStatus ? statusColor(item.currentValue)(truncateToWidth(`${statusGlyph(item.currentValue)} ${item.currentValue}`, valueWidth).padEnd(valueWidth)) : item.heading ? ink2(valuePlain) : ink3(valuePlain);
|
|
139
|
+
const actionText = item.values?.[0] && item.values[0] !== item.currentValue ? item.values[0] : "";
|
|
140
|
+
const action = actionText ? isSelected ? accent(`${actionText} \u203A`) : accentDim(actionText) : "";
|
|
141
|
+
const rail = isSelected ? accent("\u258C") : " ";
|
|
142
|
+
const body = `${rail} ${label} ${value}${action ? ` ${action}` : ""}`;
|
|
143
|
+
if (!item.heading)
|
|
144
|
+
this.#rowToIndex.set(lines.length, absolute);
|
|
145
|
+
lines.push(isSelected ? bgPanel(body) : body);
|
|
114
146
|
if (isSelected && item.description) {
|
|
115
|
-
|
|
147
|
+
if (!item.heading)
|
|
148
|
+
this.#rowToIndex.set(lines.length, absolute);
|
|
149
|
+
lines.push(` ${ink4("\u21B3")} ${ink4(truncateToWidth(item.description, Math.max(12, width - 6)))}`);
|
|
116
150
|
}
|
|
117
|
-
|
|
118
|
-
});
|
|
151
|
+
}
|
|
119
152
|
const meta = [];
|
|
120
153
|
if (this.items.length > maxVisible)
|
|
121
|
-
meta.push(`${this.selected + 1}
|
|
122
|
-
if (this.title)
|
|
123
|
-
meta.push(this.title);
|
|
154
|
+
meta.push(`${this.selected + 1} of ${this.items.length}`);
|
|
124
155
|
if (meta.length > 0)
|
|
125
|
-
lines.push(ink4(` ${meta.join(" \xB7 ")}`));
|
|
126
|
-
|
|
156
|
+
lines.push("", ink4(` ${meta.join(" \xB7 ")}`));
|
|
157
|
+
lines.push("");
|
|
158
|
+
return lines;
|
|
127
159
|
}
|
|
128
160
|
}
|
|
129
161
|
class HelpView {
|
|
@@ -207,6 +239,7 @@ class DetailComposer {
|
|
|
207
239
|
selected = 0;
|
|
208
240
|
tick = 0;
|
|
209
241
|
bodyScroll = 0;
|
|
242
|
+
#lineToAction = new Map;
|
|
210
243
|
setModel(model) {
|
|
211
244
|
const prevId = this.enabledActions()[this.selected]?.id;
|
|
212
245
|
this.model = model;
|
|
@@ -231,6 +264,17 @@ class DetailComposer {
|
|
|
231
264
|
selectedAction() {
|
|
232
265
|
return this.enabledActions()[this.selected] ?? null;
|
|
233
266
|
}
|
|
267
|
+
hitTestAction(line) {
|
|
268
|
+
return this.#lineToAction.get(line);
|
|
269
|
+
}
|
|
270
|
+
selectAction(index) {
|
|
271
|
+
const count = this.enabledActions().length;
|
|
272
|
+
if (index < 0 || index >= count)
|
|
273
|
+
return false;
|
|
274
|
+
const moved = this.selected !== index;
|
|
275
|
+
this.selected = index;
|
|
276
|
+
return moved;
|
|
277
|
+
}
|
|
234
278
|
scrollBody(delta) {
|
|
235
279
|
this.bodyScroll = Math.max(0, this.bodyScroll + delta);
|
|
236
280
|
}
|
|
@@ -260,21 +304,45 @@ class DetailComposer {
|
|
|
260
304
|
}
|
|
261
305
|
if (model.stages && model.stages.length > 0) {
|
|
262
306
|
bottom.push(sectionDivider("pipeline", width));
|
|
263
|
-
|
|
264
|
-
|
|
307
|
+
let linePlain = " ";
|
|
308
|
+
let linePainted = " ";
|
|
309
|
+
for (let i = 0;i < model.stages.length; i += 1) {
|
|
310
|
+
const stage = model.stages[i];
|
|
311
|
+
const sepPlain = linePlain.trim().length > 0 ? " \u2192 " : " ";
|
|
312
|
+
const cellPlain = `${sepPlain}? ${stage.label}`;
|
|
313
|
+
if (linePlain.length + cellPlain.length > inner - 2 && linePlain.trim().length > 0) {
|
|
314
|
+
bottom.push(linePainted);
|
|
315
|
+
linePlain = " ";
|
|
316
|
+
linePainted = " ";
|
|
317
|
+
}
|
|
318
|
+
const sep = linePlain.trim().length > 0 ? ink4(" \u2192 ") : " ";
|
|
319
|
+
linePlain += cellPlain;
|
|
320
|
+
linePainted += `${sep}${statusColor(stage.status)(statusGlyph(stage.status))} ${ink3(stage.label)}`;
|
|
321
|
+
}
|
|
322
|
+
if (linePainted.trim().length > 0)
|
|
323
|
+
bottom.push(linePainted);
|
|
265
324
|
bottom.push("");
|
|
266
325
|
}
|
|
326
|
+
const actionLines = [];
|
|
267
327
|
if (model.actions.length > 0) {
|
|
268
328
|
bottom.push(sectionDivider("actions", width));
|
|
269
329
|
const selId = this.selectedAction()?.id;
|
|
330
|
+
let enabledIndex = -1;
|
|
270
331
|
for (const action of model.actions) {
|
|
271
332
|
const on = action.enabled !== false;
|
|
333
|
+
if (on)
|
|
334
|
+
enabledIndex += 1;
|
|
272
335
|
const isSel = on && action.id === selId;
|
|
273
336
|
const rail = isSel ? accent("\u258C") : " ";
|
|
274
337
|
const labelText = `${action.glyph ? `${action.glyph} ` : ""}${action.label}`;
|
|
275
338
|
const label = !on ? ink4(labelText) : action.danger ? red(labelText) : isSel ? accent(labelText) : ink2(labelText);
|
|
276
339
|
const tail = !on ? ink4(action.value ?? "unavailable") : isSel ? ink3(action.hint ?? action.value ?? "") : ink3(action.value ?? "");
|
|
277
|
-
|
|
340
|
+
const row = `${rail} ${label}${tail ? ` ${tail}` : ""}`;
|
|
341
|
+
if (on)
|
|
342
|
+
actionLines.push(enabledIndex);
|
|
343
|
+
else
|
|
344
|
+
actionLines.push(-1);
|
|
345
|
+
bottom.push(isSel ? bgPanel(row) : row);
|
|
278
346
|
}
|
|
279
347
|
}
|
|
280
348
|
const body = [];
|
|
@@ -299,16 +367,31 @@ class DetailComposer {
|
|
|
299
367
|
}
|
|
300
368
|
}
|
|
301
369
|
const out = [...top, ...body, ...bottom];
|
|
370
|
+
const mapActions = (linesOut) => {
|
|
371
|
+
this.#lineToAction.clear();
|
|
372
|
+
if (actionLines.length === 0)
|
|
373
|
+
return;
|
|
374
|
+
const actionCount = model.actions.length;
|
|
375
|
+
const firstActionLine = linesOut.length - actionCount;
|
|
376
|
+
for (let i = 0;i < actionCount; i += 1) {
|
|
377
|
+
const enabledIdx = actionLines[i];
|
|
378
|
+
if (enabledIdx >= 0)
|
|
379
|
+
this.#lineToAction.set(firstActionLine + i, enabledIdx);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
302
382
|
if (out.length > budget) {
|
|
303
383
|
const keepTail = Math.min(bottom.length, budget - top.length);
|
|
304
|
-
|
|
384
|
+
const clipped = [...top, ...out.slice(out.length - keepTail)];
|
|
385
|
+
mapActions(clipped);
|
|
386
|
+
return clipped.map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
305
387
|
}
|
|
388
|
+
mapActions(out);
|
|
306
389
|
return out.map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
307
390
|
}
|
|
308
391
|
}
|
|
309
392
|
|
|
310
393
|
// packages/omp-extension-plugin/src/cockpit/extension.ts
|
|
311
|
-
import { accent as accent2, accentDim as accentDim2, bold as bold2, cyan as cyan2, ink as ink5, ink2 as ink22, ink3 as ink32, ink4 as ink42, red as red2, RIG_SPINNER_FRAMES as
|
|
394
|
+
import { accent as accent2, accentDim as accentDim2, bgPanel as bgPanel2, bold as bold2, cyan as cyan2, ink as ink5, ink2 as ink22, ink3 as ink32, ink4 as ink42, keyHints, red as red2, RIG_SPINNER_FRAMES, screenGlyph as screenGlyph2, yellow as yellow2 } from "@rig/std-shared/board-theme";
|
|
312
395
|
|
|
313
396
|
// packages/omp-extension-plugin/src/cockpit/drone-preloader.ts
|
|
314
397
|
var ART = [
|
|
@@ -529,8 +612,8 @@ class DronePreloaderComponent {
|
|
|
529
612
|
|
|
530
613
|
// packages/omp-extension-plugin/src/cockpit/screen-catalog.ts
|
|
531
614
|
var DEFAULT_SCREEN_CATALOG = [
|
|
532
|
-
{ id: "cockpit", title: "
|
|
533
|
-
{ id: "task-detail", title: "Task Detail" },
|
|
615
|
+
{ id: "cockpit", title: "Cockpit", label: "cockpit", shortcut: { key: "g", description: "Rig cockpit" } },
|
|
616
|
+
{ id: "task-detail", title: "Task Detail", label: "task detail" },
|
|
534
617
|
{ id: "run-detail", title: "Run Detail", label: "run detail" }
|
|
535
618
|
];
|
|
536
619
|
function buildScreenFromPanel(panel) {
|
|
@@ -569,9 +652,6 @@ function findScreen(catalog, screen) {
|
|
|
569
652
|
function isRigScreen(value, catalog = DEFAULT_SCREEN_CATALOG) {
|
|
570
653
|
return typeof value === "string" && catalog.some((screen) => screen.id === value);
|
|
571
654
|
}
|
|
572
|
-
function screenTitle(screen, catalog = DEFAULT_SCREEN_CATALOG) {
|
|
573
|
-
return findScreen(catalog, screen)?.title ?? screen;
|
|
574
|
-
}
|
|
575
655
|
function screenLabel(screen, catalog = DEFAULT_SCREEN_CATALOG) {
|
|
576
656
|
const descriptor = findScreen(catalog, screen);
|
|
577
657
|
return descriptor?.label ?? descriptor?.id ?? screen;
|
|
@@ -1323,17 +1403,6 @@ async function runCollabDoctor(ctx) {
|
|
|
1323
1403
|
]);
|
|
1324
1404
|
}
|
|
1325
1405
|
var commandFlowActions = defaultFlowActions;
|
|
1326
|
-
function sessionDescription(run) {
|
|
1327
|
-
const id = run.runId.slice(0, 8);
|
|
1328
|
-
const cwd = run.collabCwd || run.worktreePath || run.sessionPath || "(unknown cwd)";
|
|
1329
|
-
const link = collabLinks(run);
|
|
1330
|
-
return link ? `${id} \xB7 ${cwd} \xB7 ${link}` : `${id} \xB7 ${cwd}`;
|
|
1331
|
-
}
|
|
1332
|
-
function collabLinks(run) {
|
|
1333
|
-
const join = run.joinLink ? `joinLink ${run.joinLink}` : "";
|
|
1334
|
-
const web = run.webLink ? `webLink ${run.webLink}` : "";
|
|
1335
|
-
return join && web ? `${join} \xB7 ${web}` : join || web || "";
|
|
1336
|
-
}
|
|
1337
1406
|
function findRunById(runs, runId) {
|
|
1338
1407
|
if (!runId)
|
|
1339
1408
|
return null;
|
|
@@ -1361,15 +1430,30 @@ function runListActionHints(run, source) {
|
|
|
1361
1430
|
function serverLabel(server) {
|
|
1362
1431
|
return server?.alias?.trim() || "unselected";
|
|
1363
1432
|
}
|
|
1364
|
-
function
|
|
1433
|
+
function nextStep(server, runs, state) {
|
|
1365
1434
|
if (!server)
|
|
1366
|
-
return "
|
|
1367
|
-
|
|
1435
|
+
return { screen: "server", label: "choose where runs execute", detail: "no target selected \u2014 open Server" };
|
|
1436
|
+
const live = liveRunCount(runs, state);
|
|
1437
|
+
if (live > 0)
|
|
1438
|
+
return { screen: "runs", label: `watch the fleet \u2014 ${live} live`, detail: "open Runs for live status, steer, and gates" };
|
|
1439
|
+
return { screen: "tasks", label: "pick a task and dispatch", detail: `read ${server.taskSource ?? "the task source"} and send a drone at one` };
|
|
1440
|
+
}
|
|
1441
|
+
function liveRunCount(runs, state) {
|
|
1442
|
+
let count = 0;
|
|
1443
|
+
for (const run of runs) {
|
|
1368
1444
|
const classification = state.runClassifications?.get(run.runId);
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
return
|
|
1445
|
+
if (classification && classification.isActive && !classification.isTerminal)
|
|
1446
|
+
count += 1;
|
|
1447
|
+
}
|
|
1448
|
+
return count;
|
|
1449
|
+
}
|
|
1450
|
+
function attentionRunCount(runs, state) {
|
|
1451
|
+
let count = 0;
|
|
1452
|
+
for (const run of runs) {
|
|
1453
|
+
if (state.runClassifications?.get(run.runId)?.isNeedsAttention)
|
|
1454
|
+
count += 1;
|
|
1455
|
+
}
|
|
1456
|
+
return count;
|
|
1373
1457
|
}
|
|
1374
1458
|
function taskDetailModel(state, server, projection) {
|
|
1375
1459
|
const task = state.selectedTask ?? null;
|
|
@@ -1427,8 +1511,8 @@ function runDetailModel(run, source) {
|
|
|
1427
1511
|
ref: `RUN ${shortId}`,
|
|
1428
1512
|
title: run.title || `Run ${shortId}`,
|
|
1429
1513
|
status,
|
|
1430
|
-
body: run.errorSummary ||
|
|
1431
|
-
bodyLabel: "
|
|
1514
|
+
body: run.errorSummary || (classification.isTerminal ? `This run is ${status}. The facts below are its record; recovery actions appear when the read-model offers them.` : `Live ${run.source === "remote" ? "remote" : "local"} run. JOIN attaches this terminal to its OMP session; STEER drops a message into the agent's queue; gates resolve right here.`),
|
|
1515
|
+
bodyLabel: run.errorSummary ? "error" : "run",
|
|
1432
1516
|
facts: [
|
|
1433
1517
|
...run.taskId ? [{ label: "task", value: run.taskId }] : [],
|
|
1434
1518
|
{ label: "cwd", value: run.collabCwd || run.worktreePath || run.sessionPath || "(unknown cwd)" },
|
|
@@ -1460,11 +1544,20 @@ function runDetailModel(run, source) {
|
|
|
1460
1544
|
function cockpitNavValue(screen, server, runs, state) {
|
|
1461
1545
|
switch (screen) {
|
|
1462
1546
|
case "server":
|
|
1463
|
-
return serverLabel(server);
|
|
1547
|
+
return server ? `${serverLabel(server)} \xB7 ${server.kind === "remote" ? "remote" : "this checkout"}` : "unselected";
|
|
1464
1548
|
case "tasks":
|
|
1465
1549
|
return server?.taskSource ?? "configured source";
|
|
1466
|
-
case "runs":
|
|
1467
|
-
|
|
1550
|
+
case "runs": {
|
|
1551
|
+
const live = liveRunCount(runs, state);
|
|
1552
|
+
const attention = attentionRunCount(runs, state);
|
|
1553
|
+
if (runs.length === 0)
|
|
1554
|
+
return "none yet";
|
|
1555
|
+
const parts = [`${live} live`];
|
|
1556
|
+
if (attention > 0)
|
|
1557
|
+
parts.push(`${attention} waiting on you`);
|
|
1558
|
+
parts.push(`${runs.length} total`);
|
|
1559
|
+
return parts.join(" \xB7 ");
|
|
1560
|
+
}
|
|
1468
1561
|
default:
|
|
1469
1562
|
return "";
|
|
1470
1563
|
}
|
|
@@ -1474,36 +1567,38 @@ function cockpitNavRows(server, runs, state, catalog) {
|
|
|
1474
1567
|
id: `to:${screen}`,
|
|
1475
1568
|
label: nav.label,
|
|
1476
1569
|
currentValue: cockpitNavValue(screen, server, runs, state),
|
|
1477
|
-
values: ["
|
|
1570
|
+
values: ["open"],
|
|
1478
1571
|
description: nav.description
|
|
1479
1572
|
}));
|
|
1480
1573
|
}
|
|
1481
|
-
function itemsFor(screen, runs, actionRowsEnabled, _selectedRunId, state = {}, catalog = DEFAULT_SCREEN_CATALOG,
|
|
1574
|
+
function itemsFor(screen, runs, actionRowsEnabled, _selectedRunId, state = {}, catalog = DEFAULT_SCREEN_CATALOG, _projection = defaultCockpitCapabilities.taskProjection) {
|
|
1482
1575
|
const server = state.server ?? null;
|
|
1483
|
-
const projectRoot = state.projectRoot ?? rigProjectRoot();
|
|
1484
1576
|
const loadError = state.error?.trim();
|
|
1485
1577
|
if (screen === "task-detail" || screen === "run-detail")
|
|
1486
1578
|
return [];
|
|
1487
1579
|
if (loadError) {
|
|
1488
1580
|
return [
|
|
1489
|
-
{ id: "title", label:
|
|
1490
|
-
{ id: `${screen}:
|
|
1581
|
+
{ id: "title", label: screenLabel(screen, catalog), currentValue: "couldn't load", heading: true, description: loadError },
|
|
1582
|
+
{ id: `${screen}:retry`, label: "RETRY", currentValue: "reload this screen", values: ["retry"], description: "press enter (or r) to reload \u2014 esc returns to the cockpit" }
|
|
1491
1583
|
];
|
|
1492
1584
|
}
|
|
1493
1585
|
switch (screen) {
|
|
1494
|
-
case "cockpit":
|
|
1586
|
+
case "cockpit": {
|
|
1587
|
+
const step = nextStep(server, runs, state);
|
|
1495
1588
|
return [
|
|
1496
|
-
{ id: "title", label:
|
|
1497
|
-
{ id:
|
|
1589
|
+
{ id: "title", label: "cockpit", currentValue: "operate the drones", heading: true, description: "the loop: choose a target \xB7 dispatch tasks \xB7 watch runs land" },
|
|
1590
|
+
{ id: `to:${step.screen}`, label: "NEXT", currentValue: step.label, values: ["go"], description: step.detail },
|
|
1591
|
+
{ id: "sec:screens", label: "SCREENS", currentValue: "", heading: true },
|
|
1498
1592
|
...cockpitNavRows(server, runs, state, catalog)
|
|
1499
1593
|
];
|
|
1594
|
+
}
|
|
1500
1595
|
default: {
|
|
1501
1596
|
const producedRows = state.panelRows ?? [];
|
|
1502
1597
|
if (producedRows.length > 0)
|
|
1503
1598
|
return [...producedRows];
|
|
1504
1599
|
return [
|
|
1505
|
-
{ id: "title", label:
|
|
1506
|
-
{ id: `${screen}:
|
|
1600
|
+
{ id: "title", label: screenLabel(screen, catalog), currentValue: "nothing here yet", heading: true, description: "this screen's owner produced no content" },
|
|
1601
|
+
{ id: `${screen}:retry`, label: "RETRY", currentValue: "reload this screen", values: ["retry"], description: "press enter (or r) to reload \u2014 esc returns to the cockpit" }
|
|
1507
1602
|
];
|
|
1508
1603
|
}
|
|
1509
1604
|
}
|
|
@@ -1540,6 +1635,7 @@ class RigFlowComponent {
|
|
|
1540
1635
|
#refreshing = false;
|
|
1541
1636
|
#busyDepth = 0;
|
|
1542
1637
|
#animationTimer;
|
|
1638
|
+
#frame = { tabsLine: -1, viewStart: -1, viewEnd: -1, tabs: [] };
|
|
1543
1639
|
constructor(tui, api, done, onQuit, screen, runs, state, refreshRuns, refreshState, actions, actionRowsEnabled, catalog = DEFAULT_SCREEN_CATALOG, caps = defaultCockpitCapabilities, helpCatalog) {
|
|
1544
1640
|
this.tui = tui;
|
|
1545
1641
|
this.api = api;
|
|
@@ -1653,10 +1749,13 @@ class RigFlowComponent {
|
|
|
1653
1749
|
this.#genericView.setItems(itemsFor(genericScreen, this.#runs, this.actionRowsEnabled, this.#selectedRunId, this.#state, this.catalog, this.caps.taskProjection));
|
|
1654
1750
|
}
|
|
1655
1751
|
if (this.#view === "task-detail") {
|
|
1656
|
-
|
|
1752
|
+
const loadedId = this.caps.taskProjection.id(this.#state.selectedTask ?? null);
|
|
1753
|
+
const pendingId = this.#selectedTaskId;
|
|
1754
|
+
const stillLoading = Boolean(pendingId) && loadedId !== pendingId;
|
|
1755
|
+
this.#detailComposer.setModel(this.#state.error ? { screen: "task-detail", icon: screenGlyph2("task-detail"), ref: "TASK", title: "Task failed to load", body: this.#state.error, bodyLabel: "error", facts: [{ label: "hint", value: "r reloads \xB7 \u2190 returns to Tasks" }], actions: [] } : stillLoading ? { screen: "task-detail", icon: screenGlyph2("task-detail"), ref: `TASK ${pendingId}`, title: `Fetching task ${pendingId}\u2026`, body: "Reading the full task from the task source.", bodyLabel: "loading", facts: [], actions: [] } : taskDetailModel(this.#state, this.#state.server ?? null, this.caps.taskProjection));
|
|
1657
1756
|
} else if (this.#view === "run-detail") {
|
|
1658
1757
|
const run = findRunById(this.#runs, this.#selectedRunId);
|
|
1659
|
-
this.#detailComposer.setModel(this.#state.error ? { screen: "run-detail", icon: screenGlyph2("run-detail"), ref: "RUN", title: "Run failed to load", body: this.#state.error, bodyLabel: "error", facts: [{ label: "hint", value: "
|
|
1758
|
+
this.#detailComposer.setModel(this.#state.error ? { screen: "run-detail", icon: screenGlyph2("run-detail"), ref: "RUN", title: "Run failed to load", body: this.#state.error, bodyLabel: "error", facts: [{ label: "hint", value: "r reloads \xB7 \u2190 returns to Runs" }], actions: [] } : run ? runDetailModel(run, this.#state) : { screen: "run-detail", icon: screenGlyph2("run-detail"), ref: "RUN", title: "Run unavailable", facts: [{ label: "hint", value: "The selected run is no longer discoverable; \u2190 returns to Runs." }], actions: [] });
|
|
1660
1759
|
}
|
|
1661
1760
|
for (const view of this.#domainViews.values())
|
|
1662
1761
|
view.setTick(this.#tick);
|
|
@@ -1675,14 +1774,16 @@ class RigFlowComponent {
|
|
|
1675
1774
|
#setView(next) {
|
|
1676
1775
|
this.#view = next;
|
|
1677
1776
|
this.#notice = null;
|
|
1777
|
+
this.#error = "";
|
|
1678
1778
|
this.#feedViews();
|
|
1679
1779
|
this.tui.requestRender();
|
|
1680
1780
|
}
|
|
1681
1781
|
async#navigate(next, push = true) {
|
|
1682
|
-
if (push && this.#view !== "help")
|
|
1782
|
+
if (push && this.#view !== "help" && this.#view !== next)
|
|
1683
1783
|
this.#screenStack.push(this.#view);
|
|
1684
1784
|
this.#view = next;
|
|
1685
1785
|
this.#notice = null;
|
|
1786
|
+
this.#error = "";
|
|
1686
1787
|
const endBusy = this.#beginBusy();
|
|
1687
1788
|
try {
|
|
1688
1789
|
await this.#refreshCurrent();
|
|
@@ -1705,10 +1806,9 @@ class RigFlowComponent {
|
|
|
1705
1806
|
if (this.#view !== "help") {
|
|
1706
1807
|
const loadedState = await this.refreshState(this.#view, this.#selectedTaskId, this.#runs);
|
|
1707
1808
|
this.#state = runLoadError ? { ...loadedState, error: loadedState.error ? `${runLoadError}; ${loadedState.error}` : runLoadError } : loadedState;
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
this.#error = runLoadError;
|
|
1809
|
+
this.#error = this.#state.error ?? "";
|
|
1810
|
+
} else {
|
|
1811
|
+
this.#error = runLoadError ?? "";
|
|
1712
1812
|
}
|
|
1713
1813
|
this.#feedViews();
|
|
1714
1814
|
this.tui.requestRender();
|
|
@@ -1732,45 +1832,105 @@ class RigFlowComponent {
|
|
|
1732
1832
|
endBusy();
|
|
1733
1833
|
}
|
|
1734
1834
|
}
|
|
1735
|
-
#
|
|
1736
|
-
|
|
1737
|
-
|
|
1835
|
+
#tabScreens() {
|
|
1836
|
+
return [
|
|
1837
|
+
{ screen: "cockpit", label: "cockpit" },
|
|
1838
|
+
...cockpitNavScreens(this.catalog).map(({ screen, nav }) => ({ screen, label: nav.label.toLowerCase() }))
|
|
1839
|
+
];
|
|
1840
|
+
}
|
|
1841
|
+
#tabFor(view) {
|
|
1842
|
+
if (view === "run-detail")
|
|
1843
|
+
return "runs";
|
|
1844
|
+
if (view === "task-detail")
|
|
1845
|
+
return "tasks";
|
|
1846
|
+
if (view === "help")
|
|
1847
|
+
return "cockpit";
|
|
1848
|
+
return view;
|
|
1849
|
+
}
|
|
1850
|
+
#headerLine(width) {
|
|
1851
|
+
const screenName = this.#view === "help" ? "help" : screenLabel(this.#view, this.catalog).toLowerCase();
|
|
1852
|
+
const project = (this.#state.projectRoot ?? rigProjectRoot()).split("/").filter(Boolean).pop() ?? "";
|
|
1853
|
+
const live = liveRunCount(this.#runs, this.#state);
|
|
1854
|
+
const attention = attentionRunCount(this.#runs, this.#state);
|
|
1855
|
+
const dotPaint = attention > 0 ? yellow2 : live > 0 ? accent2 : ink42;
|
|
1856
|
+
const rightPlain = `\u25CF ${this.#serverLabel}${project ? ` \xB7 ${project}` : ""}`;
|
|
1857
|
+
const rightPainted = `${dotPaint("\u25CF")} ${cyan2(this.#serverLabel)}${project ? ` ${ink42("\xB7")} ${ink32(project)}` : ""}`;
|
|
1858
|
+
const leftPlain = ` \u258Drig ${screenName}`;
|
|
1859
|
+
const pad = Math.max(1, width - leftPlain.length - rightPlain.length - 1);
|
|
1860
|
+
return ` ${accent2("\u258D")}${bold2(ink5("rig"))} ${ink22(screenName)}${" ".repeat(pad)}${rightPainted}`;
|
|
1861
|
+
}
|
|
1862
|
+
#tabsLine(width) {
|
|
1863
|
+
const tabs = this.#tabScreens();
|
|
1864
|
+
const active = this.#tabFor(this.#view);
|
|
1865
|
+
this.#frame.tabs = [];
|
|
1866
|
+
let out = " ";
|
|
1867
|
+
let plainLength = 1;
|
|
1868
|
+
for (let index = 0;index < tabs.length; index += 1) {
|
|
1869
|
+
const tab = tabs[index];
|
|
1870
|
+
const text = ` ${index + 1} ${tab.label} `;
|
|
1871
|
+
this.#frame.tabs.push({ screen: tab.screen, start: plainLength, end: plainLength + text.length - 1 });
|
|
1872
|
+
out += tab.screen === active ? bgPanel2(`${accent2(` ${index + 1}`)} ${bold2(ink5(`${tab.label} `))}`) : `${ink42(` ${index + 1}`)} ${ink32(`${tab.label} `)}`;
|
|
1873
|
+
plainLength += text.length;
|
|
1874
|
+
out += " ";
|
|
1875
|
+
plainLength += 1;
|
|
1876
|
+
}
|
|
1877
|
+
const helpPlain = "? help";
|
|
1878
|
+
const pad = Math.max(1, width - plainLength - helpPlain.length - 1);
|
|
1879
|
+
return `${out}${" ".repeat(pad)}${accent2("?")}${ink32(" help")}`;
|
|
1738
1880
|
}
|
|
1739
1881
|
#noticeText() {
|
|
1740
1882
|
if (!this.#notice)
|
|
1741
1883
|
return null;
|
|
1742
|
-
const prefix = this.#busyDepth > 0 ? `${
|
|
1884
|
+
const prefix = this.#busyDepth > 0 ? `${RIG_SPINNER_FRAMES[this.#tick % RIG_SPINNER_FRAMES.length]} ` : "";
|
|
1743
1885
|
return `${prefix}${this.#notice}`;
|
|
1744
1886
|
}
|
|
1745
|
-
#footerLines() {
|
|
1887
|
+
#footerLines(width) {
|
|
1746
1888
|
if (this.#inputLine) {
|
|
1747
1889
|
const line = this.#inputLine;
|
|
1748
1890
|
const label = line.kind === "search" ? `${accent2("/")}${ink5(line.buffer)}` : `${accentDim2("steer")} ${ink32(`(${line.run.runId.slice(0, 8)})`)} ${accent2("\u276F")} ${ink5(line.buffer)}`;
|
|
1749
1891
|
return [
|
|
1750
1892
|
` ${label}${accent2("\u2588")}`,
|
|
1751
|
-
|
|
1893
|
+
keyHints(line.kind === "search" ? [["enter", "keep filter"], ["esc", "clear"]] : [["enter", "send"], ["esc", "cancel"]])
|
|
1894
|
+
];
|
|
1895
|
+
}
|
|
1896
|
+
if (this.#error) {
|
|
1897
|
+
const message = this.#error.length > width - 6 ? `${this.#error.slice(0, Math.max(8, width - 7))}\u2026` : this.#error;
|
|
1898
|
+
return [
|
|
1899
|
+
` ${red2("\u2717")} ${red2(message)}`,
|
|
1900
|
+
keyHints([["esc", "dismiss"], ["r", "retry"], ["q", "quit"]])
|
|
1901
|
+
];
|
|
1902
|
+
}
|
|
1903
|
+
const notice = this.#noticeText();
|
|
1904
|
+
if (this.#view === "help") {
|
|
1905
|
+
return [
|
|
1906
|
+
` ${notice ? accentDim2(notice) : ink42("every key on every screen")}`,
|
|
1907
|
+
keyHints([["\u2191\u2193", "scroll"], ["\u2190", "back"], ["esc", "cockpit"], ["q", "quit"]])
|
|
1752
1908
|
];
|
|
1753
1909
|
}
|
|
1754
|
-
if (this.#error)
|
|
1755
|
-
return [` ${red2(`error: ${this.#error}`)}`, ` ${accent2("esc")}${ink32(" cockpit")} ${accent2("q")}${ink32(" quit")}`];
|
|
1756
|
-
if (this.#view === "help")
|
|
1757
|
-
return [` ${accent2("\u2190")}${ink32(" back")} ${accent2("esc")}${ink32(" cockpit")} ${accent2("q")}${ink32(" quit")}`];
|
|
1758
1910
|
const domainFooter = this.#domainViews.get(this.#view)?.footer;
|
|
1759
1911
|
if (domainFooter)
|
|
1760
|
-
return domainFooter(
|
|
1912
|
+
return domainFooter(notice);
|
|
1761
1913
|
if (this.#view === "task-detail" || this.#view === "run-detail") {
|
|
1762
1914
|
const isTask = this.#view === "task-detail";
|
|
1763
|
-
const
|
|
1764
|
-
const hint = notice2 ? accentDim2(notice2) : ink42(isTask ? "review the task, then dispatch" : "live run controls");
|
|
1915
|
+
const hint = notice ? accentDim2(notice) : ink42(isTask ? "read it, then send a drone at it" : "live run controls \u2014 resolve gates in place");
|
|
1765
1916
|
return [
|
|
1766
1917
|
` ${hint}`,
|
|
1767
|
-
|
|
1918
|
+
keyHints([["\u2191\u2193", "action"], ["enter", isTask ? "dispatch" : "run"], ["\u21DE\u21DF", "scroll"], ["\u2190", "back"], ["q", "quit"]])
|
|
1768
1919
|
];
|
|
1769
1920
|
}
|
|
1770
|
-
|
|
1921
|
+
if (this.#view === "cockpit") {
|
|
1922
|
+
const live = liveRunCount(this.#runs, this.#state);
|
|
1923
|
+
const attention = attentionRunCount(this.#runs, this.#state);
|
|
1924
|
+
const fleet = this.#runs.length === 0 ? "fleet idle \u2014 dispatch something" : `${live} live \xB7 ${attention} waiting on you \xB7 ${this.#runs.length} total`;
|
|
1925
|
+
return [
|
|
1926
|
+
` ${notice ? accentDim2(notice) : ink42(fleet)}`,
|
|
1927
|
+
keyHints([["\u2191\u2193", "move"], ["enter", "open"], ["1-9", "jump"], ["?", "help"], ["q", "quit"]])
|
|
1928
|
+
];
|
|
1929
|
+
}
|
|
1930
|
+
const purpose = this.catalog.find((entry) => entry.id === this.#view)?.nav?.description ?? "";
|
|
1771
1931
|
return [
|
|
1772
|
-
` ${notice ? accentDim2(notice) : ink42(
|
|
1773
|
-
|
|
1932
|
+
` ${notice ? accentDim2(notice) : ink42(purpose || screenLabel(this.#view, this.catalog))}`,
|
|
1933
|
+
keyHints([["\u2191\u2193", "move"], ["enter", "act"], ["r", "reload"], ["\u2190", "back"], ["esc", "cockpit"], ["q", "quit"]])
|
|
1774
1934
|
];
|
|
1775
1935
|
}
|
|
1776
1936
|
async#attach(runId) {
|
|
@@ -1781,21 +1941,6 @@ class RigFlowComponent {
|
|
|
1781
1941
|
if (!this.#error)
|
|
1782
1942
|
this.done();
|
|
1783
1943
|
}
|
|
1784
|
-
async#stop(run) {
|
|
1785
|
-
this.#notice = `stop requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
1786
|
-
this.tui.requestRender();
|
|
1787
|
-
await this.#runAction(() => this.actions.act(`run-stop:${encodeURIComponent(run.runId)}`));
|
|
1788
|
-
}
|
|
1789
|
-
async#pause(run) {
|
|
1790
|
-
this.#notice = `pause requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
1791
|
-
this.tui.requestRender();
|
|
1792
|
-
await this.#runAction(() => this.actions.act(`run-pause:${encodeURIComponent(run.runId)}`));
|
|
1793
|
-
}
|
|
1794
|
-
async#resume(run) {
|
|
1795
|
-
this.#notice = `resume requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
1796
|
-
this.tui.requestRender();
|
|
1797
|
-
await this.#runAction(() => this.actions.act(`run-resume:${encodeURIComponent(run.runId)}`));
|
|
1798
|
-
}
|
|
1799
1944
|
async#steer(run, message) {
|
|
1800
1945
|
await this.#runAction(() => this.actions.act(`run-steer:${encodeURIComponent(run.runId)}`, message));
|
|
1801
1946
|
}
|
|
@@ -1829,6 +1974,10 @@ class RigFlowComponent {
|
|
|
1829
1974
|
}
|
|
1830
1975
|
return;
|
|
1831
1976
|
}
|
|
1977
|
+
if (item.id.endsWith(":retry")) {
|
|
1978
|
+
await this.#runAction(async () => {});
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1832
1981
|
if (item.id === "config:relayUrl" || item.id.startsWith("stats:") || item.id.startsWith("inspect:audit")) {
|
|
1833
1982
|
this.#notice = "informational row; no cockpit action";
|
|
1834
1983
|
this.tui.requestRender();
|
|
@@ -1844,12 +1993,15 @@ class RigFlowComponent {
|
|
|
1844
1993
|
await this.#runAction((onProgress) => this.actions.act(item.id, undefined, onProgress));
|
|
1845
1994
|
}
|
|
1846
1995
|
render(width) {
|
|
1847
|
-
const lines = [this.#headerLine(), hairline(width)];
|
|
1996
|
+
const lines = [this.#headerLine(width), this.#tabsLine(width), hairline(width)];
|
|
1997
|
+
this.#frame.tabsLine = 1;
|
|
1848
1998
|
const view = this.#view === "help" ? this.#helpView : this.#activeView();
|
|
1999
|
+
this.#frame.viewStart = lines.length;
|
|
1849
2000
|
for (const line of view.render(width))
|
|
1850
2001
|
lines.push(line);
|
|
2002
|
+
this.#frame.viewEnd = lines.length - 1;
|
|
1851
2003
|
lines.push(hairline(width));
|
|
1852
|
-
for (const line of this.#footerLines())
|
|
2004
|
+
for (const line of this.#footerLines(width))
|
|
1853
2005
|
lines.push(line);
|
|
1854
2006
|
return lines;
|
|
1855
2007
|
}
|
|
@@ -1859,7 +2011,95 @@ class RigFlowComponent {
|
|
|
1859
2011
|
this.#helpView.invalidate();
|
|
1860
2012
|
this.#genericView.invalidate();
|
|
1861
2013
|
}
|
|
2014
|
+
#activateDetailAction() {
|
|
2015
|
+
const action = this.#detailComposer.selectedAction();
|
|
2016
|
+
if (!action)
|
|
2017
|
+
return;
|
|
2018
|
+
if (action.id.startsWith("run-steer:")) {
|
|
2019
|
+
const run = findRunById(this.#runs, this.#selectedRunId);
|
|
2020
|
+
if (run) {
|
|
2021
|
+
this.#inputLine = { kind: "steer", buffer: "", run: { runId: run.runId } };
|
|
2022
|
+
this.tui.requestRender();
|
|
2023
|
+
}
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
if (action.id.startsWith("task-detail:dispatch:")) {
|
|
2027
|
+
this.#notice = "dispatch \xB7 starting\u2026";
|
|
2028
|
+
this.tui.requestRender();
|
|
2029
|
+
}
|
|
2030
|
+
if (action.id.startsWith("run-stop:")) {
|
|
2031
|
+
this.#notice = "stop requested\u2026";
|
|
2032
|
+
this.tui.requestRender();
|
|
2033
|
+
}
|
|
2034
|
+
this.#actOnItem({ id: action.id, label: action.label, values: [action.value ?? "go"] });
|
|
2035
|
+
}
|
|
2036
|
+
#handleMouse(event) {
|
|
2037
|
+
if (this.#inputLine)
|
|
2038
|
+
return;
|
|
2039
|
+
const { tabsLine, viewStart, viewEnd, tabs } = this.#frame;
|
|
2040
|
+
if (event.wheel !== null) {
|
|
2041
|
+
if (this.#view === "help")
|
|
2042
|
+
this.#helpView.scroll(event.wheel * 3);
|
|
2043
|
+
else if (this.#view === "task-detail" || this.#view === "run-detail")
|
|
2044
|
+
this.#detailComposer.scrollBody(event.wheel * 2);
|
|
2045
|
+
else {
|
|
2046
|
+
const domainView2 = this.#domainViews.get(this.#view);
|
|
2047
|
+
if (domainView2) {
|
|
2048
|
+
if (!domainView2.handleMouse?.(event, Math.max(0, event.row - viewStart)))
|
|
2049
|
+
return;
|
|
2050
|
+
} else {
|
|
2051
|
+
this.#genericView.moveSelection(event.wheel);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
this.tui.requestRender();
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
if (!event.leftClick)
|
|
2058
|
+
return;
|
|
2059
|
+
if (event.row === tabsLine) {
|
|
2060
|
+
const hit = tabs.find((tab) => event.col >= tab.start && event.col <= tab.end);
|
|
2061
|
+
if (hit && hit.screen !== this.#view)
|
|
2062
|
+
this.#navigate(hit.screen);
|
|
2063
|
+
return;
|
|
2064
|
+
}
|
|
2065
|
+
if (event.row < viewStart || event.row > viewEnd)
|
|
2066
|
+
return;
|
|
2067
|
+
const line = event.row - viewStart;
|
|
2068
|
+
if (this.#view === "help")
|
|
2069
|
+
return;
|
|
2070
|
+
if (this.#view === "task-detail" || this.#view === "run-detail") {
|
|
2071
|
+
const index2 = this.#detailComposer.hitTestAction(line);
|
|
2072
|
+
if (index2 === undefined)
|
|
2073
|
+
return;
|
|
2074
|
+
const moved2 = this.#detailComposer.selectAction(index2);
|
|
2075
|
+
this.tui.requestRender();
|
|
2076
|
+
if (!moved2)
|
|
2077
|
+
this.#activateDetailAction();
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
const domainView = this.#domainViews.get(this.#view);
|
|
2081
|
+
if (domainView) {
|
|
2082
|
+
domainView.handleMouse?.(event, line);
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
const index = this.#genericView.hitTest(line);
|
|
2086
|
+
if (index === undefined)
|
|
2087
|
+
return;
|
|
2088
|
+
const moved = this.#genericView.selectIndex(index);
|
|
2089
|
+
this.tui.requestRender();
|
|
2090
|
+
if (!moved) {
|
|
2091
|
+
const item = this.#genericView.selectedItem();
|
|
2092
|
+
if (item)
|
|
2093
|
+
this.#actOnItem(item);
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
1862
2096
|
handleInput(data) {
|
|
2097
|
+
if (data.startsWith("\x1B[<")) {
|
|
2098
|
+
const event = parseSgrMouse(data);
|
|
2099
|
+
if (event)
|
|
2100
|
+
this.#handleMouse(event);
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
1863
2103
|
if (data === "q") {
|
|
1864
2104
|
this.onQuit();
|
|
1865
2105
|
return;
|
|
@@ -1894,6 +2134,19 @@ class RigFlowComponent {
|
|
|
1894
2134
|
this.done();
|
|
1895
2135
|
return;
|
|
1896
2136
|
}
|
|
2137
|
+
if (this.#error && matchesKey(data, "escape")) {
|
|
2138
|
+
this.#error = "";
|
|
2139
|
+
this.tui.requestRender();
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2142
|
+
if (/^[1-9]$/.test(data)) {
|
|
2143
|
+
const target = this.#tabScreens()[Number(data) - 1];
|
|
2144
|
+
if (target) {
|
|
2145
|
+
if (target.screen !== this.#view)
|
|
2146
|
+
this.#navigate(target.screen);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
1897
2150
|
if (this.#view === "help") {
|
|
1898
2151
|
if (matchesKey(data, "up") || data === "k")
|
|
1899
2152
|
this.#helpView.scroll(-1);
|
|
@@ -1922,26 +2175,7 @@ class RigFlowComponent {
|
|
|
1922
2175
|
return;
|
|
1923
2176
|
}
|
|
1924
2177
|
if (matchesKey(data, "enter") || matchesKey(data, "return")) {
|
|
1925
|
-
|
|
1926
|
-
if (action) {
|
|
1927
|
-
if (action.id.startsWith("run-steer:")) {
|
|
1928
|
-
const run = findRunById(this.#runs, this.#selectedRunId);
|
|
1929
|
-
if (run) {
|
|
1930
|
-
this.#inputLine = { kind: "steer", buffer: "", run: { runId: run.runId } };
|
|
1931
|
-
this.tui.requestRender();
|
|
1932
|
-
}
|
|
1933
|
-
return;
|
|
1934
|
-
}
|
|
1935
|
-
if (action.id.startsWith("task-detail:dispatch:")) {
|
|
1936
|
-
this.#notice = "dispatch \xB7 starting\u2026";
|
|
1937
|
-
this.tui.requestRender();
|
|
1938
|
-
}
|
|
1939
|
-
if (action.id.startsWith("run-stop:")) {
|
|
1940
|
-
this.#notice = "stop requested\u2026";
|
|
1941
|
-
this.tui.requestRender();
|
|
1942
|
-
}
|
|
1943
|
-
this.#actOnItem({ id: action.id, label: action.label, values: [action.value ?? "go"] });
|
|
1944
|
-
}
|
|
2178
|
+
this.#activateDetailAction();
|
|
1945
2179
|
return;
|
|
1946
2180
|
}
|
|
1947
2181
|
if (matchesKey(data, "pageUp")) {
|