@h-rig/cli 0.0.6-alpha.82 → 0.0.6-alpha.83
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 +2798 -1440
- package/dist/src/app/board.js +62 -13
- 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.js +63 -14
- package/dist/src/app-opentui/adapters/fleet.js +84 -20
- package/dist/src/app-opentui/adapters/inbox.js +83 -19
- package/dist/src/app-opentui/adapters/init.js +87 -23
- package/dist/src/app-opentui/adapters/pi-attach.js +96 -34
- package/dist/src/app-opentui/adapters/run-detail.js +83 -19
- package/dist/src/app-opentui/adapters/server.js +100 -23
- package/dist/src/app-opentui/adapters/tasks.d.ts +11 -0
- package/dist/src/app-opentui/adapters/tasks.js +742 -94
- package/dist/src/app-opentui/bootstrap.d.ts +1 -6
- package/dist/src/app-opentui/bootstrap.js +13769 -12368
- 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/events.js +1 -1
- 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 +3802 -2882
- package/dist/src/app-opentui/intent.js +154 -48
- package/dist/src/app-opentui/keymap.d.ts +20 -0
- package/dist/src/app-opentui/keymap.js +707 -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.js +2 -2
- package/dist/src/app-opentui/pi-host-child.js +66 -16
- package/dist/src/app-opentui/pi-pty-host.d.ts +9 -0
- package/dist/src/app-opentui/pi-pty-host.js +9 -11
- package/dist/src/app-opentui/registry.js +3231 -2403
- 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/graphics.d.ts +1 -1
- package/dist/src/app-opentui/render/graphics.js +131 -16
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +408 -957
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +18 -10
- package/dist/src/app-opentui/render/image-visual-layer.js +386 -356
- 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 +62 -29
- package/dist/src/app-opentui/render/preloader.d.ts +10 -0
- package/dist/src/app-opentui/render/preloader.js +163 -0
- package/dist/src/app-opentui/render/scene.d.ts +3 -0
- package/dist/src/app-opentui/render/scene.js +12 -0
- package/dist/src/app-opentui/render/text.js +5 -1
- package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
- package/dist/src/app-opentui/render/type-bar.js +51 -16
- 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.js +2322 -1513
- package/dist/src/app-opentui/scenes/command.d.ts +3 -0
- package/dist/src/app-opentui/scenes/command.js +103 -0
- package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
- package/dist/src/app-opentui/scenes/doctor.js +53 -14
- package/dist/src/app-opentui/scenes/error.js +44 -14
- package/dist/src/app-opentui/scenes/fleet.js +40 -21
- package/dist/src/app-opentui/scenes/handoff.js +142 -27
- package/dist/src/app-opentui/scenes/help.js +63 -48
- package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
- package/dist/src/app-opentui/scenes/inbox.js +64 -17
- package/dist/src/app-opentui/scenes/init.d.ts +2 -1
- package/dist/src/app-opentui/scenes/init.js +62 -21
- package/dist/src/app-opentui/scenes/main.d.ts +2 -1
- package/dist/src/app-opentui/scenes/main.js +80 -24
- package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
- package/dist/src/app-opentui/scenes/run-detail.js +39 -25
- package/dist/src/app-opentui/scenes/server.d.ts +2 -1
- package/dist/src/app-opentui/scenes/server.js +71 -20
- package/dist/src/app-opentui/scenes/tasks.js +44 -22
- package/dist/src/app-opentui/state.js +70 -30
- 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/types.d.ts +10 -2
- package/dist/src/commands/_doctor-checks.js +62 -13
- package/dist/src/commands/_operator-view.js +63 -13
- package/dist/src/commands/_pi-frontend.js +63 -13
- package/dist/src/commands/_preflight.js +64 -14
- package/dist/src/commands/_server-client.js +82 -18
- package/dist/src/commands/_snapshot-upload.js +62 -13
- 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 +66 -13
- package/dist/src/commands/server.js +69 -14
- package/dist/src/commands/setup.js +62 -13
- package/dist/src/commands/stats.js +62 -13
- package/dist/src/commands/task-run-driver.js +62 -13
- package/dist/src/commands/task.js +65 -14
- package/dist/src/commands.js +227 -92
- package/dist/src/index.js +234 -99
- package/package.json +8 -9
- 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
|
@@ -41,95 +41,110 @@ var styles = {
|
|
|
41
41
|
function line(text, options = {}) {
|
|
42
42
|
return { text, ...options };
|
|
43
43
|
}
|
|
44
|
+
function deckRow(input) {
|
|
45
|
+
const prefix = input.active ? "\u25B8" : " ";
|
|
46
|
+
const label = input.label.toUpperCase().padEnd(10);
|
|
47
|
+
return line(`${prefix} ${label} ${input.detail}`, {
|
|
48
|
+
fg: input.active ? RIG_UI.lime : RIG_UI.ink2,
|
|
49
|
+
bold: input.active,
|
|
50
|
+
selectableIndex: input.index,
|
|
51
|
+
activateOnClick: input.activateOnClick
|
|
52
|
+
});
|
|
53
|
+
}
|
|
44
54
|
function makeSceneFrame(input) {
|
|
45
55
|
return input;
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
// packages/cli/src/app-opentui/scenes/help.ts
|
|
49
|
-
var
|
|
50
|
-
["runs", "show runs"],
|
|
51
|
-
["tasks", "
|
|
52
|
-
["type in Runs", "search loaded runs"],
|
|
53
|
-
["type in Tasks", "search loaded tasks"],
|
|
54
|
-
["tasks open", "filter to open tasks"],
|
|
55
|
-
["tasks all", "show every task returned by the source"],
|
|
56
|
-
["tasks mine", "show tasks assigned to @me"],
|
|
57
|
-
["tasks blocked", "show blocked work"],
|
|
58
|
-
["tasks closed", "show closed work"],
|
|
59
|
-
["tasks sort priority", "rank by priority"],
|
|
60
|
-
["tasks sort recency", "rank by update time"],
|
|
61
|
-
["tasks sort status", "group by status"],
|
|
62
|
-
["run <task-id>", "dispatch selected task id"],
|
|
59
|
+
var ACTIONS = [
|
|
60
|
+
["runs", "show live/completed runs"],
|
|
61
|
+
["tasks", "browse task source and dispatch work"],
|
|
63
62
|
["run next", "dispatch next runnable task"],
|
|
64
|
-
["
|
|
65
|
-
["
|
|
66
|
-
["
|
|
67
|
-
["
|
|
68
|
-
["
|
|
69
|
-
["
|
|
63
|
+
["server", "local/remote server controls"],
|
|
64
|
+
["init", "setup/reconfigure/repair wizard"],
|
|
65
|
+
["doctor", "diagnose project/server/auth"],
|
|
66
|
+
["github", "GitHub auth/repo actions"],
|
|
67
|
+
["plugin", "plugin and source actions"],
|
|
68
|
+
["setup", "bootstrap/check/preflight"],
|
|
69
|
+
["inspect", "inspect project/server state"],
|
|
70
|
+
["stats", "run/task metrics"],
|
|
71
|
+
["repo", "repo utilities"],
|
|
72
|
+
["profile", "profile/config actions"],
|
|
73
|
+
["review", "review automation"],
|
|
74
|
+
["browser", "browser tooling/wizards"],
|
|
75
|
+
["pi", "Pi install/attach/status"],
|
|
76
|
+
["queue", "queue operations"],
|
|
77
|
+
["agent", "agent/runtime operations"],
|
|
78
|
+
["inspector", "inspector tools"],
|
|
79
|
+
["dist", "distribution helpers"],
|
|
80
|
+
["workspace", "workspace/project utilities"],
|
|
81
|
+
["remote", "remote endpoint utilities"],
|
|
82
|
+
["git", "git helper actions"],
|
|
83
|
+
["harness", "harness operations"],
|
|
84
|
+
["test", "test helpers"]
|
|
85
|
+
];
|
|
86
|
+
var SHORTCUTS = [
|
|
87
|
+
["tab / \u2192", "next workspace"],
|
|
88
|
+
["\u2190 / esc", "previous/back or clear search"],
|
|
89
|
+
["\u2191 \u2193 / j k", "move selection"],
|
|
90
|
+
["enter / space / click", "activate selected action"],
|
|
70
91
|
["mouse wheel", "scroll panel under cursor"],
|
|
71
|
-
["ctrl-]", "detach from embedded Pi"],
|
|
92
|
+
["ctrl-]", "detach from embedded Pi/command terminal"],
|
|
72
93
|
["ctrl-c / q", "exit"]
|
|
73
94
|
];
|
|
74
95
|
function panelWidth(layout) {
|
|
75
96
|
return layout?.centerWidth ?? 100;
|
|
76
97
|
}
|
|
77
|
-
function panelHeight(layout, top =
|
|
78
|
-
return Math.max(
|
|
79
|
-
}
|
|
80
|
-
function clip(value, width) {
|
|
81
|
-
if (width <= 0)
|
|
82
|
-
return "";
|
|
83
|
-
return value.length <= width ? value : `${value.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
84
|
-
}
|
|
85
|
-
function commandRow(width, label, detail, index) {
|
|
86
|
-
const keyWidth = Math.min(22, Math.max(12, Math.floor(width * 0.28)));
|
|
87
|
-
const key = clip(label, keyWidth).padEnd(keyWidth);
|
|
88
|
-
return line(`${key} ${clip(detail, Math.max(8, width - keyWidth - 4))}`, { fg: index < 3 ? RIG_UI.ink : RIG_UI.ink2 });
|
|
98
|
+
function panelHeight(layout, top = 1) {
|
|
99
|
+
return Math.max(8, (layout?.centerHeight ?? 24) - top);
|
|
89
100
|
}
|
|
90
101
|
function unsupportedCommand(state) {
|
|
91
102
|
const value = state.intent.action.payload?.unsupported ?? state.intent.action.payload?.unknown;
|
|
92
|
-
|
|
103
|
+
if (typeof value !== "string" || !value.trim())
|
|
104
|
+
return null;
|
|
105
|
+
const reason = state.intent.action.payload?.reason;
|
|
106
|
+
return { command: value.trim(), ...typeof reason === "string" && reason.trim() ? { reason: reason.trim() } : {} };
|
|
93
107
|
}
|
|
94
108
|
function renderHelpScene(state, layout) {
|
|
95
|
-
const width = panelWidth(layout);
|
|
96
109
|
const unsupported = unsupportedCommand(state);
|
|
97
|
-
const
|
|
110
|
+
const selected = Math.max(0, Math.min(ACTIONS.length - 1, state.selection.index));
|
|
98
111
|
const panelLines = [
|
|
99
112
|
...unsupported ? [
|
|
100
|
-
line(`${unsupported}
|
|
101
|
-
line("
|
|
113
|
+
line(`${unsupported.command} needs the action catalog.`, { fg: RIG_UI.yellow, bold: true }),
|
|
114
|
+
line(unsupported.reason ?? "Pick an action below; explicit plain mode remains available with RIG_PLAIN=1.", { fg: RIG_UI.ink3 }),
|
|
102
115
|
line("", { fg: RIG_UI.ink3 })
|
|
103
116
|
] : [],
|
|
104
|
-
line("
|
|
117
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
118
|
+
...ACTIONS.map(([label, detail], index) => deckRow({ label, detail, index, active: selected === index, activateOnClick: true })),
|
|
105
119
|
line("", { fg: RIG_UI.ink3 }),
|
|
106
|
-
|
|
120
|
+
line("KEYS / MOUSE", { fg: RIG_UI.ink3, bold: true }),
|
|
121
|
+
...SHORTCUTS.map(([label, detail]) => line(`${label.padEnd(22)} ${detail}`, { fg: RIG_UI.ink2 }))
|
|
107
122
|
];
|
|
108
123
|
return makeSceneFrame({
|
|
109
124
|
scene: "help",
|
|
110
|
-
title: "
|
|
125
|
+
title: "Command catalog",
|
|
111
126
|
lines: [
|
|
112
127
|
line("", { fg: RIG_UI.ink4 }),
|
|
113
|
-
line("
|
|
128
|
+
line(" command catalog \xB7 TUI-first Rig", { fg: RIG_UI.ink3, bold: true })
|
|
114
129
|
],
|
|
115
130
|
panels: [{
|
|
116
131
|
id: "help-reference",
|
|
117
|
-
top:
|
|
118
|
-
width,
|
|
119
|
-
height: panelHeight(layout
|
|
132
|
+
top: 0,
|
|
133
|
+
width: panelWidth(layout),
|
|
134
|
+
height: panelHeight(layout),
|
|
120
135
|
lines: panelLines,
|
|
121
136
|
backgroundColor: RIG_UI.panel,
|
|
122
137
|
backgroundAlpha: 184,
|
|
123
138
|
opacity: 1,
|
|
124
139
|
border: false,
|
|
125
140
|
chrome: "ad-terminal",
|
|
126
|
-
headerText: "
|
|
141
|
+
headerText: "actions",
|
|
127
142
|
headerHeight: 3,
|
|
128
143
|
paddingX: layout?.compact ? 2 : 3,
|
|
129
144
|
paddingY: 1
|
|
130
145
|
}],
|
|
131
|
-
|
|
132
|
-
footer: { message: "
|
|
146
|
+
hideTypeBar: true,
|
|
147
|
+
footer: { message: "enter/click opens a workspace" },
|
|
133
148
|
live: true
|
|
134
149
|
});
|
|
135
150
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import type { StageLayout } from "../layout";
|
|
1
2
|
import type { AppSceneFrame, AppState } from "../types";
|
|
2
|
-
export declare function renderInboxScene(state: AppState): AppSceneFrame;
|
|
3
|
+
export declare function renderInboxScene(state: AppState, layout?: StageLayout): AppSceneFrame;
|
|
@@ -67,11 +67,15 @@ function statusColor(status) {
|
|
|
67
67
|
function line(text, options = {}) {
|
|
68
68
|
return { text, ...options };
|
|
69
69
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
function deckRow(input) {
|
|
71
|
+
const prefix = input.active ? "\u25B8" : " ";
|
|
72
|
+
const label = input.label.toUpperCase().padEnd(10);
|
|
73
|
+
return line(`${prefix} ${label} ${input.detail}`, {
|
|
74
|
+
fg: input.active ? RIG_UI.lime : RIG_UI.ink2,
|
|
75
|
+
bold: input.active,
|
|
76
|
+
selectableIndex: input.index,
|
|
77
|
+
activateOnClick: input.activateOnClick
|
|
78
|
+
});
|
|
75
79
|
}
|
|
76
80
|
function makeSceneFrame(input) {
|
|
77
81
|
return input;
|
|
@@ -88,28 +92,71 @@ function inboxRecords(state) {
|
|
|
88
92
|
inputs: Array.isArray(record.inputs) ? record.inputs : []
|
|
89
93
|
};
|
|
90
94
|
}
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
function panelWidth(layout) {
|
|
96
|
+
return layout?.centerWidth ?? 100;
|
|
97
|
+
}
|
|
98
|
+
function panelHeight(layout) {
|
|
99
|
+
return Math.max(8, (layout?.centerHeight ?? 24) - 1);
|
|
94
100
|
}
|
|
95
|
-
function
|
|
101
|
+
function requestLines(record, startIndex, selected) {
|
|
102
|
+
const title = `${record.title || record.requestId} \xB7 run ${record.runId.slice(0, 8)}`;
|
|
103
|
+
if (record.kind === "approvals") {
|
|
104
|
+
return [
|
|
105
|
+
line(title, { fg: statusColor(record.status), bold: true }),
|
|
106
|
+
deckRow({ label: "approve", detail: `approve ${record.requestId.slice(0, 10)}`, index: startIndex, active: selected === startIndex, activateOnClick: true }),
|
|
107
|
+
deckRow({ label: "reject", detail: `reject ${record.requestId.slice(0, 10)}`, index: startIndex + 1, active: selected === startIndex + 1, activateOnClick: true }),
|
|
108
|
+
deckRow({ label: "attach", detail: `open run ${record.runId.slice(0, 8)}`, index: startIndex + 2, active: selected === startIndex + 2, activateOnClick: true }),
|
|
109
|
+
line("", { fg: RIG_UI.ink3 })
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
return [
|
|
113
|
+
line(title, { fg: statusColor(record.status), bold: true }),
|
|
114
|
+
deckRow({ label: "answer", detail: `open answer command for ${record.requestId.slice(0, 10)}`, index: startIndex, active: selected === startIndex, activateOnClick: true }),
|
|
115
|
+
deckRow({ label: "attach", detail: `open run ${record.runId.slice(0, 8)}`, index: startIndex + 1, active: selected === startIndex + 1, activateOnClick: true }),
|
|
116
|
+
line("", { fg: RIG_UI.ink3 })
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
function renderInboxScene(state, layout) {
|
|
96
120
|
const inbox = inboxRecords(state);
|
|
97
121
|
const all = [...inbox.approvals, ...inbox.inputs];
|
|
122
|
+
const selected = Math.max(0, state.selection.index);
|
|
98
123
|
const optimistic = state.data.inboxOptimistic;
|
|
99
124
|
const optimisticLine = optimistic && typeof optimistic === "object" && !Array.isArray(optimistic) ? `${optimistic.requestId ?? "request"} ${optimistic.status ?? "pending"}` : "idle";
|
|
125
|
+
const lines = [];
|
|
126
|
+
let selectableIndex = 0;
|
|
127
|
+
if (all.length === 0) {
|
|
128
|
+
lines.push(line("No pending approvals or input requests.", { fg: RIG_UI.ink3 }), line("Runs that need a decision will appear here with approve/reject/answer actions.", { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 }), line("ACTIONS", { fg: RIG_UI.ink3, bold: true }), deckRow({ label: "refresh", detail: "reload pending requests", index: 0, active: selected === 0, activateOnClick: true }), deckRow({ label: "runs", detail: "open runs", index: 1, active: selected === 1, activateOnClick: true }), deckRow({ label: "tasks", detail: "open tasks", index: 2, active: selected === 2, activateOnClick: true }), deckRow({ label: "doctor", detail: "diagnose inbox/server/auth", index: 3, active: selected === 3, activateOnClick: true }));
|
|
129
|
+
} else {
|
|
130
|
+
for (const record of all.slice(0, 8)) {
|
|
131
|
+
lines.push(...requestLines(record, selectableIndex, selected));
|
|
132
|
+
selectableIndex += record.kind === "approvals" ? 3 : 2;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
100
135
|
return makeSceneFrame({
|
|
101
136
|
scene: "inbox",
|
|
102
137
|
title: "Inbox",
|
|
103
138
|
lines: [
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
blank(),
|
|
107
|
-
...all.length > 0 ? all.slice(0, 14).map((record, index) => line(row(record), { fg: statusColor(record.status), align: "center", selectableIndex: index })) : [line("no pending approvals or answers", { fg: RIG_UI.ink3, align: "center" })],
|
|
108
|
-
blank(),
|
|
109
|
-
line(`status ${optimisticLine}`, { fg: RIG_UI.ink4, align: "center" })
|
|
139
|
+
line("", { fg: RIG_UI.ink4 }),
|
|
140
|
+
line(` inbox \xB7 ${inbox.approvals.length} approvals \xB7 ${inbox.inputs.length} inputs \xB7 ${optimisticLine}`, { fg: RIG_UI.ink3 })
|
|
110
141
|
],
|
|
111
|
-
|
|
112
|
-
|
|
142
|
+
panels: [{
|
|
143
|
+
id: "inbox-actions",
|
|
144
|
+
top: 0,
|
|
145
|
+
width: panelWidth(layout),
|
|
146
|
+
height: panelHeight(layout),
|
|
147
|
+
lines,
|
|
148
|
+
backgroundColor: RIG_UI.panel,
|
|
149
|
+
backgroundAlpha: 184,
|
|
150
|
+
opacity: 1,
|
|
151
|
+
border: false,
|
|
152
|
+
chrome: "ad-terminal",
|
|
153
|
+
headerText: `inbox \xB7 ${all.length} pending`,
|
|
154
|
+
headerHeight: 3,
|
|
155
|
+
paddingX: layout?.compact ? 2 : 3,
|
|
156
|
+
paddingY: 1
|
|
157
|
+
}],
|
|
158
|
+
footer: { message: all.length > 0 ? "enter/click activates selected request action" : "no pending requests" },
|
|
159
|
+
hideTypeBar: true,
|
|
113
160
|
live: state.status === "action" || all.length === 0
|
|
114
161
|
});
|
|
115
162
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { AppSceneFrame, AppState } from "../types";
|
|
2
|
-
|
|
2
|
+
import type { StageLayout } from "../layout";
|
|
3
|
+
export declare function renderInitScene(state: AppState, layout?: StageLayout): AppSceneFrame;
|
|
@@ -44,8 +44,15 @@ function line(text, options = {}) {
|
|
|
44
44
|
function blank() {
|
|
45
45
|
return { text: "" };
|
|
46
46
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
47
|
+
function deckRow(input) {
|
|
48
|
+
const prefix = input.active ? "\u25B8" : " ";
|
|
49
|
+
const label = input.label.toUpperCase().padEnd(10);
|
|
50
|
+
return line(`${prefix} ${label} ${input.detail}`, {
|
|
51
|
+
fg: input.active ? RIG_UI.lime : RIG_UI.ink2,
|
|
52
|
+
bold: input.active,
|
|
53
|
+
selectableIndex: input.index,
|
|
54
|
+
activateOnClick: input.activateOnClick
|
|
55
|
+
});
|
|
49
56
|
}
|
|
50
57
|
function makeSceneFrame(input) {
|
|
51
58
|
return input;
|
|
@@ -60,32 +67,66 @@ function facts(state) {
|
|
|
60
67
|
const value = initData(state).facts;
|
|
61
68
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
62
69
|
}
|
|
63
|
-
function
|
|
70
|
+
function panelWidth(layout) {
|
|
71
|
+
return layout?.centerWidth ?? 118;
|
|
72
|
+
}
|
|
73
|
+
function panelHeight(layout) {
|
|
74
|
+
return Math.max(18, layout?.centerHeight ?? 34);
|
|
75
|
+
}
|
|
76
|
+
function selectedIndex(state, count) {
|
|
77
|
+
return Math.max(0, Math.min(count - 1, state.selection.index));
|
|
78
|
+
}
|
|
79
|
+
function statusRows(factState, status, configured) {
|
|
80
|
+
return [
|
|
81
|
+
line(`config ${configured ? factState?.configPath ?? "present" : "needs setup"}`, { fg: configured ? RIG_UI.ink2 : RIG_UI.yellow }),
|
|
82
|
+
line(`git ${factState?.hasGit ? "present" : "missing / not checked"}`, { fg: factState?.hasGit ? RIG_UI.ink3 : RIG_UI.yellow }),
|
|
83
|
+
line(`state ${status}`, { fg: configured ? RIG_UI.limeDim : RIG_UI.ink3 })
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
function renderInitScene(state, layout) {
|
|
64
87
|
const factState = facts(state);
|
|
65
88
|
const init = initData(state);
|
|
66
89
|
const status = typeof init.status === "string" ? init.status : factState?.hasConfig ? "configured" : "needs-init";
|
|
67
90
|
const configured = factState?.hasConfig === true;
|
|
91
|
+
const selected = selectedIndex(state, 6);
|
|
92
|
+
const actionRows = [
|
|
93
|
+
deckRow({ label: "wizard", detail: "full interactive setup wizard", index: 0, active: selected === 0, activateOnClick: true }),
|
|
94
|
+
deckRow({ label: "reconfig", detail: "repair/reconfigure generated config and private state", index: 1, active: selected === 1, activateOnClick: true }),
|
|
95
|
+
deckRow({ label: "demo", detail: "seed offline demo task source", index: 2, active: selected === 2, activateOnClick: true }),
|
|
96
|
+
deckRow({ label: "remote", detail: "configure remote server and checkout link", index: 3, active: selected === 3, activateOnClick: true }),
|
|
97
|
+
deckRow({ label: "auth", detail: "import GitHub auth into selected server", index: 4, active: selected === 4, activateOnClick: true }),
|
|
98
|
+
deckRow({ label: "doctor", detail: "verify setup after changes", index: 5, active: selected === 5, activateOnClick: true })
|
|
99
|
+
];
|
|
100
|
+
const panelLines = [
|
|
101
|
+
line(configured ? "project setup \xB7 configured" : "project setup \xB7 choose a path", { fg: RIG_UI.ink3 }),
|
|
102
|
+
blank(),
|
|
103
|
+
...statusRows(factState, status, configured),
|
|
104
|
+
blank(),
|
|
105
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
106
|
+
...actionRows,
|
|
107
|
+
blank(),
|
|
108
|
+
line("enter/click runs action \xB7 esc returns home \xB7 tab switches surfaces", { fg: RIG_UI.ink4 })
|
|
109
|
+
];
|
|
68
110
|
return makeSceneFrame({
|
|
69
111
|
scene: "init",
|
|
70
112
|
title: "Init",
|
|
71
|
-
lines: [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
],
|
|
87
|
-
footer: { message: configured ? "configured" : "
|
|
88
|
-
typeBarPlaceholder: configured ? "doctor \xB7 tasks \xB7 server" : "init --yes \xB7 init --server remote \xB7 help",
|
|
113
|
+
lines: [],
|
|
114
|
+
panels: [{
|
|
115
|
+
id: "init-actions",
|
|
116
|
+
top: 0,
|
|
117
|
+
width: panelWidth(layout),
|
|
118
|
+
height: panelHeight(layout),
|
|
119
|
+
lines: panelLines,
|
|
120
|
+
backgroundColor: RIG_UI.panel,
|
|
121
|
+
backgroundAlpha: 184,
|
|
122
|
+
opacity: 0.98,
|
|
123
|
+
border: false,
|
|
124
|
+
chrome: "ad-terminal",
|
|
125
|
+
headerText: "rig init \xB7 setup / repair / reconfigure",
|
|
126
|
+
paddingX: 5,
|
|
127
|
+
paddingY: 2
|
|
128
|
+
}],
|
|
129
|
+
footer: { message: configured ? "configured" : "setup needed" },
|
|
89
130
|
live: !configured || state.status === "action"
|
|
90
131
|
});
|
|
91
132
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import type { StageLayout } from "../layout";
|
|
1
2
|
import type { AppSceneFrame, AppState } from "../types";
|
|
2
|
-
export declare function renderMainScene(state: AppState): AppSceneFrame;
|
|
3
|
+
export declare function renderMainScene(state: AppState, layout?: StageLayout): AppSceneFrame;
|
|
@@ -44,9 +44,6 @@ function line(text, options = {}) {
|
|
|
44
44
|
function blank() {
|
|
45
45
|
return { text: "" };
|
|
46
46
|
}
|
|
47
|
-
function center(text, fg = RIG_UI.ink2, bold = false) {
|
|
48
|
-
return { text, fg, bold, align: "center" };
|
|
49
|
-
}
|
|
50
47
|
function deckRow(input) {
|
|
51
48
|
const prefix = input.active ? "\u25B8" : " ";
|
|
52
49
|
const label = input.label.toUpperCase().padEnd(10);
|
|
@@ -57,38 +54,97 @@ function deckRow(input) {
|
|
|
57
54
|
activateOnClick: input.activateOnClick
|
|
58
55
|
});
|
|
59
56
|
}
|
|
57
|
+
function kv(label, value, fg = RIG_UI.ink2) {
|
|
58
|
+
return line(` ${label.toUpperCase().padEnd(10)} ${value}`, { fg });
|
|
59
|
+
}
|
|
60
60
|
function makeSceneFrame(input) {
|
|
61
61
|
return input;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// packages/cli/src/app-opentui/scenes/main.ts
|
|
65
|
-
var
|
|
66
|
-
["
|
|
67
|
-
["
|
|
68
|
-
["
|
|
65
|
+
var CONFIGURED_MENU = [
|
|
66
|
+
["init", "setup, reconfigure, repair project state"],
|
|
67
|
+
["server", "local/remote target, auth, linkage"],
|
|
68
|
+
["github", "auth, selected repo, stored token"],
|
|
69
|
+
["tasks", "browse, filter, dispatch, attach active work"],
|
|
70
|
+
["runs", "attach, stop, resume, inspect live sessions"],
|
|
71
|
+
["inbox", "approve, reject, answer, attach"],
|
|
72
|
+
["doctor", "diagnose and repair broken surfaces"],
|
|
73
|
+
["help", "all actions, shortcuts, mouse controls"]
|
|
69
74
|
];
|
|
70
|
-
|
|
75
|
+
var UNCONFIGURED_MENU = [
|
|
76
|
+
["init", "full setup wizard and reconfigure flow"],
|
|
77
|
+
["server", "select local/remote target"],
|
|
78
|
+
["github", "connect or import authentication"],
|
|
79
|
+
["doctor", "find missing setup pieces"],
|
|
80
|
+
["help", "all actions and controls"]
|
|
81
|
+
];
|
|
82
|
+
function record(value) {
|
|
83
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
84
|
+
}
|
|
85
|
+
function serverSummary(state) {
|
|
86
|
+
const server = record(state.data.server);
|
|
87
|
+
const auth = record(server?.auth);
|
|
88
|
+
const signedIn = auth?.signedIn === true || auth?.authenticated === true || auth?.status === "authenticated";
|
|
89
|
+
const login = typeof auth?.login === "string" && auth.login.trim() ? auth.login.trim() : undefined;
|
|
90
|
+
return {
|
|
91
|
+
label: typeof server?.label === "string" && server.label.trim() ? server.label.trim() : state.footer.server ?? "not checked yet",
|
|
92
|
+
target: typeof server?.kind === "string" ? `${server.kind} endpoint` : "open Server to probe",
|
|
93
|
+
health: server ? server.reachable === false ? "unreachable" : "reachable" : "pending",
|
|
94
|
+
auth: server ? signedIn ? `signed in${login ? ` as ${login}` : ""}` : "not signed in / unknown" : "pending"
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function panelWidth(layout) {
|
|
98
|
+
return layout?.centerWidth ?? 118;
|
|
99
|
+
}
|
|
100
|
+
function panelHeight(layout) {
|
|
101
|
+
return Math.max(22, layout?.centerHeight ?? 36);
|
|
102
|
+
}
|
|
103
|
+
function actionRows(state, configured) {
|
|
104
|
+
const options = configured ? CONFIGURED_MENU : UNCONFIGURED_MENU;
|
|
105
|
+
const selected = Math.max(0, Math.min(options.length - 1, state.selection.index));
|
|
106
|
+
return options.map(([label, detail], index) => deckRow({ label, detail, index, active: index === selected, activateOnClick: true }));
|
|
107
|
+
}
|
|
108
|
+
function renderMainScene(state, layout) {
|
|
71
109
|
const configured = state.data.projectConfigured === true;
|
|
72
|
-
const
|
|
110
|
+
const server = serverSummary(state);
|
|
73
111
|
const lines = [
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
blank()
|
|
112
|
+
line("PROJECT COCKPIT", { fg: RIG_UI.ink3, bold: true }),
|
|
113
|
+
line("click a row or use arrows + enter \xB7 esc returns here \xB7 ctrl-c exits", { fg: RIG_UI.ink4 }),
|
|
114
|
+
blank(),
|
|
115
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
116
|
+
...actionRows(state, configured),
|
|
117
|
+
blank(),
|
|
118
|
+
line("CONTEXT", { fg: RIG_UI.ink3, bold: true }),
|
|
119
|
+
kv("workspace", "current repository", RIG_UI.ink2),
|
|
120
|
+
kv("config", configured ? "configured" : "needs setup", configured ? RIG_UI.limeDim : RIG_UI.yellow),
|
|
121
|
+
kv("server", server.label, server.health === "reachable" ? RIG_UI.limeDim : RIG_UI.yellow),
|
|
122
|
+
kv("target", server.target, RIG_UI.ink3),
|
|
123
|
+
kv("github", server.auth, server.auth.startsWith("signed in") ? RIG_UI.limeDim : RIG_UI.yellow),
|
|
124
|
+
blank(),
|
|
125
|
+
line(state.actionLabel ?? "ready", { fg: state.status === "action" ? RIG_UI.cyan : RIG_UI.ink4 })
|
|
77
126
|
];
|
|
78
|
-
if (!configured) {
|
|
79
|
-
lines.push(deckRow({ label: "init", detail: "create config and server link", index: 0, active: selected === 0 }), deckRow({ label: "help", detail: "show command reference", index: 1, active: selected === 1 }), blank(), line("enter opens selection", { fg: RIG_UI.ink4, align: "center" }));
|
|
80
|
-
} else {
|
|
81
|
-
CONFIGURED_OPTIONS.forEach(([label, detail], index) => {
|
|
82
|
-
lines.push(deckRow({ label, detail, index, active: index === selected }));
|
|
83
|
-
});
|
|
84
|
-
lines.push(blank(), line(` ${state.actionLabel ?? "ready"}`, { fg: state.status === "action" ? RIG_UI.cyan : RIG_UI.ink4 }));
|
|
85
|
-
}
|
|
86
127
|
return makeSceneFrame({
|
|
87
128
|
scene: "main",
|
|
88
|
-
title: "
|
|
89
|
-
lines,
|
|
90
|
-
|
|
91
|
-
|
|
129
|
+
title: "Project cockpit",
|
|
130
|
+
lines: [],
|
|
131
|
+
panels: [{
|
|
132
|
+
id: "project-cockpit",
|
|
133
|
+
top: 0,
|
|
134
|
+
width: panelWidth(layout),
|
|
135
|
+
height: panelHeight(layout),
|
|
136
|
+
lines,
|
|
137
|
+
backgroundColor: RIG_UI.panel,
|
|
138
|
+
backgroundAlpha: 184,
|
|
139
|
+
opacity: 0.98,
|
|
140
|
+
border: false,
|
|
141
|
+
chrome: "ad-terminal",
|
|
142
|
+
headerText: "project cockpit",
|
|
143
|
+
paddingX: layout?.compact ? 3 : 5,
|
|
144
|
+
paddingY: 2
|
|
145
|
+
}],
|
|
146
|
+
live: true,
|
|
147
|
+
hideTypeBar: true
|
|
92
148
|
});
|
|
93
149
|
}
|
|
94
150
|
export {
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { AppSceneFrame, AppState } from "../types";
|
|
2
|
-
|
|
2
|
+
import type { StageLayout } from "../layout";
|
|
3
|
+
export declare function renderRunDetailScene(state: AppState, layout?: StageLayout): AppSceneFrame;
|
|
@@ -67,12 +67,6 @@ function statusColor(status) {
|
|
|
67
67
|
function line(text, options = {}) {
|
|
68
68
|
return { text, ...options };
|
|
69
69
|
}
|
|
70
|
-
function blank() {
|
|
71
|
-
return { text: "" };
|
|
72
|
-
}
|
|
73
|
-
function center(text, fg = RIG_UI.ink2, bold = false) {
|
|
74
|
-
return { text, fg, bold, align: "center" };
|
|
75
|
-
}
|
|
76
70
|
function deckRow(input) {
|
|
77
71
|
const prefix = input.active ? "\u25B8" : " ";
|
|
78
72
|
const label = input.label.toUpperCase().padEnd(10);
|
|
@@ -103,34 +97,54 @@ function selectedRunId(state, run) {
|
|
|
103
97
|
function entryText(entry) {
|
|
104
98
|
return String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? entry.type ?? "event").replace(/\s+/g, " ").slice(0, 96);
|
|
105
99
|
}
|
|
106
|
-
function
|
|
100
|
+
function panelWidth(layout) {
|
|
101
|
+
return layout?.centerWidth ?? 100;
|
|
102
|
+
}
|
|
103
|
+
function panelHeight(layout) {
|
|
104
|
+
return Math.max(10, (layout?.centerHeight ?? 24) - 1);
|
|
105
|
+
}
|
|
106
|
+
function renderRunDetailScene(state, layout) {
|
|
107
107
|
const run = snapshot(state);
|
|
108
108
|
const runId = selectedRunId(state, run);
|
|
109
109
|
const selected = Math.max(0, Math.min(2, state.selection.index));
|
|
110
110
|
const timeline = run?.timeline.slice(-5).map((entry) => entryText(entry)) ?? [];
|
|
111
111
|
const logs = run?.logs.slice(-3).map((entry) => entryText(entry)) ?? [];
|
|
112
112
|
const status = run?.status ?? "loading";
|
|
113
|
-
const lines = [
|
|
114
|
-
center(run ? run.title : "run", RIG_UI.ink, true),
|
|
115
|
-
center(runId ? `${runId.slice(0, 8)} \xB7 ${status}` : "loading run", run ? statusColor(status) : RIG_UI.ink3),
|
|
116
|
-
blank(),
|
|
117
|
-
...runId ? [
|
|
118
|
-
deckRow({ label: "pi", detail: "attach bundled Pi", index: 0, active: selected === 0, activateOnClick: true }),
|
|
119
|
-
deckRow({ label: "stop", detail: "request stop", index: 1, active: selected === 1, activateOnClick: true }),
|
|
120
|
-
deckRow({ label: "runs", detail: "return to list", index: 2, active: selected === 2, activateOnClick: true }),
|
|
121
|
-
blank(),
|
|
122
|
-
kv("status", status, statusColor(status)),
|
|
123
|
-
kv("run", runId, RIG_UI.ink2)
|
|
124
|
-
] : [line("loading run telemetry", { fg: RIG_UI.ink3, align: "center" })],
|
|
125
|
-
...timeline.length > 0 ? [blank(), line(" timeline", { fg: RIG_UI.ink4, bold: true }), ...timeline.map((entry) => line(` \xB7 ${entry}`, { fg: RIG_UI.ink2 }))] : [],
|
|
126
|
-
...logs.length > 0 ? [blank(), line(" logs", { fg: RIG_UI.ink4, bold: true }), ...logs.map((entry) => line(` \xB7 ${entry}`, { fg: RIG_UI.ink4 }))] : []
|
|
127
|
-
];
|
|
128
113
|
return makeSceneFrame({
|
|
129
114
|
scene: "run-detail",
|
|
130
115
|
title: "Run",
|
|
131
|
-
lines
|
|
132
|
-
|
|
133
|
-
|
|
116
|
+
lines: [
|
|
117
|
+
line("", { fg: RIG_UI.ink4 }),
|
|
118
|
+
line(` run \xB7 ${runId ? `${runId.slice(0, 8)} \xB7 ${status}` : "loading"}`, { fg: run ? statusColor(status) : RIG_UI.ink3 })
|
|
119
|
+
],
|
|
120
|
+
panels: [{
|
|
121
|
+
id: "run-detail",
|
|
122
|
+
top: 0,
|
|
123
|
+
width: panelWidth(layout),
|
|
124
|
+
height: panelHeight(layout),
|
|
125
|
+
lines: [
|
|
126
|
+
line(run ? run.title : "Run telemetry", { fg: RIG_UI.ink, bold: true }),
|
|
127
|
+
...runId ? [kv("run", runId, RIG_UI.ink2), kv("status", status, statusColor(status))] : [line("loading run telemetry", { fg: RIG_UI.ink3 })],
|
|
128
|
+
line("", { fg: RIG_UI.ink3 }),
|
|
129
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
130
|
+
deckRow({ label: "pi", detail: "attach bundled Pi", index: 0, active: selected === 0, activateOnClick: true }),
|
|
131
|
+
deckRow({ label: "stop", detail: "request stop", index: 1, active: selected === 1, activateOnClick: true }),
|
|
132
|
+
deckRow({ label: "runs", detail: "return to fleet", index: 2, active: selected === 2, activateOnClick: true }),
|
|
133
|
+
...timeline.length > 0 ? [line("", { fg: RIG_UI.ink3 }), line("TIMELINE", { fg: RIG_UI.ink3, bold: true }), ...timeline.map((entry) => line(`\xB7 ${entry}`, { fg: RIG_UI.ink2 }))] : [],
|
|
134
|
+
...logs.length > 0 ? [line("", { fg: RIG_UI.ink3 }), line("LOGS", { fg: RIG_UI.ink3, bold: true }), ...logs.map((entry) => line(`\xB7 ${entry}`, { fg: RIG_UI.ink4 }))] : []
|
|
135
|
+
],
|
|
136
|
+
backgroundColor: RIG_UI.panel,
|
|
137
|
+
backgroundAlpha: 184,
|
|
138
|
+
opacity: 1,
|
|
139
|
+
border: false,
|
|
140
|
+
chrome: "ad-terminal",
|
|
141
|
+
headerText: runId ? `run ${runId.slice(0, 8)}` : "run",
|
|
142
|
+
headerHeight: 3,
|
|
143
|
+
paddingX: layout?.compact ? 2 : 3,
|
|
144
|
+
paddingY: 1
|
|
145
|
+
}],
|
|
146
|
+
footer: { run: runId ? `${runId.slice(0, 8)} ${status}` : undefined, message: "enter/click action" },
|
|
147
|
+
hideTypeBar: true,
|
|
134
148
|
live: state.status === "action" || !run
|
|
135
149
|
});
|
|
136
150
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { AppSceneFrame, AppState } from "../types";
|
|
2
|
-
|
|
2
|
+
import type { StageLayout } from "../layout";
|
|
3
|
+
export declare function renderServerScene(state: AppState, layout?: StageLayout): AppSceneFrame;
|