@h-rig/cli 0.0.6-alpha.80 → 0.0.6-alpha.82
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/rig.js +17040 -11249
- package/dist/src/app/board.js +32 -3
- package/dist/src/app/drone-ui.js +1 -1
- package/dist/src/app/theme.js +1 -0
- package/dist/src/app-opentui/adapters/common.d.ts +53 -0
- package/dist/src/app-opentui/adapters/common.js +149 -0
- package/dist/src/app-opentui/adapters/doctor.d.ts +11 -0
- package/dist/src/app-opentui/adapters/doctor.js +780 -0
- package/dist/src/app-opentui/adapters/fleet.d.ts +16 -0
- package/dist/src/app-opentui/adapters/fleet.js +874 -0
- package/dist/src/app-opentui/adapters/inbox.d.ts +33 -0
- package/dist/src/app-opentui/adapters/inbox.js +1454 -0
- package/dist/src/app-opentui/adapters/init.d.ts +13 -0
- package/dist/src/app-opentui/adapters/init.js +2357 -0
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +16 -0
- package/dist/src/app-opentui/adapters/pi-attach.js +1299 -0
- package/dist/src/app-opentui/adapters/run-detail.d.ts +20 -0
- package/dist/src/app-opentui/adapters/run-detail.js +893 -0
- package/dist/src/app-opentui/adapters/server.d.ts +14 -0
- package/dist/src/app-opentui/adapters/server.js +798 -0
- package/dist/src/app-opentui/adapters/tasks.d.ts +55 -0
- package/dist/src/app-opentui/adapters/tasks.js +3472 -0
- package/dist/src/app-opentui/bootstrap.d.ts +16 -0
- package/dist/src/app-opentui/bootstrap.js +19515 -0
- package/dist/src/app-opentui/drone.d.ts +12 -0
- package/dist/src/app-opentui/drone.js +227 -0
- package/dist/src/app-opentui/events.d.ts +7 -0
- package/dist/src/app-opentui/events.js +28 -0
- package/dist/src/app-opentui/index.d.ts +8 -0
- package/dist/src/app-opentui/index.js +3485 -0
- package/dist/src/app-opentui/intent.d.ts +3 -0
- package/dist/src/app-opentui/intent.js +211 -0
- package/dist/src/app-opentui/layout.d.ts +15 -0
- package/dist/src/app-opentui/layout.js +44 -0
- package/dist/src/app-opentui/list-search.d.ts +8 -0
- package/dist/src/app-opentui/list-search.js +43 -0
- package/dist/src/app-opentui/pi-host-child.d.ts +2 -0
- package/dist/src/app-opentui/pi-host-child.js +778 -0
- package/dist/src/app-opentui/pi-pty-host.d.ts +64 -0
- package/dist/src/app-opentui/pi-pty-host.js +388 -0
- package/dist/src/app-opentui/registry.d.ts +4 -0
- package/dist/src/app-opentui/registry.js +6839 -0
- package/dist/src/app-opentui/render/graphics.d.ts +39 -0
- package/dist/src/app-opentui/render/graphics.js +537 -0
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +2 -0
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +1484 -0
- package/dist/src/app-opentui/render/image-visual-layer-worker.d.ts +1 -0
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +1545 -0
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +94 -0
- package/dist/src/app-opentui/render/image-visual-layer.js +949 -0
- package/dist/src/app-opentui/render/panels.d.ts +10 -0
- package/dist/src/app-opentui/render/panels.js +201 -0
- package/dist/src/app-opentui/render/scene.d.ts +16 -0
- package/dist/src/app-opentui/render/scene.js +110 -0
- package/dist/src/app-opentui/render/text.d.ts +10 -0
- package/dist/src/app-opentui/render/text.js +121 -0
- package/dist/src/app-opentui/render/type-bar.d.ts +14 -0
- package/dist/src/app-opentui/render/type-bar.js +137 -0
- package/dist/src/app-opentui/runtime.d.ts +2 -0
- package/dist/src/app-opentui/runtime.js +3414 -0
- package/dist/src/app-opentui/scenes/doctor.d.ts +2 -0
- package/dist/src/app-opentui/scenes/doctor.js +91 -0
- package/dist/src/app-opentui/scenes/error.d.ts +2 -0
- package/dist/src/app-opentui/scenes/error.js +190 -0
- package/dist/src/app-opentui/scenes/fleet.d.ts +3 -0
- package/dist/src/app-opentui/scenes/fleet.js +207 -0
- package/dist/src/app-opentui/scenes/handoff.d.ts +2 -0
- package/dist/src/app-opentui/scenes/handoff.js +147 -0
- package/dist/src/app-opentui/scenes/help.d.ts +3 -0
- package/dist/src/app-opentui/scenes/help.js +138 -0
- package/dist/src/app-opentui/scenes/inbox.d.ts +2 -0
- package/dist/src/app-opentui/scenes/inbox.js +118 -0
- package/dist/src/app-opentui/scenes/init.d.ts +2 -0
- package/dist/src/app-opentui/scenes/init.js +94 -0
- package/dist/src/app-opentui/scenes/main.d.ts +2 -0
- package/dist/src/app-opentui/scenes/main.js +96 -0
- package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -0
- package/dist/src/app-opentui/scenes/run-detail.js +139 -0
- package/dist/src/app-opentui/scenes/server.d.ts +2 -0
- package/dist/src/app-opentui/scenes/server.js +88 -0
- package/dist/src/app-opentui/scenes/tasks.d.ts +3 -0
- package/dist/src/app-opentui/scenes/tasks.js +230 -0
- package/dist/src/app-opentui/state.d.ts +4 -0
- package/dist/src/app-opentui/state.js +286 -0
- package/dist/src/app-opentui/theme.d.ts +36 -0
- package/dist/src/app-opentui/theme.js +88 -0
- package/dist/src/app-opentui/types.d.ts +188 -0
- package/dist/src/app-opentui/types.js +1 -0
- package/dist/src/commands/_async-ui.js +1 -1
- package/dist/src/commands/_operator-view.js +1 -1
- package/dist/src/commands/_pi-frontend.js +1 -1
- package/dist/src/commands/_spinner.js +1 -1
- package/dist/src/commands/browser.js +1 -1
- package/dist/src/commands/doctor.js +1 -1
- package/dist/src/commands/github.js +1 -1
- package/dist/src/commands/inbox.js +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/inspect.js +1 -1
- package/dist/src/commands/run.js +1 -1
- package/dist/src/commands/setup.js +1 -1
- package/dist/src/commands/stats.js +1 -1
- package/dist/src/commands/task.js +1 -1
- package/dist/src/commands.js +33 -4
- package/dist/src/index.js +33 -4
- package/package.json +11 -8
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ScrollBoxRenderable, type CliRenderer, type MouseEvent } from "@opentui/core";
|
|
2
|
+
import type { StageLayout } from "../layout";
|
|
3
|
+
import type { AppSceneLine, AppScenePanel } from "../types";
|
|
4
|
+
import { type TextLineRenderable } from "./text";
|
|
5
|
+
export type ScrollPanelRenderable = ScrollBoxRenderable & {
|
|
6
|
+
__rigTextLines: TextLineRenderable[];
|
|
7
|
+
__rigPanelId?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function createScrollPanelLayer(renderer: CliRenderer, id: string, onLineMouseDown?: (line: AppSceneLine, event: MouseEvent) => void): ScrollPanelRenderable;
|
|
10
|
+
export declare function applyScrollPanels(panels: readonly ScrollPanelRenderable[], layout: StageLayout, scenePanels: readonly AppScenePanel[]): void;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/app-opentui/render/panels.ts
|
|
3
|
+
import { RGBA, ScrollBoxRenderable } from "@opentui/core";
|
|
4
|
+
|
|
5
|
+
// packages/cli/src/app-opentui/theme.ts
|
|
6
|
+
import {
|
|
7
|
+
bold as otuiBold,
|
|
8
|
+
dim as otuiDim,
|
|
9
|
+
fg as otuiFg,
|
|
10
|
+
t,
|
|
11
|
+
TextAttributes
|
|
12
|
+
} from "@opentui/core";
|
|
13
|
+
var RIG_UI = {
|
|
14
|
+
bg: "#070809",
|
|
15
|
+
bg2: "#0b0c0e",
|
|
16
|
+
panel: "#101115",
|
|
17
|
+
panel2: "#101115",
|
|
18
|
+
glass: "#14161b",
|
|
19
|
+
ink: "#f2f3f6",
|
|
20
|
+
ink2: "#aeb0ba",
|
|
21
|
+
ink3: "#6c6e79",
|
|
22
|
+
ink4: "#44464f",
|
|
23
|
+
lime: "#ccff4d",
|
|
24
|
+
limeDim: "#a9d63f",
|
|
25
|
+
cyan: "#56d8ff",
|
|
26
|
+
red: "#ff5d5d",
|
|
27
|
+
yellow: "#ffd24d",
|
|
28
|
+
magenta: "#ff79b0"
|
|
29
|
+
};
|
|
30
|
+
var styles = {
|
|
31
|
+
ink: otuiFg(RIG_UI.ink),
|
|
32
|
+
ink2: otuiFg(RIG_UI.ink2),
|
|
33
|
+
ink3: otuiFg(RIG_UI.ink3),
|
|
34
|
+
ink4: otuiFg(RIG_UI.ink4),
|
|
35
|
+
lime: otuiFg(RIG_UI.lime),
|
|
36
|
+
limeDim: otuiFg(RIG_UI.limeDim),
|
|
37
|
+
cyan: otuiFg(RIG_UI.cyan),
|
|
38
|
+
red: otuiFg(RIG_UI.red),
|
|
39
|
+
yellow: otuiFg(RIG_UI.yellow),
|
|
40
|
+
magenta: otuiFg(RIG_UI.magenta)
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// packages/cli/src/app-opentui/render/text.ts
|
|
44
|
+
import { TextAttributes as TextAttributes2, TextRenderable } from "@opentui/core";
|
|
45
|
+
function selectableMouseHandler(currentLineRef, onLineMouseDown) {
|
|
46
|
+
return (event) => {
|
|
47
|
+
const currentLine = currentLineRef();
|
|
48
|
+
if (currentLine?.selectableIndex === undefined)
|
|
49
|
+
return;
|
|
50
|
+
onLineMouseDown?.(currentLine, event);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function createFlowTextLine(renderer, id, onLineMouseDown) {
|
|
54
|
+
let currentLine;
|
|
55
|
+
const renderable = new TextRenderable(renderer, {
|
|
56
|
+
id,
|
|
57
|
+
content: "",
|
|
58
|
+
width: "100%",
|
|
59
|
+
height: 1,
|
|
60
|
+
flexShrink: 0,
|
|
61
|
+
fg: RIG_UI.ink2,
|
|
62
|
+
selectable: true,
|
|
63
|
+
onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown)
|
|
64
|
+
});
|
|
65
|
+
renderable.setRigSceneLine = (line) => {
|
|
66
|
+
currentLine = line;
|
|
67
|
+
};
|
|
68
|
+
return renderable;
|
|
69
|
+
}
|
|
70
|
+
function applyFlowTextLine(renderable, line, width) {
|
|
71
|
+
renderable.setRigSceneLine?.(line);
|
|
72
|
+
renderable.visible = Boolean(line);
|
|
73
|
+
renderable.height = line ? 1 : 0;
|
|
74
|
+
renderable.width = Math.max(1, width);
|
|
75
|
+
renderable.content = line?.styledText ?? line?.text ?? "";
|
|
76
|
+
renderable.fg = line?.fg ?? RIG_UI.ink2;
|
|
77
|
+
renderable.attributes = line?.bold ? TextAttributes2.BOLD : line?.dim ? TextAttributes2.DIM : 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// packages/cli/src/app-opentui/render/panels.ts
|
|
81
|
+
var TRANSPARENT = RGBA.fromInts(0, 0, 0, 0);
|
|
82
|
+
var MAX_PANEL_LINES = 420;
|
|
83
|
+
function hexToRgba(hex, alpha) {
|
|
84
|
+
const clean = hex.replace(/^#/, "");
|
|
85
|
+
const full = clean.length === 3 ? clean.split("").map((part) => `${part}${part}`).join("") : clean;
|
|
86
|
+
const value = Number.parseInt(full, 16);
|
|
87
|
+
if (!Number.isFinite(value))
|
|
88
|
+
return RGBA.fromInts(14, 15, 17, alpha);
|
|
89
|
+
return RGBA.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
|
|
90
|
+
}
|
|
91
|
+
function panelBackground(panel) {
|
|
92
|
+
return hexToRgba(panel.backgroundColor ?? RIG_UI.panel, panel.backgroundAlpha ?? 184);
|
|
93
|
+
}
|
|
94
|
+
function panelBorder(panel) {
|
|
95
|
+
return panel.borderColor ? hexToRgba(panel.borderColor, panel.borderAlpha ?? 54) : TRANSPARENT;
|
|
96
|
+
}
|
|
97
|
+
function createScrollPanelLayer(renderer, id, onLineMouseDown) {
|
|
98
|
+
const panel = new ScrollBoxRenderable(renderer, {
|
|
99
|
+
id,
|
|
100
|
+
position: "absolute",
|
|
101
|
+
left: 0,
|
|
102
|
+
top: -2,
|
|
103
|
+
width: 1,
|
|
104
|
+
height: 1,
|
|
105
|
+
backgroundColor: TRANSPARENT,
|
|
106
|
+
border: false,
|
|
107
|
+
shouldFill: true,
|
|
108
|
+
opacity: 1,
|
|
109
|
+
zIndex: 6,
|
|
110
|
+
scrollY: true,
|
|
111
|
+
scrollX: false,
|
|
112
|
+
stickyScroll: false,
|
|
113
|
+
viewportCulling: true,
|
|
114
|
+
paddingX: 2,
|
|
115
|
+
paddingY: 1,
|
|
116
|
+
verticalScrollbarOptions: {
|
|
117
|
+
showArrows: false,
|
|
118
|
+
visible: false,
|
|
119
|
+
width: 1,
|
|
120
|
+
trackOptions: {
|
|
121
|
+
backgroundColor: TRANSPARENT,
|
|
122
|
+
foregroundColor: hexToRgba(RIG_UI.ink4, 84)
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
horizontalScrollbarOptions: {
|
|
126
|
+
height: 0,
|
|
127
|
+
visible: false,
|
|
128
|
+
trackOptions: {
|
|
129
|
+
backgroundColor: TRANSPARENT,
|
|
130
|
+
foregroundColor: TRANSPARENT
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
panel.__rigTextLines = [];
|
|
135
|
+
for (let index = 0;index < MAX_PANEL_LINES; index += 1) {
|
|
136
|
+
const line = createFlowTextLine(renderer, `${id}-line-${index}`, onLineMouseDown);
|
|
137
|
+
panel.__rigTextLines.push(line);
|
|
138
|
+
panel.add(line);
|
|
139
|
+
}
|
|
140
|
+
return panel;
|
|
141
|
+
}
|
|
142
|
+
function hidePanel(panel) {
|
|
143
|
+
panel.visible = false;
|
|
144
|
+
panel.top = -2;
|
|
145
|
+
panel.left = 0;
|
|
146
|
+
panel.width = 1;
|
|
147
|
+
panel.height = 1;
|
|
148
|
+
panel.backgroundColor = TRANSPARENT;
|
|
149
|
+
panel.border = false;
|
|
150
|
+
panel.__rigPanelId = undefined;
|
|
151
|
+
panel.__rigTextLines.forEach((line) => applyFlowTextLine(line, undefined, 1));
|
|
152
|
+
}
|
|
153
|
+
function applyScrollPanels(panels, layout, scenePanels) {
|
|
154
|
+
panels.forEach((renderable, index) => {
|
|
155
|
+
const panel = scenePanels[index];
|
|
156
|
+
if (!panel || panel.height <= 0) {
|
|
157
|
+
hidePanel(renderable);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const cardLeft = Math.max(0, Math.min(layout.width - 1, layout.centerLeft + (panel.left ?? 0)));
|
|
161
|
+
const desiredWidth = panel.width ?? layout.centerWidth;
|
|
162
|
+
const cardWidth = Math.max(1, Math.min(layout.width - cardLeft, desiredWidth));
|
|
163
|
+
const cardTop = Math.max(0, Math.min(layout.height - 1, layout.centerTop + panel.top));
|
|
164
|
+
const cardHeight = Math.max(1, Math.min(layout.height - cardTop, panel.height));
|
|
165
|
+
const headerHeight = panel.chrome === "ad-terminal" ? Math.max(3, Math.min(cardHeight - 2, panel.headerHeight ?? 3)) : 0;
|
|
166
|
+
const left = cardLeft + (panel.chrome === "ad-terminal" ? 1 : 0);
|
|
167
|
+
const top = cardTop + headerHeight + (panel.chrome === "ad-terminal" ? 1 : 0);
|
|
168
|
+
const width = Math.max(1, Math.min(layout.width - left, cardWidth - (panel.chrome === "ad-terminal" ? 2 : 0)));
|
|
169
|
+
const height = Math.max(1, Math.min(layout.height - top, cardHeight - headerHeight - (panel.chrome === "ad-terminal" ? 2 : 0)));
|
|
170
|
+
const paddingX = panel.paddingX ?? (panel.chrome === "ad-terminal" ? 5 : 2);
|
|
171
|
+
const paddingY = panel.paddingY ?? (panel.chrome === "ad-terminal" ? 2 : 1);
|
|
172
|
+
const contentWidth = Math.max(1, width - paddingX * 2 - 1);
|
|
173
|
+
renderable.visible = true;
|
|
174
|
+
renderable.left = left;
|
|
175
|
+
renderable.top = top;
|
|
176
|
+
renderable.width = width;
|
|
177
|
+
renderable.height = height;
|
|
178
|
+
renderable.zIndex = panel.zIndex ?? 6;
|
|
179
|
+
renderable.opacity = panel.opacity ?? 1;
|
|
180
|
+
renderable.backgroundColor = panel.chrome === "ad-terminal" ? TRANSPARENT : panelBackground(panel);
|
|
181
|
+
renderable.border = panel.chrome === "ad-terminal" ? false : panel.border ?? false;
|
|
182
|
+
renderable.borderColor = panelBorder(panel);
|
|
183
|
+
renderable.paddingX = paddingX;
|
|
184
|
+
renderable.paddingY = paddingY;
|
|
185
|
+
renderable.stickyScroll = panel.stickyScroll ?? false;
|
|
186
|
+
renderable.stickyStart = panel.stickyStart;
|
|
187
|
+
renderable.verticalScrollBar.visible = false;
|
|
188
|
+
renderable.horizontalScrollBar.visible = false;
|
|
189
|
+
if (renderable.__rigPanelId !== panel.id) {
|
|
190
|
+
renderable.__rigPanelId = panel.id;
|
|
191
|
+
renderable.scrollTo(0);
|
|
192
|
+
}
|
|
193
|
+
renderable.__rigTextLines.forEach((line, lineIndex) => {
|
|
194
|
+
applyFlowTextLine(line, panel.lines[lineIndex], contentWidth);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
createScrollPanelLayer,
|
|
200
|
+
applyScrollPanels
|
|
201
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type StageLayout } from "../layout";
|
|
2
|
+
import type { AppSceneFrame, AppSceneLine } from "../types";
|
|
3
|
+
export declare function line(text: string, options?: Omit<AppSceneLine, "text">): AppSceneLine;
|
|
4
|
+
export declare function blank(): AppSceneLine;
|
|
5
|
+
export declare function center(text: string, fg?: string, bold?: boolean): AppSceneLine;
|
|
6
|
+
export declare function deckRow(input: {
|
|
7
|
+
readonly label: string;
|
|
8
|
+
readonly detail: string;
|
|
9
|
+
readonly index?: number;
|
|
10
|
+
readonly active?: boolean;
|
|
11
|
+
readonly activateOnClick?: boolean;
|
|
12
|
+
}): AppSceneLine;
|
|
13
|
+
export declare function kv(label: string, value: string, fg?: string): AppSceneLine;
|
|
14
|
+
export declare function fitSceneLine(input: AppSceneLine, layout: StageLayout): AppSceneLine;
|
|
15
|
+
export declare function fitSceneLines(lines: readonly AppSceneLine[], layout: StageLayout): AppSceneLine[];
|
|
16
|
+
export declare function makeSceneFrame(input: AppSceneFrame): AppSceneFrame;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/app-opentui/layout.ts
|
|
3
|
+
function visibleWidth(text) {
|
|
4
|
+
return [...text].length;
|
|
5
|
+
}
|
|
6
|
+
function alignText(text, width, align = "left") {
|
|
7
|
+
const length = visibleWidth(text);
|
|
8
|
+
if (length >= width)
|
|
9
|
+
return text;
|
|
10
|
+
const pad = width - length;
|
|
11
|
+
if (align === "right")
|
|
12
|
+
return `${" ".repeat(pad)}${text}`;
|
|
13
|
+
if (align === "center") {
|
|
14
|
+
const left = Math.floor(pad / 2);
|
|
15
|
+
return `${" ".repeat(left)}${text}${" ".repeat(pad - left)}`;
|
|
16
|
+
}
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
function truncateText(text, width) {
|
|
20
|
+
if (visibleWidth(text) <= width)
|
|
21
|
+
return text;
|
|
22
|
+
if (width <= 1)
|
|
23
|
+
return "\u2026";
|
|
24
|
+
return `${[...text].slice(0, Math.max(0, width - 1)).join("")}\u2026`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// packages/cli/src/app-opentui/theme.ts
|
|
28
|
+
import {
|
|
29
|
+
bold as otuiBold,
|
|
30
|
+
dim as otuiDim,
|
|
31
|
+
fg as otuiFg,
|
|
32
|
+
t,
|
|
33
|
+
TextAttributes
|
|
34
|
+
} from "@opentui/core";
|
|
35
|
+
var RIG_UI = {
|
|
36
|
+
bg: "#070809",
|
|
37
|
+
bg2: "#0b0c0e",
|
|
38
|
+
panel: "#101115",
|
|
39
|
+
panel2: "#101115",
|
|
40
|
+
glass: "#14161b",
|
|
41
|
+
ink: "#f2f3f6",
|
|
42
|
+
ink2: "#aeb0ba",
|
|
43
|
+
ink3: "#6c6e79",
|
|
44
|
+
ink4: "#44464f",
|
|
45
|
+
lime: "#ccff4d",
|
|
46
|
+
limeDim: "#a9d63f",
|
|
47
|
+
cyan: "#56d8ff",
|
|
48
|
+
red: "#ff5d5d",
|
|
49
|
+
yellow: "#ffd24d",
|
|
50
|
+
magenta: "#ff79b0"
|
|
51
|
+
};
|
|
52
|
+
var styles = {
|
|
53
|
+
ink: otuiFg(RIG_UI.ink),
|
|
54
|
+
ink2: otuiFg(RIG_UI.ink2),
|
|
55
|
+
ink3: otuiFg(RIG_UI.ink3),
|
|
56
|
+
ink4: otuiFg(RIG_UI.ink4),
|
|
57
|
+
lime: otuiFg(RIG_UI.lime),
|
|
58
|
+
limeDim: otuiFg(RIG_UI.limeDim),
|
|
59
|
+
cyan: otuiFg(RIG_UI.cyan),
|
|
60
|
+
red: otuiFg(RIG_UI.red),
|
|
61
|
+
yellow: otuiFg(RIG_UI.yellow),
|
|
62
|
+
magenta: otuiFg(RIG_UI.magenta)
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// packages/cli/src/app-opentui/render/scene.ts
|
|
66
|
+
function line(text, options = {}) {
|
|
67
|
+
return { text, ...options };
|
|
68
|
+
}
|
|
69
|
+
function blank() {
|
|
70
|
+
return { text: "" };
|
|
71
|
+
}
|
|
72
|
+
function center(text, fg = RIG_UI.ink2, bold = false) {
|
|
73
|
+
return { text, fg, bold, align: "center" };
|
|
74
|
+
}
|
|
75
|
+
function deckRow(input) {
|
|
76
|
+
const prefix = input.active ? "\u25B8" : " ";
|
|
77
|
+
const label = input.label.toUpperCase().padEnd(10);
|
|
78
|
+
return line(`${prefix} ${label} ${input.detail}`, {
|
|
79
|
+
fg: input.active ? RIG_UI.lime : RIG_UI.ink2,
|
|
80
|
+
bold: input.active,
|
|
81
|
+
selectableIndex: input.index,
|
|
82
|
+
activateOnClick: input.activateOnClick
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function kv(label, value, fg = RIG_UI.ink2) {
|
|
86
|
+
return line(` ${label.toUpperCase().padEnd(10)} ${value}`, { fg });
|
|
87
|
+
}
|
|
88
|
+
function fitSceneLine(input, layout) {
|
|
89
|
+
const fitted = truncateText(input.text, layout.centerWidth);
|
|
90
|
+
return {
|
|
91
|
+
...input,
|
|
92
|
+
text: alignText(fitted, layout.centerWidth, input.align ?? "left")
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function fitSceneLines(lines, layout) {
|
|
96
|
+
return lines.slice(0, layout.centerHeight).map((entry) => fitSceneLine(entry, layout));
|
|
97
|
+
}
|
|
98
|
+
function makeSceneFrame(input) {
|
|
99
|
+
return input;
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
makeSceneFrame,
|
|
103
|
+
line,
|
|
104
|
+
kv,
|
|
105
|
+
fitSceneLines,
|
|
106
|
+
fitSceneLine,
|
|
107
|
+
deckRow,
|
|
108
|
+
center,
|
|
109
|
+
blank
|
|
110
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TextRenderable, type CliRenderer, type MouseEvent } from "@opentui/core";
|
|
2
|
+
import type { AppSceneLine } from "../types";
|
|
3
|
+
export type TextLineRenderable = TextRenderable & {
|
|
4
|
+
setRigSceneLine?(line: AppSceneLine | undefined): void;
|
|
5
|
+
};
|
|
6
|
+
export declare function createTextLine(renderer: CliRenderer, id: string, top: number, onLineMouseDown?: (line: AppSceneLine, event: MouseEvent) => void): TextLineRenderable;
|
|
7
|
+
export declare function createFlowTextLine(renderer: CliRenderer, id: string, onLineMouseDown?: (line: AppSceneLine, event: MouseEvent) => void): TextLineRenderable;
|
|
8
|
+
export declare function applyTextLine(renderable: TextLineRenderable, line: AppSceneLine | undefined, top: number, left: number, width: number): void;
|
|
9
|
+
export declare function applyFlowTextLine(renderable: TextLineRenderable, line: AppSceneLine | undefined, width: number): void;
|
|
10
|
+
export declare function clearTextLines(renderables: readonly TextLineRenderable[], from?: number): void;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/app-opentui/render/text.ts
|
|
3
|
+
import { TextAttributes as TextAttributes2, TextRenderable } from "@opentui/core";
|
|
4
|
+
|
|
5
|
+
// packages/cli/src/app-opentui/theme.ts
|
|
6
|
+
import {
|
|
7
|
+
bold as otuiBold,
|
|
8
|
+
dim as otuiDim,
|
|
9
|
+
fg as otuiFg,
|
|
10
|
+
t,
|
|
11
|
+
TextAttributes
|
|
12
|
+
} from "@opentui/core";
|
|
13
|
+
var RIG_UI = {
|
|
14
|
+
bg: "#070809",
|
|
15
|
+
bg2: "#0b0c0e",
|
|
16
|
+
panel: "#101115",
|
|
17
|
+
panel2: "#101115",
|
|
18
|
+
glass: "#14161b",
|
|
19
|
+
ink: "#f2f3f6",
|
|
20
|
+
ink2: "#aeb0ba",
|
|
21
|
+
ink3: "#6c6e79",
|
|
22
|
+
ink4: "#44464f",
|
|
23
|
+
lime: "#ccff4d",
|
|
24
|
+
limeDim: "#a9d63f",
|
|
25
|
+
cyan: "#56d8ff",
|
|
26
|
+
red: "#ff5d5d",
|
|
27
|
+
yellow: "#ffd24d",
|
|
28
|
+
magenta: "#ff79b0"
|
|
29
|
+
};
|
|
30
|
+
var styles = {
|
|
31
|
+
ink: otuiFg(RIG_UI.ink),
|
|
32
|
+
ink2: otuiFg(RIG_UI.ink2),
|
|
33
|
+
ink3: otuiFg(RIG_UI.ink3),
|
|
34
|
+
ink4: otuiFg(RIG_UI.ink4),
|
|
35
|
+
lime: otuiFg(RIG_UI.lime),
|
|
36
|
+
limeDim: otuiFg(RIG_UI.limeDim),
|
|
37
|
+
cyan: otuiFg(RIG_UI.cyan),
|
|
38
|
+
red: otuiFg(RIG_UI.red),
|
|
39
|
+
yellow: otuiFg(RIG_UI.yellow),
|
|
40
|
+
magenta: otuiFg(RIG_UI.magenta)
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// packages/cli/src/app-opentui/render/text.ts
|
|
44
|
+
function selectableMouseHandler(currentLineRef, onLineMouseDown) {
|
|
45
|
+
return (event) => {
|
|
46
|
+
const currentLine = currentLineRef();
|
|
47
|
+
if (currentLine?.selectableIndex === undefined)
|
|
48
|
+
return;
|
|
49
|
+
onLineMouseDown?.(currentLine, event);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function createTextLine(renderer, id, top, onLineMouseDown) {
|
|
53
|
+
let currentLine;
|
|
54
|
+
const renderable = new TextRenderable(renderer, {
|
|
55
|
+
id,
|
|
56
|
+
content: "",
|
|
57
|
+
position: "absolute",
|
|
58
|
+
left: 0,
|
|
59
|
+
top,
|
|
60
|
+
width: 1,
|
|
61
|
+
fg: RIG_UI.ink2,
|
|
62
|
+
selectable: true,
|
|
63
|
+
onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown)
|
|
64
|
+
});
|
|
65
|
+
renderable.setRigSceneLine = (line) => {
|
|
66
|
+
currentLine = line;
|
|
67
|
+
};
|
|
68
|
+
return renderable;
|
|
69
|
+
}
|
|
70
|
+
function createFlowTextLine(renderer, id, onLineMouseDown) {
|
|
71
|
+
let currentLine;
|
|
72
|
+
const renderable = new TextRenderable(renderer, {
|
|
73
|
+
id,
|
|
74
|
+
content: "",
|
|
75
|
+
width: "100%",
|
|
76
|
+
height: 1,
|
|
77
|
+
flexShrink: 0,
|
|
78
|
+
fg: RIG_UI.ink2,
|
|
79
|
+
selectable: true,
|
|
80
|
+
onMouseDown: selectableMouseHandler(() => currentLine, onLineMouseDown)
|
|
81
|
+
});
|
|
82
|
+
renderable.setRigSceneLine = (line) => {
|
|
83
|
+
currentLine = line;
|
|
84
|
+
};
|
|
85
|
+
return renderable;
|
|
86
|
+
}
|
|
87
|
+
function applyTextLine(renderable, line, top, left, width) {
|
|
88
|
+
renderable.setRigSceneLine?.(line);
|
|
89
|
+
renderable.top = top;
|
|
90
|
+
renderable.left = left;
|
|
91
|
+
renderable.width = width;
|
|
92
|
+
renderable.content = line?.styledText ?? line?.text ?? "";
|
|
93
|
+
renderable.fg = line?.fg ?? RIG_UI.ink2;
|
|
94
|
+
renderable.attributes = line?.bold ? TextAttributes2.BOLD : line?.dim ? TextAttributes2.DIM : 0;
|
|
95
|
+
}
|
|
96
|
+
function applyFlowTextLine(renderable, line, width) {
|
|
97
|
+
renderable.setRigSceneLine?.(line);
|
|
98
|
+
renderable.visible = Boolean(line);
|
|
99
|
+
renderable.height = line ? 1 : 0;
|
|
100
|
+
renderable.width = Math.max(1, width);
|
|
101
|
+
renderable.content = line?.styledText ?? line?.text ?? "";
|
|
102
|
+
renderable.fg = line?.fg ?? RIG_UI.ink2;
|
|
103
|
+
renderable.attributes = line?.bold ? TextAttributes2.BOLD : line?.dim ? TextAttributes2.DIM : 0;
|
|
104
|
+
}
|
|
105
|
+
function clearTextLines(renderables, from = 0) {
|
|
106
|
+
for (let index = from;index < renderables.length; index += 1) {
|
|
107
|
+
const renderable = renderables[index];
|
|
108
|
+
renderable.setRigSceneLine?.(undefined);
|
|
109
|
+
renderable.content = "";
|
|
110
|
+
renderable.top = -1;
|
|
111
|
+
renderable.left = 0;
|
|
112
|
+
renderable.width = 1;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
createTextLine,
|
|
117
|
+
createFlowTextLine,
|
|
118
|
+
clearTextLines,
|
|
119
|
+
applyTextLine,
|
|
120
|
+
applyFlowTextLine
|
|
121
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { InputRenderable, TextRenderable, type CliRenderer } from "@opentui/core";
|
|
2
|
+
import type { AppFooterState, AppTypeBarState } from "../types";
|
|
3
|
+
export type TypeBarRenderables = {
|
|
4
|
+
readonly input: InputRenderable;
|
|
5
|
+
readonly prefix: TextRenderable;
|
|
6
|
+
readonly footer: TextRenderable;
|
|
7
|
+
};
|
|
8
|
+
export declare function createTypeBar(renderer: CliRenderer): TypeBarRenderables;
|
|
9
|
+
export declare function positionTypeBar(renderables: TypeBarRenderables, input: AppTypeBarState, footer: AppFooterState, width: number, typeBarTop: number, footerTop: number): void;
|
|
10
|
+
export declare function hideTypeBar(renderables: TypeBarRenderables, height: number): void;
|
|
11
|
+
export declare function bindTypeBar(renderables: TypeBarRenderables, handlers: {
|
|
12
|
+
onInput(value: string): void;
|
|
13
|
+
onEnter(value: string): void;
|
|
14
|
+
}): void;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/app-opentui/render/type-bar.ts
|
|
3
|
+
import { InputRenderable, InputRenderableEvents, TextRenderable } from "@opentui/core";
|
|
4
|
+
|
|
5
|
+
// packages/cli/src/app-opentui/theme.ts
|
|
6
|
+
import {
|
|
7
|
+
bold as otuiBold,
|
|
8
|
+
dim as otuiDim,
|
|
9
|
+
fg as otuiFg,
|
|
10
|
+
t,
|
|
11
|
+
TextAttributes
|
|
12
|
+
} from "@opentui/core";
|
|
13
|
+
var RIG_UI = {
|
|
14
|
+
bg: "#070809",
|
|
15
|
+
bg2: "#0b0c0e",
|
|
16
|
+
panel: "#101115",
|
|
17
|
+
panel2: "#101115",
|
|
18
|
+
glass: "#14161b",
|
|
19
|
+
ink: "#f2f3f6",
|
|
20
|
+
ink2: "#aeb0ba",
|
|
21
|
+
ink3: "#6c6e79",
|
|
22
|
+
ink4: "#44464f",
|
|
23
|
+
lime: "#ccff4d",
|
|
24
|
+
limeDim: "#a9d63f",
|
|
25
|
+
cyan: "#56d8ff",
|
|
26
|
+
red: "#ff5d5d",
|
|
27
|
+
yellow: "#ffd24d",
|
|
28
|
+
magenta: "#ff79b0"
|
|
29
|
+
};
|
|
30
|
+
var styles = {
|
|
31
|
+
ink: otuiFg(RIG_UI.ink),
|
|
32
|
+
ink2: otuiFg(RIG_UI.ink2),
|
|
33
|
+
ink3: otuiFg(RIG_UI.ink3),
|
|
34
|
+
ink4: otuiFg(RIG_UI.ink4),
|
|
35
|
+
lime: otuiFg(RIG_UI.lime),
|
|
36
|
+
limeDim: otuiFg(RIG_UI.limeDim),
|
|
37
|
+
cyan: otuiFg(RIG_UI.cyan),
|
|
38
|
+
red: otuiFg(RIG_UI.red),
|
|
39
|
+
yellow: otuiFg(RIG_UI.yellow),
|
|
40
|
+
magenta: otuiFg(RIG_UI.magenta)
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// packages/cli/src/app-opentui/layout.ts
|
|
44
|
+
function visibleWidth(text) {
|
|
45
|
+
return [...text].length;
|
|
46
|
+
}
|
|
47
|
+
function truncateText(text, width) {
|
|
48
|
+
if (visibleWidth(text) <= width)
|
|
49
|
+
return text;
|
|
50
|
+
if (width <= 1)
|
|
51
|
+
return "\u2026";
|
|
52
|
+
return `${[...text].slice(0, Math.max(0, width - 1)).join("")}\u2026`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// packages/cli/src/app-opentui/render/type-bar.ts
|
|
56
|
+
function createTypeBar(renderer) {
|
|
57
|
+
const prefix = new TextRenderable(renderer, {
|
|
58
|
+
id: "rig-typebar-prefix",
|
|
59
|
+
content: " rig \u203A",
|
|
60
|
+
position: "absolute",
|
|
61
|
+
left: 0,
|
|
62
|
+
top: 0,
|
|
63
|
+
fg: RIG_UI.lime,
|
|
64
|
+
selectable: true
|
|
65
|
+
});
|
|
66
|
+
const input = new InputRenderable(renderer, {
|
|
67
|
+
id: "rig-typebar-input",
|
|
68
|
+
position: "absolute",
|
|
69
|
+
left: 7,
|
|
70
|
+
top: 0,
|
|
71
|
+
width: 40,
|
|
72
|
+
placeholder: "fleet \xB7 tasks \xB7 run next \xB7 help",
|
|
73
|
+
textColor: RIG_UI.ink,
|
|
74
|
+
cursorColor: RIG_UI.lime,
|
|
75
|
+
cursorStyle: { style: "block", blinking: false },
|
|
76
|
+
showCursor: true,
|
|
77
|
+
selectable: true
|
|
78
|
+
});
|
|
79
|
+
const footer = new TextRenderable(renderer, {
|
|
80
|
+
id: "rig-footer",
|
|
81
|
+
content: "",
|
|
82
|
+
position: "absolute",
|
|
83
|
+
left: 0,
|
|
84
|
+
top: 1,
|
|
85
|
+
width: "100%",
|
|
86
|
+
fg: RIG_UI.ink4,
|
|
87
|
+
selectable: true
|
|
88
|
+
});
|
|
89
|
+
input.focus();
|
|
90
|
+
return { input, prefix, footer };
|
|
91
|
+
}
|
|
92
|
+
function positionTypeBar(renderables, input, footer, width, typeBarTop, footerTop) {
|
|
93
|
+
renderables.prefix.content = " rig \u203A";
|
|
94
|
+
renderables.prefix.top = typeBarTop;
|
|
95
|
+
renderables.input.top = typeBarTop;
|
|
96
|
+
renderables.input.left = 7;
|
|
97
|
+
renderables.input.width = Math.max(10, width - 9);
|
|
98
|
+
renderables.input.placeholder = input.placeholder;
|
|
99
|
+
renderables.input.showCursor = true;
|
|
100
|
+
renderables.footer.top = footerTop;
|
|
101
|
+
renderables.footer.width = "100%";
|
|
102
|
+
renderables.footer.content = formatFooter(footer, width);
|
|
103
|
+
if (!renderables.input.focused)
|
|
104
|
+
renderables.input.focus();
|
|
105
|
+
}
|
|
106
|
+
function hideTypeBar(renderables, height) {
|
|
107
|
+
renderables.prefix.content = "";
|
|
108
|
+
renderables.prefix.top = height + 1;
|
|
109
|
+
renderables.input.value = "";
|
|
110
|
+
renderables.input.placeholder = "";
|
|
111
|
+
renderables.input.top = height + 1;
|
|
112
|
+
renderables.input.left = 0;
|
|
113
|
+
renderables.input.width = 1;
|
|
114
|
+
renderables.input.blur();
|
|
115
|
+
renderables.footer.content = "";
|
|
116
|
+
renderables.footer.top = height + 1;
|
|
117
|
+
}
|
|
118
|
+
function bindTypeBar(renderables, handlers) {
|
|
119
|
+
renderables.input.on(InputRenderableEvents.INPUT, (value) => handlers.onInput(value));
|
|
120
|
+
renderables.input.on(InputRenderableEvents.ENTER, (value) => handlers.onEnter(value));
|
|
121
|
+
}
|
|
122
|
+
function formatFooter(footer, width) {
|
|
123
|
+
const parts = [
|
|
124
|
+
footer.project ? `project ${footer.project}` : null,
|
|
125
|
+
footer.server ? `server ${footer.server}` : null,
|
|
126
|
+
footer.auth ? `auth ${footer.auth}` : null,
|
|
127
|
+
footer.run ? `run ${footer.run}` : null,
|
|
128
|
+
footer.message ?? null
|
|
129
|
+
].filter((part) => Boolean(part));
|
|
130
|
+
return ` ${truncateText(parts.join(" \xB7 "), Math.max(8, width - 2))}`;
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
positionTypeBar,
|
|
134
|
+
hideTypeBar,
|
|
135
|
+
createTypeBar,
|
|
136
|
+
bindTypeBar
|
|
137
|
+
};
|