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