aoaoe 0.91.0 → 0.93.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 +36 -1
- package/dist/input.js +1 -1
- package/dist/tui.d.ts +18 -2
- package/dist/tui.js +47 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { wakeableSleep } from "./wake.js";
|
|
|
16
16
|
import { classifyMessages, formatUserMessages, buildReceipts, shouldSkipSleep, hasPendingFile, isInsistMessage, stripInsistPrefix } from "./message.js";
|
|
17
17
|
import { TaskManager, loadTaskDefinitions, loadTaskState, formatTaskTable } from "./task-manager.js";
|
|
18
18
|
import { runTaskCli, handleTaskSlashCommand } from "./task-cli.js";
|
|
19
|
-
import { TUI, hitTestSession, nextSortMode, SORT_MODES, formatUptime, formatClipText } from "./tui.js";
|
|
19
|
+
import { TUI, hitTestSession, nextSortMode, SORT_MODES, formatUptime, formatClipText, loadTuiPrefs, saveTuiPrefs } from "./tui.js";
|
|
20
20
|
import { isDaemonRunningFromState } from "./chat.js";
|
|
21
21
|
import { sendNotification, sendTestNotification } from "./notify.js";
|
|
22
22
|
import { startHealthServer } from "./health.js";
|
|
@@ -171,6 +171,34 @@ async function main() {
|
|
|
171
171
|
const pkg = readPkgVersion();
|
|
172
172
|
const useTui = process.stdin.isTTY === true;
|
|
173
173
|
const tui = useTui ? new TUI() : null;
|
|
174
|
+
// restore sticky prefs from previous run
|
|
175
|
+
if (tui) {
|
|
176
|
+
const prefs = loadTuiPrefs();
|
|
177
|
+
if (prefs.sortMode && SORT_MODES.includes(prefs.sortMode))
|
|
178
|
+
tui.setSortMode(prefs.sortMode);
|
|
179
|
+
if (prefs.compact)
|
|
180
|
+
tui.setCompact(true);
|
|
181
|
+
if (prefs.focus)
|
|
182
|
+
tui.setFocus(true);
|
|
183
|
+
if (prefs.bell)
|
|
184
|
+
tui.setBell(true);
|
|
185
|
+
if (prefs.autoPin)
|
|
186
|
+
tui.setAutoPin(true);
|
|
187
|
+
if (prefs.tagFilter)
|
|
188
|
+
tui.setTagFilter(prefs.tagFilter);
|
|
189
|
+
}
|
|
190
|
+
const persistPrefs = () => {
|
|
191
|
+
if (!tui)
|
|
192
|
+
return;
|
|
193
|
+
saveTuiPrefs({
|
|
194
|
+
sortMode: tui.getSortMode(),
|
|
195
|
+
compact: tui.isCompact(),
|
|
196
|
+
focus: tui.isFocused(),
|
|
197
|
+
bell: tui.isBellEnabled(),
|
|
198
|
+
autoPin: tui.isAutoPinEnabled(),
|
|
199
|
+
tagFilter: tui.getTagFilter(),
|
|
200
|
+
});
|
|
201
|
+
};
|
|
174
202
|
if (!useTui) {
|
|
175
203
|
// fallback: plain scrolling output (non-TTY / piped)
|
|
176
204
|
console.error("");
|
|
@@ -363,11 +391,13 @@ async function main() {
|
|
|
363
391
|
if (mode && SORT_MODES.includes(mode)) {
|
|
364
392
|
tui.setSortMode(mode);
|
|
365
393
|
tui.log("system", `sort: ${mode}`);
|
|
394
|
+
persistPrefs();
|
|
366
395
|
}
|
|
367
396
|
else if (!mode) {
|
|
368
397
|
const next = nextSortMode(tui.getSortMode());
|
|
369
398
|
tui.setSortMode(next);
|
|
370
399
|
tui.log("system", `sort: ${next}`);
|
|
400
|
+
persistPrefs();
|
|
371
401
|
}
|
|
372
402
|
else {
|
|
373
403
|
tui.log("system", `unknown sort mode: ${mode} (try: status, name, activity, default)`);
|
|
@@ -378,6 +408,7 @@ async function main() {
|
|
|
378
408
|
const enabled = !tui.isCompact();
|
|
379
409
|
tui.setCompact(enabled);
|
|
380
410
|
tui.log("system", `compact mode: ${enabled ? "on" : "off"}`);
|
|
411
|
+
persistPrefs();
|
|
381
412
|
});
|
|
382
413
|
// wire /mark bookmark
|
|
383
414
|
input.onMark(() => {
|
|
@@ -439,12 +470,14 @@ async function main() {
|
|
|
439
470
|
const enabled = !tui.isFocused();
|
|
440
471
|
tui.setFocus(enabled);
|
|
441
472
|
tui.log("system", `focus mode: ${enabled ? "on (pinned only)" : "off (all sessions)"}`);
|
|
473
|
+
persistPrefs();
|
|
442
474
|
});
|
|
443
475
|
// wire /bell toggle
|
|
444
476
|
input.onBell(() => {
|
|
445
477
|
const enabled = !tui.isBellEnabled();
|
|
446
478
|
tui.setBell(enabled);
|
|
447
479
|
tui.log("system", `bell notifications: ${enabled ? "on" : "off"}`);
|
|
480
|
+
persistPrefs();
|
|
448
481
|
});
|
|
449
482
|
// wire /pin toggle
|
|
450
483
|
input.onPin((target) => {
|
|
@@ -487,6 +520,7 @@ async function main() {
|
|
|
487
520
|
else {
|
|
488
521
|
tui.log("system", "filter cleared");
|
|
489
522
|
}
|
|
523
|
+
persistPrefs();
|
|
490
524
|
});
|
|
491
525
|
// wire /uptime listing
|
|
492
526
|
input.onUptime(() => {
|
|
@@ -509,6 +543,7 @@ async function main() {
|
|
|
509
543
|
const enabled = !tui.isAutoPinEnabled();
|
|
510
544
|
tui.setAutoPin(enabled);
|
|
511
545
|
tui.log("system", `auto-pin on error: ${enabled ? "on" : "off"}`);
|
|
546
|
+
persistPrefs();
|
|
512
547
|
});
|
|
513
548
|
// wire /note set/clear
|
|
514
549
|
input.onNote((target, text) => {
|
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/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. */
|
|
@@ -65,6 +69,18 @@ export declare function formatClipText(entries: readonly ActivityEntry[], n?: nu
|
|
|
65
69
|
export declare function shouldAutoPin(tag: string): boolean;
|
|
66
70
|
/** Format milliseconds as human-readable uptime: "2h 15m", "45m", "3d 2h", "< 1m". */
|
|
67
71
|
export declare function formatUptime(ms: number): string;
|
|
72
|
+
export interface TuiPrefs {
|
|
73
|
+
sortMode?: string;
|
|
74
|
+
compact?: boolean;
|
|
75
|
+
focus?: boolean;
|
|
76
|
+
bell?: boolean;
|
|
77
|
+
autoPin?: boolean;
|
|
78
|
+
tagFilter?: string | null;
|
|
79
|
+
}
|
|
80
|
+
/** Load persisted TUI preferences. Returns empty object on any error. */
|
|
81
|
+
export declare function loadTuiPrefs(): TuiPrefs;
|
|
82
|
+
/** Save TUI preferences to disk. Silently ignores errors. */
|
|
83
|
+
export declare function saveTuiPrefs(prefs: TuiPrefs): void;
|
|
68
84
|
export declare class TUI {
|
|
69
85
|
private active;
|
|
70
86
|
private countdownTimer;
|
|
@@ -229,7 +245,7 @@ export declare class TUI {
|
|
|
229
245
|
setSearch(pattern: string | null): void;
|
|
230
246
|
/** Get the current search pattern (or null if no active search). */
|
|
231
247
|
getSearchPattern(): string | null;
|
|
232
|
-
/** 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. */
|
|
233
249
|
setTagFilter(tag: string | null): void;
|
|
234
250
|
/** Get the current tag filter (or null if none active). */
|
|
235
251
|
getTagFilter(): string | null;
|
package/dist/tui.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
// tui.ts — block-style terminal UI for aoaoe daemon
|
|
2
|
+
// OpenCode-inspired design: box-drawn panels, 256-color palette, phase spinner,
|
|
3
|
+
// visual hierarchy. no external deps — raw ANSI escape codes only.
|
|
4
|
+
//
|
|
5
|
+
// layout (top to bottom):
|
|
6
|
+
// ┌─ header bar (1 row, BG_DARK) ─────────────────────────────────────────┐
|
|
7
|
+
// │ sessions panel (box-drawn, 1 row per session + 2 border rows) │
|
|
8
|
+
// ├─ separator with hints ────────────────────────────────────────────────┤
|
|
9
|
+
// │ activity scroll region (all daemon output scrolls here) │
|
|
10
|
+
// └─ input line (phase-aware prompt) ─────────────────────────────────────┘
|
|
11
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { homedir } from "node:os";
|
|
1
14
|
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
15
|
import { appendHistoryEntry } from "./tui-history.js";
|
|
3
16
|
// ── ANSI helpers ────────────────────────────────────────────────────────────
|
|
@@ -181,11 +194,24 @@ export function formatMuteBadge(count) {
|
|
|
181
194
|
const label = count > 999 ? "999+" : String(count);
|
|
182
195
|
return `${DIM}(${label})${RESET}`;
|
|
183
196
|
}
|
|
184
|
-
/** 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). */
|
|
185
198
|
export function matchesTagFilter(entry, tag) {
|
|
186
199
|
if (!tag)
|
|
187
200
|
return true;
|
|
188
|
-
|
|
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;
|
|
189
215
|
}
|
|
190
216
|
/** Format the tag filter indicator text for the separator bar. */
|
|
191
217
|
export function formatTagFilterIndicator(tag, matchCount, totalCount) {
|
|
@@ -223,7 +249,23 @@ export function formatUptime(ms) {
|
|
|
223
249
|
return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
|
|
224
250
|
return `${minutes}m`;
|
|
225
251
|
}
|
|
226
|
-
|
|
252
|
+
const PREFS_PATH = join(homedir(), ".aoaoe", "tui-prefs.json");
|
|
253
|
+
/** Load persisted TUI preferences. Returns empty object on any error. */
|
|
254
|
+
export function loadTuiPrefs() {
|
|
255
|
+
try {
|
|
256
|
+
return JSON.parse(readFileSync(PREFS_PATH, "utf-8"));
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
return {};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** Save TUI preferences to disk. Silently ignores errors. */
|
|
263
|
+
export function saveTuiPrefs(prefs) {
|
|
264
|
+
try {
|
|
265
|
+
writeFileSync(PREFS_PATH, JSON.stringify(prefs) + "\n", "utf-8");
|
|
266
|
+
}
|
|
267
|
+
catch { /* best effort */ }
|
|
268
|
+
}
|
|
227
269
|
export class TUI {
|
|
228
270
|
active = false;
|
|
229
271
|
countdownTimer = null;
|
|
@@ -886,9 +928,9 @@ export class TUI {
|
|
|
886
928
|
return this.searchPattern;
|
|
887
929
|
}
|
|
888
930
|
// ── Tag filter ─────────────────────────────────────────────────────────
|
|
889
|
-
/** 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. */
|
|
890
932
|
setTagFilter(tag) {
|
|
891
|
-
this.filterTag = tag && tag.length > 0 ? tag : null;
|
|
933
|
+
this.filterTag = tag && tag.length > 0 ? resolveFilterPreset(tag) : null;
|
|
892
934
|
this.scrollOffset = 0;
|
|
893
935
|
this.newWhileScrolled = 0;
|
|
894
936
|
if (this.active && this.viewMode === "overview") {
|