aoaoe 0.81.0 → 0.82.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/index.js +6 -0
- package/dist/input.d.ts +3 -0
- package/dist/input.js +14 -0
- package/dist/tui.d.ts +8 -1
- package/dist/tui.js +57 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -378,6 +378,12 @@ async function main() {
|
|
|
378
378
|
tui.setCompact(enabled);
|
|
379
379
|
tui.log("system", `compact mode: ${enabled ? "on" : "off"}`);
|
|
380
380
|
});
|
|
381
|
+
// wire /focus toggle
|
|
382
|
+
input.onFocus(() => {
|
|
383
|
+
const enabled = !tui.isFocused();
|
|
384
|
+
tui.setFocus(enabled);
|
|
385
|
+
tui.log("system", `focus mode: ${enabled ? "on (pinned only)" : "off (all sessions)"}`);
|
|
386
|
+
});
|
|
381
387
|
// wire /bell toggle
|
|
382
388
|
input.onBell(() => {
|
|
383
389
|
const enabled = !tui.isBellEnabled();
|
package/dist/input.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export type SortHandler = (mode: string | null) => void;
|
|
|
7
7
|
export type CompactHandler = () => void;
|
|
8
8
|
export type PinHandler = (target: string) => void;
|
|
9
9
|
export type BellHandler = () => void;
|
|
10
|
+
export type FocusHandler = () => void;
|
|
10
11
|
export interface MouseEvent {
|
|
11
12
|
button: number;
|
|
12
13
|
col: number;
|
|
@@ -36,6 +37,7 @@ export declare class InputReader {
|
|
|
36
37
|
private compactHandler;
|
|
37
38
|
private pinHandler;
|
|
38
39
|
private bellHandler;
|
|
40
|
+
private focusHandler;
|
|
39
41
|
private mouseDataListener;
|
|
40
42
|
onScroll(handler: (dir: ScrollDirection) => void): void;
|
|
41
43
|
onQueueChange(handler: (count: number) => void): void;
|
|
@@ -49,6 +51,7 @@ export declare class InputReader {
|
|
|
49
51
|
onCompact(handler: CompactHandler): void;
|
|
50
52
|
onPin(handler: PinHandler): void;
|
|
51
53
|
onBell(handler: BellHandler): void;
|
|
54
|
+
onFocus(handler: FocusHandler): void;
|
|
52
55
|
private notifyQueueChange;
|
|
53
56
|
start(): void;
|
|
54
57
|
drain(): string[];
|
package/dist/input.js
CHANGED
|
@@ -39,6 +39,7 @@ export class InputReader {
|
|
|
39
39
|
compactHandler = null;
|
|
40
40
|
pinHandler = null;
|
|
41
41
|
bellHandler = null;
|
|
42
|
+
focusHandler = null;
|
|
42
43
|
mouseDataListener = null;
|
|
43
44
|
// register a callback for scroll key events (PgUp/PgDn/Home/End)
|
|
44
45
|
onScroll(handler) {
|
|
@@ -88,6 +89,10 @@ export class InputReader {
|
|
|
88
89
|
onBell(handler) {
|
|
89
90
|
this.bellHandler = handler;
|
|
90
91
|
}
|
|
92
|
+
// register a callback for focus mode toggle (/focus)
|
|
93
|
+
onFocus(handler) {
|
|
94
|
+
this.focusHandler = handler;
|
|
95
|
+
}
|
|
91
96
|
notifyQueueChange() {
|
|
92
97
|
this.queueChangeHandler?.(this.queue.length);
|
|
93
98
|
}
|
|
@@ -269,6 +274,7 @@ ${BOLD}navigation:${RESET}
|
|
|
269
274
|
/compact toggle compact mode (dense session panel)
|
|
270
275
|
/pin [N|name] pin/unpin a session to the top (toggle)
|
|
271
276
|
/bell toggle terminal bell on errors/completions
|
|
277
|
+
/focus toggle focus mode (show only pinned sessions)
|
|
272
278
|
/search <pattern> filter activity entries by substring (case-insensitive)
|
|
273
279
|
/search clear active search filter
|
|
274
280
|
click session click an agent card to drill down (click again to go back)
|
|
@@ -389,6 +395,14 @@ ${BOLD}other:${RESET}
|
|
|
389
395
|
console.error(`${DIM}bell not available (no TUI)${RESET}`);
|
|
390
396
|
}
|
|
391
397
|
break;
|
|
398
|
+
case "/focus":
|
|
399
|
+
if (this.focusHandler) {
|
|
400
|
+
this.focusHandler();
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
console.error(`${DIM}focus not available (no TUI)${RESET}`);
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
392
406
|
case "/search": {
|
|
393
407
|
const searchArg = line.slice("/search".length).trim();
|
|
394
408
|
if (this.searchHandler) {
|
package/dist/tui.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare class TUI {
|
|
|
53
53
|
private prevLastActivity;
|
|
54
54
|
private compactMode;
|
|
55
55
|
private pinnedIds;
|
|
56
|
+
private focusMode;
|
|
56
57
|
private bellEnabled;
|
|
57
58
|
private lastBellAt;
|
|
58
59
|
private viewMode;
|
|
@@ -70,7 +71,7 @@ export declare class TUI {
|
|
|
70
71
|
start(version: string): void;
|
|
71
72
|
stop(): void;
|
|
72
73
|
isActive(): boolean;
|
|
73
|
-
/** Return the current number of sessions (for mouse hit testing) */
|
|
74
|
+
/** Return the current number of visible sessions (for mouse hit testing) */
|
|
74
75
|
getSessionCount(): number;
|
|
75
76
|
/** Set the session sort mode and repaint. */
|
|
76
77
|
setSortMode(mode: SortMode): void;
|
|
@@ -89,6 +90,12 @@ export declare class TUI {
|
|
|
89
90
|
isPinned(id: string): boolean;
|
|
90
91
|
/** Return count of pinned sessions. */
|
|
91
92
|
getPinnedCount(): number;
|
|
93
|
+
/** Enable or disable focus mode. When focused, only pinned sessions are visible. */
|
|
94
|
+
setFocus(enabled: boolean): void;
|
|
95
|
+
/** Return whether focus mode is enabled. */
|
|
96
|
+
isFocused(): boolean;
|
|
97
|
+
/** Return count of visible sessions (all in normal mode, pinned-only in focus mode). */
|
|
98
|
+
private getVisibleCount;
|
|
92
99
|
/** Enable or disable terminal bell notifications. */
|
|
93
100
|
setBell(enabled: boolean): void;
|
|
94
101
|
/** Return whether terminal bell is enabled. */
|
package/dist/tui.js
CHANGED
|
@@ -161,6 +161,7 @@ export class TUI {
|
|
|
161
161
|
prevLastActivity = new Map(); // session ID → previous lastActivity string
|
|
162
162
|
compactMode = false;
|
|
163
163
|
pinnedIds = new Set(); // pinned session IDs (always sort to top)
|
|
164
|
+
focusMode = false; // focus mode: hide all sessions except pinned
|
|
164
165
|
bellEnabled = false;
|
|
165
166
|
lastBellAt = 0;
|
|
166
167
|
// drill-down mode: show a single session's full output
|
|
@@ -215,9 +216,9 @@ export class TUI {
|
|
|
215
216
|
isActive() {
|
|
216
217
|
return this.active;
|
|
217
218
|
}
|
|
218
|
-
/** Return the current number of sessions (for mouse hit testing) */
|
|
219
|
+
/** Return the current number of visible sessions (for mouse hit testing) */
|
|
219
220
|
getSessionCount() {
|
|
220
|
-
return this.
|
|
221
|
+
return this.getVisibleCount();
|
|
221
222
|
}
|
|
222
223
|
/** Set the session sort mode and repaint. */
|
|
223
224
|
setSortMode(mode) {
|
|
@@ -240,7 +241,7 @@ export class TUI {
|
|
|
240
241
|
return;
|
|
241
242
|
this.compactMode = enabled;
|
|
242
243
|
if (this.active) {
|
|
243
|
-
this.computeLayout(this.
|
|
244
|
+
this.computeLayout(this.getVisibleCount());
|
|
244
245
|
this.paintAll();
|
|
245
246
|
}
|
|
246
247
|
}
|
|
@@ -285,6 +286,31 @@ export class TUI {
|
|
|
285
286
|
getPinnedCount() {
|
|
286
287
|
return this.pinnedIds.size;
|
|
287
288
|
}
|
|
289
|
+
/** Enable or disable focus mode. When focused, only pinned sessions are visible. */
|
|
290
|
+
setFocus(enabled) {
|
|
291
|
+
if (enabled === this.focusMode)
|
|
292
|
+
return;
|
|
293
|
+
this.focusMode = enabled;
|
|
294
|
+
if (this.active) {
|
|
295
|
+
this.computeLayout(this.getVisibleCount());
|
|
296
|
+
this.paintAll();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** Return whether focus mode is enabled. */
|
|
300
|
+
isFocused() {
|
|
301
|
+
return this.focusMode;
|
|
302
|
+
}
|
|
303
|
+
/** Return count of visible sessions (all in normal mode, pinned-only in focus mode). */
|
|
304
|
+
getVisibleCount() {
|
|
305
|
+
if (!this.focusMode)
|
|
306
|
+
return this.sessions.length;
|
|
307
|
+
let count = 0;
|
|
308
|
+
for (const s of this.sessions) {
|
|
309
|
+
if (this.pinnedIds.has(s.id))
|
|
310
|
+
count++;
|
|
311
|
+
}
|
|
312
|
+
return count;
|
|
313
|
+
}
|
|
288
314
|
/** Enable or disable terminal bell notifications. */
|
|
289
315
|
setBell(enabled) {
|
|
290
316
|
this.bellEnabled = enabled;
|
|
@@ -319,10 +345,11 @@ export class TUI {
|
|
|
319
345
|
this.prevLastActivity.set(s.id, s.lastActivity);
|
|
320
346
|
}
|
|
321
347
|
const sorted = sortSessions(opts.sessions, this.sortMode, this.lastChangeAt, this.pinnedIds);
|
|
322
|
-
const
|
|
348
|
+
const prevVisibleCount = this.getVisibleCount();
|
|
323
349
|
this.sessions = sorted;
|
|
324
|
-
|
|
325
|
-
|
|
350
|
+
const newVisibleCount = this.getVisibleCount();
|
|
351
|
+
if (newVisibleCount !== prevVisibleCount) {
|
|
352
|
+
this.computeLayout(newVisibleCount);
|
|
326
353
|
this.paintAll();
|
|
327
354
|
return;
|
|
328
355
|
}
|
|
@@ -516,7 +543,7 @@ export class TUI {
|
|
|
516
543
|
this.drilldownNewWhileScrolled = 0;
|
|
517
544
|
this.hoverSessionIdx = null;
|
|
518
545
|
if (this.active) {
|
|
519
|
-
this.computeLayout(this.
|
|
546
|
+
this.computeLayout(this.getVisibleCount());
|
|
520
547
|
this.paintAll();
|
|
521
548
|
}
|
|
522
549
|
return true;
|
|
@@ -531,7 +558,7 @@ export class TUI {
|
|
|
531
558
|
this.drilldownNewWhileScrolled = 0;
|
|
532
559
|
this.hoverSessionIdx = null;
|
|
533
560
|
if (this.active) {
|
|
534
|
-
this.computeLayout(this.
|
|
561
|
+
this.computeLayout(this.getVisibleCount());
|
|
535
562
|
this.paintAll();
|
|
536
563
|
}
|
|
537
564
|
}
|
|
@@ -594,8 +621,9 @@ export class TUI {
|
|
|
594
621
|
}
|
|
595
622
|
else {
|
|
596
623
|
// overview: header (1) + sessions box + separator + activity + input
|
|
624
|
+
const visibleSessions = this.sessions.slice(0, this.getVisibleCount());
|
|
597
625
|
const sessBodyRows = this.compactMode
|
|
598
|
-
? computeCompactRowCount(
|
|
626
|
+
? computeCompactRowCount(visibleSessions, this.cols - 2)
|
|
599
627
|
: Math.max(sessionCount, 1);
|
|
600
628
|
this.sessionRows = sessBodyRows + 2; // + top/bottom borders
|
|
601
629
|
this.separatorRow = this.headerHeight + this.sessionRows + 1;
|
|
@@ -608,7 +636,7 @@ export class TUI {
|
|
|
608
636
|
}
|
|
609
637
|
}
|
|
610
638
|
onResize() {
|
|
611
|
-
this.computeLayout(this.
|
|
639
|
+
this.computeLayout(this.getVisibleCount());
|
|
612
640
|
this.paintAll();
|
|
613
641
|
}
|
|
614
642
|
// ── Painting ────────────────────────────────────────────────────────────
|
|
@@ -636,7 +664,10 @@ export class TUI {
|
|
|
636
664
|
}
|
|
637
665
|
else {
|
|
638
666
|
const phaseText = phaseDisplay(this.phase, this.paused, this.spinnerFrame);
|
|
639
|
-
const
|
|
667
|
+
const visCount = this.getVisibleCount();
|
|
668
|
+
const sessCount = this.focusMode
|
|
669
|
+
? `${visCount}/${this.sessions.length} agent${this.sessions.length !== 1 ? "s" : ""}`
|
|
670
|
+
: `${this.sessions.length} agent${this.sessions.length !== 1 ? "s" : ""}`;
|
|
640
671
|
const activeCount = this.sessions.filter((s) => s.userActive).length;
|
|
641
672
|
const activeTag = activeCount > 0 ? ` ${SLATE}│${RESET} ${AMBER}${activeCount} user${RESET}` : "";
|
|
642
673
|
// countdown to next tick (only in sleeping phase)
|
|
@@ -656,23 +687,29 @@ export class TUI {
|
|
|
656
687
|
paintSessions() {
|
|
657
688
|
const startRow = this.headerHeight + 1;
|
|
658
689
|
const innerWidth = this.cols - 2; // inside the box borders
|
|
659
|
-
|
|
690
|
+
const visibleCount = this.getVisibleCount();
|
|
691
|
+
const visibleSessions = this.sessions.slice(0, visibleCount); // pinned sort to top
|
|
692
|
+
// top border with label (includes focus/compact/sort mode tags)
|
|
693
|
+
const focusTag = this.focusMode ? "focus" : "";
|
|
660
694
|
const sortTag = this.sortMode !== "default" ? this.sortMode : "";
|
|
661
695
|
const compactTag = this.compactMode ? "compact" : "";
|
|
662
|
-
const tags = [compactTag, sortTag].filter(Boolean).join(", ");
|
|
696
|
+
const tags = [focusTag, compactTag, sortTag].filter(Boolean).join(", ");
|
|
663
697
|
const label = tags ? ` agents (${tags}) ` : " agents ";
|
|
664
698
|
const borderAfterLabel = Math.max(0, innerWidth - label.length);
|
|
665
699
|
const topBorder = `${SLATE}${BOX.rtl}${BOX.h}${RESET}${SLATE}${label}${RESET}${SLATE}${BOX.h.repeat(borderAfterLabel)}${BOX.rtr}${RESET}`;
|
|
666
700
|
process.stderr.write(SAVE_CURSOR + moveTo(startRow, 1) + CLEAR_LINE + truncateAnsi(topBorder, this.cols));
|
|
667
|
-
if (
|
|
701
|
+
if (visibleSessions.length === 0) {
|
|
668
702
|
// empty state
|
|
669
|
-
const
|
|
703
|
+
const msg = this.focusMode && this.sessions.length > 0
|
|
704
|
+
? `${DIM}no pinned agents — /pin to add, /focus to exit${RESET}`
|
|
705
|
+
: `${DIM}no agents connected${RESET}`;
|
|
706
|
+
const empty = `${SLATE}${BOX.v}${RESET} ${msg}`;
|
|
670
707
|
const padded = padBoxLine(empty, this.cols);
|
|
671
708
|
process.stderr.write(moveTo(startRow + 1, 1) + CLEAR_LINE + padded);
|
|
672
709
|
}
|
|
673
710
|
else if (this.compactMode) {
|
|
674
711
|
// compact: inline tokens, multiple per row (with pin indicators)
|
|
675
|
-
const compactRows = formatCompactRows(
|
|
712
|
+
const compactRows = formatCompactRows(visibleSessions, innerWidth - 1, this.pinnedIds);
|
|
676
713
|
for (let r = 0; r < compactRows.length; r++) {
|
|
677
714
|
const line = `${SLATE}${BOX.v}${RESET} ${compactRows[r]}`;
|
|
678
715
|
const padded = padBoxLine(line, this.cols);
|
|
@@ -680,8 +717,8 @@ export class TUI {
|
|
|
680
717
|
}
|
|
681
718
|
}
|
|
682
719
|
else {
|
|
683
|
-
for (let i = 0; i <
|
|
684
|
-
const s =
|
|
720
|
+
for (let i = 0; i < visibleSessions.length; i++) {
|
|
721
|
+
const s = visibleSessions[i];
|
|
685
722
|
const isHovered = this.hoverSessionIdx === i + 1; // 1-indexed
|
|
686
723
|
const bg = isHovered ? BG_HOVER : "";
|
|
687
724
|
const pinned = this.pinnedIds.has(s.id);
|
|
@@ -694,8 +731,8 @@ export class TUI {
|
|
|
694
731
|
}
|
|
695
732
|
// bottom border
|
|
696
733
|
const bodyRows = this.compactMode
|
|
697
|
-
? computeCompactRowCount(
|
|
698
|
-
: Math.max(
|
|
734
|
+
? computeCompactRowCount(visibleSessions, innerWidth)
|
|
735
|
+
: Math.max(visibleCount, 1);
|
|
699
736
|
const bottomRow = startRow + 1 + bodyRows;
|
|
700
737
|
const bottomBorder = `${SLATE}${BOX.rbl}${BOX.h.repeat(Math.max(0, this.cols - 2))}${BOX.rbr}${RESET}`;
|
|
701
738
|
process.stderr.write(moveTo(bottomRow, 1) + CLEAR_LINE + truncateAnsi(bottomBorder, this.cols));
|