@h-rig/cli 0.0.6-alpha.82 → 0.0.6-alpha.84
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/bin/build-rig-binaries.js +40 -8
- package/dist/bin/rig.js +23402 -14577
- package/dist/src/app/board.js +217 -41
- package/dist/src/app-opentui/adapters/command.d.ts +2 -0
- package/dist/src/app-opentui/adapters/command.js +329 -0
- package/dist/src/app-opentui/adapters/common.js +2 -2
- package/dist/src/app-opentui/adapters/doctor.d.ts +0 -2
- package/dist/src/app-opentui/adapters/doctor.js +64 -39
- package/dist/src/app-opentui/adapters/family.d.ts +62 -0
- package/dist/src/app-opentui/adapters/family.js +14305 -0
- package/dist/src/app-opentui/adapters/fleet.d.ts +0 -2
- package/dist/src/app-opentui/adapters/fleet.js +90 -60
- package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
- package/dist/src/app-opentui/adapters/inbox.js +137 -78
- package/dist/src/app-opentui/adapters/init.d.ts +0 -2
- package/dist/src/app-opentui/adapters/init.js +85 -47
- package/dist/src/app-opentui/adapters/inspect.d.ts +52 -0
- package/dist/src/app-opentui/adapters/inspect.js +1024 -0
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +15 -6
- package/dist/src/app-opentui/adapters/pi-attach.js +442 -125
- package/dist/src/app-opentui/adapters/pi.d.ts +23 -0
- package/dist/src/app-opentui/adapters/pi.js +363 -0
- package/dist/src/app-opentui/adapters/plugin.d.ts +84 -0
- package/dist/src/app-opentui/adapters/plugin.js +544 -0
- package/dist/src/app-opentui/adapters/repo.d.ts +37 -0
- package/dist/src/app-opentui/adapters/repo.js +186 -0
- package/dist/src/app-opentui/adapters/run-detail.d.ts +9 -2
- package/dist/src/app-opentui/adapters/run-detail.js +180 -63
- package/dist/src/app-opentui/adapters/server.d.ts +10 -2
- package/dist/src/app-opentui/adapters/server.js +191 -45
- package/dist/src/app-opentui/adapters/tasks.d.ts +11 -2
- package/dist/src/app-opentui/adapters/tasks.js +1123 -143
- package/dist/src/app-opentui/adapters/workspace.d.ts +49 -0
- package/dist/src/app-opentui/adapters/workspace.js +333 -0
- package/dist/src/app-opentui/autocomplete.d.ts +20 -0
- package/dist/src/app-opentui/autocomplete.js +576 -0
- package/dist/src/app-opentui/bootstrap.d.ts +1 -6
- package/dist/src/app-opentui/bootstrap.js +25252 -16474
- package/dist/src/app-opentui/command-palette.d.ts +3 -0
- package/dist/src/app-opentui/command-palette.js +1010 -0
- package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
- package/dist/src/app-opentui/command-pty-host.js +248 -0
- package/dist/src/app-opentui/drone.js +8 -6
- package/dist/src/app-opentui/events.js +1 -1
- package/dist/src/app-opentui/fleet-stats.d.ts +32 -0
- package/dist/src/app-opentui/fleet-stats.js +114 -0
- package/dist/src/app-opentui/focus-manager.d.ts +14 -0
- package/dist/src/app-opentui/focus-manager.js +24 -0
- package/dist/src/app-opentui/index.js +5431 -2797
- package/dist/src/app-opentui/intent.js +179 -50
- package/dist/src/app-opentui/keymap.d.ts +21 -0
- package/dist/src/app-opentui/keymap.js +1748 -0
- package/dist/src/app-opentui/launch-routing.d.ts +16 -0
- package/dist/src/app-opentui/launch-routing.js +55 -0
- package/dist/src/app-opentui/layout.d.ts +7 -0
- package/dist/src/app-opentui/layout.js +13 -6
- package/dist/src/app-opentui/list-search.d.ts +24 -0
- package/dist/src/app-opentui/list-search.js +88 -1
- package/dist/src/app-opentui/pi-host-child.js +99 -17
- package/dist/src/app-opentui/pi-pty-host.d.ts +14 -0
- package/dist/src/app-opentui/pi-pty-host.js +30 -14
- package/dist/src/app-opentui/react/App.d.ts +9 -0
- package/dist/src/app-opentui/react/App.js +5144 -0
- package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
- package/dist/src/app-opentui/react/Backdrop.js +1834 -0
- package/dist/src/app-opentui/react/ChromeHost.d.ts +5 -0
- package/dist/src/app-opentui/react/ChromeHost.js +2942 -0
- package/dist/src/app-opentui/react/SceneFrameView.d.ts +7 -0
- package/dist/src/app-opentui/react/SceneFrameView.js +529 -0
- package/dist/src/app-opentui/react/context.d.ts +17 -0
- package/dist/src/app-opentui/react/context.js +37 -0
- package/dist/src/app-opentui/react/launch.d.ts +2 -0
- package/dist/src/app-opentui/react/launch.js +5743 -0
- package/dist/src/app-opentui/react/nav.d.ts +18 -0
- package/dist/src/app-opentui/react/nav.js +54 -0
- package/dist/src/app-opentui/react/scroll.d.ts +12 -0
- package/dist/src/app-opentui/react/scroll.js +21 -0
- package/dist/src/app-opentui/react/syntax.d.ts +2 -0
- package/dist/src/app-opentui/react/syntax.js +64 -0
- package/dist/src/app-opentui/registry.js +20428 -4828
- package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
- package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
- package/dist/src/app-opentui/render/constants.d.ts +31 -0
- package/dist/src/app-opentui/render/constants.js +66 -0
- package/dist/src/app-opentui/render/graphics.d.ts +2 -1
- package/dist/src/app-opentui/render/graphics.js +228 -46
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +469 -930
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +25 -10
- package/dist/src/app-opentui/render/image-visual-layer.js +448 -329
- package/dist/src/app-opentui/render/native-host.d.ts +37 -0
- package/dist/src/app-opentui/render/native-host.js +179 -0
- package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
- package/dist/src/app-opentui/render/panel-layout.js +48 -0
- package/dist/src/app-opentui/render/panels.d.ts +2 -0
- package/dist/src/app-opentui/render/panels.js +78 -38
- package/dist/src/app-opentui/render/preloader.d.ts +10 -0
- package/dist/src/app-opentui/render/preloader.js +165 -0
- package/dist/src/app-opentui/render/scene.d.ts +53 -1
- package/dist/src/app-opentui/render/scene.js +195 -6
- package/dist/src/app-opentui/render/text.d.ts +7 -1
- package/dist/src/app-opentui/render/text.js +15 -8
- package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
- package/dist/src/app-opentui/render/type-bar.js +113 -39
- package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
- package/dist/src/app-opentui/runtime-resources.js +62 -0
- package/dist/src/app-opentui/runtime.d.ts +44 -1
- package/dist/src/app-opentui/runtime.js +5415 -2738
- package/dist/src/app-opentui/scenes/command.d.ts +3 -0
- package/dist/src/app-opentui/scenes/command.js +117 -0
- package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
- package/dist/src/app-opentui/scenes/doctor.js +221 -17
- package/dist/src/app-opentui/scenes/error.js +60 -20
- package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/agent.js +348 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.js +195 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.js +243 -0
- package/dist/src/app-opentui/scenes/family-domains/git.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/git.js +195 -0
- package/dist/src/app-opentui/scenes/family-domains/github.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/github.js +274 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.js +152 -0
- package/dist/src/app-opentui/scenes/family-domains/index.d.ts +4 -0
- package/dist/src/app-opentui/scenes/family-domains/index.js +1679 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +76 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.js +305 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.js +212 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.js +146 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.js +518 -0
- package/dist/src/app-opentui/scenes/family-domains/review.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/review.js +280 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.js +267 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.js +370 -0
- package/dist/src/app-opentui/scenes/family.d.ts +3 -0
- package/dist/src/app-opentui/scenes/family.js +2144 -0
- package/dist/src/app-opentui/scenes/fleet.js +552 -43
- package/dist/src/app-opentui/scenes/handoff.js +342 -35
- package/dist/src/app-opentui/scenes/help.js +640 -56
- package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
- package/dist/src/app-opentui/scenes/inbox.js +329 -21
- package/dist/src/app-opentui/scenes/init.d.ts +2 -1
- package/dist/src/app-opentui/scenes/init.js +120 -34
- package/dist/src/app-opentui/scenes/inspect.d.ts +3 -0
- package/dist/src/app-opentui/scenes/inspect.js +793 -0
- package/dist/src/app-opentui/scenes/main.d.ts +2 -1
- package/dist/src/app-opentui/scenes/main.js +264 -29
- package/dist/src/app-opentui/scenes/pi.d.ts +3 -0
- package/dist/src/app-opentui/scenes/pi.js +508 -0
- package/dist/src/app-opentui/scenes/plugin.d.ts +3 -0
- package/dist/src/app-opentui/scenes/plugin.js +486 -0
- package/dist/src/app-opentui/scenes/repo.d.ts +3 -0
- package/dist/src/app-opentui/scenes/repo.js +424 -0
- package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
- package/dist/src/app-opentui/scenes/run-detail.js +362 -35
- package/dist/src/app-opentui/scenes/server.d.ts +2 -1
- package/dist/src/app-opentui/scenes/server.js +243 -26
- package/dist/src/app-opentui/scenes/tasks.js +518 -41
- package/dist/src/app-opentui/scenes/workspace.d.ts +3 -0
- package/dist/src/app-opentui/scenes/workspace.js +426 -0
- package/dist/src/app-opentui/selectable.d.ts +19 -0
- package/dist/src/app-opentui/selectable.js +79 -0
- package/dist/src/app-opentui/state.js +129 -36
- package/dist/src/app-opentui/surface-catalog.d.ts +20 -0
- package/dist/src/app-opentui/surface-catalog.js +540 -0
- package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
- package/dist/src/app-opentui/terminal-capabilities.js +15 -0
- package/dist/src/app-opentui/theme.d.ts +28 -6
- package/dist/src/app-opentui/theme.js +61 -8
- package/dist/src/app-opentui/types.d.ts +130 -5
- package/dist/src/commands/_authority-runs.d.ts +1 -1
- package/dist/src/commands/_authority-runs.js +2 -12
- package/dist/src/commands/_doctor-checks.js +62 -13
- package/dist/src/commands/_help-catalog.js +95 -15
- package/dist/src/commands/_operator-view.js +97 -15
- package/dist/src/commands/_pi-frontend.d.ts +2 -0
- package/dist/src/commands/_pi-frontend.js +97 -13
- package/dist/src/commands/_preflight.js +64 -14
- package/dist/src/commands/_server-client.js +82 -18
- package/dist/src/commands/_server-events.d.ts +26 -0
- package/dist/src/commands/_server-events.js +310 -0
- package/dist/src/commands/_snapshot-upload.js +62 -13
- package/dist/src/commands/agent.js +2 -12
- package/dist/src/commands/connect.js +7 -1
- package/dist/src/commands/doctor.js +62 -13
- package/dist/src/commands/github.js +144 -23
- package/dist/src/commands/inbox.js +62 -13
- package/dist/src/commands/init.js +82 -18
- package/dist/src/commands/inspect.js +62 -13
- package/dist/src/commands/run.js +100 -15
- package/dist/src/commands/server.js +71 -26
- package/dist/src/commands/setup.js +62 -13
- package/dist/src/commands/stats.js +157 -28
- package/dist/src/commands/task-run-driver.js +64 -25
- package/dist/src/commands/task.js +196 -43
- package/dist/src/commands.js +419 -123
- package/dist/src/index.js +426 -130
- package/package.json +11 -10
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
|
@@ -11,15 +11,17 @@ var RIG_UI = {
|
|
|
11
11
|
bg: "#070809",
|
|
12
12
|
bg2: "#0b0c0e",
|
|
13
13
|
panel: "#101115",
|
|
14
|
-
panel2: "#
|
|
15
|
-
glass: "#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
panel2: "#14161b",
|
|
15
|
+
glass: "#1e2230",
|
|
16
|
+
border: "#2a2e3a",
|
|
17
|
+
ink: "#f4f5f8",
|
|
18
|
+
ink2: "#c7c9d3",
|
|
19
|
+
ink3: "#9aa0ae",
|
|
20
|
+
ink4: "#787b86",
|
|
20
21
|
lime: "#ccff4d",
|
|
21
22
|
limeDim: "#a9d63f",
|
|
22
23
|
cyan: "#56d8ff",
|
|
24
|
+
cyanDim: "#3f9fbd",
|
|
23
25
|
red: "#ff5d5d",
|
|
24
26
|
yellow: "#ffd24d",
|
|
25
27
|
magenta: "#ff79b0"
|
|
@@ -38,11 +40,11 @@ var styles = {
|
|
|
38
40
|
};
|
|
39
41
|
function statusColor(status) {
|
|
40
42
|
switch (status) {
|
|
41
|
-
case "running":
|
|
42
43
|
case "success":
|
|
43
44
|
case "completed":
|
|
44
45
|
case "merged":
|
|
45
46
|
return RIG_UI.lime;
|
|
47
|
+
case "running":
|
|
46
48
|
case "preparing":
|
|
47
49
|
case "created":
|
|
48
50
|
case "validating":
|
|
@@ -62,15 +64,225 @@ function statusColor(status) {
|
|
|
62
64
|
return RIG_UI.ink3;
|
|
63
65
|
}
|
|
64
66
|
}
|
|
67
|
+
function statusGlyph(status) {
|
|
68
|
+
switch (status) {
|
|
69
|
+
case "success":
|
|
70
|
+
case "completed":
|
|
71
|
+
case "merged":
|
|
72
|
+
return "\u2713";
|
|
73
|
+
case "running":
|
|
74
|
+
return "\u25CF";
|
|
75
|
+
case "preparing":
|
|
76
|
+
case "created":
|
|
77
|
+
case "validating":
|
|
78
|
+
case "reviewing":
|
|
79
|
+
case "closing-out":
|
|
80
|
+
case "stopping":
|
|
81
|
+
case "loading":
|
|
82
|
+
case "action":
|
|
83
|
+
return "\u25D0";
|
|
84
|
+
case "needs-attention":
|
|
85
|
+
case "needs_attention":
|
|
86
|
+
return "\u26A0";
|
|
87
|
+
case "failed":
|
|
88
|
+
case "error":
|
|
89
|
+
return "\u2717";
|
|
90
|
+
default:
|
|
91
|
+
return "\xB7";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function noColorActive() {
|
|
95
|
+
const noColor = process.env.NO_COLOR;
|
|
96
|
+
if (noColor !== undefined && noColor !== "") {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return process.env.RIG_NO_COLOR !== undefined;
|
|
100
|
+
}
|
|
101
|
+
function statusLabel(status) {
|
|
102
|
+
return {
|
|
103
|
+
glyph: statusGlyph(status),
|
|
104
|
+
color: noColorActive() ? RIG_UI.ink : statusColor(status)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// packages/cli/src/app-opentui/drone.ts
|
|
109
|
+
import { RGBA, StyledText, TextAttributes as TextAttributes2 } from "@opentui/core";
|
|
110
|
+
var MINI_DRONE = [
|
|
111
|
+
"(!!!) (!!!)",
|
|
112
|
+
" \\%==%/ ",
|
|
113
|
+
" %%?%% ",
|
|
114
|
+
" /%==%\\ ",
|
|
115
|
+
"(!!!) (!!!)"
|
|
116
|
+
];
|
|
117
|
+
var LEAD_MARK = [
|
|
118
|
+
" .-=-. ",
|
|
119
|
+
"=%%?%%=",
|
|
120
|
+
" '-=-' "
|
|
121
|
+
];
|
|
122
|
+
var BLADE_FRAMES = ["---", "\\\\\\", "|||", "///"];
|
|
123
|
+
var EYE_FRAMES = ["o", "@", "\u2022", "."];
|
|
124
|
+
var COLOR = {
|
|
125
|
+
body: RGBA.fromHex(RIG_UI.lime),
|
|
126
|
+
mini: RGBA.fromHex(RIG_UI.limeDim),
|
|
127
|
+
rotor: RGBA.fromHex(RIG_UI.cyan),
|
|
128
|
+
path: RGBA.fromHex(RIG_UI.cyan),
|
|
129
|
+
eye: RGBA.fromHex(RIG_UI.ink),
|
|
130
|
+
dim: RGBA.fromHex(RIG_UI.ink4),
|
|
131
|
+
ink: RGBA.fromHex(RIG_UI.ink2)
|
|
132
|
+
};
|
|
133
|
+
function bladeForTick(tick, phase = 0) {
|
|
134
|
+
return BLADE_FRAMES[(Math.floor(tick / 3) + phase) % BLADE_FRAMES.length];
|
|
135
|
+
}
|
|
136
|
+
function eyeForTick(tick, phase = 0) {
|
|
137
|
+
const pulse = Math.sin(tick * 0.09 + phase);
|
|
138
|
+
return pulse > 0.55 ? EYE_FRAMES[1] : pulse > 0.1 ? EYE_FRAMES[0] : pulse > -0.45 ? EYE_FRAMES[2] : EYE_FRAMES[3];
|
|
139
|
+
}
|
|
140
|
+
function chunk(text, fg, bold = false, dim = false) {
|
|
141
|
+
let attributes = TextAttributes2.NONE;
|
|
142
|
+
if (bold)
|
|
143
|
+
attributes |= TextAttributes2.BOLD;
|
|
144
|
+
if (dim)
|
|
145
|
+
attributes |= TextAttributes2.DIM;
|
|
146
|
+
return { __isChunk: true, text, fg, ...attributes !== TextAttributes2.NONE ? { attributes } : {} };
|
|
147
|
+
}
|
|
148
|
+
function styledLine(text, colorFor) {
|
|
149
|
+
const chunks = [];
|
|
150
|
+
let run = "";
|
|
151
|
+
let runColor = null;
|
|
152
|
+
const flush = () => {
|
|
153
|
+
if (!run || !runColor)
|
|
154
|
+
return;
|
|
155
|
+
chunks.push(chunk(run, COLOR[runColor], runColor === "body" || runColor === "eye", runColor === "dim"));
|
|
156
|
+
run = "";
|
|
157
|
+
};
|
|
158
|
+
for (const char of text) {
|
|
159
|
+
const next = colorFor(char);
|
|
160
|
+
if (next !== runColor) {
|
|
161
|
+
flush();
|
|
162
|
+
runColor = next;
|
|
163
|
+
}
|
|
164
|
+
run += char;
|
|
165
|
+
}
|
|
166
|
+
flush();
|
|
167
|
+
return new StyledText(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
|
|
168
|
+
}
|
|
169
|
+
function droneColor(char) {
|
|
170
|
+
if (char === "?" || char === "o" || char === "@" || char === "\u2022")
|
|
171
|
+
return "eye";
|
|
172
|
+
if (char === "%" || char === "=")
|
|
173
|
+
return "mini";
|
|
174
|
+
if (char === "$")
|
|
175
|
+
return "body";
|
|
176
|
+
if (char === "(" || char === ")" || char === "/" || char === "\\" || char === "|" || char === "-")
|
|
177
|
+
return "rotor";
|
|
178
|
+
if (char === "\xB7" || char === "\u2022" || char === "'" || char === ".")
|
|
179
|
+
return "path";
|
|
180
|
+
if (char.trim() === "")
|
|
181
|
+
return "dim";
|
|
182
|
+
return "ink";
|
|
183
|
+
}
|
|
184
|
+
function motionColor(char) {
|
|
185
|
+
if (char === "\u25CF" || char === "\u25C6" || char === "\u25C9")
|
|
186
|
+
return "body";
|
|
187
|
+
if (char === "\u2022" || char === "\xB7" || char === "\u2500" || char === "\u2502" || char === "\u2571" || char === "\u2572" || char === "\u256D" || char === "\u256E" || char === "\u2570" || char === "\u256F")
|
|
188
|
+
return "path";
|
|
189
|
+
if (char === "\u258C" || char === "\u2590" || char === "\u2581" || char === "\u2594")
|
|
190
|
+
return "mini";
|
|
191
|
+
return droneColor(char);
|
|
192
|
+
}
|
|
193
|
+
function materializeDrone(lines, tick, phase = 0) {
|
|
194
|
+
const blade = bladeForTick(tick, phase);
|
|
195
|
+
const eye = eyeForTick(tick, phase);
|
|
196
|
+
return lines.map((line) => line.replaceAll("!!!", blade).replaceAll("?", eye));
|
|
197
|
+
}
|
|
198
|
+
function miniDroneLines(tick, align = "left", phase = 0) {
|
|
199
|
+
return materializeDrone(MINI_DRONE, tick, phase).map((text) => ({
|
|
200
|
+
text,
|
|
201
|
+
styledText: styledLine(text, droneColor),
|
|
202
|
+
fg: RIG_UI.limeDim,
|
|
203
|
+
align
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
function brandFleetLines(tick, align = "center") {
|
|
207
|
+
const left = materializeDrone(MINI_DRONE, tick, 0);
|
|
208
|
+
const right = materializeDrone(MINI_DRONE, tick, 2);
|
|
209
|
+
const lead = materializeDrone(LEAD_MARK, tick, 1);
|
|
210
|
+
const packet = ["\xB7", "\u2022", "\u25CF", "\u2022"][Math.floor(tick / 2) % 4];
|
|
211
|
+
const bridge = [
|
|
212
|
+
` ${left[0]} ${lead[0]} ${right[0]}`,
|
|
213
|
+
` ${left[1]} \xB7\u2500\u2500${packet}\u2500\u2500\xB7 ${lead[1]} \xB7\u2500\u2500${packet}\u2500\u2500\xB7 ${right[1]}`,
|
|
214
|
+
` ${left[2]} \xB7' '${lead[2]}' '\xB7 ${right[2]}`,
|
|
215
|
+
` ${left[3]} \u2572 signal bus \u2571 ${right[3]}`,
|
|
216
|
+
` ${left[4]} \xB7\u2500\u2500\u2500${packet}\u2500\u2500\u2500\u2500\u2500\u2500${packet}\u2500\u2500\u2500\xB7 ${right[4]}`
|
|
217
|
+
];
|
|
218
|
+
return bridge.map((text) => ({
|
|
219
|
+
text,
|
|
220
|
+
styledText: styledLine(text, motionColor),
|
|
221
|
+
fg: RIG_UI.limeDim,
|
|
222
|
+
align
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
function actionDrone(tick, phase = 0) {
|
|
226
|
+
const blade = bladeForTick(tick, phase);
|
|
227
|
+
const eye = eyeForTick(tick, phase);
|
|
228
|
+
return `(${blade})\u2572${eye}\u2571(${blade})`;
|
|
229
|
+
}
|
|
230
|
+
function actionDroneLine(tick, text, fg = RIG_UI.ink2) {
|
|
231
|
+
const prefix = actionDrone(tick);
|
|
232
|
+
const content = `${prefix} ${text}`;
|
|
233
|
+
return { text: content, styledText: styledLine(content, motionColor), fg, align: "center" };
|
|
234
|
+
}
|
|
65
235
|
|
|
66
236
|
// packages/cli/src/app-opentui/render/scene.ts
|
|
67
237
|
function line(text, options = {}) {
|
|
68
238
|
return { text, ...options };
|
|
69
239
|
}
|
|
240
|
+
function blank() {
|
|
241
|
+
return { text: "" };
|
|
242
|
+
}
|
|
243
|
+
function deckRow(input) {
|
|
244
|
+
const prefix = input.active ? "\u25B8" : " ";
|
|
245
|
+
const label = input.label.toUpperCase().padEnd(10);
|
|
246
|
+
return line(`${prefix} ${label} ${input.detail}`, {
|
|
247
|
+
fg: input.active ? RIG_UI.lime : RIG_UI.ink2,
|
|
248
|
+
bold: input.active,
|
|
249
|
+
selectableIndex: input.index,
|
|
250
|
+
activateOnClick: input.activateOnClick
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
function loadingRows(label, tick = 0, compact = false) {
|
|
254
|
+
const mascot = compact ? miniDroneLines(tick, "center") : brandFleetLines(tick, "center");
|
|
255
|
+
return [
|
|
256
|
+
blank(),
|
|
257
|
+
...mascot,
|
|
258
|
+
blank(),
|
|
259
|
+
{ ...actionDroneLine(tick, `loading ${label}\u2026`, RIG_UI.cyan), align: "center" }
|
|
260
|
+
];
|
|
261
|
+
}
|
|
262
|
+
function errorBanner(message, hint) {
|
|
263
|
+
return [
|
|
264
|
+
line(`\u2717 failed to load \u2014 ${message}`, { fg: RIG_UI.red, bold: true }),
|
|
265
|
+
...hint ? [line(` ${hint}`, { fg: RIG_UI.ink3 })] : [],
|
|
266
|
+
line(" select refresh/retry below", { fg: RIG_UI.ink4 }),
|
|
267
|
+
line("", { fg: RIG_UI.ink3 })
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
function lastRefreshError(state) {
|
|
271
|
+
const value = state.data.lastRefreshError;
|
|
272
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
273
|
+
}
|
|
70
274
|
function makeSceneFrame(input) {
|
|
71
275
|
return input;
|
|
72
276
|
}
|
|
73
277
|
|
|
278
|
+
// packages/cli/src/app-opentui/selectable.ts
|
|
279
|
+
function selectableDeckRow(deck, item) {
|
|
280
|
+
return { ...deckRow({ ...deck, activateOnClick: true }), selectable: item };
|
|
281
|
+
}
|
|
282
|
+
function withSelectable(line2, item) {
|
|
283
|
+
return { ...line2, selectable: item, activateOnClick: true };
|
|
284
|
+
}
|
|
285
|
+
|
|
74
286
|
// packages/cli/src/app-opentui/list-search.ts
|
|
75
287
|
function isListSearchScene(scene) {
|
|
76
288
|
return scene === "fleet" || scene === "tasks";
|
|
@@ -103,8 +315,86 @@ function filterTasksForSearch(tasks, query) {
|
|
|
103
315
|
function searchSummary(kind, query, visible, total) {
|
|
104
316
|
return query.trim() ? `search ${JSON.stringify(query)} \xB7 ${visible}/${total} ${kind}` : `${total} ${kind}`;
|
|
105
317
|
}
|
|
318
|
+
function taskSortSpec(value) {
|
|
319
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
320
|
+
return null;
|
|
321
|
+
const record = value;
|
|
322
|
+
const key = record.key;
|
|
323
|
+
const dir = record.dir;
|
|
324
|
+
if ((key === "status" || key === "id" || key === "priority" || key === "assignee" || key === "title") && (dir === "asc" || dir === "desc")) {
|
|
325
|
+
return { key, dir };
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
function cycleTaskSort(current, key) {
|
|
330
|
+
if (!current || current.key !== key)
|
|
331
|
+
return { key, dir: "asc" };
|
|
332
|
+
if (current.dir === "asc")
|
|
333
|
+
return { key, dir: "desc" };
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
function applyDir(rows, compare, dir) {
|
|
337
|
+
const sorted = [...rows].sort(compare);
|
|
338
|
+
return dir === "desc" ? sorted.reverse() : sorted;
|
|
339
|
+
}
|
|
340
|
+
function sortTasks(tasks, spec) {
|
|
341
|
+
if (!spec)
|
|
342
|
+
return [...tasks];
|
|
343
|
+
const { key, dir } = spec;
|
|
344
|
+
const compare = (a, b) => {
|
|
345
|
+
if (key === "status")
|
|
346
|
+
return a.status.localeCompare(b.status) || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
347
|
+
if (key === "priority") {
|
|
348
|
+
const left = a.priority ?? Number.NEGATIVE_INFINITY;
|
|
349
|
+
const right = b.priority ?? Number.NEGATIVE_INFINITY;
|
|
350
|
+
return right - left || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
351
|
+
}
|
|
352
|
+
if (key === "assignee")
|
|
353
|
+
return (a.assignees[0] ?? "").localeCompare(b.assignees[0] ?? "") || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
354
|
+
if (key === "title")
|
|
355
|
+
return a.title.localeCompare(b.title, undefined, { sensitivity: "base" }) || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
356
|
+
return a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
357
|
+
};
|
|
358
|
+
return applyDir(tasks, compare, dir);
|
|
359
|
+
}
|
|
106
360
|
|
|
107
361
|
// packages/cli/src/app-opentui/scenes/tasks.ts
|
|
362
|
+
var TASK_RECOVERY_ITEMS = [
|
|
363
|
+
{ id: "refresh", label: "refresh", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Refresh tasks" } }, message: "refresh task source" },
|
|
364
|
+
{ id: "next", label: "next", intent: { scene: "command", argv: ["task", "run", "--next"], action: { kind: "command-run", label: "Run next task" } }, message: "dispatch next runnable task" },
|
|
365
|
+
{ id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair task source" } }, message: "repair project/task source" },
|
|
366
|
+
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
367
|
+
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose task source" }
|
|
368
|
+
];
|
|
369
|
+
var COL = {
|
|
370
|
+
glyph: 1,
|
|
371
|
+
id: 11,
|
|
372
|
+
status: 12,
|
|
373
|
+
priority: 5,
|
|
374
|
+
assignee: 12
|
|
375
|
+
};
|
|
376
|
+
var GUTTER = " ";
|
|
377
|
+
var TASK_COLUMNS = [
|
|
378
|
+
{ key: "status", label: "status", hint: "by task state" },
|
|
379
|
+
{ key: "id", label: "task-id", hint: "by id" },
|
|
380
|
+
{ key: "priority", label: "priority", hint: "by priority" },
|
|
381
|
+
{ key: "assignee", label: "assignee", hint: "by assignee" },
|
|
382
|
+
{ key: "title", label: "title", hint: "by title" }
|
|
383
|
+
];
|
|
384
|
+
function taskSelectableItem(task) {
|
|
385
|
+
const taskId = task.id?.trim();
|
|
386
|
+
if (!taskId)
|
|
387
|
+
return null;
|
|
388
|
+
const title = (task.title || "task").trim() || "task";
|
|
389
|
+
const activeRunId = task.activeRun?.runId?.trim();
|
|
390
|
+
return {
|
|
391
|
+
id: taskId,
|
|
392
|
+
label: title,
|
|
393
|
+
data: { taskDetailId: taskId, selectedTaskId: taskId, ...activeRunId ? { selectedRunId: activeRunId } : {} },
|
|
394
|
+
intent: { scene: "tasks", argv: ["tasks", taskId], action: { kind: "refresh", label: `Open ${title}`, payload: { taskDetailId: taskId } } },
|
|
395
|
+
message: `open ${title} detail`
|
|
396
|
+
};
|
|
397
|
+
}
|
|
108
398
|
function taskView(state) {
|
|
109
399
|
const tasks = state.data.tasks;
|
|
110
400
|
return tasks && typeof tasks === "object" && !Array.isArray(tasks) ? tasks : null;
|
|
@@ -113,6 +403,32 @@ function taskRecords(state) {
|
|
|
113
403
|
const records = taskView(state)?.records;
|
|
114
404
|
return Array.isArray(records) ? records : [];
|
|
115
405
|
}
|
|
406
|
+
function dispatchingFor(state) {
|
|
407
|
+
const value = state.data.dispatchingRun;
|
|
408
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
409
|
+
return null;
|
|
410
|
+
const record = value;
|
|
411
|
+
if (typeof record.taskId !== "string" || !record.taskId.trim())
|
|
412
|
+
return null;
|
|
413
|
+
return { taskId: record.taskId, status: typeof record.status === "string" ? record.status : "dispatching" };
|
|
414
|
+
}
|
|
415
|
+
function updatedAgoLabel(state) {
|
|
416
|
+
const refreshedAt = taskView(state)?.refreshedAt;
|
|
417
|
+
if (typeof refreshedAt !== "string")
|
|
418
|
+
return;
|
|
419
|
+
const parsed = Date.parse(refreshedAt);
|
|
420
|
+
if (!Number.isFinite(parsed))
|
|
421
|
+
return;
|
|
422
|
+
const seconds = Math.max(0, Math.round((Date.now() - parsed) / 1000));
|
|
423
|
+
if (seconds < 1)
|
|
424
|
+
return "updated just now";
|
|
425
|
+
if (seconds < 60)
|
|
426
|
+
return `updated ${seconds}s ago`;
|
|
427
|
+
const minutes = Math.round(seconds / 60);
|
|
428
|
+
if (minutes < 60)
|
|
429
|
+
return `updated ${minutes}m ago`;
|
|
430
|
+
return `updated ${Math.round(minutes / 60)}h ago`;
|
|
431
|
+
}
|
|
116
432
|
function panelWidth(layout) {
|
|
117
433
|
return layout?.centerWidth ?? 100;
|
|
118
434
|
}
|
|
@@ -124,9 +440,19 @@ function clip(value, width) {
|
|
|
124
440
|
return "";
|
|
125
441
|
return value.length <= width ? value : `${value.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
126
442
|
}
|
|
443
|
+
function cell(value, width) {
|
|
444
|
+
return clip(value, width).padEnd(width);
|
|
445
|
+
}
|
|
127
446
|
function formatAssignee(value) {
|
|
128
447
|
return value.startsWith("@") ? value : `@${value}`;
|
|
129
448
|
}
|
|
449
|
+
function assigneeCell(task) {
|
|
450
|
+
const first = task.assignees[0];
|
|
451
|
+
return first ? formatAssignee(first) : "\u2014";
|
|
452
|
+
}
|
|
453
|
+
function priorityCell(task) {
|
|
454
|
+
return task.priority === undefined ? "\u2014" : `P${String(task.priority).slice(0, 3)}`;
|
|
455
|
+
}
|
|
130
456
|
function taskViewLabel(view) {
|
|
131
457
|
const filters = view?.filters && typeof view.filters === "object" && !Array.isArray(view.filters) ? view.filters : {};
|
|
132
458
|
const filter = typeof filters.preset === "string" && filters.preset !== "custom" ? filters.preset : [
|
|
@@ -142,67 +468,215 @@ function taskViewLabel(view) {
|
|
|
142
468
|
const count = visible !== undefined && total !== undefined ? `${visible}/${total}` : "syncing";
|
|
143
469
|
return `filter ${filter} \xB7 sort ${sort} \xB7 ${count}`;
|
|
144
470
|
}
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
471
|
+
function sortArrow(spec, key) {
|
|
472
|
+
if (!spec || spec.key !== key)
|
|
473
|
+
return "";
|
|
474
|
+
return spec.dir === "asc" ? "\u25B2" : "\u25BC";
|
|
475
|
+
}
|
|
476
|
+
function headerRow(spec) {
|
|
477
|
+
const text = [
|
|
478
|
+
" ",
|
|
479
|
+
cell(`task-id${sortArrow(spec, "id")}`, COL.id),
|
|
480
|
+
cell(`status${sortArrow(spec, "status")}`, COL.status),
|
|
481
|
+
cell(`prio${sortArrow(spec, "priority")}`, COL.priority),
|
|
482
|
+
cell(`assignee${sortArrow(spec, "assignee")}`, COL.assignee),
|
|
483
|
+
`title${sortArrow(spec, "title")}`
|
|
484
|
+
].join(GUTTER);
|
|
485
|
+
return line(text, { fg: RIG_UI.ink, bold: true, bg: RIG_UI.glass });
|
|
486
|
+
}
|
|
487
|
+
function sortToggleRow(column, current) {
|
|
488
|
+
const arrow = sortArrow(current, column.key);
|
|
489
|
+
const active = current?.key === column.key;
|
|
490
|
+
const next = cycleTaskSort(current, column.key);
|
|
491
|
+
const marker = active ? "\u25B8" : " ";
|
|
492
|
+
const label = `${column.label}${arrow ? ` ${arrow}` : ""}`.padEnd(12);
|
|
493
|
+
const row = line(`${marker} ${label} ${column.hint}`, {
|
|
494
|
+
fg: active ? RIG_UI.lime : RIG_UI.ink2,
|
|
495
|
+
bold: active
|
|
496
|
+
});
|
|
497
|
+
return withSelectable(row, {
|
|
498
|
+
id: `task-sort-${column.key}`,
|
|
499
|
+
label: `sort by ${column.label}`,
|
|
500
|
+
data: { taskSort: next },
|
|
501
|
+
message: `sort tasks ${next ? `${column.label} ${next.dir}` : "default"}`
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
function sortStrip(spec) {
|
|
505
|
+
return [
|
|
506
|
+
line("SORT", { fg: RIG_UI.ink3, bold: true }),
|
|
507
|
+
...TASK_COLUMNS.map((column) => sortToggleRow(column, spec)),
|
|
508
|
+
line("", { fg: RIG_UI.ink3 })
|
|
509
|
+
];
|
|
510
|
+
}
|
|
511
|
+
function taskRow(width, task, active, optimistic) {
|
|
512
|
+
const effectiveStatus = optimistic ?? task.status;
|
|
513
|
+
const { glyph } = statusLabel(effectiveStatus);
|
|
149
514
|
const marker = active ? "\u258C" : " ";
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
515
|
+
const status = effectiveStatus.replace(/[_-]/g, " ");
|
|
516
|
+
const fixed = `${marker} ${glyph}${GUTTER}${cell(task.id, COL.id)}${GUTTER}${cell(status, COL.status)}${GUTTER}${cell(priorityCell(task), COL.priority)}${GUTTER}${cell(assigneeCell(task), COL.assignee)}${GUTTER}`;
|
|
517
|
+
const activeRun = task.activeRun;
|
|
518
|
+
const activeSuffix = activeRun ? ` \xB7 attach ${activeRun.runId.slice(0, 8)}${activeRun.status ? ` ${activeRun.status}` : ""}` : "";
|
|
519
|
+
const titleWidth = Math.max(8, width - fixed.length - 2);
|
|
520
|
+
const row = line(`${fixed}${clip(`${task.title}${activeSuffix}`, titleWidth)}`, {
|
|
521
|
+
fg: active ? RIG_UI.ink : RIG_UI.ink2,
|
|
154
522
|
bold: active,
|
|
155
|
-
|
|
523
|
+
...active ? { bg: RIG_UI.glass } : {}
|
|
156
524
|
});
|
|
525
|
+
const item = taskSelectableItem(task);
|
|
526
|
+
return item ? withSelectable(row, item) : row;
|
|
527
|
+
}
|
|
528
|
+
var RECOVERY_DECKS = [
|
|
529
|
+
{ label: "refresh", detail: "reload task source" },
|
|
530
|
+
{ label: "next", detail: "dispatch next runnable task" },
|
|
531
|
+
{ label: "repair", detail: "repair project/task source link" },
|
|
532
|
+
{ label: "server", detail: "open server controls" },
|
|
533
|
+
{ label: "doctor", detail: "diagnose task source" }
|
|
534
|
+
];
|
|
535
|
+
function recoveryRows(selected, reason) {
|
|
536
|
+
return [
|
|
537
|
+
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
538
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
539
|
+
...RECOVERY_DECKS.map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, TASK_RECOVERY_ITEMS[index]))
|
|
540
|
+
];
|
|
157
541
|
}
|
|
158
|
-
function emptyRows(query, total) {
|
|
542
|
+
function emptyRows(query, total, selected) {
|
|
543
|
+
if (!query.trim() && total === 0)
|
|
544
|
+
return recoveryRows(selected, "No tasks loaded.");
|
|
159
545
|
if (query.trim() && total > 0) {
|
|
160
546
|
return [
|
|
161
|
-
|
|
162
|
-
line(`search ${JSON.stringify(query)} returned 0/${total}`, { fg: RIG_UI.ink3 }),
|
|
163
|
-
line("escape clears search", { fg: RIG_UI.ink4 })
|
|
547
|
+
...recoveryRows(selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
164
548
|
];
|
|
165
549
|
}
|
|
166
|
-
return
|
|
167
|
-
line("No tasks loaded.", { fg: RIG_UI.ink2, bold: true }),
|
|
168
|
-
line("Check the task source or switch filters from Help.", { fg: RIG_UI.ink3 }),
|
|
169
|
-
line("tab switches screens", { fg: RIG_UI.ink4 })
|
|
170
|
-
];
|
|
550
|
+
return recoveryRows(selected, "No tasks are visible with this filter.");
|
|
171
551
|
}
|
|
172
|
-
function degradedRows(state) {
|
|
552
|
+
function degradedRows(state, selected) {
|
|
173
553
|
if (!state.error)
|
|
174
554
|
return [];
|
|
175
|
-
return
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
555
|
+
return recoveryRows(selected, state.error.message);
|
|
556
|
+
}
|
|
557
|
+
function rawString(raw, key) {
|
|
558
|
+
const value = raw?.[key];
|
|
559
|
+
return typeof value === "string" ? value : "";
|
|
560
|
+
}
|
|
561
|
+
function taskBody(state, task) {
|
|
562
|
+
const preview = state.data.taskPreviewRaw;
|
|
563
|
+
if (preview && typeof preview === "object" && !Array.isArray(preview)) {
|
|
564
|
+
const fromPreview = rawString(preview, "body");
|
|
565
|
+
if (fromPreview.trim())
|
|
566
|
+
return fromPreview;
|
|
567
|
+
}
|
|
568
|
+
return rawString(task?.raw, "body");
|
|
569
|
+
}
|
|
570
|
+
function renderTaskDetail(state, taskId, layout) {
|
|
571
|
+
const task = taskRecords(state).find((entry) => entry.id === taskId);
|
|
572
|
+
const title = (task?.title || taskId).trim();
|
|
573
|
+
const status = task?.status ?? "unknown";
|
|
574
|
+
const { glyph, color } = statusLabel(status);
|
|
575
|
+
const body = taskBody(state, task);
|
|
576
|
+
const activeRunId = task?.activeRun?.runId?.trim();
|
|
577
|
+
const width = panelWidth(layout);
|
|
578
|
+
const selected = Math.max(0, state.selection.index);
|
|
579
|
+
const headerLines = [
|
|
580
|
+
line(`${glyph} ${title}`, { fg: color, bold: true }),
|
|
581
|
+
line(`task ${taskId} \xB7 ${status}`, { fg: RIG_UI.ink3 }),
|
|
582
|
+
...task && task.labels.length > 0 ? [line(`labels: ${task.labels.join(", ")}`, { fg: RIG_UI.ink4 })] : [],
|
|
583
|
+
...task && task.assignees.length > 0 ? [line(`assignees: ${task.assignees.join(", ")}`, { fg: RIG_UI.ink4 })] : [],
|
|
584
|
+
line("", { fg: RIG_UI.ink3 }),
|
|
585
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true })
|
|
179
586
|
];
|
|
587
|
+
let index = 0;
|
|
588
|
+
const actionRows = [];
|
|
589
|
+
actionRows.push(selectableDeckRow({ label: "back", detail: "return to the task list", index, active: selected === index }, { id: "task-detail-back", label: "back", data: { taskDetailId: undefined }, message: "back to task list" }));
|
|
590
|
+
index += 1;
|
|
591
|
+
actionRows.push(selectableDeckRow({ label: "dispatch", detail: "submit a Pi run for this task", index, active: selected === index }, { id: `task-detail-run:${taskId}`, label: `dispatch ${taskId}`, intent: { scene: "tasks", argv: ["run", taskId], action: { kind: "task-run-id", payload: { task: taskId }, label: `Dispatching ${taskId}` } }, message: `dispatch task ${taskId}` }));
|
|
592
|
+
index += 1;
|
|
593
|
+
if (activeRunId) {
|
|
594
|
+
actionRows.push(selectableDeckRow({ label: "attach", detail: `attach the Pi console to run ${activeRunId.slice(0, 8)}`, index, active: selected === index }, { id: `task-detail-attach:${taskId}`, label: `attach ${activeRunId.slice(0, 8)}`, intent: { scene: "handoff", argv: ["attach", activeRunId], action: { kind: "run-attach", payload: { runId: activeRunId }, label: `Attach Pi ${activeRunId.slice(0, 8)}` } }, message: `attach Pi to ${activeRunId.slice(0, 8)}` }));
|
|
595
|
+
index += 1;
|
|
596
|
+
}
|
|
597
|
+
const bodyHeading = [line("", { fg: RIG_UI.ink3 }), line("BODY", { fg: RIG_UI.ink3, bold: true })];
|
|
598
|
+
const bodyLines = body.trim() ? body.split(`
|
|
599
|
+
`).slice(0, 400).map((text) => line(text, { fg: RIG_UI.ink2 })) : [line("(no description)", { fg: RIG_UI.ink4 })];
|
|
600
|
+
const panelLines = [...headerLines, ...actionRows, ...bodyHeading, ...bodyLines];
|
|
601
|
+
const paddingX = layout?.compact ? 2 : 3;
|
|
602
|
+
const chromeTopInset = 3 + 1;
|
|
603
|
+
const headerCount = headerLines.length + actionRows.length + bodyHeading.length;
|
|
604
|
+
const native = body.trim() ? {
|
|
605
|
+
kind: "markdown",
|
|
606
|
+
content: body,
|
|
607
|
+
top: (layout?.centerTop ?? 1) + chromeTopInset + headerCount,
|
|
608
|
+
left: (layout?.centerLeft ?? 2) + paddingX,
|
|
609
|
+
width: Math.max(20, width - paddingX * 2),
|
|
610
|
+
height: Math.max(6, panelHeight(layout, 0) - chromeTopInset - headerCount - 1)
|
|
611
|
+
} : undefined;
|
|
612
|
+
return makeSceneFrame({
|
|
613
|
+
scene: "tasks",
|
|
614
|
+
title: "Task",
|
|
615
|
+
lines: [],
|
|
616
|
+
...native ? { native } : {},
|
|
617
|
+
panels: [{
|
|
618
|
+
id: "task-detail",
|
|
619
|
+
top: 0,
|
|
620
|
+
width,
|
|
621
|
+
height: panelHeight(layout, 0),
|
|
622
|
+
lines: panelLines,
|
|
623
|
+
backgroundColor: RIG_UI.panel,
|
|
624
|
+
backgroundAlpha: 184,
|
|
625
|
+
opacity: 1,
|
|
626
|
+
border: false,
|
|
627
|
+
stickyScroll: true,
|
|
628
|
+
stickyStart: "top",
|
|
629
|
+
chrome: "ad-terminal",
|
|
630
|
+
headerText: `task ${taskId}`,
|
|
631
|
+
headerHeight: 3,
|
|
632
|
+
paddingX,
|
|
633
|
+
paddingY: 1
|
|
634
|
+
}],
|
|
635
|
+
footer: { run: activeRunId ? `${activeRunId.slice(0, 8)} active` : undefined, message: "back returns to the list \xB7 dispatch runs the task" },
|
|
636
|
+
live: state.status === "action"
|
|
637
|
+
});
|
|
180
638
|
}
|
|
181
639
|
function renderTasksScene(state, layout) {
|
|
640
|
+
const detailId = typeof state.data.taskDetailId === "string" ? state.data.taskDetailId.trim() : "";
|
|
641
|
+
if (detailId)
|
|
642
|
+
return renderTaskDetail(state, detailId, layout);
|
|
182
643
|
const width = panelWidth(layout);
|
|
183
644
|
const view = taskView(state);
|
|
184
645
|
const allTasks = taskRecords(state);
|
|
185
646
|
const query = listSearchQuery(state);
|
|
186
|
-
const
|
|
647
|
+
const spec = taskSortSpec(state.data.taskSort);
|
|
648
|
+
const tasks = sortTasks(filterTasksForSearch(allTasks, query), spec);
|
|
187
649
|
const selected = typeof state.data.selectedTaskId === "string" && tasks.some((task) => task.id === state.data.selectedTaskId) ? state.data.selectedTaskId : tasks[0]?.id;
|
|
188
650
|
const selectedIndex = Math.max(0, tasks.findIndex((task) => task.id === selected));
|
|
189
|
-
const
|
|
190
|
-
const
|
|
651
|
+
const recoveryIndex = Math.max(0, Math.min(4, state.selection.index));
|
|
652
|
+
const dispatching = dispatchingFor(state);
|
|
653
|
+
const dispatchLine = dispatching ? ` \xB7 ${state.data.dispatchingRun?.runId ?? "new"} ${dispatching.status}` : "";
|
|
654
|
+
const updatedAgo = updatedAgoLabel(state);
|
|
191
655
|
const panelTop = 0;
|
|
192
656
|
const contentWidth = Math.max(12, width - (layout?.compact ? 8 : 10));
|
|
657
|
+
const loading = state.status === "loading" && allTasks.length === 0;
|
|
658
|
+
const refreshError = lastRefreshError(state);
|
|
659
|
+
const banner = refreshError && !state.error ? errorBanner(refreshError) : [];
|
|
193
660
|
const panelLines = [
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
661
|
+
...banner,
|
|
662
|
+
...tasks.length > 0 ? [
|
|
663
|
+
...degradedRows(state, recoveryIndex),
|
|
664
|
+
...query.trim() ? [line(searchSummary("tasks", query, tasks.length, allTasks.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
665
|
+
...sortStrip(spec),
|
|
666
|
+
headerRow(spec),
|
|
667
|
+
line("", { fg: RIG_UI.ink3 }),
|
|
668
|
+
...tasks.map((task, index) => taskRow(contentWidth, task, index === selectedIndex, dispatching && dispatching.taskId === task.id ? dispatching.status : undefined))
|
|
669
|
+
] : state.error ? degradedRows(state, recoveryIndex) : loading ? loadingRows("tasks", state.tick) : [
|
|
670
|
+
...query.trim() ? [line(searchSummary("tasks", query, tasks.length, allTasks.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
671
|
+
...emptyRows(query, allTasks.length, recoveryIndex)
|
|
672
|
+
]
|
|
199
673
|
];
|
|
200
674
|
return makeSceneFrame({
|
|
201
675
|
scene: "tasks",
|
|
202
676
|
title: "Tasks",
|
|
203
677
|
lines: [
|
|
204
678
|
line("", { fg: RIG_UI.ink4 }),
|
|
205
|
-
line(query.trim() ? `
|
|
679
|
+
line(`${query.trim() ? ` tasks --search ${JSON.stringify(query)}` : ` tasks \xB7 ${taskViewLabel(view)}${dispatchLine}`}${updatedAgo ? ` \xB7 ${updatedAgo}` : ""}`, { fg: RIG_UI.ink3 })
|
|
206
680
|
],
|
|
207
681
|
panels: [{
|
|
208
682
|
id: "tasks-list",
|
|
@@ -215,12 +689,15 @@ function renderTasksScene(state, layout) {
|
|
|
215
689
|
opacity: 1,
|
|
216
690
|
border: false,
|
|
217
691
|
chrome: "ad-terminal",
|
|
218
|
-
headerText: query.trim() ? `
|
|
692
|
+
headerText: query.trim() ? `tasks --search ${JSON.stringify(query)}` : `tasks \xB7 ${taskViewLabel(view)}${dispatchLine}`,
|
|
219
693
|
headerHeight: 3,
|
|
220
694
|
paddingX: layout?.compact ? 2 : 3,
|
|
221
695
|
paddingY: 1
|
|
222
696
|
}],
|
|
223
|
-
footer: {
|
|
697
|
+
footer: {
|
|
698
|
+
message: query.trim() ? searchSummary("tasks", query, tasks.length, allTasks.length) : taskViewLabel(view),
|
|
699
|
+
...updatedAgo ? { updated: updatedAgo } : {}
|
|
700
|
+
},
|
|
224
701
|
typeBarPlaceholder: "search tasks\u2026",
|
|
225
702
|
live: true
|
|
226
703
|
});
|