@h-rig/cli 0.0.6-alpha.83 → 0.0.6-alpha.85
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 +22060 -14620
- package/dist/src/app/board.js +155 -28
- package/dist/src/app-opentui/adapters/doctor.d.ts +0 -2
- package/dist/src/app-opentui/adapters/doctor.js +1 -25
- 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 +6 -40
- package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
- package/dist/src/app-opentui/adapters/inbox.js +54 -59
- package/dist/src/app-opentui/adapters/init.d.ts +0 -2
- package/dist/src/app-opentui/adapters/init.js +0 -26
- 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 +348 -93
- 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 +97 -44
- package/dist/src/app-opentui/adapters/server.d.ts +10 -2
- package/dist/src/app-opentui/adapters/server.js +96 -27
- package/dist/src/app-opentui/adapters/tasks.d.ts +0 -2
- package/dist/src/app-opentui/adapters/tasks.js +437 -105
- 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.js +24313 -16963
- 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/drone.js +8 -6
- 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/index.js +3438 -1724
- package/dist/src/app-opentui/intent.js +71 -48
- package/dist/src/app-opentui/keymap.d.ts +6 -5
- package/dist/src/app-opentui/keymap.js +1064 -23
- 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 +33 -1
- package/dist/src/app-opentui/pi-pty-host.d.ts +5 -0
- package/dist/src/app-opentui/pi-pty-host.js +21 -3
- package/dist/src/app-opentui/react/App.d.ts +9 -0
- package/dist/src/app-opentui/react/App.js +5099 -0
- package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
- package/dist/src/app-opentui/react/Backdrop.js +829 -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 +5698 -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 +19923 -5151
- 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 +106 -39
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +108 -20
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +7 -0
- package/dist/src/app-opentui/render/image-visual-layer.js +109 -20
- 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/panels.js +18 -11
- package/dist/src/app-opentui/render/preloader.js +8 -6
- package/dist/src/app-opentui/render/scene.d.ts +50 -1
- package/dist/src/app-opentui/render/scene.js +183 -6
- package/dist/src/app-opentui/render/text.d.ts +7 -1
- package/dist/src/app-opentui/render/text.js +10 -7
- package/dist/src/app-opentui/render/type-bar.js +69 -30
- package/dist/src/app-opentui/runtime.d.ts +44 -1
- package/dist/src/app-opentui/runtime.js +3231 -1363
- package/dist/src/app-opentui/scenes/command.js +20 -6
- package/dist/src/app-opentui/scenes/doctor.js +176 -11
- package/dist/src/app-opentui/scenes/error.js +20 -10
- 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 +521 -31
- package/dist/src/app-opentui/scenes/handoff.js +204 -12
- package/dist/src/app-opentui/scenes/help.js +609 -40
- package/dist/src/app-opentui/scenes/inbox.js +278 -17
- package/dist/src/app-opentui/scenes/init.js +84 -39
- 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.js +218 -39
- 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.js +333 -20
- package/dist/src/app-opentui/scenes/server.js +181 -15
- package/dist/src/app-opentui/scenes/tasks.js +486 -31
- 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 +83 -30
- 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/theme.d.ts +28 -6
- package/dist/src/app-opentui/theme.js +61 -8
- package/dist/src/app-opentui/types.d.ts +121 -4
- package/dist/src/commands/_authority-runs.d.ts +1 -1
- package/dist/src/commands/_authority-runs.js +2 -12
- package/dist/src/commands/_help-catalog.js +95 -15
- package/dist/src/commands/_operator-view.js +34 -2
- package/dist/src/commands/_pi-frontend.d.ts +2 -0
- package/dist/src/commands/_pi-frontend.js +34 -0
- package/dist/src/commands/_server-events.d.ts +26 -0
- package/dist/src/commands/_server-events.js +310 -0
- package/dist/src/commands/agent.js +2 -12
- package/dist/src/commands/run.js +34 -2
- package/dist/src/commands/server.js +2 -12
- package/dist/src/commands/stats.js +95 -15
- package/dist/src/commands/task-run-driver.js +2 -12
- package/dist/src/commands/task.js +131 -29
- package/dist/src/commands.js +192 -31
- package/dist/src/index.js +192 -31
- package/package.json +11 -9
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/app-opentui/react/Backdrop.tsx
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { useRenderer } from "@opentui/react";
|
|
5
|
+
|
|
6
|
+
// packages/cli/src/app-opentui/layout.ts
|
|
7
|
+
var MIN_TERMINAL_WIDTH = 48;
|
|
8
|
+
var MIN_TERMINAL_HEIGHT = 16;
|
|
9
|
+
function computeStageLayout(width, height) {
|
|
10
|
+
const rawWidth = Math.trunc(width || 80);
|
|
11
|
+
const rawHeight = Math.trunc(height || 24);
|
|
12
|
+
const tooSmall = rawWidth < MIN_TERMINAL_WIDTH || rawHeight < MIN_TERMINAL_HEIGHT;
|
|
13
|
+
const safeWidth = Math.max(40, rawWidth);
|
|
14
|
+
const safeHeight = Math.max(18, rawHeight);
|
|
15
|
+
const compact = safeWidth < 92 || safeHeight < 30;
|
|
16
|
+
const horizontalGutter = compact ? 1 : 2;
|
|
17
|
+
const centerWidth = Math.max(36, safeWidth - horizontalGutter * 2);
|
|
18
|
+
const centerLeft = horizontalGutter;
|
|
19
|
+
const footerTop = Math.max(0, safeHeight - 1);
|
|
20
|
+
const typeBarTop = Math.max(0, footerTop - 1);
|
|
21
|
+
const centerTop = compact ? 1 : Math.max(1, Math.floor(safeHeight * 0.055));
|
|
22
|
+
const centerHeight = Math.max(6, typeBarTop - centerTop);
|
|
23
|
+
return { width: safeWidth, height: safeHeight, centerWidth, centerLeft, centerTop, centerHeight, typeBarTop, footerTop, compact, tooSmall };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// packages/cli/src/app-opentui/render/graphics.ts
|
|
27
|
+
import { FrameBufferRenderable, RGBA } from "@opentui/core";
|
|
28
|
+
|
|
29
|
+
// packages/cli/src/app-opentui/theme.ts
|
|
30
|
+
import {
|
|
31
|
+
bold as otuiBold,
|
|
32
|
+
dim as otuiDim,
|
|
33
|
+
fg as otuiFg,
|
|
34
|
+
t,
|
|
35
|
+
TextAttributes
|
|
36
|
+
} from "@opentui/core";
|
|
37
|
+
var RIG_UI = {
|
|
38
|
+
bg: "#070809",
|
|
39
|
+
bg2: "#0b0c0e",
|
|
40
|
+
panel: "#101115",
|
|
41
|
+
panel2: "#14161b",
|
|
42
|
+
glass: "#1e2230",
|
|
43
|
+
border: "#2a2e3a",
|
|
44
|
+
ink: "#f4f5f8",
|
|
45
|
+
ink2: "#c7c9d3",
|
|
46
|
+
ink3: "#9aa0ae",
|
|
47
|
+
ink4: "#787b86",
|
|
48
|
+
lime: "#ccff4d",
|
|
49
|
+
limeDim: "#a9d63f",
|
|
50
|
+
cyan: "#56d8ff",
|
|
51
|
+
cyanDim: "#3f9fbd",
|
|
52
|
+
red: "#ff5d5d",
|
|
53
|
+
yellow: "#ffd24d",
|
|
54
|
+
magenta: "#ff79b0"
|
|
55
|
+
};
|
|
56
|
+
var styles = {
|
|
57
|
+
ink: otuiFg(RIG_UI.ink),
|
|
58
|
+
ink2: otuiFg(RIG_UI.ink2),
|
|
59
|
+
ink3: otuiFg(RIG_UI.ink3),
|
|
60
|
+
ink4: otuiFg(RIG_UI.ink4),
|
|
61
|
+
lime: otuiFg(RIG_UI.lime),
|
|
62
|
+
limeDim: otuiFg(RIG_UI.limeDim),
|
|
63
|
+
cyan: otuiFg(RIG_UI.cyan),
|
|
64
|
+
red: otuiFg(RIG_UI.red),
|
|
65
|
+
yellow: otuiFg(RIG_UI.yellow),
|
|
66
|
+
magenta: otuiFg(RIG_UI.magenta)
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// packages/cli/src/app-opentui/render/ascii-fleet.ts
|
|
70
|
+
var LEAD_DRONE = [
|
|
71
|
+
" .-=-. .-=-. ",
|
|
72
|
+
" ( !!! ) ( !!! ) ",
|
|
73
|
+
" '-=-'._ _.'-=-' ",
|
|
74
|
+
" '._ _.' ",
|
|
75
|
+
" '=$$$$$$$=.' ",
|
|
76
|
+
" =$$$$$$$$$$$= ",
|
|
77
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
78
|
+
" $$$@@ @@$$$ ",
|
|
79
|
+
" $$@ ? @$$$ ",
|
|
80
|
+
" $$$@ '-' @$$$ ",
|
|
81
|
+
" $$$@@ @@$$$ ",
|
|
82
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
83
|
+
" =$$$$$$$$$$$= ",
|
|
84
|
+
" '=$$$$$$$=.' ",
|
|
85
|
+
" _.' '._ ",
|
|
86
|
+
" .-=-.' '.-=-. ",
|
|
87
|
+
" ( !!! ) ( !!! ) ",
|
|
88
|
+
" '-=-' '-=-' "
|
|
89
|
+
];
|
|
90
|
+
var MINI_DRONE = [
|
|
91
|
+
"(!!!) (!!!)",
|
|
92
|
+
" \\%==%/ ",
|
|
93
|
+
" %%?%% ",
|
|
94
|
+
" /%==%\\ ",
|
|
95
|
+
"(!!!) (!!!)"
|
|
96
|
+
];
|
|
97
|
+
var ROTORS = ["---", "\\\\\\", "|||", "///"];
|
|
98
|
+
var FLEET_GRID_WIDTH = 52;
|
|
99
|
+
var FLEET_GRID_HEIGHT = 27;
|
|
100
|
+
var FLEET = [
|
|
101
|
+
{ art: MINI_DRONE, x: 0, y: 2, amp: 1, speed: 0.05, phase: 0, dx: 1, driftSpeed: 0.02 },
|
|
102
|
+
{ art: MINI_DRONE, x: 39, y: 2, amp: 1, speed: 0.044, phase: 2.1, dx: 1, driftSpeed: 0.017 },
|
|
103
|
+
{ art: MINI_DRONE, x: 1, y: 20, amp: 1, speed: 0.048, phase: 4.2, dx: 1, driftSpeed: 0.023 },
|
|
104
|
+
{ art: MINI_DRONE, x: 38, y: 20, amp: 1, speed: 0.041, phase: 1.3, dx: 1, driftSpeed: 0.015 },
|
|
105
|
+
{ art: LEAD_DRONE, x: 10, y: 5, amp: 2, speed: 0.04, phase: 0, dx: 0, driftSpeed: 0.011 }
|
|
106
|
+
];
|
|
107
|
+
function fleetRows(tick, options = {}) {
|
|
108
|
+
const animate = options.animate ?? true;
|
|
109
|
+
const t2 = animate ? tick : 0;
|
|
110
|
+
const blade = ROTORS[Math.floor(t2 / 4) % ROTORS.length];
|
|
111
|
+
const pulse = Math.sin(t2 * 0.07);
|
|
112
|
+
const eye = pulse > 0.45 ? "@" : pulse > -0.1 ? "o" : ".";
|
|
113
|
+
const grid = Array.from({ length: FLEET_GRID_HEIGHT }, () => Array.from({ length: FLEET_GRID_WIDTH }, () => " "));
|
|
114
|
+
for (const drone of FLEET) {
|
|
115
|
+
const yOffset = drone.y + Math.round(drone.amp * Math.sin(t2 * drone.speed + drone.phase));
|
|
116
|
+
const xOffset = drone.x + Math.round(drone.dx * Math.sin(t2 * drone.driftSpeed + drone.phase));
|
|
117
|
+
for (let row = 0;row < drone.art.length; row += 1) {
|
|
118
|
+
const source = drone.art[row];
|
|
119
|
+
const targetY = yOffset + row;
|
|
120
|
+
if (targetY < 0 || targetY >= FLEET_GRID_HEIGHT)
|
|
121
|
+
continue;
|
|
122
|
+
for (let col = 0;col < source.length; col += 1) {
|
|
123
|
+
let char = source[col];
|
|
124
|
+
if (char === " ")
|
|
125
|
+
continue;
|
|
126
|
+
const targetX = xOffset + col;
|
|
127
|
+
if (targetX < 0 || targetX >= FLEET_GRID_WIDTH)
|
|
128
|
+
continue;
|
|
129
|
+
if (source.slice(col, col + 3) === "!!!") {
|
|
130
|
+
for (let rotorIndex = 0;rotorIndex < 3; rotorIndex += 1) {
|
|
131
|
+
if (targetX + rotorIndex < FLEET_GRID_WIDTH)
|
|
132
|
+
grid[targetY][targetX + rotorIndex] = blade[rotorIndex];
|
|
133
|
+
}
|
|
134
|
+
col += 2;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (char === "?")
|
|
138
|
+
char = eye;
|
|
139
|
+
grid[targetY][targetX] = char;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return grid.map((row) => row.join("").replace(/\s+$/, ""));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// packages/cli/src/app-opentui/render/panel-layout.ts
|
|
147
|
+
function panelCellRect(layout, panel) {
|
|
148
|
+
const left = Math.max(0, Math.min(layout.width - 1, layout.centerLeft + (panel.left ?? 0)));
|
|
149
|
+
const desiredWidth = panel.width ?? layout.centerWidth;
|
|
150
|
+
const width = Math.max(1, Math.min(layout.width - left, desiredWidth));
|
|
151
|
+
const top = Math.max(0, Math.min(layout.height - 1, layout.centerTop + panel.top));
|
|
152
|
+
const height = Math.max(1, Math.min(layout.height - top, panel.height));
|
|
153
|
+
if (width <= 3 || height <= 3)
|
|
154
|
+
return null;
|
|
155
|
+
const right = left + width - 1;
|
|
156
|
+
const bottom = top + height - 1;
|
|
157
|
+
const headerHeight = panel.chrome === "ad-terminal" ? Math.max(3, Math.min(height - 2, panel.headerHeight ?? 3)) : 0;
|
|
158
|
+
const dividerY = headerHeight ? Math.min(bottom - 1, top + headerHeight) : top;
|
|
159
|
+
return { left, top, width, height, right, bottom, headerHeight, dividerY };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// packages/cli/src/app-opentui/render/constants.ts
|
|
163
|
+
var LCG_MULTIPLIER = 1664525;
|
|
164
|
+
var LCG_INCREMENT = 1013904223;
|
|
165
|
+
var LCG_DIVISOR = 4294967295;
|
|
166
|
+
var PACKET_CYAN_PROBABILITY = 0.22;
|
|
167
|
+
var LANE_INTERP_STEPS = 32;
|
|
168
|
+
var LANE_LEN_BASE = 0.32;
|
|
169
|
+
var LANE_LEN_SPREAD = 0.42;
|
|
170
|
+
var LANE_CURVE_RANGE = 0.7;
|
|
171
|
+
var PACKET_SPEED_BASE = 0.003;
|
|
172
|
+
var PACKET_SPEED_SPREAD = 0.009;
|
|
173
|
+
var DISPATCH_LANES_COMPACT = 7;
|
|
174
|
+
var DISPATCH_LANES_WIDE = 12;
|
|
175
|
+
var DISPATCH_PACKETS_COMPACT = 70;
|
|
176
|
+
var DISPATCH_PACKETS_WIDE = 150;
|
|
177
|
+
var CARRIER_NODES_COMPACT = 5;
|
|
178
|
+
var CARRIER_NODES_WIDE = 7;
|
|
179
|
+
var LOOP_GATES_COMPACT = 4;
|
|
180
|
+
var LOOP_GATES_WIDE = 5;
|
|
181
|
+
var DISPATCH_DRONES_COMPACT = 4;
|
|
182
|
+
var DISPATCH_DRONES_WIDE = 8;
|
|
183
|
+
var CORE_DISPATCH_X = 0.3;
|
|
184
|
+
var CORE_DISPATCH_Y = 0.45;
|
|
185
|
+
var CORE_CARRIER_X = 0.5;
|
|
186
|
+
var CORE_CARRIER_Y = 0.54;
|
|
187
|
+
var CORE_LOOP_X = 0.09;
|
|
188
|
+
var CORE_LOOP_Y = 0.56;
|
|
189
|
+
var RAIL_YS_LOOP = [0.18, 0.5, 0.82];
|
|
190
|
+
var RAIL_YS_CARRIER = [0.24, 0.54, 0.82];
|
|
191
|
+
var RAIL_YS_DISPATCH = [0.18, 0.58, 0.82];
|
|
192
|
+
var GLOW_FALLOFF_EXP_ASCII = 2.2;
|
|
193
|
+
|
|
194
|
+
// packages/cli/src/app-opentui/render/graphics.ts
|
|
195
|
+
var BRAILLE_SAMPLES_X = 2;
|
|
196
|
+
var BRAILLE_SAMPLES_Y = 4;
|
|
197
|
+
var TRANSPARENT = RGBA.fromValues(0, 0, 0, 0);
|
|
198
|
+
var BACKDROP = RGBA.fromHex(RIG_UI.bg);
|
|
199
|
+
var PANEL_BG = RGBA.fromInts(16, 17, 21, 184);
|
|
200
|
+
var PANEL_HEADER_BG = RGBA.fromInts(16, 17, 21, 188);
|
|
201
|
+
var PANEL_LINE = RGBA.fromInts(255, 255, 255, 20);
|
|
202
|
+
var PANEL_LINE_DIM = RGBA.fromInts(255, 255, 255, 8);
|
|
203
|
+
var PANEL_TEXT_DIM = RGBA.fromInts(108, 110, 121, 255);
|
|
204
|
+
var AC_RGB = [204, 255, 77];
|
|
205
|
+
var C2_RGB = [86, 216, 255];
|
|
206
|
+
var MG_RGB = [255, 121, 176];
|
|
207
|
+
var INK_RGB = [108, 110, 121];
|
|
208
|
+
var BRAILLE_BITS = [
|
|
209
|
+
[1, 8],
|
|
210
|
+
[2, 16],
|
|
211
|
+
[4, 32],
|
|
212
|
+
[64, 128]
|
|
213
|
+
];
|
|
214
|
+
function sceneKind(scene) {
|
|
215
|
+
if (scene === "tasks")
|
|
216
|
+
return "loop";
|
|
217
|
+
if (scene === "help")
|
|
218
|
+
return "carrier";
|
|
219
|
+
return "dispatch";
|
|
220
|
+
}
|
|
221
|
+
function seeded(seed) {
|
|
222
|
+
let value = seed >>> 0;
|
|
223
|
+
return () => {
|
|
224
|
+
value = value * LCG_MULTIPLIER + LCG_INCREMENT >>> 0;
|
|
225
|
+
return value / LCG_DIVISOR;
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function channelBuffer(canvas, channel) {
|
|
229
|
+
switch (channel) {
|
|
230
|
+
case 0:
|
|
231
|
+
return canvas.ac;
|
|
232
|
+
case 1:
|
|
233
|
+
return canvas.c2;
|
|
234
|
+
case 2:
|
|
235
|
+
return canvas.mg;
|
|
236
|
+
case 3:
|
|
237
|
+
return canvas.ink;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function addSample(canvas, channel, x, y, value) {
|
|
241
|
+
const ix = Math.trunc(x);
|
|
242
|
+
const iy = Math.trunc(y);
|
|
243
|
+
if (ix < 0 || iy < 0 || ix >= canvas.width || iy >= canvas.height)
|
|
244
|
+
return;
|
|
245
|
+
const buffer = channelBuffer(canvas, channel);
|
|
246
|
+
const index = iy * canvas.width + ix;
|
|
247
|
+
buffer[index] = Math.min(1, buffer[index] + value);
|
|
248
|
+
}
|
|
249
|
+
function drawDot(canvas, channel, cx, cy, radius, value) {
|
|
250
|
+
const minX = Math.floor(cx - radius);
|
|
251
|
+
const maxX = Math.ceil(cx + radius);
|
|
252
|
+
const minY = Math.floor(cy - radius);
|
|
253
|
+
const maxY = Math.ceil(cy + radius);
|
|
254
|
+
for (let y = minY;y <= maxY; y += 1) {
|
|
255
|
+
for (let x = minX;x <= maxX; x += 1) {
|
|
256
|
+
const dx = x - cx;
|
|
257
|
+
const dy = y - cy;
|
|
258
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
259
|
+
if (distance > radius)
|
|
260
|
+
continue;
|
|
261
|
+
const falloff = 1 - distance / Math.max(0.001, radius);
|
|
262
|
+
addSample(canvas, channel, x, y, value * (0.28 + falloff * 0.72));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function drawGlow(canvas, channel, cx, cy, radius, value) {
|
|
267
|
+
const minX = Math.floor(cx - radius);
|
|
268
|
+
const maxX = Math.ceil(cx + radius);
|
|
269
|
+
const minY = Math.floor(cy - radius);
|
|
270
|
+
const maxY = Math.ceil(cy + radius);
|
|
271
|
+
for (let y = minY;y <= maxY; y += 1) {
|
|
272
|
+
for (let x = minX;x <= maxX; x += 1) {
|
|
273
|
+
const dx = x - cx;
|
|
274
|
+
const dy = y - cy;
|
|
275
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
276
|
+
if (distance > radius)
|
|
277
|
+
continue;
|
|
278
|
+
const falloff = Math.pow(1 - distance / Math.max(0.001, radius), GLOW_FALLOFF_EXP_ASCII);
|
|
279
|
+
addSample(canvas, channel, x, y, value * falloff);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function drawLine(canvas, channel, x0, y0, x1, y1, value, width = 0.8) {
|
|
284
|
+
const dx = x1 - x0;
|
|
285
|
+
const dy = y1 - y0;
|
|
286
|
+
const steps = Math.max(1, Math.ceil(Math.hypot(dx, dy) * 1.7));
|
|
287
|
+
for (let step = 0;step <= steps; step += 1) {
|
|
288
|
+
const t2 = step / steps;
|
|
289
|
+
const x = x0 + dx * t2;
|
|
290
|
+
const y = y0 + dy * t2;
|
|
291
|
+
drawDot(canvas, channel, x, y, width, value);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function drawCircleStroke(canvas, channel, cx, cy, radius, value) {
|
|
295
|
+
const steps = Math.max(18, Math.ceil(radius * 8));
|
|
296
|
+
for (let step = 0;step < steps; step += 1) {
|
|
297
|
+
const a = step / steps * Math.PI * 2;
|
|
298
|
+
drawDot(canvas, channel, cx + Math.cos(a) * radius, cy + Math.sin(a) * radius, 0.72, value);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function paletteColor(ac, c2, mg, ink) {
|
|
302
|
+
const total = Math.max(0.001, ac + c2 + mg + ink);
|
|
303
|
+
const r = (AC_RGB[0] * ac + C2_RGB[0] * c2 + MG_RGB[0] * mg + INK_RGB[0] * ink) / total;
|
|
304
|
+
const g = (AC_RGB[1] * ac + C2_RGB[1] * c2 + MG_RGB[1] * mg + INK_RGB[1] * ink) / total;
|
|
305
|
+
const b = (AC_RGB[2] * ac + C2_RGB[2] * c2 + MG_RGB[2] * mg + INK_RGB[2] * ink) / total;
|
|
306
|
+
const intensity = Math.min(1, total / 4);
|
|
307
|
+
const lift = 0.34 + intensity * 0.66;
|
|
308
|
+
return RGBA.fromInts(Math.round(r * lift), Math.round(g * lift), Math.round(b * lift), 255);
|
|
309
|
+
}
|
|
310
|
+
function clearCanvas(canvas) {
|
|
311
|
+
canvas.ac.fill(0);
|
|
312
|
+
canvas.c2.fill(0);
|
|
313
|
+
canvas.mg.fill(0);
|
|
314
|
+
canvas.ink.fill(0);
|
|
315
|
+
}
|
|
316
|
+
function makeCanvas(layout) {
|
|
317
|
+
const width = Math.max(1, layout.width * BRAILLE_SAMPLES_X);
|
|
318
|
+
const height = Math.max(1, layout.height * BRAILLE_SAMPLES_Y);
|
|
319
|
+
const size = width * height;
|
|
320
|
+
return {
|
|
321
|
+
width,
|
|
322
|
+
height,
|
|
323
|
+
ac: new Float32Array(size),
|
|
324
|
+
c2: new Float32Array(size),
|
|
325
|
+
mg: new Float32Array(size),
|
|
326
|
+
ink: new Float32Array(size)
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
class MarketingGlyphCanvas {
|
|
331
|
+
rand = seeded(6221137);
|
|
332
|
+
canvas;
|
|
333
|
+
layout;
|
|
334
|
+
activeKind = null;
|
|
335
|
+
lanes = [];
|
|
336
|
+
motes = [];
|
|
337
|
+
packets = [];
|
|
338
|
+
constructor(layout) {
|
|
339
|
+
this.layout = layout;
|
|
340
|
+
this.canvas = makeCanvas(layout);
|
|
341
|
+
this.reset("dispatch");
|
|
342
|
+
}
|
|
343
|
+
resize(layout) {
|
|
344
|
+
if (layout.width === this.layout.width && layout.height === this.layout.height)
|
|
345
|
+
return;
|
|
346
|
+
this.layout = layout;
|
|
347
|
+
this.canvas = makeCanvas(layout);
|
|
348
|
+
this.reset(this.activeKind ?? "dispatch");
|
|
349
|
+
}
|
|
350
|
+
render(layer, scene, tick) {
|
|
351
|
+
const kind = sceneKind(scene);
|
|
352
|
+
if (kind !== this.activeKind)
|
|
353
|
+
this.reset(kind);
|
|
354
|
+
clearCanvas(this.canvas);
|
|
355
|
+
this.drawMarketingRails(kind, tick);
|
|
356
|
+
if (kind === "loop")
|
|
357
|
+
this.drawLoop(tick);
|
|
358
|
+
else if (kind === "carrier")
|
|
359
|
+
this.drawCarrier(tick);
|
|
360
|
+
else
|
|
361
|
+
this.drawDispatch(tick);
|
|
362
|
+
this.blit(layer);
|
|
363
|
+
}
|
|
364
|
+
reset(kind) {
|
|
365
|
+
this.activeKind = kind;
|
|
366
|
+
this.lanes = [];
|
|
367
|
+
this.motes = [];
|
|
368
|
+
this.packets = [];
|
|
369
|
+
if (kind === "dispatch")
|
|
370
|
+
this.setupDispatch();
|
|
371
|
+
else if (kind === "loop")
|
|
372
|
+
this.setupLoop();
|
|
373
|
+
else
|
|
374
|
+
this.setupCarrier();
|
|
375
|
+
}
|
|
376
|
+
setupDispatch() {
|
|
377
|
+
const count = this.layout.compact ? DISPATCH_LANES_COMPACT : DISPATCH_LANES_WIDE;
|
|
378
|
+
for (let i = 0;i < count; i += 1) {
|
|
379
|
+
const ang = (-0.9 + 1.8 * (i / Math.max(1, count - 1))) * (Math.PI * 0.5);
|
|
380
|
+
this.lanes.push({ ang, len: this.canvas.width * (LANE_LEN_BASE + this.rand() * LANE_LEN_SPREAD), curve: (this.rand() - 0.5) * LANE_CURVE_RANGE, phase: this.rand() * Math.PI * 2 });
|
|
381
|
+
}
|
|
382
|
+
const packets = this.layout.compact ? DISPATCH_PACKETS_COMPACT : DISPATCH_PACKETS_WIDE;
|
|
383
|
+
for (let i = 0;i < packets; i += 1)
|
|
384
|
+
this.packets.push(this.packet(true));
|
|
385
|
+
}
|
|
386
|
+
setupLoop() {
|
|
387
|
+
const lanes = this.layout.compact ? 4 : 7;
|
|
388
|
+
for (let i = 0;i < lanes; i += 1)
|
|
389
|
+
this.packets.push(this.packet(true));
|
|
390
|
+
}
|
|
391
|
+
setupCarrier() {
|
|
392
|
+
const nodes = this.layout.compact ? CARRIER_NODES_COMPACT : CARRIER_NODES_WIDE;
|
|
393
|
+
for (let i = 0;i < nodes * 6; i += 1)
|
|
394
|
+
this.packets.push(this.packet(true));
|
|
395
|
+
}
|
|
396
|
+
packet(random = false) {
|
|
397
|
+
return {
|
|
398
|
+
lane: Math.floor(this.rand() * Math.max(1, this.lanes.length || 7)),
|
|
399
|
+
p: random ? this.rand() : 0,
|
|
400
|
+
spd: PACKET_SPEED_BASE + this.rand() * PACKET_SPEED_SPREAD,
|
|
401
|
+
channel: this.rand() < PACKET_CYAN_PROBABILITY ? 1 : 0,
|
|
402
|
+
wobble: (this.rand() - 0.5) * 7,
|
|
403
|
+
size: 0.8 + this.rand() * 1.3
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
core(kind) {
|
|
407
|
+
if (kind === "dispatch")
|
|
408
|
+
return { x: this.canvas.width * CORE_DISPATCH_X, y: this.canvas.height * CORE_DISPATCH_Y };
|
|
409
|
+
if (kind === "carrier")
|
|
410
|
+
return { x: this.canvas.width * CORE_CARRIER_X, y: this.canvas.height * CORE_CARRIER_Y };
|
|
411
|
+
return { x: this.canvas.width * CORE_LOOP_X, y: this.canvas.height * CORE_LOOP_Y };
|
|
412
|
+
}
|
|
413
|
+
lanePoint(lane, p, kind = "dispatch") {
|
|
414
|
+
const core = this.core(kind);
|
|
415
|
+
const dist = lane.len * p;
|
|
416
|
+
const bend = Math.sin(p * Math.PI) * lane.curve * 28;
|
|
417
|
+
const ux = Math.cos(lane.ang);
|
|
418
|
+
const uy = Math.sin(lane.ang);
|
|
419
|
+
return { x: core.x + ux * dist + -uy * bend, y: core.y + uy * dist + ux * bend };
|
|
420
|
+
}
|
|
421
|
+
drawMotes(tick) {
|
|
422
|
+
for (const mote of this.motes) {
|
|
423
|
+
mote.x += 0.1 * mote.z;
|
|
424
|
+
if (mote.x > this.canvas.width + 2)
|
|
425
|
+
mote.x = -2;
|
|
426
|
+
const alpha = (0.035 + 0.08 * mote.z) * (0.55 + 0.45 * Math.sin(tick * 0.03 + mote.tw));
|
|
427
|
+
drawDot(this.canvas, mote.channel, mote.x, mote.y, 0.45 * mote.z, alpha);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
drawMarketingRails(kind, tick) {
|
|
431
|
+
const ys = kind === "loop" ? RAIL_YS_LOOP : kind === "carrier" ? RAIL_YS_CARRIER : RAIL_YS_DISPATCH;
|
|
432
|
+
ys.forEach((ratio, index) => {
|
|
433
|
+
const y = this.canvas.height * ratio + Math.sin(tick * 0.018 + index) * 1.8;
|
|
434
|
+
drawLine(this.canvas, index === 1 ? 0 : 1, this.canvas.width * 0.06, y, this.canvas.width * 0.94, y + Math.sin(index) * 2, index === 1 ? 0.11 : 0.07, 0.55);
|
|
435
|
+
for (let p = (tick * 0.004 + index * 0.21) % 1;p < 1; p += 0.18 + index * 0.02) {
|
|
436
|
+
const x = this.canvas.width * (0.06 + 0.88 * p);
|
|
437
|
+
drawDot(this.canvas, index === 2 ? 1 : 0, x, y, 1 + index * 0.25, 0.24);
|
|
438
|
+
drawGlow(this.canvas, index === 2 ? 1 : 0, x, y, 3.8, 0.035);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
drawDispatch(tick) {
|
|
443
|
+
const core = this.core("dispatch");
|
|
444
|
+
drawGlow(this.canvas, 0, core.x, core.y, 30, 0.12);
|
|
445
|
+
drawDot(this.canvas, 0, core.x, core.y, 2.2, 0.85);
|
|
446
|
+
for (const lane of this.lanes) {
|
|
447
|
+
let prev = this.lanePoint(lane, 0);
|
|
448
|
+
for (let i = 1;i <= LANE_INTERP_STEPS; i += 1) {
|
|
449
|
+
const next = this.lanePoint(lane, i / LANE_INTERP_STEPS);
|
|
450
|
+
drawLine(this.canvas, lane.phase > Math.PI ? 1 : 0, prev.x, prev.y, next.x, next.y, 0.045, 0.38);
|
|
451
|
+
prev = next;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
for (const packet of this.packets) {
|
|
455
|
+
packet.p += packet.spd;
|
|
456
|
+
if (packet.p > 1)
|
|
457
|
+
Object.assign(packet, this.packet(false));
|
|
458
|
+
const lane = this.lanes[packet.lane % Math.max(1, this.lanes.length)];
|
|
459
|
+
if (!lane)
|
|
460
|
+
continue;
|
|
461
|
+
const pt = this.lanePoint(lane, packet.p);
|
|
462
|
+
const fade = packet.p < 0.1 ? packet.p / 0.1 : packet.p > 0.88 ? (1 - packet.p) / 0.12 : 1;
|
|
463
|
+
const y = pt.y + packet.wobble * Math.sin(packet.p * Math.PI * 2);
|
|
464
|
+
drawLine(this.canvas, packet.channel, pt.x - 4, y - 1, pt.x, y, 0.08 * fade, 0.38);
|
|
465
|
+
drawDot(this.canvas, packet.channel, pt.x, y, packet.size, 0.5 * fade);
|
|
466
|
+
drawGlow(this.canvas, packet.channel, pt.x, y, packet.size * 4, 0.045 * fade);
|
|
467
|
+
}
|
|
468
|
+
for (let i = 0;i < (this.layout.compact ? DISPATCH_DRONES_COMPACT : DISPATCH_DRONES_WIDE); i += 1) {
|
|
469
|
+
const lane = this.lanes[i % Math.max(1, this.lanes.length)];
|
|
470
|
+
if (!lane)
|
|
471
|
+
continue;
|
|
472
|
+
const p = (tick * 0.002 + i * 0.13) % 1;
|
|
473
|
+
const pt = this.lanePoint(lane, p);
|
|
474
|
+
this.drawDrone(pt.x, pt.y + Math.sin(tick * 0.04 + i) * 2, 2.6 + i % 2 * 0.6, tick + i * 11, i % 3 === 0 ? 1 : 0);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
drawLoop(tick) {
|
|
478
|
+
const y = this.canvas.height * 0.56;
|
|
479
|
+
const x0 = this.canvas.width * 0.09;
|
|
480
|
+
const x1 = this.canvas.width * 0.91;
|
|
481
|
+
drawLine(this.canvas, 0, x0, y, x1, y, 0.12, 0.55);
|
|
482
|
+
const gates = this.layout.compact ? LOOP_GATES_COMPACT : LOOP_GATES_WIDE;
|
|
483
|
+
const active = Math.floor(tick / 16) % gates;
|
|
484
|
+
for (let i = 0;i < gates; i += 1) {
|
|
485
|
+
const x = x0 + (x1 - x0) * (i / Math.max(1, gates - 1));
|
|
486
|
+
drawLine(this.canvas, i === active ? 0 : 3, x, y - 22, x, y + 22, i === active ? 0.25 : 0.08, i === active ? 0.7 : 0.42);
|
|
487
|
+
drawDot(this.canvas, i <= active ? 0 : 3, x, y, i === active ? 2.2 : 1.2, i === active ? 0.72 : 0.25);
|
|
488
|
+
drawCircleStroke(this.canvas, i <= active ? 0 : 3, x, y, i === active ? 4.2 : 2.4, i === active ? 0.18 : 0.08);
|
|
489
|
+
}
|
|
490
|
+
for (const packet of this.packets) {
|
|
491
|
+
packet.p += packet.spd * 0.7;
|
|
492
|
+
if (packet.p > 1)
|
|
493
|
+
packet.p = 0;
|
|
494
|
+
const x = x0 + (x1 - x0) * packet.p;
|
|
495
|
+
const segment = Math.min(gates - 1, Math.floor(packet.p * gates));
|
|
496
|
+
const channel = segment < active ? 0 : segment === active ? 1 : 3;
|
|
497
|
+
const py = y + packet.wobble * Math.sin(packet.p * Math.PI * 2);
|
|
498
|
+
drawLine(this.canvas, channel, x - 6, py, x, py, 0.1, 0.42);
|
|
499
|
+
drawDot(this.canvas, channel, x, py, packet.size, channel === 3 ? 0.22 : 0.58);
|
|
500
|
+
drawGlow(this.canvas, channel, x, py, 3.8, channel === 3 ? 0.02 : 0.04);
|
|
501
|
+
}
|
|
502
|
+
this.drawDrone(x0 + (x1 - x0) * (tick * 0.003 % 1), y - 18, 2.7, tick, 0);
|
|
503
|
+
this.drawDrone(x0 + (x1 - x0) * ((tick * 0.002 + 0.5) % 1), y + 16, 2.2, tick + 40, 2);
|
|
504
|
+
}
|
|
505
|
+
drawCarrier(tick) {
|
|
506
|
+
const core = this.core("carrier");
|
|
507
|
+
drawGlow(this.canvas, 0, core.x, core.y, 26, 0.12);
|
|
508
|
+
drawDot(this.canvas, 0, core.x, core.y, 2.4, 0.92);
|
|
509
|
+
drawCircleStroke(this.canvas, 0, core.x, core.y, 8 + Math.sin(tick * 0.06) * 2, 0.14);
|
|
510
|
+
const nodes = this.layout.compact ? CARRIER_NODES_COMPACT : CARRIER_NODES_WIDE;
|
|
511
|
+
const rx = this.canvas.width * 0.36;
|
|
512
|
+
const ry = this.canvas.height * 0.22;
|
|
513
|
+
for (let i = 0;i < nodes; i += 1) {
|
|
514
|
+
const a = i / nodes * Math.PI * 2 - Math.PI / 2 + tick * 0.006;
|
|
515
|
+
const x = core.x + Math.cos(a) * rx;
|
|
516
|
+
const y = core.y + Math.sin(a) * ry;
|
|
517
|
+
drawLine(this.canvas, i % 2 ? 1 : 0, core.x, core.y, x, y, 0.055, 0.36);
|
|
518
|
+
drawCircleStroke(this.canvas, i % 2 ? 1 : 0, x, y, 4.2, 0.15);
|
|
519
|
+
drawDot(this.canvas, i % 2 ? 1 : 0, x, y, 1.7, 0.62);
|
|
520
|
+
this.drawDrone(x, y - 8, 2.1, tick + i * 9, i % 2 ? 1 : 0);
|
|
521
|
+
}
|
|
522
|
+
for (const packet of this.packets) {
|
|
523
|
+
packet.p += packet.spd;
|
|
524
|
+
if (packet.p > 1)
|
|
525
|
+
packet.p = 0;
|
|
526
|
+
const lane = packet.lane % nodes;
|
|
527
|
+
const a = lane / nodes * Math.PI * 2 - Math.PI / 2 + tick * 0.006;
|
|
528
|
+
const nx = core.x + Math.cos(a) * rx;
|
|
529
|
+
const ny = core.y + Math.sin(a) * ry;
|
|
530
|
+
const x = core.x + (nx - core.x) * packet.p;
|
|
531
|
+
const y = core.y + (ny - core.y) * packet.p;
|
|
532
|
+
drawDot(this.canvas, packet.channel, x, y, packet.size, 0.48);
|
|
533
|
+
drawGlow(this.canvas, packet.channel, x, y, 3.2, 0.035);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
drawDrone(x, y, scale, tick, channel) {
|
|
537
|
+
const wobble = Math.sin(tick * 0.08) * 0.7;
|
|
538
|
+
drawDot(this.canvas, channel, x, y + wobble, scale, 0.58);
|
|
539
|
+
drawDot(this.canvas, 3, x, y + wobble, Math.max(0.6, scale * 0.28), 0.42);
|
|
540
|
+
const rotor = scale * 1.75;
|
|
541
|
+
const arms = [
|
|
542
|
+
[-rotor, -rotor * 0.75],
|
|
543
|
+
[rotor, -rotor * 0.75],
|
|
544
|
+
[-rotor, rotor * 0.75],
|
|
545
|
+
[rotor, rotor * 0.75]
|
|
546
|
+
];
|
|
547
|
+
for (const [dx, dy] of arms) {
|
|
548
|
+
drawLine(this.canvas, channel, x, y + wobble, x + dx, y + dy + wobble, 0.11, 0.38);
|
|
549
|
+
drawCircleStroke(this.canvas, channel, x + dx, y + dy + wobble, scale * (0.65 + Math.abs(Math.sin(tick * 0.18)) * 0.25), 0.16);
|
|
550
|
+
drawDot(this.canvas, channel, x + dx, y + dy + wobble, 0.7, 0.25);
|
|
551
|
+
}
|
|
552
|
+
drawLine(this.canvas, channel === 1 ? 0 : 1, x - rotor * 2.4, y + wobble + 1.2, x - rotor * 1.2, y + wobble, 0.05, 0.35);
|
|
553
|
+
}
|
|
554
|
+
blit(layer) {
|
|
555
|
+
const fb = layer.frameBuffer;
|
|
556
|
+
fb.clear(BACKDROP);
|
|
557
|
+
const { width, height, ac, c2, mg, ink } = this.canvas;
|
|
558
|
+
for (let cy = 0;cy < this.layout.height; cy += 1) {
|
|
559
|
+
for (let cx = 0;cx < this.layout.width; cx += 1) {
|
|
560
|
+
let bits = 0;
|
|
561
|
+
let acSum = 0;
|
|
562
|
+
let c2Sum = 0;
|
|
563
|
+
let mgSum = 0;
|
|
564
|
+
let inkSum = 0;
|
|
565
|
+
for (let sy = 0;sy < BRAILLE_SAMPLES_Y; sy += 1) {
|
|
566
|
+
for (let sx = 0;sx < BRAILLE_SAMPLES_X; sx += 1) {
|
|
567
|
+
const px = cx * BRAILLE_SAMPLES_X + sx;
|
|
568
|
+
const py = cy * BRAILLE_SAMPLES_Y + sy;
|
|
569
|
+
if (px >= width || py >= height)
|
|
570
|
+
continue;
|
|
571
|
+
const index = py * width + px;
|
|
572
|
+
const a = ac[index];
|
|
573
|
+
const c = c2[index];
|
|
574
|
+
const m = mg[index];
|
|
575
|
+
const k = ink[index];
|
|
576
|
+
const total2 = a + c + m + k;
|
|
577
|
+
acSum += a;
|
|
578
|
+
c2Sum += c;
|
|
579
|
+
mgSum += m;
|
|
580
|
+
inkSum += k;
|
|
581
|
+
if (total2 > 0.11)
|
|
582
|
+
bits |= BRAILLE_BITS[sy][sx];
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
const total = acSum + c2Sum + mgSum + inkSum;
|
|
586
|
+
if (bits === 0 || total <= 0.02)
|
|
587
|
+
continue;
|
|
588
|
+
const char = String.fromCharCode(10240 + bits);
|
|
589
|
+
fb.setCellWithAlphaBlending(cx, cy, char, paletteColor(acSum, c2Sum, mgSum, inkSum), TRANSPARENT);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function createGraphicsLayer(renderer, layout) {
|
|
595
|
+
const layer = new FrameBufferRenderable(renderer, {
|
|
596
|
+
id: "rig-marketing-glyph-canvas",
|
|
597
|
+
width: layout.width,
|
|
598
|
+
height: layout.height,
|
|
599
|
+
position: "absolute",
|
|
600
|
+
left: 0,
|
|
601
|
+
top: 0,
|
|
602
|
+
respectAlpha: true
|
|
603
|
+
});
|
|
604
|
+
layer.__rigMarketingCanvas = new MarketingGlyphCanvas(layout);
|
|
605
|
+
return layer;
|
|
606
|
+
}
|
|
607
|
+
function resizeGraphicsLayer(layer, layout) {
|
|
608
|
+
if (layer.width !== layout.width)
|
|
609
|
+
layer.width = layout.width;
|
|
610
|
+
if (layer.height !== layout.height)
|
|
611
|
+
layer.height = layout.height;
|
|
612
|
+
layer.__rigMarketingCanvas?.resize(layout);
|
|
613
|
+
}
|
|
614
|
+
function clearGraphicsLayer(layer) {
|
|
615
|
+
layer.frameBuffer.clear(BACKDROP);
|
|
616
|
+
layer.__rigAmbientKey = undefined;
|
|
617
|
+
}
|
|
618
|
+
function writeCell(layer, x, y, char, fg, bg) {
|
|
619
|
+
layer.frameBuffer.setCellWithAlphaBlending(x, y, char, fg, bg);
|
|
620
|
+
}
|
|
621
|
+
function drawFullCell(layer, x, y, bg) {
|
|
622
|
+
writeCell(layer, x, y, " ", TRANSPARENT, bg);
|
|
623
|
+
}
|
|
624
|
+
function drawCornerCut(layer, x, y, char, fg) {
|
|
625
|
+
writeCell(layer, x, y, char, fg, BACKDROP);
|
|
626
|
+
}
|
|
627
|
+
function drawRoundedFill(layer, left, top, right, bottom, dividerY) {
|
|
628
|
+
const bgForY = (y) => y < dividerY ? PANEL_HEADER_BG : PANEL_BG;
|
|
629
|
+
for (let y = top;y <= bottom; y += 1) {
|
|
630
|
+
const bg = bgForY(y);
|
|
631
|
+
for (let x = left;x <= right; x += 1)
|
|
632
|
+
drawFullCell(layer, x, y, bg);
|
|
633
|
+
}
|
|
634
|
+
drawCornerCut(layer, left, top, "\u2597", PANEL_HEADER_BG);
|
|
635
|
+
drawCornerCut(layer, right, top, "\u2596", PANEL_HEADER_BG);
|
|
636
|
+
drawCornerCut(layer, left, bottom, "\u259D", PANEL_BG);
|
|
637
|
+
drawCornerCut(layer, right, bottom, "\u2598", PANEL_BG);
|
|
638
|
+
}
|
|
639
|
+
function drawAdTerminalPanel(layer, layout, panel) {
|
|
640
|
+
const rect = panelCellRect(layout, panel);
|
|
641
|
+
if (!rect)
|
|
642
|
+
return;
|
|
643
|
+
const { left, top, width, right, bottom, headerHeight, dividerY } = rect;
|
|
644
|
+
drawRoundedFill(layer, left, top, right, bottom, dividerY);
|
|
645
|
+
if (dividerY > top && dividerY < bottom) {
|
|
646
|
+
for (let x = left + 2;x < right - 1; x += 1) {
|
|
647
|
+
writeCell(layer, x, dividerY, "\u2500", PANEL_LINE_DIM, PANEL_BG);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (panel.headerText) {
|
|
651
|
+
const x = left + Math.max(2, Math.min(5, panel.paddingX ?? 4));
|
|
652
|
+
const y = top + Math.max(1, Math.floor(headerHeight / 2));
|
|
653
|
+
layer.frameBuffer.drawText(panel.headerText.slice(0, Math.max(0, width - 8)), x, y, PANEL_TEXT_DIM, TRANSPARENT);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
function drawPanelChrome(layer, layout, panels) {
|
|
657
|
+
for (const panel of panels) {
|
|
658
|
+
if (panel.chrome === "ad-terminal")
|
|
659
|
+
drawAdTerminalPanel(layer, layout, panel);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
function staticFleetTick(scene) {
|
|
663
|
+
let hash = 0;
|
|
664
|
+
for (let index = 0;index < scene.length; index += 1)
|
|
665
|
+
hash = hash * 33 + scene.charCodeAt(index) >>> 0;
|
|
666
|
+
return 11 + hash % 97;
|
|
667
|
+
}
|
|
668
|
+
function withAlpha(hex, alpha) {
|
|
669
|
+
const a = Math.max(0, Math.min(255, Math.round(alpha * 255)));
|
|
670
|
+
const [r, g, b] = RGBA.fromHex(hex).toInts();
|
|
671
|
+
return RGBA.fromInts(r, g, b, a);
|
|
672
|
+
}
|
|
673
|
+
function asciiFleetColor(char, row, alpha) {
|
|
674
|
+
if (char === "@" || char === "$" || char === "o")
|
|
675
|
+
return withAlpha(RIG_UI.lime, alpha);
|
|
676
|
+
if (char === "%" || char === "!" || char === "/" || char === "\\" || char === "|")
|
|
677
|
+
return withAlpha(RIG_UI.cyan, alpha);
|
|
678
|
+
if (char === "." || char === "'" || char === "_" || row < 3 || row > FLEET_GRID_HEIGHT - 4) {
|
|
679
|
+
return RGBA.fromInts(108, 110, 121, Math.min(170, Math.max(0, Math.min(255, Math.round(alpha * 255)))));
|
|
680
|
+
}
|
|
681
|
+
return withAlpha(RIG_UI.limeDim, alpha);
|
|
682
|
+
}
|
|
683
|
+
var AMBIENT_LOAD_BUCKETS = 5;
|
|
684
|
+
function ambientLoadBucket(load) {
|
|
685
|
+
if (!Number.isFinite(load))
|
|
686
|
+
return 0;
|
|
687
|
+
return Math.max(0, Math.min(AMBIENT_LOAD_BUCKETS, Math.round(load * AMBIENT_LOAD_BUCKETS)));
|
|
688
|
+
}
|
|
689
|
+
function drawAmbientField(layer, layout, _tick, scene = "fleet", load = 0, activeRuns = 0) {
|
|
690
|
+
const bucket = ambientLoadBucket(load);
|
|
691
|
+
const rows = fleetRows(staticFleetTick(scene), { animate: true });
|
|
692
|
+
let droneTotal = 0;
|
|
693
|
+
for (const line of rows)
|
|
694
|
+
for (const char of line)
|
|
695
|
+
if (char === "@" || char === "$" || char === "%")
|
|
696
|
+
droneTotal += 1;
|
|
697
|
+
const litTarget = Math.max(0, Math.min(droneTotal, Math.floor(activeRuns)));
|
|
698
|
+
const key = `${layout.width}x${layout.height}|${scene}|l${bucket}|d${litTarget}`;
|
|
699
|
+
if (layer.__rigAmbientKey === key)
|
|
700
|
+
return;
|
|
701
|
+
const fb = layer.frameBuffer;
|
|
702
|
+
fb.clear(BACKDROP);
|
|
703
|
+
const left = Math.floor((layout.width - FLEET_GRID_WIDTH) / 2);
|
|
704
|
+
const top = Math.floor((layout.height - FLEET_GRID_HEIGHT) / 2);
|
|
705
|
+
const baseAlpha = 0.62 + bucket / AMBIENT_LOAD_BUCKETS * 0.18;
|
|
706
|
+
let droneIndex = 0;
|
|
707
|
+
for (let row = 0;row < rows.length; row += 1) {
|
|
708
|
+
const y = top + row;
|
|
709
|
+
if (y < 0 || y >= layout.height)
|
|
710
|
+
continue;
|
|
711
|
+
const line = rows[row];
|
|
712
|
+
for (let col = 0;col < line.length; col += 1) {
|
|
713
|
+
const x = left + col;
|
|
714
|
+
if (x < 0 || x >= layout.width)
|
|
715
|
+
continue;
|
|
716
|
+
const char = line[col];
|
|
717
|
+
if (char === " ")
|
|
718
|
+
continue;
|
|
719
|
+
const isDrone = char === "@" || char === "$" || char === "%";
|
|
720
|
+
const lit = isDrone && droneIndex < litTarget;
|
|
721
|
+
if (isDrone)
|
|
722
|
+
droneIndex += 1;
|
|
723
|
+
const alpha = lit ? 1 : baseAlpha;
|
|
724
|
+
fb.setCellWithAlphaBlending(x, y, char, asciiFleetColor(char, row, alpha), TRANSPARENT);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
layer.__rigAmbientKey = key;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// packages/cli/src/app-opentui/fleet-stats.ts
|
|
731
|
+
var ACTIVE_STATUSES = new Set([
|
|
732
|
+
"running",
|
|
733
|
+
"preparing",
|
|
734
|
+
"created",
|
|
735
|
+
"validating",
|
|
736
|
+
"reviewing",
|
|
737
|
+
"closing-out",
|
|
738
|
+
"stopping",
|
|
739
|
+
"loading"
|
|
740
|
+
]);
|
|
741
|
+
function normalizeStatus(status) {
|
|
742
|
+
return status.replace(/_/g, "-").toLowerCase();
|
|
743
|
+
}
|
|
744
|
+
function runsFromState(state) {
|
|
745
|
+
const fleet = state.data.fleet;
|
|
746
|
+
if (!fleet || typeof fleet !== "object" || Array.isArray(fleet))
|
|
747
|
+
return [];
|
|
748
|
+
const runs = fleet.runs;
|
|
749
|
+
return Array.isArray(runs) ? runs : [];
|
|
750
|
+
}
|
|
751
|
+
function computeFleetStats(runs) {
|
|
752
|
+
const byStatus = new Map;
|
|
753
|
+
let active = 0;
|
|
754
|
+
let succeeded = 0;
|
|
755
|
+
let failed = 0;
|
|
756
|
+
for (const run of runs) {
|
|
757
|
+
const status = normalizeStatus(run.status ?? "");
|
|
758
|
+
byStatus.set(status, (byStatus.get(status) ?? 0) + 1);
|
|
759
|
+
if (ACTIVE_STATUSES.has(status))
|
|
760
|
+
active += 1;
|
|
761
|
+
else if (status === "success" || status === "completed" || status === "merged")
|
|
762
|
+
succeeded += 1;
|
|
763
|
+
else if (status === "failed" || status === "error")
|
|
764
|
+
failed += 1;
|
|
765
|
+
}
|
|
766
|
+
const total = runs.length;
|
|
767
|
+
const load = total === 0 ? 0 : active / total;
|
|
768
|
+
const sparkline = buildSparklineSeries(active, succeeded, failed);
|
|
769
|
+
return { total, active, succeeded, failed, byStatus, load, sparkline };
|
|
770
|
+
}
|
|
771
|
+
function buildSparklineSeries(active, succeeded, failed) {
|
|
772
|
+
const peak = Math.max(1, active, succeeded, failed);
|
|
773
|
+
const base = [succeeded, Math.round(succeeded * 0.6 + failed * 0.4), failed, Math.round((active + failed) / 2), active];
|
|
774
|
+
return base.map((value) => Math.max(0, Math.min(peak, value)) / peak);
|
|
775
|
+
}
|
|
776
|
+
function fleetStatsFromState(state) {
|
|
777
|
+
return computeFleetStats(runsFromState(state));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// packages/cli/src/app-opentui/react/Backdrop.tsx
|
|
781
|
+
var ANIMATION_SLOWDOWN = 1;
|
|
782
|
+
function isTerminalScene(scene) {
|
|
783
|
+
return scene === "handoff" || scene === "command";
|
|
784
|
+
}
|
|
785
|
+
function Backdrop(props) {
|
|
786
|
+
const renderer = useRenderer();
|
|
787
|
+
const graphicsRef = useRef(null);
|
|
788
|
+
useEffect(() => {
|
|
789
|
+
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
790
|
+
const graphics = createGraphicsLayer(renderer, layout);
|
|
791
|
+
renderer.root.add(graphics);
|
|
792
|
+
graphicsRef.current = graphics;
|
|
793
|
+
return () => {
|
|
794
|
+
const g = graphicsRef.current;
|
|
795
|
+
if (g) {
|
|
796
|
+
try {
|
|
797
|
+
renderer.root.remove(g.id);
|
|
798
|
+
} catch {}
|
|
799
|
+
}
|
|
800
|
+
graphicsRef.current = null;
|
|
801
|
+
};
|
|
802
|
+
}, [renderer]);
|
|
803
|
+
useEffect(() => {
|
|
804
|
+
const graphics = graphicsRef.current;
|
|
805
|
+
if (!graphics)
|
|
806
|
+
return;
|
|
807
|
+
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
808
|
+
if (layout.tooSmall) {
|
|
809
|
+
clearGraphicsLayer(graphics);
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
const stats = fleetStatsFromState(props.state);
|
|
813
|
+
const animationTick = Math.floor(props.state.tick / ANIMATION_SLOWDOWN);
|
|
814
|
+
const panels = (props.frame.panels ?? []).map((panel) => ({ ...panel }));
|
|
815
|
+
const terminalActive = props.frame.terminalActive ?? isTerminalScene(props.state.scene);
|
|
816
|
+
const fullScreen = Boolean(props.frame.fullScreen);
|
|
817
|
+
resizeGraphicsLayer(graphics, layout);
|
|
818
|
+
if (terminalActive || fullScreen) {
|
|
819
|
+
clearGraphicsLayer(graphics);
|
|
820
|
+
} else {
|
|
821
|
+
drawAmbientField(graphics, layout, animationTick, props.state.scene, stats.load, stats.active);
|
|
822
|
+
drawPanelChrome(graphics, layout, panels);
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
return null;
|
|
826
|
+
}
|
|
827
|
+
export {
|
|
828
|
+
Backdrop
|
|
829
|
+
};
|