aoaoe 0.82.0 → 0.83.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
@@ -378,6 +378,38 @@ async function main() {
378
378
  tui.setCompact(enabled);
379
379
  tui.log("system", `compact mode: ${enabled ? "on" : "off"}`);
380
380
  });
381
+ // wire /mark bookmark
382
+ input.onMark(() => {
383
+ const num = tui.addBookmark();
384
+ if (num > 0) {
385
+ tui.log("system", `bookmark #${num} saved`);
386
+ }
387
+ else {
388
+ tui.log("system", "nothing to bookmark (activity buffer empty)");
389
+ }
390
+ });
391
+ // wire /jump to bookmark
392
+ input.onJump((num) => {
393
+ const ok = tui.jumpToBookmark(num);
394
+ if (ok) {
395
+ tui.log("system", `jumped to bookmark #${num}`);
396
+ }
397
+ else {
398
+ tui.log("system", `bookmark #${num} not found`);
399
+ }
400
+ });
401
+ // wire /marks listing
402
+ input.onMarks(() => {
403
+ const bms = tui.getBookmarks();
404
+ if (bms.length === 0) {
405
+ tui.log("system", "no bookmarks — use /mark to save one");
406
+ }
407
+ else {
408
+ for (let i = 0; i < bms.length; i++) {
409
+ tui.log("system", ` #${i + 1}: ${bms[i].label}`);
410
+ }
411
+ }
412
+ });
381
413
  // wire /focus toggle
382
414
  input.onFocus(() => {
383
415
  const enabled = !tui.isFocused();
package/dist/input.d.ts CHANGED
@@ -8,6 +8,9 @@ export type CompactHandler = () => void;
8
8
  export type PinHandler = (target: string) => void;
9
9
  export type BellHandler = () => void;
10
10
  export type FocusHandler = () => void;
11
+ export type MarkHandler = () => void;
12
+ export type JumpHandler = (num: number) => void;
13
+ export type MarksHandler = () => void;
11
14
  export interface MouseEvent {
12
15
  button: number;
13
16
  col: number;
@@ -38,6 +41,9 @@ export declare class InputReader {
38
41
  private pinHandler;
39
42
  private bellHandler;
40
43
  private focusHandler;
44
+ private markHandler;
45
+ private jumpHandler;
46
+ private marksHandler;
41
47
  private mouseDataListener;
42
48
  onScroll(handler: (dir: ScrollDirection) => void): void;
43
49
  onQueueChange(handler: (count: number) => void): void;
@@ -52,6 +58,9 @@ export declare class InputReader {
52
58
  onPin(handler: PinHandler): void;
53
59
  onBell(handler: BellHandler): void;
54
60
  onFocus(handler: FocusHandler): void;
61
+ onMark(handler: MarkHandler): void;
62
+ onJump(handler: JumpHandler): void;
63
+ onMarks(handler: MarksHandler): void;
55
64
  private notifyQueueChange;
56
65
  start(): void;
57
66
  drain(): string[];
package/dist/input.js CHANGED
@@ -40,6 +40,9 @@ export class InputReader {
40
40
  pinHandler = null;
41
41
  bellHandler = null;
42
42
  focusHandler = null;
43
+ markHandler = null;
44
+ jumpHandler = null;
45
+ marksHandler = null;
43
46
  mouseDataListener = null;
44
47
  // register a callback for scroll key events (PgUp/PgDn/Home/End)
45
48
  onScroll(handler) {
@@ -93,6 +96,18 @@ export class InputReader {
93
96
  onFocus(handler) {
94
97
  this.focusHandler = handler;
95
98
  }
99
+ // register a callback for adding bookmarks (/mark)
100
+ onMark(handler) {
101
+ this.markHandler = handler;
102
+ }
103
+ // register a callback for jumping to bookmarks (/jump N)
104
+ onJump(handler) {
105
+ this.jumpHandler = handler;
106
+ }
107
+ // register a callback for listing bookmarks (/marks)
108
+ onMarks(handler) {
109
+ this.marksHandler = handler;
110
+ }
96
111
  notifyQueueChange() {
97
112
  this.queueChangeHandler?.(this.queue.length);
98
113
  }
@@ -275,6 +290,9 @@ ${BOLD}navigation:${RESET}
275
290
  /pin [N|name] pin/unpin a session to the top (toggle)
276
291
  /bell toggle terminal bell on errors/completions
277
292
  /focus toggle focus mode (show only pinned sessions)
293
+ /mark bookmark current activity position
294
+ /jump N jump to bookmark N
295
+ /marks list all bookmarks
278
296
  /search <pattern> filter activity entries by substring (case-insensitive)
279
297
  /search clear active search filter
280
298
  click session click an agent card to drill down (click again to go back)
@@ -403,6 +421,36 @@ ${BOLD}other:${RESET}
403
421
  console.error(`${DIM}focus not available (no TUI)${RESET}`);
404
422
  }
405
423
  break;
424
+ case "/mark":
425
+ if (this.markHandler) {
426
+ this.markHandler();
427
+ }
428
+ else {
429
+ console.error(`${DIM}bookmarks not available (no TUI)${RESET}`);
430
+ }
431
+ break;
432
+ case "/jump": {
433
+ const jumpArg = line.slice("/jump".length).trim();
434
+ const jumpNum = parseInt(jumpArg, 10);
435
+ if (this.jumpHandler && !isNaN(jumpNum) && jumpNum > 0) {
436
+ this.jumpHandler(jumpNum);
437
+ }
438
+ else if (!this.jumpHandler) {
439
+ console.error(`${DIM}bookmarks not available (no TUI)${RESET}`);
440
+ }
441
+ else {
442
+ console.error(`${DIM}usage: /jump N — jump to bookmark number N${RESET}`);
443
+ }
444
+ break;
445
+ }
446
+ case "/marks":
447
+ if (this.marksHandler) {
448
+ this.marksHandler();
449
+ }
450
+ else {
451
+ console.error(`${DIM}bookmarks not available (no TUI)${RESET}`);
452
+ }
453
+ break;
406
454
  case "/search": {
407
455
  const searchArg = line.slice("/search".length).trim();
408
456
  if (this.searchHandler) {
package/dist/tui.d.ts CHANGED
@@ -10,6 +10,18 @@ declare function nextSortMode(current: SortMode): SortMode;
10
10
  export declare const BELL_COOLDOWN_MS = 5000;
11
11
  /** Determine if an activity entry should trigger a terminal bell. High-signal events only. */
12
12
  export declare function shouldBell(tag: string, text: string): boolean;
13
+ export interface Bookmark {
14
+ index: number;
15
+ label: string;
16
+ }
17
+ /** Max number of bookmarks. */
18
+ export declare const MAX_BOOKMARKS = 20;
19
+ /**
20
+ * Compute the scroll offset needed to show a bookmarked entry.
21
+ * Centers the entry in the visible region when possible.
22
+ * Returns 0 (live) if the entry is within the visible tail.
23
+ */
24
+ export declare function computeBookmarkOffset(bookmarkIndex: number, bufferLen: number, visibleLines: number): number;
13
25
  /** Max name length in compact token. */
14
26
  declare const COMPACT_NAME_LEN = 10;
15
27
  /** Pin indicator for pinned sessions. */
@@ -54,6 +66,7 @@ export declare class TUI {
54
66
  private compactMode;
55
67
  private pinnedIds;
56
68
  private focusMode;
69
+ private bookmarks;
57
70
  private bellEnabled;
58
71
  private lastBellAt;
59
72
  private viewMode;
@@ -100,6 +113,20 @@ export declare class TUI {
100
113
  setBell(enabled: boolean): void;
101
114
  /** Return whether terminal bell is enabled. */
102
115
  isBellEnabled(): boolean;
116
+ /**
117
+ * Add a bookmark at the current activity position.
118
+ * Returns the bookmark number (1-indexed) or 0 if buffer is empty.
119
+ */
120
+ addBookmark(): number;
121
+ /**
122
+ * Jump to a bookmark by number (1-indexed). Returns false if not found.
123
+ * Adjusts scroll offset to center the bookmarked entry.
124
+ */
125
+ jumpToBookmark(num: number): boolean;
126
+ /** Return all bookmarks (for /marks listing). */
127
+ getBookmarks(): readonly Bookmark[];
128
+ /** Return bookmark count. */
129
+ getBookmarkCount(): number;
103
130
  updateState(opts: {
104
131
  phase?: DaemonPhase;
105
132
  pollCount?: number;
package/dist/tui.js CHANGED
@@ -63,6 +63,23 @@ export function shouldBell(tag, text) {
63
63
  return true;
64
64
  return false;
65
65
  }
66
+ /** Max number of bookmarks. */
67
+ export const MAX_BOOKMARKS = 20;
68
+ /**
69
+ * Compute the scroll offset needed to show a bookmarked entry.
70
+ * Centers the entry in the visible region when possible.
71
+ * Returns 0 (live) if the entry is within the visible tail.
72
+ */
73
+ export function computeBookmarkOffset(bookmarkIndex, bufferLen, visibleLines) {
74
+ // entry position from the end of the buffer
75
+ const fromEnd = bufferLen - 1 - bookmarkIndex;
76
+ // if entry is within the visible tail, no scroll needed
77
+ if (fromEnd < visibleLines)
78
+ return 0;
79
+ // center the entry in the visible region
80
+ const half = Math.floor(visibleLines / 2);
81
+ return Math.max(0, fromEnd - half);
82
+ }
66
83
  // ── Compact mode ────────────────────────────────────────────────────────────
67
84
  /** Max name length in compact token. */
68
85
  const COMPACT_NAME_LEN = 10;
@@ -162,6 +179,7 @@ export class TUI {
162
179
  compactMode = false;
163
180
  pinnedIds = new Set(); // pinned session IDs (always sort to top)
164
181
  focusMode = false; // focus mode: hide all sessions except pinned
182
+ bookmarks = []; // saved positions in activity buffer
165
183
  bellEnabled = false;
166
184
  lastBellAt = 0;
167
185
  // drill-down mode: show a single session's full output
@@ -319,6 +337,55 @@ export class TUI {
319
337
  isBellEnabled() {
320
338
  return this.bellEnabled;
321
339
  }
340
+ /**
341
+ * Add a bookmark at the current activity position.
342
+ * Returns the bookmark number (1-indexed) or 0 if buffer is empty.
343
+ */
344
+ addBookmark() {
345
+ if (this.activityBuffer.length === 0)
346
+ return 0;
347
+ // bookmark the entry at the current view position
348
+ const visibleLines = this.scrollBottom - this.scrollTop + 1;
349
+ const { start } = computeScrollSlice(this.activityBuffer.length, visibleLines, this.scrollOffset);
350
+ const entry = this.activityBuffer[start];
351
+ if (!entry)
352
+ return 0;
353
+ const bm = { index: start, label: `${entry.time} ${entry.tag}` };
354
+ this.bookmarks.push(bm);
355
+ if (this.bookmarks.length > MAX_BOOKMARKS) {
356
+ this.bookmarks = this.bookmarks.slice(-MAX_BOOKMARKS);
357
+ }
358
+ return this.bookmarks.length;
359
+ }
360
+ /**
361
+ * Jump to a bookmark by number (1-indexed). Returns false if not found.
362
+ * Adjusts scroll offset to center the bookmarked entry.
363
+ */
364
+ jumpToBookmark(num) {
365
+ const bm = this.bookmarks[num - 1];
366
+ if (!bm)
367
+ return false;
368
+ // clamp index to current buffer
369
+ if (bm.index >= this.activityBuffer.length)
370
+ return false;
371
+ const visibleLines = this.scrollBottom - this.scrollTop + 1;
372
+ this.scrollOffset = computeBookmarkOffset(bm.index, this.activityBuffer.length, visibleLines);
373
+ if (this.scrollOffset === 0)
374
+ this.newWhileScrolled = 0;
375
+ if (this.active && this.viewMode === "overview") {
376
+ this.repaintActivityRegion();
377
+ this.paintSeparator();
378
+ }
379
+ return true;
380
+ }
381
+ /** Return all bookmarks (for /marks listing). */
382
+ getBookmarks() {
383
+ return this.bookmarks;
384
+ }
385
+ /** Return bookmark count. */
386
+ getBookmarkCount() {
387
+ return this.bookmarks.length;
388
+ }
322
389
  // ── State updates ───────────────────────────────────────────────────────
323
390
  updateState(opts) {
324
391
  if (opts.phase !== undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aoaoe",
3
- "version": "0.82.0",
3
+ "version": "0.83.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",