aoaoe 0.74.0 → 0.75.0
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/colors.d.ts +1 -0
- package/dist/colors.js +1 -0
- package/dist/index.js +7 -0
- package/dist/input.d.ts +4 -0
- package/dist/input.js +13 -0
- package/dist/tui.d.ts +9 -1
- package/dist/tui.js +58 -7
- package/package.json +1 -1
package/dist/colors.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare const ROSE = "\u001B[38;5;204m";
|
|
|
14
14
|
export declare const LIME = "\u001B[38;5;114m";
|
|
15
15
|
export declare const SKY = "\u001B[38;5;117m";
|
|
16
16
|
export declare const BG_DARK = "\u001B[48;5;236m";
|
|
17
|
+
export declare const BG_HOVER = "\u001B[48;5;238m";
|
|
17
18
|
export declare const BOX: {
|
|
18
19
|
readonly tl: "┌";
|
|
19
20
|
readonly tr: "┐";
|
package/dist/colors.js
CHANGED
|
@@ -19,6 +19,7 @@ export const LIME = "\x1b[38;5;114m"; // fresh green for success/working
|
|
|
19
19
|
export const SKY = "\x1b[38;5;117m"; // light blue for reasoning
|
|
20
20
|
// background variants (256-color)
|
|
21
21
|
export const BG_DARK = "\x1b[48;5;236m"; // dark gray for header bar
|
|
22
|
+
export const BG_HOVER = "\x1b[48;5;238m"; // slightly brighter gray for hover highlight
|
|
22
23
|
// box-drawing characters — Unicode block elements
|
|
23
24
|
export const BOX = {
|
|
24
25
|
tl: "┌", tr: "┐", bl: "└", br: "┘",
|
package/dist/index.js
CHANGED
|
@@ -335,6 +335,13 @@ async function main() {
|
|
|
335
335
|
tui.log("system", "search cleared");
|
|
336
336
|
}
|
|
337
337
|
});
|
|
338
|
+
// wire mouse move to hover highlight on session cards
|
|
339
|
+
input.onMouseMove((row, _col) => {
|
|
340
|
+
if (tui.getViewMode() === "overview") {
|
|
341
|
+
const sessionIdx = hitTestSession(row, 1, tui.getSessionCount());
|
|
342
|
+
tui.setHoverSession(sessionIdx);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
338
345
|
// wire mouse wheel to scroll (3 lines per tick for smooth scrolling)
|
|
339
346
|
input.onMouseWheel((direction) => {
|
|
340
347
|
if (tui.getViewMode() === "drilldown") {
|
package/dist/input.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface MouseEvent {
|
|
|
10
10
|
}
|
|
11
11
|
export type MouseClickHandler = (row: number, col: number) => void;
|
|
12
12
|
export type MouseWheelHandler = (direction: "up" | "down") => void;
|
|
13
|
+
export type MouseMoveHandler = (row: number, col: number) => void;
|
|
13
14
|
/** Parse an SGR extended mouse event from raw terminal data. Returns null if not a mouse event. */
|
|
14
15
|
export declare function parseMouseEvent(data: string): MouseEvent | null;
|
|
15
16
|
export declare class InputReader {
|
|
@@ -22,6 +23,8 @@ export declare class InputReader {
|
|
|
22
23
|
private viewHandler;
|
|
23
24
|
private mouseClickHandler;
|
|
24
25
|
private mouseWheelHandler;
|
|
26
|
+
private mouseMoveHandler;
|
|
27
|
+
private lastMoveRow;
|
|
25
28
|
private searchHandler;
|
|
26
29
|
private mouseDataListener;
|
|
27
30
|
onScroll(handler: (dir: ScrollDirection) => void): void;
|
|
@@ -29,6 +32,7 @@ export declare class InputReader {
|
|
|
29
32
|
onView(handler: ViewHandler): void;
|
|
30
33
|
onMouseClick(handler: MouseClickHandler): void;
|
|
31
34
|
onMouseWheel(handler: MouseWheelHandler): void;
|
|
35
|
+
onMouseMove(handler: MouseMoveHandler): void;
|
|
32
36
|
onSearch(handler: SearchHandler): void;
|
|
33
37
|
private notifyQueueChange;
|
|
34
38
|
start(): void;
|
package/dist/input.js
CHANGED
|
@@ -31,6 +31,8 @@ export class InputReader {
|
|
|
31
31
|
viewHandler = null;
|
|
32
32
|
mouseClickHandler = null;
|
|
33
33
|
mouseWheelHandler = null;
|
|
34
|
+
mouseMoveHandler = null;
|
|
35
|
+
lastMoveRow = 0; // debounce: only fire move handler when row changes
|
|
34
36
|
searchHandler = null;
|
|
35
37
|
mouseDataListener = null;
|
|
36
38
|
// register a callback for scroll key events (PgUp/PgDn/Home/End)
|
|
@@ -53,6 +55,10 @@ export class InputReader {
|
|
|
53
55
|
onMouseWheel(handler) {
|
|
54
56
|
this.mouseWheelHandler = handler;
|
|
55
57
|
}
|
|
58
|
+
// register a callback for mouse move events (only fires on row change for efficiency)
|
|
59
|
+
onMouseMove(handler) {
|
|
60
|
+
this.mouseMoveHandler = handler;
|
|
61
|
+
}
|
|
56
62
|
// register a callback for search commands (/search <pattern> or /search to clear)
|
|
57
63
|
onSearch(handler) {
|
|
58
64
|
this.searchHandler = handler;
|
|
@@ -91,6 +97,13 @@ export class InputReader {
|
|
|
91
97
|
else if (evt.button === 65 && this.mouseWheelHandler) {
|
|
92
98
|
this.mouseWheelHandler("down");
|
|
93
99
|
}
|
|
100
|
+
// mouse motion: bit 5 set (button 32-35), only fire on row change
|
|
101
|
+
if (evt.button >= 32 && evt.button <= 35 && this.mouseMoveHandler) {
|
|
102
|
+
if (evt.row !== this.lastMoveRow) {
|
|
103
|
+
this.lastMoveRow = evt.row;
|
|
104
|
+
this.mouseMoveHandler(evt.row, evt.col);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
94
107
|
};
|
|
95
108
|
process.stdin.on("data", this.mouseDataListener);
|
|
96
109
|
process.stdin.on("keypress", (_ch, key) => {
|
package/dist/tui.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare class TUI {
|
|
|
24
24
|
private newWhileScrolled;
|
|
25
25
|
private pendingCount;
|
|
26
26
|
private searchPattern;
|
|
27
|
+
private hoverSessionIdx;
|
|
27
28
|
private viewMode;
|
|
28
29
|
private drilldownSessionId;
|
|
29
30
|
private sessionOutputs;
|
|
@@ -75,12 +76,18 @@ export declare class TUI {
|
|
|
75
76
|
setSearch(pattern: string | null): void;
|
|
76
77
|
/** Get the current search pattern (or null if no active search). */
|
|
77
78
|
getSearchPattern(): string | null;
|
|
79
|
+
/** Set the hovered session index (1-indexed) or null to clear. Only repaints the affected cards. */
|
|
80
|
+
setHoverSession(idx: number | null): void;
|
|
81
|
+
/** Get the current hovered session index (1-indexed, null if none). */
|
|
82
|
+
getHoverSession(): number | null;
|
|
78
83
|
private updateDimensions;
|
|
79
84
|
private computeLayout;
|
|
80
85
|
private onResize;
|
|
81
86
|
private paintAll;
|
|
82
87
|
private paintHeader;
|
|
83
88
|
private paintSessions;
|
|
89
|
+
/** Repaint a single session card by 1-indexed position (for hover updates). */
|
|
90
|
+
private repaintSessionCard;
|
|
84
91
|
private paintSeparator;
|
|
85
92
|
private writeActivityLine;
|
|
86
93
|
private repaintActivityRegion;
|
|
@@ -91,6 +98,7 @@ export declare class TUI {
|
|
|
91
98
|
declare function formatSessionCard(s: DaemonSessionState, maxWidth: number): string;
|
|
92
99
|
declare function formatActivity(entry: ActivityEntry, maxCols: number): string;
|
|
93
100
|
declare function padBoxLine(line: string, totalWidth: number): string;
|
|
101
|
+
declare function padBoxLineHover(line: string, totalWidth: number, hovered: boolean): string;
|
|
94
102
|
declare function padToWidth(line: string, totalWidth: number): string;
|
|
95
103
|
declare function stripAnsiForLen(str: string): number;
|
|
96
104
|
declare function truncateAnsi(str: string, maxCols: number): string;
|
|
@@ -120,5 +128,5 @@ declare function formatSearchIndicator(pattern: string, matchCount: number, tota
|
|
|
120
128
|
* (row = headerHeight + 2 + i for 0-indexed session i)
|
|
121
129
|
*/
|
|
122
130
|
export declare function hitTestSession(row: number, headerHeight: number, sessionCount: number): number | null;
|
|
123
|
-
export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator };
|
|
131
|
+
export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padBoxLineHover, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator };
|
|
124
132
|
//# sourceMappingURL=tui.d.ts.map
|
package/dist/tui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BOLD, DIM, RESET, GREEN, CYAN, WHITE, BG_DARK, INDIGO, TEAL, AMBER, SLATE, ROSE, LIME, SKY, BOX, SPINNER, DOT, } from "./colors.js";
|
|
1
|
+
import { BOLD, DIM, RESET, GREEN, CYAN, WHITE, BG_DARK, BG_HOVER, INDIGO, TEAL, AMBER, SLATE, ROSE, LIME, SKY, BOX, SPINNER, DOT, } from "./colors.js";
|
|
2
2
|
import { appendHistoryEntry } from "./tui-history.js";
|
|
3
3
|
// ── ANSI helpers ────────────────────────────────────────────────────────────
|
|
4
4
|
const ESC = "\x1b";
|
|
@@ -12,9 +12,11 @@ const CURSOR_HIDE = `${CSI}?25l`;
|
|
|
12
12
|
const CURSOR_SHOW = `${CSI}?25h`;
|
|
13
13
|
const SAVE_CURSOR = `${ESC}7`;
|
|
14
14
|
const RESTORE_CURSOR = `${ESC}8`;
|
|
15
|
-
// mouse tracking (SGR extended mode —
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
// mouse tracking (SGR extended mode — any-event tracking + extended coordinates)
|
|
16
|
+
// ?1003h = report all mouse events including motion (needed for hover)
|
|
17
|
+
// ?1006h = SGR extended format (supports large coordinates)
|
|
18
|
+
const MOUSE_ON = `${CSI}?1003h${CSI}?1006h`;
|
|
19
|
+
const MOUSE_OFF = `${CSI}?1003l${CSI}?1006l`;
|
|
18
20
|
// cursor movement
|
|
19
21
|
const moveTo = (row, col) => `${CSI}${row};${col}H`;
|
|
20
22
|
const setScrollRegion = (top, bottom) => `${CSI}${top};${bottom}r`;
|
|
@@ -62,6 +64,7 @@ export class TUI {
|
|
|
62
64
|
newWhileScrolled = 0; // entries added while user is scrolled back
|
|
63
65
|
pendingCount = 0; // queued user messages awaiting next tick
|
|
64
66
|
searchPattern = null; // active search filter pattern
|
|
67
|
+
hoverSessionIdx = null; // 1-indexed session under mouse cursor (null = none)
|
|
65
68
|
// drill-down mode: show a single session's full output
|
|
66
69
|
viewMode = "overview";
|
|
67
70
|
drilldownSessionId = null;
|
|
@@ -318,6 +321,7 @@ export class TUI {
|
|
|
318
321
|
this.drilldownSessionId = sessionId;
|
|
319
322
|
this.drilldownScrollOffset = 0;
|
|
320
323
|
this.drilldownNewWhileScrolled = 0;
|
|
324
|
+
this.hoverSessionIdx = null;
|
|
321
325
|
if (this.active) {
|
|
322
326
|
this.computeLayout(this.sessions.length);
|
|
323
327
|
this.paintAll();
|
|
@@ -332,6 +336,7 @@ export class TUI {
|
|
|
332
336
|
this.drilldownSessionId = null;
|
|
333
337
|
this.drilldownScrollOffset = 0;
|
|
334
338
|
this.drilldownNewWhileScrolled = 0;
|
|
339
|
+
this.hoverSessionIdx = null;
|
|
335
340
|
if (this.active) {
|
|
336
341
|
this.computeLayout(this.sessions.length);
|
|
337
342
|
this.paintAll();
|
|
@@ -360,6 +365,25 @@ export class TUI {
|
|
|
360
365
|
getSearchPattern() {
|
|
361
366
|
return this.searchPattern;
|
|
362
367
|
}
|
|
368
|
+
// ── Hover ───────────────────────────────────────────────────────────────
|
|
369
|
+
/** Set the hovered session index (1-indexed) or null to clear. Only repaints the affected cards. */
|
|
370
|
+
setHoverSession(idx) {
|
|
371
|
+
if (idx === this.hoverSessionIdx)
|
|
372
|
+
return; // no change
|
|
373
|
+
const prev = this.hoverSessionIdx;
|
|
374
|
+
this.hoverSessionIdx = idx;
|
|
375
|
+
if (this.active && this.viewMode === "overview") {
|
|
376
|
+
// repaint only the affected session cards (previous and new hover)
|
|
377
|
+
if (prev !== null)
|
|
378
|
+
this.repaintSessionCard(prev);
|
|
379
|
+
if (idx !== null)
|
|
380
|
+
this.repaintSessionCard(idx);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/** Get the current hovered session index (1-indexed, null if none). */
|
|
384
|
+
getHoverSession() {
|
|
385
|
+
return this.hoverSessionIdx;
|
|
386
|
+
}
|
|
363
387
|
// ── Layout computation ──────────────────────────────────────────────────
|
|
364
388
|
updateDimensions() {
|
|
365
389
|
this.cols = process.stderr.columns || 80;
|
|
@@ -451,8 +475,10 @@ export class TUI {
|
|
|
451
475
|
else {
|
|
452
476
|
for (let i = 0; i < this.sessions.length; i++) {
|
|
453
477
|
const s = this.sessions[i];
|
|
454
|
-
const
|
|
455
|
-
const
|
|
478
|
+
const isHovered = this.hoverSessionIdx === i + 1; // 1-indexed
|
|
479
|
+
const bg = isHovered ? BG_HOVER : "";
|
|
480
|
+
const line = `${bg}${SLATE}${BOX.v}${RESET}${bg} ${formatSessionCard(s, innerWidth - 1)}`;
|
|
481
|
+
const padded = padBoxLineHover(line, this.cols, isHovered);
|
|
456
482
|
process.stderr.write(moveTo(startRow + 1 + i, 1) + CLEAR_LINE + padded);
|
|
457
483
|
}
|
|
458
484
|
}
|
|
@@ -467,6 +493,22 @@ export class TUI {
|
|
|
467
493
|
}
|
|
468
494
|
process.stderr.write(RESTORE_CURSOR);
|
|
469
495
|
}
|
|
496
|
+
/** Repaint a single session card by 1-indexed position (for hover updates). */
|
|
497
|
+
repaintSessionCard(idx) {
|
|
498
|
+
if (!this.active || this.viewMode !== "overview")
|
|
499
|
+
return;
|
|
500
|
+
const i = idx - 1; // 0-indexed
|
|
501
|
+
if (i < 0 || i >= this.sessions.length)
|
|
502
|
+
return;
|
|
503
|
+
const startRow = this.headerHeight + 1;
|
|
504
|
+
const innerWidth = this.cols - 2;
|
|
505
|
+
const s = this.sessions[i];
|
|
506
|
+
const isHovered = this.hoverSessionIdx === idx;
|
|
507
|
+
const bg = isHovered ? BG_HOVER : "";
|
|
508
|
+
const line = `${bg}${SLATE}${BOX.v}${RESET}${bg} ${formatSessionCard(s, innerWidth - 1)}`;
|
|
509
|
+
const padded = padBoxLineHover(line, this.cols, isHovered);
|
|
510
|
+
process.stderr.write(SAVE_CURSOR + moveTo(startRow + 1 + i, 1) + CLEAR_LINE + padded + RESTORE_CURSOR);
|
|
511
|
+
}
|
|
470
512
|
paintSeparator() {
|
|
471
513
|
const prefix = `${BOX.h}${BOX.h} activity `;
|
|
472
514
|
let hints;
|
|
@@ -644,6 +686,15 @@ function padBoxLine(line, totalWidth) {
|
|
|
644
686
|
const pad = Math.max(0, totalWidth - visible - 1); // -1 for closing border
|
|
645
687
|
return line + " ".repeat(pad) + `${SLATE}${BOX.v}${RESET}`;
|
|
646
688
|
}
|
|
689
|
+
// pad a box line with optional hover background that extends through the padding
|
|
690
|
+
function padBoxLineHover(line, totalWidth, hovered) {
|
|
691
|
+
const visible = stripAnsiForLen(line);
|
|
692
|
+
const pad = Math.max(0, totalWidth - visible - 1);
|
|
693
|
+
if (hovered) {
|
|
694
|
+
return line + `${BG_HOVER}${" ".repeat(pad)}${RESET}${SLATE}${BOX.v}${RESET}`;
|
|
695
|
+
}
|
|
696
|
+
return line + " ".repeat(pad) + `${SLATE}${BOX.v}${RESET}`;
|
|
697
|
+
}
|
|
647
698
|
// pad the header bar to fill the full width with background color
|
|
648
699
|
function padToWidth(line, totalWidth) {
|
|
649
700
|
const visible = stripAnsiForLen(line);
|
|
@@ -784,5 +835,5 @@ export function hitTestSession(row, headerHeight, sessionCount) {
|
|
|
784
835
|
return row - firstSessionRow + 1; // 1-indexed
|
|
785
836
|
}
|
|
786
837
|
// ── Exported pure helpers (for testing) ─────────────────────────────────────
|
|
787
|
-
export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator };
|
|
838
|
+
export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padBoxLineHover, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator };
|
|
788
839
|
//# sourceMappingURL=tui.js.map
|