aoaoe 0.86.0 → 0.87.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 +10 -0
- package/dist/input.d.ts +3 -0
- package/dist/input.js +16 -0
- package/dist/tui.d.ts +9 -0
- package/dist/tui.js +45 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -454,6 +454,16 @@ async function main() {
|
|
|
454
454
|
tui.log("system", "no sessions are muted");
|
|
455
455
|
}
|
|
456
456
|
});
|
|
457
|
+
// wire /filter tag
|
|
458
|
+
input.onTagFilter((tag) => {
|
|
459
|
+
tui.setTagFilter(tag);
|
|
460
|
+
if (tag) {
|
|
461
|
+
tui.log("system", `filter: ${tag}`);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
tui.log("system", "filter cleared");
|
|
465
|
+
}
|
|
466
|
+
});
|
|
457
467
|
// wire /note set/clear
|
|
458
468
|
input.onNote((target, text) => {
|
|
459
469
|
const num = /^\d+$/.test(target) ? parseInt(target, 10) : undefined;
|
package/dist/input.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export type JumpHandler = (num: number) => void;
|
|
|
13
13
|
export type MarksHandler = () => void;
|
|
14
14
|
export type MuteHandler = (target: string) => void;
|
|
15
15
|
export type UnmuteAllHandler = () => void;
|
|
16
|
+
export type TagFilterHandler = (tag: string | null) => void;
|
|
16
17
|
export type NoteHandler = (target: string, text: string) => void;
|
|
17
18
|
export type NotesHandler = () => void;
|
|
18
19
|
export interface MouseEvent {
|
|
@@ -50,6 +51,7 @@ export declare class InputReader {
|
|
|
50
51
|
private marksHandler;
|
|
51
52
|
private muteHandler;
|
|
52
53
|
private unmuteAllHandler;
|
|
54
|
+
private tagFilterHandler;
|
|
53
55
|
private noteHandler;
|
|
54
56
|
private notesHandler;
|
|
55
57
|
private mouseDataListener;
|
|
@@ -71,6 +73,7 @@ export declare class InputReader {
|
|
|
71
73
|
onMarks(handler: MarksHandler): void;
|
|
72
74
|
onMute(handler: MuteHandler): void;
|
|
73
75
|
onUnmuteAll(handler: UnmuteAllHandler): void;
|
|
76
|
+
onTagFilter(handler: TagFilterHandler): void;
|
|
74
77
|
onNote(handler: NoteHandler): void;
|
|
75
78
|
onNotes(handler: NotesHandler): void;
|
|
76
79
|
private notifyQueueChange;
|
package/dist/input.js
CHANGED
|
@@ -45,6 +45,7 @@ export class InputReader {
|
|
|
45
45
|
marksHandler = null;
|
|
46
46
|
muteHandler = null;
|
|
47
47
|
unmuteAllHandler = null;
|
|
48
|
+
tagFilterHandler = null;
|
|
48
49
|
noteHandler = null;
|
|
49
50
|
notesHandler = null;
|
|
50
51
|
mouseDataListener = null;
|
|
@@ -120,6 +121,10 @@ export class InputReader {
|
|
|
120
121
|
onUnmuteAll(handler) {
|
|
121
122
|
this.unmuteAllHandler = handler;
|
|
122
123
|
}
|
|
124
|
+
// register a callback for tag filter commands (/filter <tag>)
|
|
125
|
+
onTagFilter(handler) {
|
|
126
|
+
this.tagFilterHandler = handler;
|
|
127
|
+
}
|
|
123
128
|
// register a callback for note commands (/note <target> <text>)
|
|
124
129
|
onNote(handler) {
|
|
125
130
|
this.noteHandler = handler;
|
|
@@ -312,6 +317,7 @@ ${BOLD}navigation:${RESET}
|
|
|
312
317
|
/focus toggle focus mode (show only pinned sessions)
|
|
313
318
|
/mute [N|name] mute/unmute a session's activity entries (toggle)
|
|
314
319
|
/unmute-all unmute all sessions at once
|
|
320
|
+
/filter [tag] filter activity by tag (error, system, etc. — no arg = clear)
|
|
315
321
|
/note N|name text attach a note to a session (no text = clear)
|
|
316
322
|
/notes list all session notes
|
|
317
323
|
/mark bookmark current activity position
|
|
@@ -468,6 +474,16 @@ ${BOLD}other:${RESET}
|
|
|
468
474
|
console.error(`${DIM}unmute-all not available (no TUI)${RESET}`);
|
|
469
475
|
}
|
|
470
476
|
break;
|
|
477
|
+
case "/filter": {
|
|
478
|
+
const filterArg = line.slice("/filter".length).trim();
|
|
479
|
+
if (this.tagFilterHandler) {
|
|
480
|
+
this.tagFilterHandler(filterArg || null);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
console.error(`${DIM}filter not available (no TUI)${RESET}`);
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
471
487
|
case "/note": {
|
|
472
488
|
const noteArg = line.slice("/note".length).trim();
|
|
473
489
|
if (this.noteHandler) {
|
package/dist/tui.d.ts
CHANGED
|
@@ -53,6 +53,10 @@ export declare function truncateNote(text: string): string;
|
|
|
53
53
|
export declare function shouldMuteEntry(entry: ActivityEntry, mutedIds: Set<string>): boolean;
|
|
54
54
|
/** Format a suppressed entry count badge for muted sessions. Returns empty string for 0. */
|
|
55
55
|
export declare function formatMuteBadge(count: number): string;
|
|
56
|
+
/** Check if an activity entry matches a tag filter (case-insensitive exact match on tag). */
|
|
57
|
+
export declare function matchesTagFilter(entry: ActivityEntry, tag: string): boolean;
|
|
58
|
+
/** Format the tag filter indicator text for the separator bar. */
|
|
59
|
+
export declare function formatTagFilterIndicator(tag: string, matchCount: number, totalCount: number): string;
|
|
56
60
|
export declare class TUI {
|
|
57
61
|
private active;
|
|
58
62
|
private countdownTimer;
|
|
@@ -71,6 +75,7 @@ export declare class TUI {
|
|
|
71
75
|
private newWhileScrolled;
|
|
72
76
|
private pendingCount;
|
|
73
77
|
private searchPattern;
|
|
78
|
+
private filterTag;
|
|
74
79
|
private hoverSessionIdx;
|
|
75
80
|
private activityTimestamps;
|
|
76
81
|
private sortMode;
|
|
@@ -204,6 +209,10 @@ export declare class TUI {
|
|
|
204
209
|
setSearch(pattern: string | null): void;
|
|
205
210
|
/** Get the current search pattern (or null if no active search). */
|
|
206
211
|
getSearchPattern(): string | null;
|
|
212
|
+
/** Set or clear the tag filter. Resets scroll and repaints. */
|
|
213
|
+
setTagFilter(tag: string | null): void;
|
|
214
|
+
/** Get the current tag filter (or null if none active). */
|
|
215
|
+
getTagFilter(): string | null;
|
|
207
216
|
/** Set the hovered session index (1-indexed) or null to clear. Only repaints the affected cards. */
|
|
208
217
|
setHoverSession(idx: number | null): void;
|
|
209
218
|
/** Get the current hovered session index (1-indexed, null if none). */
|
package/dist/tui.js
CHANGED
|
@@ -181,6 +181,16 @@ export function formatMuteBadge(count) {
|
|
|
181
181
|
const label = count > 999 ? "999+" : String(count);
|
|
182
182
|
return `${DIM}(${label})${RESET}`;
|
|
183
183
|
}
|
|
184
|
+
/** Check if an activity entry matches a tag filter (case-insensitive exact match on tag). */
|
|
185
|
+
export function matchesTagFilter(entry, tag) {
|
|
186
|
+
if (!tag)
|
|
187
|
+
return true;
|
|
188
|
+
return entry.tag.toLowerCase() === tag.toLowerCase();
|
|
189
|
+
}
|
|
190
|
+
/** Format the tag filter indicator text for the separator bar. */
|
|
191
|
+
export function formatTagFilterIndicator(tag, matchCount, totalCount) {
|
|
192
|
+
return `${SLATE}filter:${RESET} ${AMBER}${tag}${RESET} ${DIM}(${matchCount}/${totalCount})${RESET}`;
|
|
193
|
+
}
|
|
184
194
|
// ── TUI class ───────────────────────────────────────────────────────────────
|
|
185
195
|
export class TUI {
|
|
186
196
|
active = false;
|
|
@@ -200,6 +210,7 @@ export class TUI {
|
|
|
200
210
|
newWhileScrolled = 0; // entries added while user is scrolled back
|
|
201
211
|
pendingCount = 0; // queued user messages awaiting next tick
|
|
202
212
|
searchPattern = null; // active search filter pattern
|
|
213
|
+
filterTag = null; // active tag filter (exact match on entry.tag)
|
|
203
214
|
hoverSessionIdx = null; // 1-indexed session under mouse cursor (null = none)
|
|
204
215
|
activityTimestamps = []; // epoch ms of each log() call for sparkline
|
|
205
216
|
sortMode = "default";
|
|
@@ -593,6 +604,9 @@ export class TUI {
|
|
|
593
604
|
if (shouldMuteEntry(entry, this.mutedIds)) {
|
|
594
605
|
// silently skip display — entry is in buffer for scroll-back if unmuted later
|
|
595
606
|
}
|
|
607
|
+
else if (this.filterTag && !matchesTagFilter(entry, this.filterTag)) {
|
|
608
|
+
// tag filter active: silently skip non-matching entries
|
|
609
|
+
}
|
|
596
610
|
else if (this.searchPattern) {
|
|
597
611
|
// search active: only show new entry if it matches
|
|
598
612
|
if (matchesSearch(entry, this.searchPattern)) {
|
|
@@ -638,6 +652,8 @@ export class TUI {
|
|
|
638
652
|
let filtered = this.mutedIds.size > 0
|
|
639
653
|
? this.activityBuffer.filter((e) => !shouldMuteEntry(e, this.mutedIds))
|
|
640
654
|
: this.activityBuffer;
|
|
655
|
+
if (this.filterTag)
|
|
656
|
+
filtered = filtered.filter((e) => matchesTagFilter(e, this.filterTag));
|
|
641
657
|
const entryCount = this.searchPattern
|
|
642
658
|
? filtered.filter((e) => matchesSearch(e, this.searchPattern)).length
|
|
643
659
|
: filtered.length;
|
|
@@ -665,6 +681,8 @@ export class TUI {
|
|
|
665
681
|
let filtered = this.mutedIds.size > 0
|
|
666
682
|
? this.activityBuffer.filter((e) => !shouldMuteEntry(e, this.mutedIds))
|
|
667
683
|
: this.activityBuffer;
|
|
684
|
+
if (this.filterTag)
|
|
685
|
+
filtered = filtered.filter((e) => matchesTagFilter(e, this.filterTag));
|
|
668
686
|
const entryCount = this.searchPattern
|
|
669
687
|
? filtered.filter((e) => matchesSearch(e, this.searchPattern)).length
|
|
670
688
|
: filtered.length;
|
|
@@ -802,6 +820,21 @@ export class TUI {
|
|
|
802
820
|
getSearchPattern() {
|
|
803
821
|
return this.searchPattern;
|
|
804
822
|
}
|
|
823
|
+
// ── Tag filter ─────────────────────────────────────────────────────────
|
|
824
|
+
/** Set or clear the tag filter. Resets scroll and repaints. */
|
|
825
|
+
setTagFilter(tag) {
|
|
826
|
+
this.filterTag = tag && tag.length > 0 ? tag : null;
|
|
827
|
+
this.scrollOffset = 0;
|
|
828
|
+
this.newWhileScrolled = 0;
|
|
829
|
+
if (this.active && this.viewMode === "overview") {
|
|
830
|
+
this.repaintActivityRegion();
|
|
831
|
+
this.paintSeparator();
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
/** Get the current tag filter (or null if none active). */
|
|
835
|
+
getTagFilter() {
|
|
836
|
+
return this.filterTag;
|
|
837
|
+
}
|
|
805
838
|
// ── Hover ───────────────────────────────────────────────────────────────
|
|
806
839
|
/** Set the hovered session index (1-indexed) or null to clear. Only repaints the affected cards. */
|
|
807
840
|
setHoverSession(idx) {
|
|
@@ -1000,7 +1033,15 @@ export class TUI {
|
|
|
1000
1033
|
paintSeparator() {
|
|
1001
1034
|
const prefix = `${BOX.h}${BOX.h} activity `;
|
|
1002
1035
|
let hints;
|
|
1003
|
-
if (this.
|
|
1036
|
+
if (this.filterTag) {
|
|
1037
|
+
// tag filter takes precedence in the separator display
|
|
1038
|
+
let source = this.mutedIds.size > 0
|
|
1039
|
+
? this.activityBuffer.filter((e) => !shouldMuteEntry(e, this.mutedIds))
|
|
1040
|
+
: this.activityBuffer;
|
|
1041
|
+
const matchCount = source.filter((e) => matchesTagFilter(e, this.filterTag)).length;
|
|
1042
|
+
hints = formatTagFilterIndicator(this.filterTag, matchCount, source.length);
|
|
1043
|
+
}
|
|
1044
|
+
else if (this.searchPattern) {
|
|
1004
1045
|
const filtered = this.activityBuffer.filter((e) => matchesSearch(e, this.searchPattern));
|
|
1005
1046
|
hints = formatSearchIndicator(this.searchPattern, filtered.length, this.activityBuffer.length);
|
|
1006
1047
|
}
|
|
@@ -1030,10 +1071,12 @@ export class TUI {
|
|
|
1030
1071
|
}
|
|
1031
1072
|
repaintActivityRegion() {
|
|
1032
1073
|
const visibleLines = this.scrollBottom - this.scrollTop + 1;
|
|
1033
|
-
// filter: muted
|
|
1074
|
+
// filter pipeline: muted → tag → search
|
|
1034
1075
|
let source = this.mutedIds.size > 0
|
|
1035
1076
|
? this.activityBuffer.filter((e) => !shouldMuteEntry(e, this.mutedIds))
|
|
1036
1077
|
: this.activityBuffer;
|
|
1078
|
+
if (this.filterTag)
|
|
1079
|
+
source = source.filter((e) => matchesTagFilter(e, this.filterTag));
|
|
1037
1080
|
if (this.searchPattern) {
|
|
1038
1081
|
source = source.filter((e) => matchesSearch(e, this.searchPattern));
|
|
1039
1082
|
}
|