aoaoe 0.92.0 → 0.94.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/input.js +1 -1
- package/dist/stats.d.ts +3 -0
- package/dist/stats.js +25 -1
- package/dist/tui.d.ts +6 -2
- package/dist/tui.js +17 -4
- package/package.json +1 -1
package/dist/input.js
CHANGED
|
@@ -337,7 +337,7 @@ ${BOLD}navigation:${RESET}
|
|
|
337
337
|
/focus toggle focus mode (show only pinned sessions)
|
|
338
338
|
/mute [N|name] mute/unmute a session's activity entries (toggle)
|
|
339
339
|
/unmute-all unmute all sessions at once
|
|
340
|
-
/filter [tag] filter activity by tag
|
|
340
|
+
/filter [tag] filter activity by tag — presets: errors, actions, system (no arg = clear)
|
|
341
341
|
/uptime show session uptimes (time since first observed)
|
|
342
342
|
/auto-pin toggle auto-pin on error (pin sessions that emit errors)
|
|
343
343
|
/note N|name text attach a note to a session (no text = clear)
|
package/dist/stats.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface ActionStats {
|
|
|
15
15
|
export interface HistoryStats {
|
|
16
16
|
total: number;
|
|
17
17
|
byTag: Map<string, number>;
|
|
18
|
+
byHour: number[];
|
|
18
19
|
firstTs: number;
|
|
19
20
|
lastTs: number;
|
|
20
21
|
}
|
|
@@ -51,4 +52,6 @@ export declare function formatRate(count: number, spanMs: number): string;
|
|
|
51
52
|
* Format the full stats display for terminal output.
|
|
52
53
|
*/
|
|
53
54
|
export declare function formatStats(stats: CombinedStats, windowLabel?: string): string;
|
|
55
|
+
/** Format a 24-element heatmap as a colored block string. */
|
|
56
|
+
export declare function formatHeatmap(counts: number[]): string;
|
|
54
57
|
//# sourceMappingURL=stats.d.ts.map
|
package/dist/stats.js
CHANGED
|
@@ -59,6 +59,7 @@ export function parseActionStats(lines, maxAgeMs, now) {
|
|
|
59
59
|
export function parseHistoryStats(entries, maxAgeMs, now) {
|
|
60
60
|
const cutoff = maxAgeMs ? (now ?? Date.now()) - maxAgeMs : 0;
|
|
61
61
|
const byTag = new Map();
|
|
62
|
+
const byHour = new Array(24).fill(0);
|
|
62
63
|
let total = 0;
|
|
63
64
|
let firstTs = Infinity;
|
|
64
65
|
let lastTs = 0;
|
|
@@ -71,10 +72,11 @@ export function parseHistoryStats(entries, maxAgeMs, now) {
|
|
|
71
72
|
if (entry.ts > lastTs)
|
|
72
73
|
lastTs = entry.ts;
|
|
73
74
|
byTag.set(entry.tag, (byTag.get(entry.tag) ?? 0) + 1);
|
|
75
|
+
byHour[new Date(entry.ts).getHours()]++;
|
|
74
76
|
}
|
|
75
77
|
if (total === 0)
|
|
76
78
|
return null;
|
|
77
|
-
return { total, byTag, firstTs, lastTs };
|
|
79
|
+
return { total, byTag, byHour, firstTs, lastTs };
|
|
78
80
|
}
|
|
79
81
|
/**
|
|
80
82
|
* Combine action and history stats into a unified stats object.
|
|
@@ -214,8 +216,30 @@ export function formatStats(stats, windowLabel) {
|
|
|
214
216
|
lines.push(` ${color}${tag.padEnd(18)}${RESET} ${String(count).padStart(4)} ${SLATE}${bar}${RESET} ${DIM}${pct}%${RESET}`);
|
|
215
217
|
}
|
|
216
218
|
}
|
|
219
|
+
// hourly heatmap
|
|
220
|
+
if (stats.history && stats.history.total > 0) {
|
|
221
|
+
lines.push("");
|
|
222
|
+
lines.push(` ${BOLD}hourly activity${RESET}`);
|
|
223
|
+
lines.push(` ${formatHeatmap(stats.history.byHour)}`);
|
|
224
|
+
lines.push(` ${DIM}${"0".padEnd(6)}${"6".padEnd(6)}${"12".padEnd(6)}${"18".padEnd(5)}23${RESET}`);
|
|
225
|
+
}
|
|
217
226
|
lines.push(` ${hr}`);
|
|
218
227
|
lines.push("");
|
|
219
228
|
return lines.join("\n");
|
|
220
229
|
}
|
|
230
|
+
// ── Heatmap ──────────────────────────────────────────────────────────────────
|
|
231
|
+
const HEAT_BLOCKS = [" ", "░", "▒", "▓", "█"];
|
|
232
|
+
/** Format a 24-element heatmap as a colored block string. */
|
|
233
|
+
export function formatHeatmap(counts) {
|
|
234
|
+
const max = Math.max(...counts);
|
|
235
|
+
if (max === 0)
|
|
236
|
+
return DIM + HEAT_BLOCKS[0].repeat(24) + RESET;
|
|
237
|
+
return counts.map((c) => {
|
|
238
|
+
if (c === 0)
|
|
239
|
+
return `${SLATE}${HEAT_BLOCKS[0]}${RESET}`;
|
|
240
|
+
const level = Math.min(HEAT_BLOCKS.length - 1, Math.ceil((c / max) * (HEAT_BLOCKS.length - 1)));
|
|
241
|
+
const color = level <= 1 ? SLATE : level <= 2 ? SKY : level <= 3 ? AMBER : LIME;
|
|
242
|
+
return `${color}${HEAT_BLOCKS[level]}${RESET}`;
|
|
243
|
+
}).join("");
|
|
244
|
+
}
|
|
221
245
|
//# sourceMappingURL=stats.js.map
|
package/dist/tui.d.ts
CHANGED
|
@@ -53,8 +53,12 @@ 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
|
|
56
|
+
/** Check if an activity entry matches a tag filter (case-insensitive, supports pipe-separated multi-tag). */
|
|
57
57
|
export declare function matchesTagFilter(entry: ActivityEntry, tag: string): boolean;
|
|
58
|
+
/** Built-in filter presets: name → pipe-separated tag pattern. */
|
|
59
|
+
export declare const FILTER_PRESETS: Record<string, string>;
|
|
60
|
+
/** Resolve a filter string — expands preset names, returns raw tag otherwise. */
|
|
61
|
+
export declare function resolveFilterPreset(input: string): string;
|
|
58
62
|
/** Format the tag filter indicator text for the separator bar. */
|
|
59
63
|
export declare function formatTagFilterIndicator(tag: string, matchCount: number, totalCount: number): string;
|
|
60
64
|
/** Default number of entries for /clip when no count specified. */
|
|
@@ -241,7 +245,7 @@ export declare class TUI {
|
|
|
241
245
|
setSearch(pattern: string | null): void;
|
|
242
246
|
/** Get the current search pattern (or null if no active search). */
|
|
243
247
|
getSearchPattern(): string | null;
|
|
244
|
-
/** Set or clear the tag filter. Resets scroll and repaints. */
|
|
248
|
+
/** Set or clear the tag filter. Resolves presets (e.g. "errors"). Resets scroll and repaints. */
|
|
245
249
|
setTagFilter(tag: string | null): void;
|
|
246
250
|
/** Get the current tag filter (or null if none active). */
|
|
247
251
|
getTagFilter(): string | null;
|
package/dist/tui.js
CHANGED
|
@@ -194,11 +194,24 @@ export function formatMuteBadge(count) {
|
|
|
194
194
|
const label = count > 999 ? "999+" : String(count);
|
|
195
195
|
return `${DIM}(${label})${RESET}`;
|
|
196
196
|
}
|
|
197
|
-
/** Check if an activity entry matches a tag filter (case-insensitive
|
|
197
|
+
/** Check if an activity entry matches a tag filter (case-insensitive, supports pipe-separated multi-tag). */
|
|
198
198
|
export function matchesTagFilter(entry, tag) {
|
|
199
199
|
if (!tag)
|
|
200
200
|
return true;
|
|
201
|
-
|
|
201
|
+
const lower = entry.tag.toLowerCase();
|
|
202
|
+
if (tag.includes("|"))
|
|
203
|
+
return tag.toLowerCase().split("|").some((t) => lower === t.trim());
|
|
204
|
+
return lower === tag.toLowerCase();
|
|
205
|
+
}
|
|
206
|
+
/** Built-in filter presets: name → pipe-separated tag pattern. */
|
|
207
|
+
export const FILTER_PRESETS = {
|
|
208
|
+
errors: "error|! action",
|
|
209
|
+
actions: "+ action|! action",
|
|
210
|
+
system: "system|status",
|
|
211
|
+
};
|
|
212
|
+
/** Resolve a filter string — expands preset names, returns raw tag otherwise. */
|
|
213
|
+
export function resolveFilterPreset(input) {
|
|
214
|
+
return FILTER_PRESETS[input.toLowerCase()] ?? input;
|
|
202
215
|
}
|
|
203
216
|
/** Format the tag filter indicator text for the separator bar. */
|
|
204
217
|
export function formatTagFilterIndicator(tag, matchCount, totalCount) {
|
|
@@ -915,9 +928,9 @@ export class TUI {
|
|
|
915
928
|
return this.searchPattern;
|
|
916
929
|
}
|
|
917
930
|
// ── Tag filter ─────────────────────────────────────────────────────────
|
|
918
|
-
/** Set or clear the tag filter. Resets scroll and repaints. */
|
|
931
|
+
/** Set or clear the tag filter. Resolves presets (e.g. "errors"). Resets scroll and repaints. */
|
|
919
932
|
setTagFilter(tag) {
|
|
920
|
-
this.filterTag = tag && tag.length > 0 ? tag : null;
|
|
933
|
+
this.filterTag = tag && tag.length > 0 ? resolveFilterPreset(tag) : null;
|
|
921
934
|
this.scrollOffset = 0;
|
|
922
935
|
this.newWhileScrolled = 0;
|
|
923
936
|
if (this.active && this.viewMode === "overview") {
|