omegon 0.7.1 → 0.7.2
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.
|
@@ -14,7 +14,11 @@ import type { Component, TUI } from "@styrene-lab/pi-tui";
|
|
|
14
14
|
import { truncateToWidth } from "@styrene-lab/pi-tui";
|
|
15
15
|
import {
|
|
16
16
|
LOGO_LINES,
|
|
17
|
+
WORDMARK_LINES,
|
|
17
18
|
LINE_WIDTH,
|
|
19
|
+
COMPACT_LOGO_LINES,
|
|
20
|
+
COMPACT_LINE_WIDTH,
|
|
21
|
+
COMPACT_MARK_ROWS,
|
|
18
22
|
FRAME_INTERVAL_MS,
|
|
19
23
|
TOTAL_FRAMES,
|
|
20
24
|
HOLD_FRAMES,
|
|
@@ -95,8 +99,9 @@ const PENDING_GLYPH = "· ";
|
|
|
95
99
|
// ---------------------------------------------------------------------------
|
|
96
100
|
class SplashHeader implements Component {
|
|
97
101
|
private tui: TUI;
|
|
102
|
+
private lines: string[];
|
|
98
103
|
private frame = 0;
|
|
99
|
-
private frameMap
|
|
104
|
+
private frameMap: ReturnType<typeof assignUnlockFrames>;
|
|
100
105
|
private noiseSeed = (Date.now() * 7) & 0x7fffffff;
|
|
101
106
|
private timer: ReturnType<typeof setInterval> | null = null;
|
|
102
107
|
private scanFrame = 0;
|
|
@@ -107,9 +112,16 @@ class SplashHeader implements Component {
|
|
|
107
112
|
private cachedLines: string[] | undefined;
|
|
108
113
|
private cachedWidth: number | undefined;
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
private markRows: number;
|
|
116
|
+
private logoWidth: number;
|
|
117
|
+
|
|
118
|
+
constructor(tui: TUI, onTransition: () => void, lines: string[], markRows: number, logoWidth: number) {
|
|
111
119
|
this.tui = tui;
|
|
112
120
|
this.onTransition = onTransition;
|
|
121
|
+
this.lines = lines;
|
|
122
|
+
this.markRows = markRows;
|
|
123
|
+
this.logoWidth = logoWidth;
|
|
124
|
+
this.frameMap = assignUnlockFrames(lines, TOTAL_FRAMES, Date.now() & 0xffff);
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
start(): void {
|
|
@@ -147,14 +159,14 @@ class SplashHeader implements Component {
|
|
|
147
159
|
const lines: string[] = [];
|
|
148
160
|
|
|
149
161
|
// Centre the logo horizontally
|
|
150
|
-
const logoW =
|
|
162
|
+
const logoW = this.logoWidth;
|
|
151
163
|
const pad = Math.max(0, Math.floor((width - logoW) / 2));
|
|
152
164
|
const padStr = " ".repeat(pad);
|
|
153
165
|
|
|
154
166
|
// Render logo frame
|
|
155
167
|
const logoFrame = this.transitioned
|
|
156
|
-
? renderFrame(TOTAL_FRAMES + 1,
|
|
157
|
-
: renderFrame(Math.min(this.frame, TOTAL_FRAMES),
|
|
168
|
+
? renderFrame(TOTAL_FRAMES + 1, this.lines, this.frameMap, this.noiseSeed, this.markRows)
|
|
169
|
+
: renderFrame(Math.min(this.frame, TOTAL_FRAMES), this.lines, this.frameMap, this.noiseSeed, this.markRows);
|
|
158
170
|
|
|
159
171
|
lines.push(""); // top spacer
|
|
160
172
|
for (const row of logoFrame) {
|
|
@@ -295,15 +307,42 @@ export default function splashExtension(pi: ExtensionAPI): void {
|
|
|
295
307
|
// after a version update), it renders as a one-liner below the splash.
|
|
296
308
|
// This is acceptable — it only appears once per update.
|
|
297
309
|
const termWidth = process.stdout.columns ?? 80;
|
|
298
|
-
|
|
299
|
-
|
|
310
|
+
const termRows = process.stdout.rows ?? 24;
|
|
311
|
+
|
|
312
|
+
// Four tiers based on terminal size:
|
|
313
|
+
// Full (sigil + wordmark): needs ~46 rows and LINE_WIDTH+4 cols (~84 cols)
|
|
314
|
+
// Compact (smaller sigil + wordmark): needs ~34 rows and COMPACT_LINE_WIDTH+4 cols (~58 cols)
|
|
315
|
+
// Wordmark only: needs ~14 rows and LINE_WIDTH+4 cols
|
|
316
|
+
// Minimal (no animation): everything else
|
|
317
|
+
const canFitFull = termWidth >= LINE_WIDTH + 4 && termRows >= LOGO_LINES.length + 6;
|
|
318
|
+
const canFitCompact = termWidth >= COMPACT_LINE_WIDTH + 4 && termRows >= COMPACT_LOGO_LINES.length + 6;
|
|
319
|
+
const canFitWordmark = termWidth >= LINE_WIDTH + 4 && termRows >= WORDMARK_LINES.length + 6;
|
|
320
|
+
|
|
321
|
+
if (!canFitCompact && !canFitWordmark) {
|
|
322
|
+
// Too small for any animation — minimal branded header
|
|
300
323
|
ctx.ui.setHeader(() => new BrandedHeader(version));
|
|
301
324
|
} else {
|
|
325
|
+
let artLines: string[];
|
|
326
|
+
let markRows: number;
|
|
327
|
+
let logoWidth: number;
|
|
328
|
+
if (canFitFull) {
|
|
329
|
+
artLines = LOGO_LINES;
|
|
330
|
+
markRows = 31; // MARK_ROWS
|
|
331
|
+
logoWidth = LINE_WIDTH;
|
|
332
|
+
} else if (canFitCompact) {
|
|
333
|
+
artLines = COMPACT_LOGO_LINES;
|
|
334
|
+
markRows = COMPACT_MARK_ROWS;
|
|
335
|
+
logoWidth = COMPACT_LINE_WIDTH;
|
|
336
|
+
} else {
|
|
337
|
+
artLines = WORDMARK_LINES;
|
|
338
|
+
markRows = 0; // all wordmark
|
|
339
|
+
logoWidth = LINE_WIDTH;
|
|
340
|
+
}
|
|
302
341
|
ctx.ui.setHeader((tui, _theme) => {
|
|
303
342
|
const splash = new SplashHeader(tui, () => {
|
|
304
343
|
// Transition to minimal branded header
|
|
305
344
|
ctx.ui.setHeader((_, _t) => new BrandedHeader(version));
|
|
306
|
-
});
|
|
345
|
+
}, artLines, markRows, logoWidth);
|
|
307
346
|
splash.start();
|
|
308
347
|
return splash;
|
|
309
348
|
});
|
|
@@ -139,6 +139,7 @@ export function renderFrame(
|
|
|
139
139
|
lines: string[],
|
|
140
140
|
frameMap: FrameMap,
|
|
141
141
|
noiseSeed: number,
|
|
142
|
+
markRows: number = MARK_ROWS,
|
|
142
143
|
): string[] {
|
|
143
144
|
const rng = new SimpleRNG(noiseSeed + frame * 997);
|
|
144
145
|
const output: string[] = [];
|
|
@@ -162,7 +163,7 @@ export function renderFrame(
|
|
|
162
163
|
buf += " ";
|
|
163
164
|
} else if (frame >= unlock) {
|
|
164
165
|
// Resolved — final glyph
|
|
165
|
-
const color = y >=
|
|
166
|
+
const color = y >= markRows + 1 ? `${BOLD}${BRIGHT}` : PRIMARY;
|
|
166
167
|
if (color !== lastColor) { buf += color; lastColor = color; }
|
|
167
168
|
buf += ch;
|
|
168
169
|
} else {
|
|
@@ -190,5 +191,56 @@ export function renderFrame(
|
|
|
190
191
|
// ---------------------------------------------------------------------------
|
|
191
192
|
// Pre-computed data for the default logo
|
|
192
193
|
// ---------------------------------------------------------------------------
|
|
193
|
-
|
|
194
|
+
/** Wordmark-only lines (spacer + 7 wordmark rows) for compact terminals. */
|
|
195
|
+
const WORDMARK_LINES: string[] = LOGO_LINES.slice(MARK_ROWS + 1); // skip sigil + first spacer, keep second spacer + wordmark
|
|
196
|
+
// Pad to same width
|
|
197
|
+
for (let i = 0; i < WORDMARK_LINES.length; i++) {
|
|
198
|
+
WORDMARK_LINES[i] = WORDMARK_LINES[i].padEnd(LINE_WIDTH);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Compact logo — sigil + wordmark for mid-size terminals (~56 cols)
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
const COMPACT_MARK_ROWS = 23;
|
|
205
|
+
|
|
206
|
+
const COMPACT_LOGO_LINES: string[] = [
|
|
207
|
+
" * ``` #` ",
|
|
208
|
+
" ` ```##` ``````##` .#` ",
|
|
209
|
+
"````##`######### `############`##` ",
|
|
210
|
+
"*`*############## `##################` ",
|
|
211
|
+
"##:````*` `####` `#########` *#######:## ",
|
|
212
|
+
"` ##### ``####### ######`#` ",
|
|
213
|
+
" `##### #######. #########` ",
|
|
214
|
+
" ####`` ``*@@@@@@@@@@`* `## #### ",
|
|
215
|
+
" ##### `@@@@@@@@@@@@@@@@@@@ `#@ :` ",
|
|
216
|
+
" #####`@@@@@@@@@@@@@@@@@@@@@@@@` `#` ",
|
|
217
|
+
" ##*@@@@@@@@@@@@@@@@@@@@@@@@@@@` ",
|
|
218
|
+
" :@@@@@@@@@@@``##```@@@@@@@@@@@`` ",
|
|
219
|
+
" @@@@@@@@*#:` `#######`@@@@@@@@` ` ` ",
|
|
220
|
+
" @@@@@@@#####` `########`@@@@@@@`####`#` ",
|
|
221
|
+
" @@@@@@ ###### `#`#####`@@@@@@########` ",
|
|
222
|
+
" @@@@@ ###### `::``#*@@@@@`##` #### ",
|
|
223
|
+
" `@@@@@####### `@@@@@`###` `*## ",
|
|
224
|
+
" ``#` .@@@@`##### `@@@@@` ``###` `**",
|
|
225
|
+
" ``:######```@@@@@#` `.@@@@. `#.##` ",
|
|
226
|
+
" ######`####`* `@@@@@@ ``@@@@@` ``#####` ",
|
|
227
|
+
" #* .@@@@@@@@@@@@@@ :@@@@@@@@@@@@@@## ",
|
|
228
|
+
" ` .@@@@@@@@@@@@@@ :@@@@@@@@@@@@@@` ",
|
|
229
|
+
" .@ ` ` ",
|
|
230
|
+
// spacer
|
|
231
|
+
" ",
|
|
232
|
+
// wordmark (4 rows)
|
|
233
|
+
" @@@@@@@ @@@` `@@@ @@@@@@``@@@@@@ `@@@@@@@`@@@` @@ ",
|
|
234
|
+
" @@ @@ @@@@`@@@@ @@```` `@@` `@@ @@ @@@@ @@ ",
|
|
235
|
+
" @@ @@ @@ @*@`@@ @@@@` `@@`@@@ `@@ @@ @@ *@@@ ",
|
|
236
|
+
" @@@@@@@ @@ `@``@@ @@@@@@``@@@@@@ `@@@@@@@`@@ `@@ ",
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
const COMPACT_LINE_WIDTH = Math.max(...COMPACT_LOGO_LINES.map(l => l.length));
|
|
240
|
+
for (let i = 0; i < COMPACT_LOGO_LINES.length; i++) {
|
|
241
|
+
COMPACT_LOGO_LINES[i] = COMPACT_LOGO_LINES[i].padEnd(COMPACT_LINE_WIDTH);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export { LOGO_LINES, WORDMARK_LINES, LINE_WIDTH, MARK_ROWS };
|
|
245
|
+
export { COMPACT_LOGO_LINES, COMPACT_LINE_WIDTH, COMPACT_MARK_ROWS };
|
|
194
246
|
export { PRIMARY, PRIMARY_DIM, DIM, BRIGHT, SUCCESS, ERROR_CLR, RESET, BOLD };
|
|
@@ -471,9 +471,9 @@ function restartOmegon(): never {
|
|
|
471
471
|
"done",
|
|
472
472
|
// Extra grace period for fd/terminal release
|
|
473
473
|
"sleep 0.2",
|
|
474
|
-
//
|
|
475
|
-
//
|
|
476
|
-
"printf '\\033[<u\\033[>4;0m\\033[?2004l' 2>/dev/null",
|
|
474
|
+
// Full terminal protocol reset — stty sane only resets line discipline,
|
|
475
|
+
// not terminal protocol state (kitty keyboard, bracketed paste, cursor, SGR)
|
|
476
|
+
"printf '\\033[<u\\033[>4;0m\\033[?2004l\\033[?25h\\033[0m\\033[r' 2>/dev/null",
|
|
477
477
|
"stty sane 2>/dev/null",
|
|
478
478
|
// Clean up this script
|
|
479
479
|
`rm -f "${script}"`,
|
|
@@ -484,15 +484,20 @@ function restartOmegon(): never {
|
|
|
484
484
|
// Reset terminal to cooked mode BEFORE exiting so the restart script
|
|
485
485
|
// (and the user) aren't stuck with raw-mode terminal if something goes wrong.
|
|
486
486
|
try {
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
// script (and any keystrokes during the wait) dump raw kitty sequences.
|
|
487
|
+
// Full terminal protocol teardown: pop kitty keyboard protocol,
|
|
488
|
+
// disable modifyOtherKeys, disable bracketed paste, show cursor,
|
|
489
|
+
// reset SGR attributes, and clear any pending scroll region.
|
|
491
490
|
process.stdout.write(
|
|
492
491
|
"\x1b[<u" + // Pop kitty keyboard protocol flags
|
|
493
492
|
"\x1b[>4;0m" + // Disable modifyOtherKeys
|
|
494
|
-
"\x1b[?2004l"
|
|
493
|
+
"\x1b[?2004l" + // Disable bracketed paste
|
|
494
|
+
"\x1b[?25h" + // Show cursor
|
|
495
|
+
"\x1b[0m" + // Reset all SGR attributes
|
|
496
|
+
"\x1b[r" // Reset scroll region to full screen
|
|
495
497
|
);
|
|
498
|
+
// Pause stdin to prevent buffered input from being re-interpreted
|
|
499
|
+
// after raw mode is disabled (prevents Ctrl+D from closing parent shell).
|
|
500
|
+
process.stdin.pause();
|
|
496
501
|
if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
497
502
|
process.stdin.setRawMode(false);
|
|
498
503
|
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omegon",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Omegon — an opinionated distribution of pi (by Mario Zechner) with extensions for lifecycle management, memory, orchestration, and visualization",
|
|
5
5
|
"bin": {
|
|
6
6
|
"omegon": "bin/omegon.mjs",
|