@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
package/dist/src/plugin.js
CHANGED
|
@@ -21,6 +21,7 @@ import { truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
|
21
21
|
import {
|
|
22
22
|
accent,
|
|
23
23
|
accentDim,
|
|
24
|
+
bgPanel,
|
|
24
25
|
bold,
|
|
25
26
|
cyan,
|
|
26
27
|
ink,
|
|
@@ -28,10 +29,6 @@ import {
|
|
|
28
29
|
ink3,
|
|
29
30
|
ink4,
|
|
30
31
|
red,
|
|
31
|
-
DRONE_WIDTH,
|
|
32
|
-
renderDroneFrame,
|
|
33
|
-
renderMicroDroneFrame,
|
|
34
|
-
RIG_SPINNER_FRAMES,
|
|
35
32
|
screenGlyph,
|
|
36
33
|
sectionDivider,
|
|
37
34
|
statusColor,
|
|
@@ -49,6 +46,7 @@ class BoardSettingsList {
|
|
|
49
46
|
selected = 0;
|
|
50
47
|
title = "";
|
|
51
48
|
emptyMessage = "nothing to show";
|
|
49
|
+
#rowToIndex = new Map;
|
|
52
50
|
setItems(items) {
|
|
53
51
|
this.items = [...items];
|
|
54
52
|
if (!this.selectableAt(this.selected))
|
|
@@ -79,44 +77,77 @@ class BoardSettingsList {
|
|
|
79
77
|
selectedItem() {
|
|
80
78
|
return this.selectableAt(this.selected) ? this.items[this.selected] : null;
|
|
81
79
|
}
|
|
80
|
+
hitTest(line) {
|
|
81
|
+
const index = this.#rowToIndex.get(line);
|
|
82
|
+
return index !== undefined && this.selectableAt(index) ? index : undefined;
|
|
83
|
+
}
|
|
84
|
+
selectIndex(index) {
|
|
85
|
+
if (!this.selectableAt(index))
|
|
86
|
+
return false;
|
|
87
|
+
const moved = this.selected !== index;
|
|
88
|
+
this.selected = index;
|
|
89
|
+
return moved;
|
|
90
|
+
}
|
|
82
91
|
invalidate() {}
|
|
83
92
|
render(width) {
|
|
84
93
|
return this.renderLines(width).map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
85
94
|
}
|
|
86
95
|
renderLines(width) {
|
|
96
|
+
this.#rowToIndex.clear();
|
|
87
97
|
if (this.items.length === 0) {
|
|
88
98
|
return ["", ` ${ink2(this.emptyMessage)}`, ""];
|
|
89
99
|
}
|
|
90
|
-
const maxVisible = Math.max(8, Math.min(
|
|
100
|
+
const maxVisible = Math.max(8, Math.min(18, (process.stdout.rows ?? 30) - 10));
|
|
91
101
|
const start = Math.max(0, Math.min(this.selected - Math.floor(maxVisible / 2), this.items.length - maxVisible));
|
|
92
102
|
const window = this.items.slice(start, start + maxVisible);
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
const labelWidth = Math.min(28, Math.max(10, ...window.map((item) => {
|
|
104
|
+
const navGlyph = item.id.startsWith("to:") ? 2 : 0;
|
|
105
|
+
return item.label.length + navGlyph;
|
|
106
|
+
})));
|
|
107
|
+
const actionWidth = Math.max(0, ...window.map((item) => item.values?.[0] && item.values[0] !== item.currentValue ? item.values[0].length + 2 : 0));
|
|
108
|
+
const valueWidth = Math.max(12, width - labelWidth - actionWidth - 8);
|
|
109
|
+
const lines = [""];
|
|
110
|
+
for (let index = 0;index < window.length; index += 1) {
|
|
111
|
+
const item = window[index];
|
|
96
112
|
const absolute = start + index;
|
|
97
113
|
const isSelected = absolute === this.selected;
|
|
98
|
-
|
|
114
|
+
if (item.id === "title") {
|
|
115
|
+
lines.push(` ${accent("\u258D")}${bold(ink(item.label))}${item.currentValue ? ` ${ink3(item.currentValue)}` : ""}`);
|
|
116
|
+
if (item.description)
|
|
117
|
+
lines.push(` ${ink4(truncateToWidth(item.description, Math.max(12, width - 4)))}`);
|
|
118
|
+
lines.push("");
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (item.heading && !item.currentValue) {
|
|
122
|
+
lines.push(sectionDivider(item.label.toLowerCase(), width));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
99
125
|
const navGlyph = item.id.startsWith("to:") ? `${screenGlyph(item.id.slice(3))} ` : "";
|
|
100
|
-
const
|
|
101
|
-
const isTitle = item.id === "title";
|
|
126
|
+
const labelPlain = truncateToWidth(`${navGlyph}${item.label}`, labelWidth).padEnd(labelWidth);
|
|
102
127
|
const isStatus = item.id.endsWith(":status");
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
const
|
|
128
|
+
const valuePlain = truncateToWidth(item.currentValue ?? "", valueWidth).padEnd(valueWidth);
|
|
129
|
+
const label = isSelected ? ink(labelPlain) : item.heading ? ink3(labelPlain) : ink2(labelPlain);
|
|
130
|
+
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);
|
|
131
|
+
const actionText = item.values?.[0] && item.values[0] !== item.currentValue ? item.values[0] : "";
|
|
132
|
+
const action = actionText ? isSelected ? accent(`${actionText} \u203A`) : accentDim(actionText) : "";
|
|
133
|
+
const rail = isSelected ? accent("\u258C") : " ";
|
|
134
|
+
const body = `${rail} ${label} ${value}${action ? ` ${action}` : ""}`;
|
|
135
|
+
if (!item.heading)
|
|
136
|
+
this.#rowToIndex.set(lines.length, absolute);
|
|
137
|
+
lines.push(isSelected ? bgPanel(body) : body);
|
|
107
138
|
if (isSelected && item.description) {
|
|
108
|
-
|
|
139
|
+
if (!item.heading)
|
|
140
|
+
this.#rowToIndex.set(lines.length, absolute);
|
|
141
|
+
lines.push(` ${ink4("\u21B3")} ${ink4(truncateToWidth(item.description, Math.max(12, width - 6)))}`);
|
|
109
142
|
}
|
|
110
|
-
|
|
111
|
-
});
|
|
143
|
+
}
|
|
112
144
|
const meta = [];
|
|
113
145
|
if (this.items.length > maxVisible)
|
|
114
|
-
meta.push(`${this.selected + 1}
|
|
115
|
-
if (this.title)
|
|
116
|
-
meta.push(this.title);
|
|
146
|
+
meta.push(`${this.selected + 1} of ${this.items.length}`);
|
|
117
147
|
if (meta.length > 0)
|
|
118
|
-
lines.push(ink4(` ${meta.join(" \xB7 ")}`));
|
|
119
|
-
|
|
148
|
+
lines.push("", ink4(` ${meta.join(" \xB7 ")}`));
|
|
149
|
+
lines.push("");
|
|
150
|
+
return lines;
|
|
120
151
|
}
|
|
121
152
|
}
|
|
122
153
|
|
|
@@ -200,6 +231,7 @@ class DetailComposer {
|
|
|
200
231
|
selected = 0;
|
|
201
232
|
tick = 0;
|
|
202
233
|
bodyScroll = 0;
|
|
234
|
+
#lineToAction = new Map;
|
|
203
235
|
setModel(model) {
|
|
204
236
|
const prevId = this.enabledActions()[this.selected]?.id;
|
|
205
237
|
this.model = model;
|
|
@@ -224,6 +256,17 @@ class DetailComposer {
|
|
|
224
256
|
selectedAction() {
|
|
225
257
|
return this.enabledActions()[this.selected] ?? null;
|
|
226
258
|
}
|
|
259
|
+
hitTestAction(line) {
|
|
260
|
+
return this.#lineToAction.get(line);
|
|
261
|
+
}
|
|
262
|
+
selectAction(index) {
|
|
263
|
+
const count = this.enabledActions().length;
|
|
264
|
+
if (index < 0 || index >= count)
|
|
265
|
+
return false;
|
|
266
|
+
const moved = this.selected !== index;
|
|
267
|
+
this.selected = index;
|
|
268
|
+
return moved;
|
|
269
|
+
}
|
|
227
270
|
scrollBody(delta) {
|
|
228
271
|
this.bodyScroll = Math.max(0, this.bodyScroll + delta);
|
|
229
272
|
}
|
|
@@ -253,21 +296,45 @@ class DetailComposer {
|
|
|
253
296
|
}
|
|
254
297
|
if (model.stages && model.stages.length > 0) {
|
|
255
298
|
bottom.push(sectionDivider("pipeline", width));
|
|
256
|
-
|
|
257
|
-
|
|
299
|
+
let linePlain = " ";
|
|
300
|
+
let linePainted = " ";
|
|
301
|
+
for (let i = 0;i < model.stages.length; i += 1) {
|
|
302
|
+
const stage = model.stages[i];
|
|
303
|
+
const sepPlain = linePlain.trim().length > 0 ? " \u2192 " : " ";
|
|
304
|
+
const cellPlain = `${sepPlain}? ${stage.label}`;
|
|
305
|
+
if (linePlain.length + cellPlain.length > inner - 2 && linePlain.trim().length > 0) {
|
|
306
|
+
bottom.push(linePainted);
|
|
307
|
+
linePlain = " ";
|
|
308
|
+
linePainted = " ";
|
|
309
|
+
}
|
|
310
|
+
const sep = linePlain.trim().length > 0 ? ink4(" \u2192 ") : " ";
|
|
311
|
+
linePlain += cellPlain;
|
|
312
|
+
linePainted += `${sep}${statusColor(stage.status)(statusGlyph(stage.status))} ${ink3(stage.label)}`;
|
|
313
|
+
}
|
|
314
|
+
if (linePainted.trim().length > 0)
|
|
315
|
+
bottom.push(linePainted);
|
|
258
316
|
bottom.push("");
|
|
259
317
|
}
|
|
318
|
+
const actionLines = [];
|
|
260
319
|
if (model.actions.length > 0) {
|
|
261
320
|
bottom.push(sectionDivider("actions", width));
|
|
262
321
|
const selId = this.selectedAction()?.id;
|
|
322
|
+
let enabledIndex = -1;
|
|
263
323
|
for (const action of model.actions) {
|
|
264
324
|
const on = action.enabled !== false;
|
|
325
|
+
if (on)
|
|
326
|
+
enabledIndex += 1;
|
|
265
327
|
const isSel = on && action.id === selId;
|
|
266
328
|
const rail = isSel ? accent("\u258C") : " ";
|
|
267
329
|
const labelText = `${action.glyph ? `${action.glyph} ` : ""}${action.label}`;
|
|
268
330
|
const label = !on ? ink4(labelText) : action.danger ? red(labelText) : isSel ? accent(labelText) : ink2(labelText);
|
|
269
331
|
const tail = !on ? ink4(action.value ?? "unavailable") : isSel ? ink3(action.hint ?? action.value ?? "") : ink3(action.value ?? "");
|
|
270
|
-
|
|
332
|
+
const row = `${rail} ${label}${tail ? ` ${tail}` : ""}`;
|
|
333
|
+
if (on)
|
|
334
|
+
actionLines.push(enabledIndex);
|
|
335
|
+
else
|
|
336
|
+
actionLines.push(-1);
|
|
337
|
+
bottom.push(isSel ? bgPanel(row) : row);
|
|
271
338
|
}
|
|
272
339
|
}
|
|
273
340
|
const body = [];
|
|
@@ -292,10 +359,25 @@ class DetailComposer {
|
|
|
292
359
|
}
|
|
293
360
|
}
|
|
294
361
|
const out = [...top, ...body, ...bottom];
|
|
362
|
+
const mapActions = (linesOut) => {
|
|
363
|
+
this.#lineToAction.clear();
|
|
364
|
+
if (actionLines.length === 0)
|
|
365
|
+
return;
|
|
366
|
+
const actionCount = model.actions.length;
|
|
367
|
+
const firstActionLine = linesOut.length - actionCount;
|
|
368
|
+
for (let i = 0;i < actionCount; i += 1) {
|
|
369
|
+
const enabledIdx = actionLines[i];
|
|
370
|
+
if (enabledIdx >= 0)
|
|
371
|
+
this.#lineToAction.set(firstActionLine + i, enabledIdx);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
295
374
|
if (out.length > budget) {
|
|
296
375
|
const keepTail = Math.min(bottom.length, budget - top.length);
|
|
297
|
-
|
|
376
|
+
const clipped = [...top, ...out.slice(out.length - keepTail)];
|
|
377
|
+
mapActions(clipped);
|
|
378
|
+
return clipped.map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
298
379
|
}
|
|
380
|
+
mapActions(out);
|
|
299
381
|
return out.map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
300
382
|
}
|
|
301
383
|
}
|
|
@@ -551,9 +633,6 @@ function findScreen(catalog, screen) {
|
|
|
551
633
|
function isRigScreen(value, catalog = DEFAULT_SCREEN_CATALOG) {
|
|
552
634
|
return typeof value === "string" && catalog.some((screen) => screen.id === value);
|
|
553
635
|
}
|
|
554
|
-
function screenTitle(screen, catalog = DEFAULT_SCREEN_CATALOG) {
|
|
555
|
-
return findScreen(catalog, screen)?.title ?? screen;
|
|
556
|
-
}
|
|
557
636
|
function screenLabel(screen, catalog = DEFAULT_SCREEN_CATALOG) {
|
|
558
637
|
const descriptor = findScreen(catalog, screen);
|
|
559
638
|
return descriptor?.label ?? descriptor?.id ?? screen;
|
|
@@ -567,8 +646,8 @@ function cockpitNavScreens(catalog = DEFAULT_SCREEN_CATALOG) {
|
|
|
567
646
|
var DEFAULT_SCREEN_CATALOG;
|
|
568
647
|
var init_screen_catalog = __esm(() => {
|
|
569
648
|
DEFAULT_SCREEN_CATALOG = [
|
|
570
|
-
{ id: "cockpit", title: "
|
|
571
|
-
{ id: "task-detail", title: "Task Detail" },
|
|
649
|
+
{ id: "cockpit", title: "Cockpit", label: "cockpit", shortcut: { key: "g", description: "Rig cockpit" } },
|
|
650
|
+
{ id: "task-detail", title: "Task Detail", label: "task detail" },
|
|
572
651
|
{ id: "run-detail", title: "Run Detail", label: "run detail" }
|
|
573
652
|
];
|
|
574
653
|
});
|
|
@@ -653,9 +732,9 @@ import { DOCTOR } from "@rig/contracts";
|
|
|
653
732
|
import { RIG_COCKPIT_PANEL_SLOT } from "@rig/contracts";
|
|
654
733
|
import { defineCapability } from "@rig/core/capability";
|
|
655
734
|
import { loadCapabilityForRoot, requireCapabilityForRoot } from "@rig/core/capability-loaders";
|
|
656
|
-
import { isKeyRelease, matchesKey } from "@oh-my-pi/pi-tui";
|
|
735
|
+
import { isKeyRelease, matchesKey, parseSgrMouse } from "@oh-my-pi/pi-tui";
|
|
657
736
|
import { Duration, Effect, Fiber, Stream } from "effect";
|
|
658
|
-
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
|
|
737
|
+
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";
|
|
659
738
|
import { resolvePluginHost } from "@rig/core/project-plugins";
|
|
660
739
|
import { rigProjectRootFromEnv as rigProjectRoot } from "@rig/core/root-resolver";
|
|
661
740
|
function isProjectedRunClassification(value) {
|
|
@@ -1328,17 +1407,6 @@ async function runCollabDoctor(ctx) {
|
|
|
1328
1407
|
{ label: "join-links", level: runs.some((run) => run.joinLink) ? "ok" : "warn", detail: `${runs.filter((run) => run.joinLink).length} joinable run(s)` }
|
|
1329
1408
|
]);
|
|
1330
1409
|
}
|
|
1331
|
-
function sessionDescription(run) {
|
|
1332
|
-
const id = run.runId.slice(0, 8);
|
|
1333
|
-
const cwd = run.collabCwd || run.worktreePath || run.sessionPath || "(unknown cwd)";
|
|
1334
|
-
const link = collabLinks(run);
|
|
1335
|
-
return link ? `${id} \xB7 ${cwd} \xB7 ${link}` : `${id} \xB7 ${cwd}`;
|
|
1336
|
-
}
|
|
1337
|
-
function collabLinks(run) {
|
|
1338
|
-
const join = run.joinLink ? `joinLink ${run.joinLink}` : "";
|
|
1339
|
-
const web = run.webLink ? `webLink ${run.webLink}` : "";
|
|
1340
|
-
return join && web ? `${join} \xB7 ${web}` : join || web || "";
|
|
1341
|
-
}
|
|
1342
1410
|
function findRunById(runs, runId) {
|
|
1343
1411
|
if (!runId)
|
|
1344
1412
|
return null;
|
|
@@ -1366,15 +1434,30 @@ function runListActionHints(run, source) {
|
|
|
1366
1434
|
function serverLabel(server) {
|
|
1367
1435
|
return server?.alias?.trim() || "unselected";
|
|
1368
1436
|
}
|
|
1369
|
-
function
|
|
1437
|
+
function nextStep(server, runs, state) {
|
|
1370
1438
|
if (!server)
|
|
1371
|
-
return "
|
|
1372
|
-
|
|
1439
|
+
return { screen: "server", label: "choose where runs execute", detail: "no target selected \u2014 open Server" };
|
|
1440
|
+
const live = liveRunCount(runs, state);
|
|
1441
|
+
if (live > 0)
|
|
1442
|
+
return { screen: "runs", label: `watch the fleet \u2014 ${live} live`, detail: "open Runs for live status, steer, and gates" };
|
|
1443
|
+
return { screen: "tasks", label: "pick a task and dispatch", detail: `read ${server.taskSource ?? "the task source"} and send a drone at one` };
|
|
1444
|
+
}
|
|
1445
|
+
function liveRunCount(runs, state) {
|
|
1446
|
+
let count = 0;
|
|
1447
|
+
for (const run of runs) {
|
|
1373
1448
|
const classification = state.runClassifications?.get(run.runId);
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
return
|
|
1449
|
+
if (classification && classification.isActive && !classification.isTerminal)
|
|
1450
|
+
count += 1;
|
|
1451
|
+
}
|
|
1452
|
+
return count;
|
|
1453
|
+
}
|
|
1454
|
+
function attentionRunCount(runs, state) {
|
|
1455
|
+
let count = 0;
|
|
1456
|
+
for (const run of runs) {
|
|
1457
|
+
if (state.runClassifications?.get(run.runId)?.isNeedsAttention)
|
|
1458
|
+
count += 1;
|
|
1459
|
+
}
|
|
1460
|
+
return count;
|
|
1378
1461
|
}
|
|
1379
1462
|
function taskDetailModel(state, server, projection) {
|
|
1380
1463
|
const task = state.selectedTask ?? null;
|
|
@@ -1432,8 +1515,8 @@ function runDetailModel(run, source) {
|
|
|
1432
1515
|
ref: `RUN ${shortId}`,
|
|
1433
1516
|
title: run.title || `Run ${shortId}`,
|
|
1434
1517
|
status,
|
|
1435
|
-
body: run.errorSummary ||
|
|
1436
|
-
bodyLabel: "
|
|
1518
|
+
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.`),
|
|
1519
|
+
bodyLabel: run.errorSummary ? "error" : "run",
|
|
1437
1520
|
facts: [
|
|
1438
1521
|
...run.taskId ? [{ label: "task", value: run.taskId }] : [],
|
|
1439
1522
|
{ label: "cwd", value: run.collabCwd || run.worktreePath || run.sessionPath || "(unknown cwd)" },
|
|
@@ -1465,11 +1548,20 @@ function runDetailModel(run, source) {
|
|
|
1465
1548
|
function cockpitNavValue(screen, server, runs, state) {
|
|
1466
1549
|
switch (screen) {
|
|
1467
1550
|
case "server":
|
|
1468
|
-
return serverLabel(server);
|
|
1551
|
+
return server ? `${serverLabel(server)} \xB7 ${server.kind === "remote" ? "remote" : "this checkout"}` : "unselected";
|
|
1469
1552
|
case "tasks":
|
|
1470
1553
|
return server?.taskSource ?? "configured source";
|
|
1471
|
-
case "runs":
|
|
1472
|
-
|
|
1554
|
+
case "runs": {
|
|
1555
|
+
const live = liveRunCount(runs, state);
|
|
1556
|
+
const attention = attentionRunCount(runs, state);
|
|
1557
|
+
if (runs.length === 0)
|
|
1558
|
+
return "none yet";
|
|
1559
|
+
const parts = [`${live} live`];
|
|
1560
|
+
if (attention > 0)
|
|
1561
|
+
parts.push(`${attention} waiting on you`);
|
|
1562
|
+
parts.push(`${runs.length} total`);
|
|
1563
|
+
return parts.join(" \xB7 ");
|
|
1564
|
+
}
|
|
1473
1565
|
default:
|
|
1474
1566
|
return "";
|
|
1475
1567
|
}
|
|
@@ -1479,36 +1571,38 @@ function cockpitNavRows(server, runs, state, catalog) {
|
|
|
1479
1571
|
id: `to:${screen}`,
|
|
1480
1572
|
label: nav.label,
|
|
1481
1573
|
currentValue: cockpitNavValue(screen, server, runs, state),
|
|
1482
|
-
values: ["
|
|
1574
|
+
values: ["open"],
|
|
1483
1575
|
description: nav.description
|
|
1484
1576
|
}));
|
|
1485
1577
|
}
|
|
1486
|
-
function itemsFor(screen, runs, actionRowsEnabled, _selectedRunId, state = {}, catalog = DEFAULT_SCREEN_CATALOG,
|
|
1578
|
+
function itemsFor(screen, runs, actionRowsEnabled, _selectedRunId, state = {}, catalog = DEFAULT_SCREEN_CATALOG, _projection = defaultCockpitCapabilities.taskProjection) {
|
|
1487
1579
|
const server = state.server ?? null;
|
|
1488
|
-
const projectRoot = state.projectRoot ?? rigProjectRoot();
|
|
1489
1580
|
const loadError = state.error?.trim();
|
|
1490
1581
|
if (screen === "task-detail" || screen === "run-detail")
|
|
1491
1582
|
return [];
|
|
1492
1583
|
if (loadError) {
|
|
1493
1584
|
return [
|
|
1494
|
-
{ id: "title", label:
|
|
1495
|
-
{ id: `${screen}:
|
|
1585
|
+
{ id: "title", label: screenLabel(screen, catalog), currentValue: "couldn't load", heading: true, description: loadError },
|
|
1586
|
+
{ id: `${screen}:retry`, label: "RETRY", currentValue: "reload this screen", values: ["retry"], description: "press enter (or r) to reload \u2014 esc returns to the cockpit" }
|
|
1496
1587
|
];
|
|
1497
1588
|
}
|
|
1498
1589
|
switch (screen) {
|
|
1499
|
-
case "cockpit":
|
|
1590
|
+
case "cockpit": {
|
|
1591
|
+
const step = nextStep(server, runs, state);
|
|
1500
1592
|
return [
|
|
1501
|
-
{ id: "title", label:
|
|
1502
|
-
{ id:
|
|
1593
|
+
{ id: "title", label: "cockpit", currentValue: "operate the drones", heading: true, description: "the loop: choose a target \xB7 dispatch tasks \xB7 watch runs land" },
|
|
1594
|
+
{ id: `to:${step.screen}`, label: "NEXT", currentValue: step.label, values: ["go"], description: step.detail },
|
|
1595
|
+
{ id: "sec:screens", label: "SCREENS", currentValue: "", heading: true },
|
|
1503
1596
|
...cockpitNavRows(server, runs, state, catalog)
|
|
1504
1597
|
];
|
|
1598
|
+
}
|
|
1505
1599
|
default: {
|
|
1506
1600
|
const producedRows = state.panelRows ?? [];
|
|
1507
1601
|
if (producedRows.length > 0)
|
|
1508
1602
|
return [...producedRows];
|
|
1509
1603
|
return [
|
|
1510
|
-
{ id: "title", label:
|
|
1511
|
-
{ id: `${screen}:
|
|
1604
|
+
{ id: "title", label: screenLabel(screen, catalog), currentValue: "nothing here yet", heading: true, description: "this screen's owner produced no content" },
|
|
1605
|
+
{ id: `${screen}:retry`, label: "RETRY", currentValue: "reload this screen", values: ["retry"], description: "press enter (or r) to reload \u2014 esc returns to the cockpit" }
|
|
1512
1606
|
];
|
|
1513
1607
|
}
|
|
1514
1608
|
}
|
|
@@ -1545,6 +1639,7 @@ class RigFlowComponent {
|
|
|
1545
1639
|
#refreshing = false;
|
|
1546
1640
|
#busyDepth = 0;
|
|
1547
1641
|
#animationTimer;
|
|
1642
|
+
#frame = { tabsLine: -1, viewStart: -1, viewEnd: -1, tabs: [] };
|
|
1548
1643
|
constructor(tui, api, done, onQuit, screen, runs, state, refreshRuns, refreshState, actions, actionRowsEnabled, catalog = DEFAULT_SCREEN_CATALOG, caps = defaultCockpitCapabilities, helpCatalog) {
|
|
1549
1644
|
this.tui = tui;
|
|
1550
1645
|
this.api = api;
|
|
@@ -1658,10 +1753,13 @@ class RigFlowComponent {
|
|
|
1658
1753
|
this.#genericView.setItems(itemsFor(genericScreen, this.#runs, this.actionRowsEnabled, this.#selectedRunId, this.#state, this.catalog, this.caps.taskProjection));
|
|
1659
1754
|
}
|
|
1660
1755
|
if (this.#view === "task-detail") {
|
|
1661
|
-
|
|
1756
|
+
const loadedId = this.caps.taskProjection.id(this.#state.selectedTask ?? null);
|
|
1757
|
+
const pendingId = this.#selectedTaskId;
|
|
1758
|
+
const stillLoading = Boolean(pendingId) && loadedId !== pendingId;
|
|
1759
|
+
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));
|
|
1662
1760
|
} else if (this.#view === "run-detail") {
|
|
1663
1761
|
const run = findRunById(this.#runs, this.#selectedRunId);
|
|
1664
|
-
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: "
|
|
1762
|
+
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: [] });
|
|
1665
1763
|
}
|
|
1666
1764
|
for (const view of this.#domainViews.values())
|
|
1667
1765
|
view.setTick(this.#tick);
|
|
@@ -1680,14 +1778,16 @@ class RigFlowComponent {
|
|
|
1680
1778
|
#setView(next) {
|
|
1681
1779
|
this.#view = next;
|
|
1682
1780
|
this.#notice = null;
|
|
1781
|
+
this.#error = "";
|
|
1683
1782
|
this.#feedViews();
|
|
1684
1783
|
this.tui.requestRender();
|
|
1685
1784
|
}
|
|
1686
1785
|
async#navigate(next, push = true) {
|
|
1687
|
-
if (push && this.#view !== "help")
|
|
1786
|
+
if (push && this.#view !== "help" && this.#view !== next)
|
|
1688
1787
|
this.#screenStack.push(this.#view);
|
|
1689
1788
|
this.#view = next;
|
|
1690
1789
|
this.#notice = null;
|
|
1790
|
+
this.#error = "";
|
|
1691
1791
|
const endBusy = this.#beginBusy();
|
|
1692
1792
|
try {
|
|
1693
1793
|
await this.#refreshCurrent();
|
|
@@ -1710,10 +1810,9 @@ class RigFlowComponent {
|
|
|
1710
1810
|
if (this.#view !== "help") {
|
|
1711
1811
|
const loadedState = await this.refreshState(this.#view, this.#selectedTaskId, this.#runs);
|
|
1712
1812
|
this.#state = runLoadError ? { ...loadedState, error: loadedState.error ? `${runLoadError}; ${loadedState.error}` : runLoadError } : loadedState;
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
this.#error = runLoadError;
|
|
1813
|
+
this.#error = this.#state.error ?? "";
|
|
1814
|
+
} else {
|
|
1815
|
+
this.#error = runLoadError ?? "";
|
|
1717
1816
|
}
|
|
1718
1817
|
this.#feedViews();
|
|
1719
1818
|
this.tui.requestRender();
|
|
@@ -1737,45 +1836,105 @@ class RigFlowComponent {
|
|
|
1737
1836
|
endBusy();
|
|
1738
1837
|
}
|
|
1739
1838
|
}
|
|
1740
|
-
#
|
|
1741
|
-
|
|
1742
|
-
|
|
1839
|
+
#tabScreens() {
|
|
1840
|
+
return [
|
|
1841
|
+
{ screen: "cockpit", label: "cockpit" },
|
|
1842
|
+
...cockpitNavScreens(this.catalog).map(({ screen, nav }) => ({ screen, label: nav.label.toLowerCase() }))
|
|
1843
|
+
];
|
|
1844
|
+
}
|
|
1845
|
+
#tabFor(view) {
|
|
1846
|
+
if (view === "run-detail")
|
|
1847
|
+
return "runs";
|
|
1848
|
+
if (view === "task-detail")
|
|
1849
|
+
return "tasks";
|
|
1850
|
+
if (view === "help")
|
|
1851
|
+
return "cockpit";
|
|
1852
|
+
return view;
|
|
1853
|
+
}
|
|
1854
|
+
#headerLine(width) {
|
|
1855
|
+
const screenName = this.#view === "help" ? "help" : screenLabel(this.#view, this.catalog).toLowerCase();
|
|
1856
|
+
const project = (this.#state.projectRoot ?? rigProjectRoot()).split("/").filter(Boolean).pop() ?? "";
|
|
1857
|
+
const live = liveRunCount(this.#runs, this.#state);
|
|
1858
|
+
const attention = attentionRunCount(this.#runs, this.#state);
|
|
1859
|
+
const dotPaint = attention > 0 ? yellow2 : live > 0 ? accent2 : ink42;
|
|
1860
|
+
const rightPlain = `\u25CF ${this.#serverLabel}${project ? ` \xB7 ${project}` : ""}`;
|
|
1861
|
+
const rightPainted = `${dotPaint("\u25CF")} ${cyan2(this.#serverLabel)}${project ? ` ${ink42("\xB7")} ${ink32(project)}` : ""}`;
|
|
1862
|
+
const leftPlain = ` \u258Drig ${screenName}`;
|
|
1863
|
+
const pad = Math.max(1, width - leftPlain.length - rightPlain.length - 1);
|
|
1864
|
+
return ` ${accent2("\u258D")}${bold2(ink5("rig"))} ${ink22(screenName)}${" ".repeat(pad)}${rightPainted}`;
|
|
1865
|
+
}
|
|
1866
|
+
#tabsLine(width) {
|
|
1867
|
+
const tabs = this.#tabScreens();
|
|
1868
|
+
const active = this.#tabFor(this.#view);
|
|
1869
|
+
this.#frame.tabs = [];
|
|
1870
|
+
let out = " ";
|
|
1871
|
+
let plainLength = 1;
|
|
1872
|
+
for (let index = 0;index < tabs.length; index += 1) {
|
|
1873
|
+
const tab = tabs[index];
|
|
1874
|
+
const text = ` ${index + 1} ${tab.label} `;
|
|
1875
|
+
this.#frame.tabs.push({ screen: tab.screen, start: plainLength, end: plainLength + text.length - 1 });
|
|
1876
|
+
out += tab.screen === active ? bgPanel2(`${accent2(` ${index + 1}`)} ${bold2(ink5(`${tab.label} `))}`) : `${ink42(` ${index + 1}`)} ${ink32(`${tab.label} `)}`;
|
|
1877
|
+
plainLength += text.length;
|
|
1878
|
+
out += " ";
|
|
1879
|
+
plainLength += 1;
|
|
1880
|
+
}
|
|
1881
|
+
const helpPlain = "? help";
|
|
1882
|
+
const pad = Math.max(1, width - plainLength - helpPlain.length - 1);
|
|
1883
|
+
return `${out}${" ".repeat(pad)}${accent2("?")}${ink32(" help")}`;
|
|
1743
1884
|
}
|
|
1744
1885
|
#noticeText() {
|
|
1745
1886
|
if (!this.#notice)
|
|
1746
1887
|
return null;
|
|
1747
|
-
const prefix = this.#busyDepth > 0 ? `${
|
|
1888
|
+
const prefix = this.#busyDepth > 0 ? `${RIG_SPINNER_FRAMES[this.#tick % RIG_SPINNER_FRAMES.length]} ` : "";
|
|
1748
1889
|
return `${prefix}${this.#notice}`;
|
|
1749
1890
|
}
|
|
1750
|
-
#footerLines() {
|
|
1891
|
+
#footerLines(width) {
|
|
1751
1892
|
if (this.#inputLine) {
|
|
1752
1893
|
const line = this.#inputLine;
|
|
1753
1894
|
const label = line.kind === "search" ? `${accent2("/")}${ink5(line.buffer)}` : `${accentDim2("steer")} ${ink32(`(${line.run.runId.slice(0, 8)})`)} ${accent2("\u276F")} ${ink5(line.buffer)}`;
|
|
1754
1895
|
return [
|
|
1755
1896
|
` ${label}${accent2("\u2588")}`,
|
|
1756
|
-
|
|
1897
|
+
keyHints(line.kind === "search" ? [["enter", "keep filter"], ["esc", "clear"]] : [["enter", "send"], ["esc", "cancel"]])
|
|
1898
|
+
];
|
|
1899
|
+
}
|
|
1900
|
+
if (this.#error) {
|
|
1901
|
+
const message = this.#error.length > width - 6 ? `${this.#error.slice(0, Math.max(8, width - 7))}\u2026` : this.#error;
|
|
1902
|
+
return [
|
|
1903
|
+
` ${red2("\u2717")} ${red2(message)}`,
|
|
1904
|
+
keyHints([["esc", "dismiss"], ["r", "retry"], ["q", "quit"]])
|
|
1905
|
+
];
|
|
1906
|
+
}
|
|
1907
|
+
const notice = this.#noticeText();
|
|
1908
|
+
if (this.#view === "help") {
|
|
1909
|
+
return [
|
|
1910
|
+
` ${notice ? accentDim2(notice) : ink42("every key on every screen")}`,
|
|
1911
|
+
keyHints([["\u2191\u2193", "scroll"], ["\u2190", "back"], ["esc", "cockpit"], ["q", "quit"]])
|
|
1757
1912
|
];
|
|
1758
1913
|
}
|
|
1759
|
-
if (this.#error)
|
|
1760
|
-
return [` ${red2(`error: ${this.#error}`)}`, ` ${accent2("esc")}${ink32(" cockpit")} ${accent2("q")}${ink32(" quit")}`];
|
|
1761
|
-
if (this.#view === "help")
|
|
1762
|
-
return [` ${accent2("\u2190")}${ink32(" back")} ${accent2("esc")}${ink32(" cockpit")} ${accent2("q")}${ink32(" quit")}`];
|
|
1763
1914
|
const domainFooter = this.#domainViews.get(this.#view)?.footer;
|
|
1764
1915
|
if (domainFooter)
|
|
1765
|
-
return domainFooter(
|
|
1916
|
+
return domainFooter(notice);
|
|
1766
1917
|
if (this.#view === "task-detail" || this.#view === "run-detail") {
|
|
1767
1918
|
const isTask = this.#view === "task-detail";
|
|
1768
|
-
const
|
|
1769
|
-
const hint = notice2 ? accentDim2(notice2) : ink42(isTask ? "review the task, then dispatch" : "live run controls");
|
|
1919
|
+
const hint = notice ? accentDim2(notice) : ink42(isTask ? "read it, then send a drone at it" : "live run controls \u2014 resolve gates in place");
|
|
1770
1920
|
return [
|
|
1771
1921
|
` ${hint}`,
|
|
1772
|
-
|
|
1922
|
+
keyHints([["\u2191\u2193", "action"], ["enter", isTask ? "dispatch" : "run"], ["\u21DE\u21DF", "scroll"], ["\u2190", "back"], ["q", "quit"]])
|
|
1773
1923
|
];
|
|
1774
1924
|
}
|
|
1775
|
-
|
|
1925
|
+
if (this.#view === "cockpit") {
|
|
1926
|
+
const live = liveRunCount(this.#runs, this.#state);
|
|
1927
|
+
const attention = attentionRunCount(this.#runs, this.#state);
|
|
1928
|
+
const fleet = this.#runs.length === 0 ? "fleet idle \u2014 dispatch something" : `${live} live \xB7 ${attention} waiting on you \xB7 ${this.#runs.length} total`;
|
|
1929
|
+
return [
|
|
1930
|
+
` ${notice ? accentDim2(notice) : ink42(fleet)}`,
|
|
1931
|
+
keyHints([["\u2191\u2193", "move"], ["enter", "open"], ["1-9", "jump"], ["?", "help"], ["q", "quit"]])
|
|
1932
|
+
];
|
|
1933
|
+
}
|
|
1934
|
+
const purpose = this.catalog.find((entry) => entry.id === this.#view)?.nav?.description ?? "";
|
|
1776
1935
|
return [
|
|
1777
|
-
` ${notice ? accentDim2(notice) : ink42(
|
|
1778
|
-
|
|
1936
|
+
` ${notice ? accentDim2(notice) : ink42(purpose || screenLabel(this.#view, this.catalog))}`,
|
|
1937
|
+
keyHints([["\u2191\u2193", "move"], ["enter", "act"], ["r", "reload"], ["\u2190", "back"], ["esc", "cockpit"], ["q", "quit"]])
|
|
1779
1938
|
];
|
|
1780
1939
|
}
|
|
1781
1940
|
async#attach(runId) {
|
|
@@ -1786,21 +1945,6 @@ class RigFlowComponent {
|
|
|
1786
1945
|
if (!this.#error)
|
|
1787
1946
|
this.done();
|
|
1788
1947
|
}
|
|
1789
|
-
async#stop(run) {
|
|
1790
|
-
this.#notice = `stop requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
1791
|
-
this.tui.requestRender();
|
|
1792
|
-
await this.#runAction(() => this.actions.act(`run-stop:${encodeURIComponent(run.runId)}`));
|
|
1793
|
-
}
|
|
1794
|
-
async#pause(run) {
|
|
1795
|
-
this.#notice = `pause requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
1796
|
-
this.tui.requestRender();
|
|
1797
|
-
await this.#runAction(() => this.actions.act(`run-pause:${encodeURIComponent(run.runId)}`));
|
|
1798
|
-
}
|
|
1799
|
-
async#resume(run) {
|
|
1800
|
-
this.#notice = `resume requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
1801
|
-
this.tui.requestRender();
|
|
1802
|
-
await this.#runAction(() => this.actions.act(`run-resume:${encodeURIComponent(run.runId)}`));
|
|
1803
|
-
}
|
|
1804
1948
|
async#steer(run, message) {
|
|
1805
1949
|
await this.#runAction(() => this.actions.act(`run-steer:${encodeURIComponent(run.runId)}`, message));
|
|
1806
1950
|
}
|
|
@@ -1834,6 +1978,10 @@ class RigFlowComponent {
|
|
|
1834
1978
|
}
|
|
1835
1979
|
return;
|
|
1836
1980
|
}
|
|
1981
|
+
if (item.id.endsWith(":retry")) {
|
|
1982
|
+
await this.#runAction(async () => {});
|
|
1983
|
+
return;
|
|
1984
|
+
}
|
|
1837
1985
|
if (item.id === "config:relayUrl" || item.id.startsWith("stats:") || item.id.startsWith("inspect:audit")) {
|
|
1838
1986
|
this.#notice = "informational row; no cockpit action";
|
|
1839
1987
|
this.tui.requestRender();
|
|
@@ -1849,12 +1997,15 @@ class RigFlowComponent {
|
|
|
1849
1997
|
await this.#runAction((onProgress) => this.actions.act(item.id, undefined, onProgress));
|
|
1850
1998
|
}
|
|
1851
1999
|
render(width) {
|
|
1852
|
-
const lines = [this.#headerLine(), hairline(width)];
|
|
2000
|
+
const lines = [this.#headerLine(width), this.#tabsLine(width), hairline(width)];
|
|
2001
|
+
this.#frame.tabsLine = 1;
|
|
1853
2002
|
const view = this.#view === "help" ? this.#helpView : this.#activeView();
|
|
2003
|
+
this.#frame.viewStart = lines.length;
|
|
1854
2004
|
for (const line of view.render(width))
|
|
1855
2005
|
lines.push(line);
|
|
2006
|
+
this.#frame.viewEnd = lines.length - 1;
|
|
1856
2007
|
lines.push(hairline(width));
|
|
1857
|
-
for (const line of this.#footerLines())
|
|
2008
|
+
for (const line of this.#footerLines(width))
|
|
1858
2009
|
lines.push(line);
|
|
1859
2010
|
return lines;
|
|
1860
2011
|
}
|
|
@@ -1864,7 +2015,95 @@ class RigFlowComponent {
|
|
|
1864
2015
|
this.#helpView.invalidate();
|
|
1865
2016
|
this.#genericView.invalidate();
|
|
1866
2017
|
}
|
|
2018
|
+
#activateDetailAction() {
|
|
2019
|
+
const action = this.#detailComposer.selectedAction();
|
|
2020
|
+
if (!action)
|
|
2021
|
+
return;
|
|
2022
|
+
if (action.id.startsWith("run-steer:")) {
|
|
2023
|
+
const run = findRunById(this.#runs, this.#selectedRunId);
|
|
2024
|
+
if (run) {
|
|
2025
|
+
this.#inputLine = { kind: "steer", buffer: "", run: { runId: run.runId } };
|
|
2026
|
+
this.tui.requestRender();
|
|
2027
|
+
}
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
if (action.id.startsWith("task-detail:dispatch:")) {
|
|
2031
|
+
this.#notice = "dispatch \xB7 starting\u2026";
|
|
2032
|
+
this.tui.requestRender();
|
|
2033
|
+
}
|
|
2034
|
+
if (action.id.startsWith("run-stop:")) {
|
|
2035
|
+
this.#notice = "stop requested\u2026";
|
|
2036
|
+
this.tui.requestRender();
|
|
2037
|
+
}
|
|
2038
|
+
this.#actOnItem({ id: action.id, label: action.label, values: [action.value ?? "go"] });
|
|
2039
|
+
}
|
|
2040
|
+
#handleMouse(event) {
|
|
2041
|
+
if (this.#inputLine)
|
|
2042
|
+
return;
|
|
2043
|
+
const { tabsLine, viewStart, viewEnd, tabs } = this.#frame;
|
|
2044
|
+
if (event.wheel !== null) {
|
|
2045
|
+
if (this.#view === "help")
|
|
2046
|
+
this.#helpView.scroll(event.wheel * 3);
|
|
2047
|
+
else if (this.#view === "task-detail" || this.#view === "run-detail")
|
|
2048
|
+
this.#detailComposer.scrollBody(event.wheel * 2);
|
|
2049
|
+
else {
|
|
2050
|
+
const domainView2 = this.#domainViews.get(this.#view);
|
|
2051
|
+
if (domainView2) {
|
|
2052
|
+
if (!domainView2.handleMouse?.(event, Math.max(0, event.row - viewStart)))
|
|
2053
|
+
return;
|
|
2054
|
+
} else {
|
|
2055
|
+
this.#genericView.moveSelection(event.wheel);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
this.tui.requestRender();
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
2061
|
+
if (!event.leftClick)
|
|
2062
|
+
return;
|
|
2063
|
+
if (event.row === tabsLine) {
|
|
2064
|
+
const hit = tabs.find((tab) => event.col >= tab.start && event.col <= tab.end);
|
|
2065
|
+
if (hit && hit.screen !== this.#view)
|
|
2066
|
+
this.#navigate(hit.screen);
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
if (event.row < viewStart || event.row > viewEnd)
|
|
2070
|
+
return;
|
|
2071
|
+
const line = event.row - viewStart;
|
|
2072
|
+
if (this.#view === "help")
|
|
2073
|
+
return;
|
|
2074
|
+
if (this.#view === "task-detail" || this.#view === "run-detail") {
|
|
2075
|
+
const index2 = this.#detailComposer.hitTestAction(line);
|
|
2076
|
+
if (index2 === undefined)
|
|
2077
|
+
return;
|
|
2078
|
+
const moved2 = this.#detailComposer.selectAction(index2);
|
|
2079
|
+
this.tui.requestRender();
|
|
2080
|
+
if (!moved2)
|
|
2081
|
+
this.#activateDetailAction();
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
const domainView = this.#domainViews.get(this.#view);
|
|
2085
|
+
if (domainView) {
|
|
2086
|
+
domainView.handleMouse?.(event, line);
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
const index = this.#genericView.hitTest(line);
|
|
2090
|
+
if (index === undefined)
|
|
2091
|
+
return;
|
|
2092
|
+
const moved = this.#genericView.selectIndex(index);
|
|
2093
|
+
this.tui.requestRender();
|
|
2094
|
+
if (!moved) {
|
|
2095
|
+
const item = this.#genericView.selectedItem();
|
|
2096
|
+
if (item)
|
|
2097
|
+
this.#actOnItem(item);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
1867
2100
|
handleInput(data) {
|
|
2101
|
+
if (data.startsWith("\x1B[<")) {
|
|
2102
|
+
const event = parseSgrMouse(data);
|
|
2103
|
+
if (event)
|
|
2104
|
+
this.#handleMouse(event);
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
1868
2107
|
if (data === "q") {
|
|
1869
2108
|
this.onQuit();
|
|
1870
2109
|
return;
|
|
@@ -1899,6 +2138,19 @@ class RigFlowComponent {
|
|
|
1899
2138
|
this.done();
|
|
1900
2139
|
return;
|
|
1901
2140
|
}
|
|
2141
|
+
if (this.#error && matchesKey(data, "escape")) {
|
|
2142
|
+
this.#error = "";
|
|
2143
|
+
this.tui.requestRender();
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
if (/^[1-9]$/.test(data)) {
|
|
2147
|
+
const target = this.#tabScreens()[Number(data) - 1];
|
|
2148
|
+
if (target) {
|
|
2149
|
+
if (target.screen !== this.#view)
|
|
2150
|
+
this.#navigate(target.screen);
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
1902
2154
|
if (this.#view === "help") {
|
|
1903
2155
|
if (matchesKey(data, "up") || data === "k")
|
|
1904
2156
|
this.#helpView.scroll(-1);
|
|
@@ -1927,26 +2179,7 @@ class RigFlowComponent {
|
|
|
1927
2179
|
return;
|
|
1928
2180
|
}
|
|
1929
2181
|
if (matchesKey(data, "enter") || matchesKey(data, "return")) {
|
|
1930
|
-
|
|
1931
|
-
if (action) {
|
|
1932
|
-
if (action.id.startsWith("run-steer:")) {
|
|
1933
|
-
const run = findRunById(this.#runs, this.#selectedRunId);
|
|
1934
|
-
if (run) {
|
|
1935
|
-
this.#inputLine = { kind: "steer", buffer: "", run: { runId: run.runId } };
|
|
1936
|
-
this.tui.requestRender();
|
|
1937
|
-
}
|
|
1938
|
-
return;
|
|
1939
|
-
}
|
|
1940
|
-
if (action.id.startsWith("task-detail:dispatch:")) {
|
|
1941
|
-
this.#notice = "dispatch \xB7 starting\u2026";
|
|
1942
|
-
this.tui.requestRender();
|
|
1943
|
-
}
|
|
1944
|
-
if (action.id.startsWith("run-stop:")) {
|
|
1945
|
-
this.#notice = "stop requested\u2026";
|
|
1946
|
-
this.tui.requestRender();
|
|
1947
|
-
}
|
|
1948
|
-
this.#actOnItem({ id: action.id, label: action.label, values: [action.value ?? "go"] });
|
|
1949
|
-
}
|
|
2182
|
+
this.#activateDetailAction();
|
|
1950
2183
|
return;
|
|
1951
2184
|
}
|
|
1952
2185
|
if (matchesKey(data, "pageUp")) {
|