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 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aoaoe",
3
- "version": "0.89.0",
3
+ "version": "0.91.0",
4
4
  "description": "Autonomous supervisor for agent-of-empires sessions using OpenCode or Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",