aoaoe 0.89.0 → 0.91.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 +49 -1
- package/dist/input.d.ts +6 -0
- package/dist/input.js +40 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.js +13 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
2
3
|
import { loadConfig, validateEnvironment, parseCliArgs, printHelp, configFileExists, findConfigFile, DEFAULTS, computeConfigDiff } from "./config.js";
|
|
3
4
|
import { Poller, computeTmuxName } from "./poller.js";
|
|
4
5
|
import { createReasoner } from "./reasoner/index.js";
|
|
@@ -15,7 +16,7 @@ import { wakeableSleep } from "./wake.js";
|
|
|
15
16
|
import { classifyMessages, formatUserMessages, buildReceipts, shouldSkipSleep, hasPendingFile, isInsistMessage, stripInsistPrefix } from "./message.js";
|
|
16
17
|
import { TaskManager, loadTaskDefinitions, loadTaskState, formatTaskTable } from "./task-manager.js";
|
|
17
18
|
import { runTaskCli, handleTaskSlashCommand } from "./task-cli.js";
|
|
18
|
-
import { TUI, hitTestSession, nextSortMode, SORT_MODES, formatUptime } from "./tui.js";
|
|
19
|
+
import { TUI, hitTestSession, nextSortMode, SORT_MODES, formatUptime, formatClipText } from "./tui.js";
|
|
19
20
|
import { isDaemonRunningFromState } from "./chat.js";
|
|
20
21
|
import { sendNotification, sendTestNotification } from "./notify.js";
|
|
21
22
|
import { startHealthServer } from "./health.js";
|
|
@@ -410,6 +411,29 @@ async function main() {
|
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
413
|
});
|
|
414
|
+
// wire /diff N to show activity since a bookmark
|
|
415
|
+
input.onDiff((num) => {
|
|
416
|
+
const bms = tui.getBookmarks();
|
|
417
|
+
const bm = bms[num - 1];
|
|
418
|
+
if (!bm) {
|
|
419
|
+
tui.log("system", `bookmark #${num} not found`);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const buffer = tui.getActivityBuffer();
|
|
423
|
+
const entries = buffer.slice(bm.index);
|
|
424
|
+
if (entries.length === 0) {
|
|
425
|
+
tui.log("system", `no activity since bookmark #${num}`);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
tui.log("system", `${entries.length} entries since bookmark #${num} (${bm.label}):`);
|
|
429
|
+
for (const e of entries.slice(-30)) { // cap at last 30 to avoid spam
|
|
430
|
+
tui.log("system", ` [${e.time}] ${e.tag}: ${e.text}`);
|
|
431
|
+
}
|
|
432
|
+
if (entries.length > 30) {
|
|
433
|
+
tui.log("system", ` ... (${entries.length - 30} more — use /clip to export all)`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
});
|
|
413
437
|
// wire /focus toggle
|
|
414
438
|
input.onFocus(() => {
|
|
415
439
|
const enabled = !tui.isFocused();
|
|
@@ -517,6 +541,30 @@ async function main() {
|
|
|
517
541
|
}
|
|
518
542
|
}
|
|
519
543
|
});
|
|
544
|
+
// wire /clip to export activity entries to clipboard or file
|
|
545
|
+
input.onClip((count) => {
|
|
546
|
+
const buffer = tui.getActivityBuffer();
|
|
547
|
+
if (buffer.length === 0) {
|
|
548
|
+
tui.log("system", "no activity to clip");
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const text = formatClipText(buffer, count);
|
|
552
|
+
const entryCount = Math.min(count, buffer.length);
|
|
553
|
+
try {
|
|
554
|
+
execSync("pbcopy", { input: text, timeout: 5000 });
|
|
555
|
+
tui.log("system", `copied ${entryCount} entries to clipboard`);
|
|
556
|
+
}
|
|
557
|
+
catch {
|
|
558
|
+
try {
|
|
559
|
+
const clipPath = join(homedir(), ".aoaoe", "clip.txt");
|
|
560
|
+
writeFileSync(clipPath, text, "utf-8");
|
|
561
|
+
tui.log("system", `saved ${entryCount} entries to ~/.aoaoe/clip.txt`);
|
|
562
|
+
}
|
|
563
|
+
catch (writeErr) {
|
|
564
|
+
tui.log("error", `clip failed: ${writeErr}`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
});
|
|
520
568
|
// wire mouse move to hover highlight on session cards (disabled in compact)
|
|
521
569
|
input.onMouseMove((row, _col) => {
|
|
522
570
|
if (tui.getViewMode() === "overview" && !tui.isCompact()) {
|
package/dist/input.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export type UptimeHandler = () => void;
|
|
|
18
18
|
export type AutoPinHandler = () => void;
|
|
19
19
|
export type NoteHandler = (target: string, text: string) => void;
|
|
20
20
|
export type NotesHandler = () => void;
|
|
21
|
+
export type ClipHandler = (count: number) => void;
|
|
22
|
+
export type DiffHandler = (bookmarkNum: number) => void;
|
|
21
23
|
export interface MouseEvent {
|
|
22
24
|
button: number;
|
|
23
25
|
col: number;
|
|
@@ -58,6 +60,8 @@ export declare class InputReader {
|
|
|
58
60
|
private autoPinHandler;
|
|
59
61
|
private noteHandler;
|
|
60
62
|
private notesHandler;
|
|
63
|
+
private clipHandler;
|
|
64
|
+
private diffHandler;
|
|
61
65
|
private mouseDataListener;
|
|
62
66
|
onScroll(handler: (dir: ScrollDirection) => void): void;
|
|
63
67
|
onQueueChange(handler: (count: number) => void): void;
|
|
@@ -82,6 +86,8 @@ export declare class InputReader {
|
|
|
82
86
|
onAutoPin(handler: AutoPinHandler): void;
|
|
83
87
|
onNote(handler: NoteHandler): void;
|
|
84
88
|
onNotes(handler: NotesHandler): void;
|
|
89
|
+
onClip(handler: ClipHandler): void;
|
|
90
|
+
onDiff(handler: DiffHandler): void;
|
|
85
91
|
private notifyQueueChange;
|
|
86
92
|
start(): void;
|
|
87
93
|
drain(): string[];
|
package/dist/input.js
CHANGED
|
@@ -50,6 +50,8 @@ export class InputReader {
|
|
|
50
50
|
autoPinHandler = null;
|
|
51
51
|
noteHandler = null;
|
|
52
52
|
notesHandler = null;
|
|
53
|
+
clipHandler = null;
|
|
54
|
+
diffHandler = null;
|
|
53
55
|
mouseDataListener = null;
|
|
54
56
|
// register a callback for scroll key events (PgUp/PgDn/Home/End)
|
|
55
57
|
onScroll(handler) {
|
|
@@ -143,6 +145,14 @@ export class InputReader {
|
|
|
143
145
|
onNotes(handler) {
|
|
144
146
|
this.notesHandler = handler;
|
|
145
147
|
}
|
|
148
|
+
// register a callback for clipboard export (/clip [N])
|
|
149
|
+
onClip(handler) {
|
|
150
|
+
this.clipHandler = handler;
|
|
151
|
+
}
|
|
152
|
+
// register a callback for bookmark diff (/diff N)
|
|
153
|
+
onDiff(handler) {
|
|
154
|
+
this.diffHandler = handler;
|
|
155
|
+
}
|
|
146
156
|
notifyQueueChange() {
|
|
147
157
|
this.queueChangeHandler?.(this.queue.length);
|
|
148
158
|
}
|
|
@@ -332,6 +342,8 @@ ${BOLD}navigation:${RESET}
|
|
|
332
342
|
/auto-pin toggle auto-pin on error (pin sessions that emit errors)
|
|
333
343
|
/note N|name text attach a note to a session (no text = clear)
|
|
334
344
|
/notes list all session notes
|
|
345
|
+
/clip [N] copy last N activity entries to clipboard (default 20)
|
|
346
|
+
/diff N show activity since bookmark N
|
|
335
347
|
/mark bookmark current activity position
|
|
336
348
|
/jump N jump to bookmark N
|
|
337
349
|
/marks list all bookmarks
|
|
@@ -543,6 +555,34 @@ ${BOLD}other:${RESET}
|
|
|
543
555
|
console.error(`${DIM}notes not available (no TUI)${RESET}`);
|
|
544
556
|
}
|
|
545
557
|
break;
|
|
558
|
+
case "/clip": {
|
|
559
|
+
const clipArg = line.slice("/clip".length).trim();
|
|
560
|
+
const clipCount = clipArg ? parseInt(clipArg, 10) : 20;
|
|
561
|
+
if (this.clipHandler && !isNaN(clipCount) && clipCount > 0) {
|
|
562
|
+
this.clipHandler(clipCount);
|
|
563
|
+
}
|
|
564
|
+
else if (!this.clipHandler) {
|
|
565
|
+
console.error(`${DIM}clip not available (no TUI)${RESET}`);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
console.error(`${DIM}usage: /clip [N] — copy last N activity entries to clipboard${RESET}`);
|
|
569
|
+
}
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
case "/diff": {
|
|
573
|
+
const diffArg = line.slice("/diff".length).trim();
|
|
574
|
+
const diffNum = parseInt(diffArg, 10);
|
|
575
|
+
if (this.diffHandler && !isNaN(diffNum) && diffNum > 0) {
|
|
576
|
+
this.diffHandler(diffNum);
|
|
577
|
+
}
|
|
578
|
+
else if (!this.diffHandler) {
|
|
579
|
+
console.error(`${DIM}diff not available (no TUI)${RESET}`);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
console.error(`${DIM}usage: /diff N — show activity since bookmark N${RESET}`);
|
|
583
|
+
}
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
546
586
|
case "/mark":
|
|
547
587
|
if (this.markHandler) {
|
|
548
588
|
this.markHandler();
|
package/dist/tui.d.ts
CHANGED
|
@@ -57,6 +57,10 @@ export declare function formatMuteBadge(count: number): string;
|
|
|
57
57
|
export declare function matchesTagFilter(entry: ActivityEntry, tag: string): boolean;
|
|
58
58
|
/** Format the tag filter indicator text for the separator bar. */
|
|
59
59
|
export declare function formatTagFilterIndicator(tag: string, matchCount: number, totalCount: number): string;
|
|
60
|
+
/** Default number of entries for /clip when no count specified. */
|
|
61
|
+
export declare const CLIP_DEFAULT_COUNT = 20;
|
|
62
|
+
/** Format activity entries as plain text for clipboard/export. One line per entry. */
|
|
63
|
+
export declare function formatClipText(entries: readonly ActivityEntry[], n?: number): string;
|
|
60
64
|
/** Determine if a log entry should trigger auto-pin (error-like tags). */
|
|
61
65
|
export declare function shouldAutoPin(tag: string): boolean;
|
|
62
66
|
/** Format milliseconds as human-readable uptime: "2h 15m", "45m", "3d 2h", "< 1m". */
|
|
@@ -175,6 +179,8 @@ export declare class TUI {
|
|
|
175
179
|
getUptime(id: string): number;
|
|
176
180
|
/** Return all session first-seen timestamps (for /uptime listing). */
|
|
177
181
|
getAllFirstSeen(): ReadonlyMap<string, number>;
|
|
182
|
+
/** Return the activity buffer (for /clip export). */
|
|
183
|
+
getActivityBuffer(): readonly ActivityEntry[];
|
|
178
184
|
/**
|
|
179
185
|
* Add a bookmark at the current activity position.
|
|
180
186
|
* Returns the bookmark number (1-indexed) or 0 if buffer is empty.
|
package/dist/tui.js
CHANGED
|
@@ -191,6 +191,15 @@ export function matchesTagFilter(entry, tag) {
|
|
|
191
191
|
export function formatTagFilterIndicator(tag, matchCount, totalCount) {
|
|
192
192
|
return `${SLATE}filter:${RESET} ${AMBER}${tag}${RESET} ${DIM}(${matchCount}/${totalCount})${RESET}`;
|
|
193
193
|
}
|
|
194
|
+
// ── Clip ─────────────────────────────────────────────────────────────────────
|
|
195
|
+
/** Default number of entries for /clip when no count specified. */
|
|
196
|
+
export const CLIP_DEFAULT_COUNT = 20;
|
|
197
|
+
/** Format activity entries as plain text for clipboard/export. One line per entry. */
|
|
198
|
+
export function formatClipText(entries, n) {
|
|
199
|
+
const count = n ?? CLIP_DEFAULT_COUNT;
|
|
200
|
+
const slice = entries.slice(-Math.max(1, count));
|
|
201
|
+
return slice.map((e) => `[${e.time}] ${e.tag}: ${e.text}`).join("\n") + "\n";
|
|
202
|
+
}
|
|
194
203
|
// ── Auto-pin ─────────────────────────────────────────────────────────────────
|
|
195
204
|
/** Determine if a log entry should trigger auto-pin (error-like tags). */
|
|
196
205
|
export function shouldAutoPin(tag) {
|
|
@@ -527,6 +536,10 @@ export class TUI {
|
|
|
527
536
|
getAllFirstSeen() {
|
|
528
537
|
return this.sessionFirstSeen;
|
|
529
538
|
}
|
|
539
|
+
/** Return the activity buffer (for /clip export). */
|
|
540
|
+
getActivityBuffer() {
|
|
541
|
+
return this.activityBuffer;
|
|
542
|
+
}
|
|
530
543
|
/**
|
|
531
544
|
* Add a bookmark at the current activity position.
|
|
532
545
|
* Returns the bookmark number (1-indexed) or 0 if buffer is empty.
|