aoaoe 0.76.0 → 0.77.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/tui.d.ts CHANGED
@@ -25,6 +25,7 @@ export declare class TUI {
25
25
  private pendingCount;
26
26
  private searchPattern;
27
27
  private hoverSessionIdx;
28
+ private activityTimestamps;
28
29
  private viewMode;
29
30
  private drilldownSessionId;
30
31
  private sessionOutputs;
@@ -116,6 +117,10 @@ declare function computeScrollSlice(bufferLen: number, visibleLines: number, scr
116
117
  };
117
118
  declare function formatScrollIndicator(offset: number, totalEntries: number, visibleLines: number, newCount: number): string;
118
119
  declare function formatDrilldownScrollIndicator(offset: number, totalLines: number, visibleLines: number, newCount: number): string;
120
+ /** Compute sparkline bucket counts from activity timestamps. Returns array of SPARK_BUCKETS counts. */
121
+ declare function computeSparkline(timestamps: number[], now?: number, buckets?: number, windowMs?: number): number[];
122
+ /** Format sparkline bucket counts as a colored Unicode block string. Returns empty string if all zeros. */
123
+ declare function formatSparkline(counts: number[]): string;
119
124
  /** Case-insensitive substring match against an activity entry's tag, text, and time. */
120
125
  declare function matchesSearch(entry: ActivityEntry, pattern: string): boolean;
121
126
  /** Format the search indicator text for the separator bar. */
@@ -128,5 +133,5 @@ declare function formatSearchIndicator(pattern: string, matchCount: number, tota
128
133
  * (row = headerHeight + 2 + i for 0-indexed session i)
129
134
  */
130
135
  export declare function hitTestSession(row: number, headerHeight: number, sessionCount: number): number | null;
131
- export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padBoxLineHover, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator };
136
+ export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padBoxLineHover, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator, computeSparkline, formatSparkline };
132
137
  //# sourceMappingURL=tui.d.ts.map
package/dist/tui.js CHANGED
@@ -65,6 +65,7 @@ export class TUI {
65
65
  pendingCount = 0; // queued user messages awaiting next tick
66
66
  searchPattern = null; // active search filter pattern
67
67
  hoverSessionIdx = null; // 1-indexed session under mouse cursor (null = none)
68
+ activityTimestamps = []; // epoch ms of each log() call for sparkline
68
69
  // drill-down mode: show a single session's full output
69
70
  viewMode = "overview";
70
71
  drilldownSessionId = null;
@@ -158,8 +159,10 @@ export class TUI {
158
159
  const time = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}`;
159
160
  const entry = { time, tag, text };
160
161
  this.activityBuffer.push(entry);
162
+ this.activityTimestamps.push(now.getTime());
161
163
  if (this.activityBuffer.length > this.maxActivity) {
162
164
  this.activityBuffer = this.activityBuffer.slice(-this.maxActivity);
165
+ this.activityTimestamps = this.activityTimestamps.slice(-this.maxActivity);
163
166
  }
164
167
  if (this.active) {
165
168
  if (this.searchPattern) {
@@ -520,7 +523,9 @@ export class TUI {
520
523
  hints = formatScrollIndicator(this.scrollOffset, this.activityBuffer.length, this.scrollBottom - this.scrollTop + 1, this.newWhileScrolled);
521
524
  }
522
525
  else {
523
- hints = " click agent to view esc esc: interrupt /help ";
526
+ // live mode: show sparkline + minimal hints
527
+ const spark = formatSparkline(computeSparkline(this.activityTimestamps));
528
+ hints = spark ? ` ${spark} /help ` : " click agent to view esc esc: interrupt /help ";
524
529
  }
525
530
  const totalLen = prefix.length + hints.length;
526
531
  const fill = Math.max(0, this.cols - totalLen);
@@ -803,6 +808,41 @@ function formatDrilldownScrollIndicator(offset, totalLines, visibleLines, newCou
803
808
  const newTag = newCount > 0 ? ` ${newCount} new ↓` : "";
804
809
  return ` ↑ ${offset} lines │ ${position}/${totalLines} │ scroll: navigate End=live${newTag} `;
805
810
  }
811
+ // ── Sparkline helpers (pure, exported for testing) ──────────────────────────
812
+ const SPARK_BLOCKS = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
813
+ const SPARK_BUCKETS = 20; // number of time buckets
814
+ const SPARK_WINDOW_MS = 10 * 60 * 1000; // 10 minutes
815
+ /** Compute sparkline bucket counts from activity timestamps. Returns array of SPARK_BUCKETS counts. */
816
+ function computeSparkline(timestamps, now, buckets, windowMs) {
817
+ const n = buckets ?? SPARK_BUCKETS;
818
+ const window = windowMs ?? SPARK_WINDOW_MS;
819
+ const nowMs = now ?? Date.now();
820
+ const cutoff = nowMs - window;
821
+ const bucketSize = window / n;
822
+ const counts = new Array(n).fill(0);
823
+ for (const ts of timestamps) {
824
+ if (ts < cutoff)
825
+ continue;
826
+ const idx = Math.min(n - 1, Math.floor((ts - cutoff) / bucketSize));
827
+ counts[idx]++;
828
+ }
829
+ return counts;
830
+ }
831
+ /** Format sparkline bucket counts as a colored Unicode block string. Returns empty string if all zeros. */
832
+ function formatSparkline(counts) {
833
+ const max = Math.max(...counts);
834
+ if (max === 0)
835
+ return "";
836
+ const blocks = counts.map((c) => {
837
+ if (c === 0)
838
+ return `${SLATE} ${RESET}`;
839
+ const level = Math.min(SPARK_BLOCKS.length - 1, Math.floor((c / max) * (SPARK_BLOCKS.length - 1)));
840
+ // color gradient: low=SLATE, mid=SKY, high=LIME
841
+ const color = level < 3 ? SLATE : level < 6 ? SKY : LIME;
842
+ return `${color}${SPARK_BLOCKS[level]}${RESET}`;
843
+ });
844
+ return blocks.join("");
845
+ }
806
846
  // ── Search helpers (pure, exported for testing) ─────────────────────────────
807
847
  /** Case-insensitive substring match against an activity entry's tag, text, and time. */
808
848
  function matchesSearch(entry, pattern) {
@@ -835,5 +875,5 @@ export function hitTestSession(row, headerHeight, sessionCount) {
835
875
  return row - firstSessionRow + 1; // 1-indexed
836
876
  }
837
877
  // ── Exported pure helpers (for testing) ─────────────────────────────────────
838
- export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padBoxLineHover, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator };
878
+ export { formatActivity, formatSessionCard, truncateAnsi, truncatePlain, padBoxLine, padBoxLineHover, padToWidth, stripAnsiForLen, phaseDisplay, computeScrollSlice, formatScrollIndicator, formatDrilldownScrollIndicator, formatPrompt, formatDrilldownHeader, matchesSearch, formatSearchIndicator, computeSparkline, formatSparkline };
839
879
  //# sourceMappingURL=tui.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aoaoe",
3
- "version": "0.76.0",
3
+ "version": "0.77.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",