aoaoe 0.95.0 → 0.114.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/README.md CHANGED
@@ -1,19 +1,23 @@
1
1
  <p align="center">
2
2
  <h1 align="center">Agent of Agent of Empires (aoaoe)</h1>
3
3
  <p align="center">
4
+ <a href="https://github.com/Talador12/agent-of-agent-of-empires/actions/workflows/ci.yml"><img src="https://github.com/Talador12/agent-of-agent-of-empires/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
4
5
  <a href="https://www.npmjs.com/package/aoaoe"><img src="https://img.shields.io/npm/v/aoaoe" alt="npm version"></a>
5
6
  <a href="https://github.com/Talador12/agent-of-agent-of-empires/releases"><img src="https://img.shields.io/github/v/release/Talador12/agent-of-agent-of-empires" alt="GitHub release"></a>
7
+ <img src="https://img.shields.io/badge/tests-1739-brightgreen" alt="tests">
8
+ <img src="https://img.shields.io/badge/node-%3E%3D20-blue" alt="Node.js >= 20">
9
+ <img src="https://img.shields.io/badge/runtime%20deps-0-brightgreen" alt="zero runtime dependencies">
6
10
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
7
11
  </p>
8
12
  </p>
9
13
 
10
- An autonomous supervisor that manages [Agent of Empires](https://github.com/njbrake/agent-of-empires) sessions using [OpenCode](https://github.com/anomalyco/opencode) or [Claude Code](https://docs.anthropic.com/en/docs/claude-code) as the reasoning engine.
14
+ An autonomous supervisor for [Agent of Empires](https://github.com/njbrake/agent-of-empires) sessions. Uses [OpenCode](https://github.com/anomalyco/opencode) or [Claude Code](https://docs.anthropic.com/en/docs/claude-code) as the reasoning engine.
11
15
 
12
- > Built on top of [Agent of Empires (AoE)](https://github.com/njbrake/agent-of-empires) by [Nate Brake](https://x.com/natebrake). AoE is the session manager -- aoaoe is the brain that drives it.
16
+ **This project is a companion to [Agent of Empires (AoE)](https://github.com/njbrake/agent-of-empires) by [Nate Brake](https://x.com/natebrake).** AoE is the foundation -- it manages multiple AI coding agents in tmux sessions with git worktrees. aoaoe adds an autonomous supervisor layer on top. You need AoE running first; aoaoe plugs into it.
13
17
 
14
18
  ## What is this?
15
19
 
16
- [Agent of Empires (AoE)](https://github.com/njbrake/agent-of-empires) manages multiple AI coding agents (Claude Code, OpenCode, Gemini CLI, Codex, etc.) in tmux sessions with git worktrees. It is great at spawning and organizing agents, but someone still needs to watch the tmux panes and intervene when agents get stuck, ask questions, or finish their work.
20
+ [AoE](https://github.com/njbrake/agent-of-empires) is great at spawning and organizing agents, but someone still needs to watch the tmux panes and intervene when agents get stuck, ask questions, or finish their work.
17
21
 
18
22
  **aoaoe** is that someone -- except it is an LLM. It polls your AoE sessions, reads agent output, decides when to act, and executes without you needing to be there.
19
23
 
@@ -171,19 +175,38 @@ aoaoe can automatically create and manage AoE sessions from a task list. Define
171
175
 
172
176
  ```json
173
177
  [
174
- { "repo": "github/adventure", "tool": "opencode", "goal": "Continue the roadmap in claude.md" },
175
- { "repo": "github/cloud-hypervisor", "goal": "Address PR review feedback" },
176
- { "repo": "cc/cloudchamber" }
178
+ {
179
+ "repo": "github/adventure",
180
+ "sessionTitle": "adventure",
181
+ "sessionMode": "existing",
182
+ "goal": "Process queued TODOs in this existing AoE session"
183
+ },
184
+ {
185
+ "repo": "github/agent-of-agent-of-empires",
186
+ "sessionTitle": "aoaoe-roadmap",
187
+ "sessionMode": "new",
188
+ "tool": "opencode",
189
+ "goal": "Ship next roadmap item with tests"
190
+ },
191
+ {
192
+ "repo": "github/cloud-hypervisor",
193
+ "sessionMode": "auto",
194
+ "goal": "Address PR review feedback"
195
+ }
177
196
  ]
178
197
  ```
179
198
 
180
199
  | Field | Required | Description |
181
200
  |-------|:--------:|-------------|
182
201
  | `repo` | Yes | Path to the project directory (relative to cwd or absolute) |
202
+ | `sessionTitle` | No | AoE session title to target. Default: derived from `repo` basename |
203
+ | `sessionMode` | No | Session allocation strategy: `existing` (link only), `new` (create), `auto` (link or create). Default: `auto` |
183
204
  | `tool` | No | Agent tool to use (`opencode`, `claude-code`, etc.). Default: `opencode` |
184
205
  | `goal` | No | Goal text injected into the supervisor's context for this task |
185
206
 
186
- When the daemon starts, it reconciles sessions automatically: creates new AoE sessions for tasks that don't have one, links existing sessions to matching tasks. Progress is tracked persistently in `~/.aoaoe/task-state.json` and survives session cleanup.
207
+ When the daemon starts, it now auto-imports any currently visible AoE sessions into the task list (mode=`existing`) so active and inactive sessions are immediately schedulable. Then it reconciles tasks: creates new AoE sessions when needed, links existing sessions by title, and starts linked sessions as needed. Progress is tracked persistently in `~/.aoaoe/task-state.json` and survives session cleanup.
208
+
209
+ Interactive task updates (`aoaoe task new/edit/rm` or `/task ...`) also sync back to `aoaoe.tasks.json`, so your list evolves as you go.
187
210
 
188
211
  The supervisor can report progress milestones and mark tasks complete via two special actions:
189
212
  - `report_progress` — logs a milestone summary to persistent state
@@ -195,9 +218,117 @@ View task status:
195
218
  aoaoe tasks # show task progress table
196
219
  ```
197
220
 
221
+ ## Daemon TUI Commands
222
+
223
+ The daemon runs an interactive TUI with a rich command set. These commands are available when the daemon is running (started with `aoaoe`).
224
+
225
+ ### Talking to the AI
226
+
227
+ | Command | What it does |
228
+ |---------|-------------|
229
+ | _(any text)_ | Send a message -- queued for the next reasoning cycle |
230
+ | `!message` | Insist -- interrupt + deliver message immediately |
231
+ | `/insist <msg>` | Same as `!message` |
232
+ | `/explain` | Ask the AI to explain what's happening right now |
233
+
234
+ ### Controls
235
+
236
+ | Command | What it does |
237
+ |---------|-------------|
238
+ | `/pause` | Pause the supervisor (stops reasoning) |
239
+ | `/resume` | Resume after pause |
240
+ | `/mode [name]` | Switch mode at runtime: `observe`, `dry-run`, `confirm`, `autopilot` (no arg = show current) |
241
+ | `/interrupt` | Interrupt the AI mid-thought |
242
+ | ESC ESC | Same as `/interrupt` (shortcut) |
243
+
244
+ ### Navigation
245
+
246
+ | Command | What it does |
247
+ |---------|-------------|
248
+ | `1`-`9` | Quick-switch: jump to session N |
249
+ | `/view [N\|name]` | Drill into a session's live output (default: 1) |
250
+ | `/back` | Return to overview from drill-down |
251
+ | `/sort [mode]` | Sort sessions: `status`, `name`, `activity`, `default` (no arg = cycle) |
252
+ | `/compact` | Toggle compact mode (dense session panel) |
253
+ | `/pin [N\|name]` | Pin/unpin a session to the top |
254
+ | `/bell` | Toggle terminal bell on errors/completions |
255
+ | `/focus` | Toggle focus mode (show only pinned sessions) |
256
+ | `/mute [N\|name]` | Mute/unmute a session's activity entries |
257
+ | `/unmute-all` | Unmute all sessions at once |
258
+ | `/filter [tag]` | Filter activity by tag -- presets: `errors`, `actions`, `system` (no arg = clear) |
259
+ | `/who` | Show fleet status: status, uptime, idle-since, context, errors, group, note |
260
+ | `/uptime` | Show session uptimes |
261
+ | `/top [mode]` | Rank sessions by `errors` (default), `burn`, or `idle` |
262
+ | `/auto-pin` | Toggle auto-pin on error |
263
+ | `/note N\|name text` | Attach a note to a session (no text = clear) |
264
+ | `/notes` | List all session notes |
265
+ | `/group N\|name tag` | Assign session to a group (lowercase, max 16 chars; no tag = clear) |
266
+ | `/groups` | List all groups and their members |
267
+ | `/group-filter [tag]` | Show only sessions in a group (no arg = clear) |
268
+ | `/rename N\|name [display]` | Set custom TUI display name (no display = clear); persisted |
269
+ | `/watchdog [N]` | Alert if session stalls N minutes (default 10); `/watchdog off` to disable |
270
+ | `/broadcast <msg>` | Send message to all sessions; `/broadcast group:<tag> <msg>` for group |
271
+ | `/clip [N]` | Copy last N activity entries to clipboard (default 20) |
272
+ | `/diff N` | Show activity since bookmark N |
273
+ | `/mark` | Bookmark current activity position |
274
+ | `/jump N` | Jump to bookmark N |
275
+ | `/marks` | List all bookmarks |
276
+ | `/search <pattern>` | Filter activity entries by substring (no arg = clear) |
277
+ | Click session | Click an agent card to drill down (click again to go back) |
278
+ | Mouse wheel | Scroll activity (overview) or session output (drill-down) |
279
+ | PgUp / PgDn | Scroll through activity or session output |
280
+ | Home / End | Jump to oldest / return to live |
281
+
282
+ ### Info
283
+
284
+ | Command | What it does |
285
+ |---------|-------------|
286
+ | `/status` | Show daemon state (mode, reasoner, poll counts, last cycle) |
287
+ | `/dashboard` | Show full dashboard |
288
+ | `/tasks` | Show task progress table |
289
+ | `/t ...` `/todo ...` `/idea ...` | Aliases for `/task ...` |
290
+ | `/task [sub] [args]` | Task management (list, start, stop, edit, new, rm) |
291
+ | `/task <session> :: <goal>` | Fast path: update/create task for an existing session and set its goal |
292
+ | `:<goal>` | Fastest path in drill-down: set goal for that session |
293
+ | `just type` (in drill-down) | Default behavior: update goal for the focused session |
294
+ | `/burn-rate` | Show context token burn rates (tokens/min) for all sessions |
295
+ | `/ceiling` | Show context token usage vs limit for all sessions |
296
+ | `/snapshot [md]` | Export session state snapshot to `~/.aoaoe/snapshot-<ts>.json` (or `.md`) |
297
+ | `/alias /x /cmd` | Create command alias (`/x` expands to `/cmd`); no args = list |
298
+
299
+ ### Other
300
+
301
+ | Command | What it does |
302
+ |---------|-------------|
303
+ | `/verbose` | Toggle detailed logging |
304
+ | `/clear` | Clear the screen |
305
+ | `/help` | Show all commands |
306
+
307
+ ### TUI Features
308
+
309
+ - **Activity sparkline** -- 10-minute activity rate chart in the separator bar (Unicode blocks with color gradient)
310
+ - **Session cards** -- per-session status with pin `▲`, mute `◌`, note `✎`, group `⊹tag`, and health score `⬡N` indicators
311
+ - **Health score** -- composite 0–100 badge per session (errors, burn rate, context ceiling, stall time); LIME ≥80, AMBER ≥60, ROSE <60
312
+ - **Error sparklines** -- ROSE 5-bucket mini-chart of recent error frequency in each card (last 5 min)
313
+ - **Idle-since** -- time since last output change shown in idle/done card status and `/who` output
314
+ - **Session grouping** -- `/group` assigns sessions to named groups; `/group-filter` narrows the panel view
315
+ - **Session rename** -- `/rename` sets a custom TUI display name (bold with original dim alongside); persisted
316
+ - **Watchdog** -- `/watchdog N` fires an alert if a session stalls for N minutes (rate-limited to once per 5 min)
317
+ - **Burn-rate alerts** -- automatic "status" alert when context token usage exceeds 5k tokens/min; `/burn-rate` for on-demand view
318
+ - **Context ceiling warning** -- automatic alert at 90% context usage when "X / Y tokens" format available; `/ceiling` for on-demand view
319
+ - **Snapshot export** -- `/snapshot [md]` exports full session state (status, group, note, uptime, context, errors, burn rate) to `~/.aoaoe/`
320
+ - **Broadcast** -- `/broadcast [group:<tag>] <message>` sends a message to all (or group-filtered) sessions via tmux
321
+ - **Ranked view** -- `/top [errors|burn|idle]` ranks sessions by composite attention score or a single metric
322
+ - **Sticky preferences** -- sort, compact, focus, bell, auto-pin, tag filter, aliases, groups, and renames persist across restarts
323
+ - **Filter pipeline** -- mute, tag filter, and search compose: mute → tag → search
324
+ - **Aliases** -- `/alias /x /cmd` creates command shortcuts; up to 50, persisted
325
+ - **Activity heatmap** -- 24-hour colored block chart via `aoaoe stats`
326
+ - **Bookmarks** -- mark positions in the activity stream, jump back to them, diff since a bookmark
327
+ - **Clipboard export** -- `/clip` copies activity to system clipboard (macOS) or `~/.aoaoe/clip.txt`
328
+
198
329
  ## Chat UI Commands
199
330
 
200
- Once inside the chat UI (via `aoe` -> select "aoaoe"):
331
+ The chat UI (`aoaoe-chat`) runs inside an AoE tmux pane. Register it with `aoaoe register`, then access via `aoe` -> select "aoaoe".
201
332
 
202
333
  | Command | What it does |
203
334
  |---------|-------------|
@@ -491,38 +622,43 @@ The daemon and chat UI communicate via files in `~/.aoaoe/`:
491
622
 
492
623
  ```
493
624
  src/
494
- index.ts # daemon entry point, main loop, subcommands
495
- loop.ts # extracted tick logic (poll->reason->execute), testable with mocks
496
- chat.ts # interactive chat UI (aoaoe-chat binary)
497
- config.ts # config loader and CLI arg parser
498
- types.ts # shared types (SessionSnapshot, Action, DaemonState, etc.)
499
- poller.ts # aoe CLI + tmux capture-pane wrapper
500
- executor.ts # maps action decisions to shell commands
501
- console.ts # conversation log + file-based IPC
502
- dashboard.ts # periodic CLI status table with task column
503
- daemon-state.ts # shared IPC state file + interrupt flag
504
- tui.ts # in-place terminal UI (alternate screen, scroll regions)
505
- tui-history.ts # persisted TUI history (JSONL file with rotation, replay on startup)
506
- input.ts # stdin readline listener with inject() for post-interrupt
507
- init.ts # `aoaoe init`: auto-discover tools, sessions, generate config
508
- notify.ts # webhook + Slack notification dispatcher for daemon events
509
- health.ts # HTTP health check endpoint (GET /health JSON status)
510
- colors.ts # shared ANSI color/style constants
511
- context.ts # discoverContextFiles, resolveProjectDir, loadSessionContext
512
- activity.ts # detect human keystrokes in tmux sessions
513
- prompt-watcher.ts # reactive permission prompt clearing via tmux pipe-pane
514
- task-manager.ts # task orchestration: definitions, persistent state
515
- task-cli.ts # `aoaoe task` subcommand: list, start, stop, new, rm, edit
516
- task-parser.ts # parse OpenCode TODO patterns, model, tokens, cost from tmux
517
- message.ts # classifyMessages, formatUserMessages, shouldSkipSleep
518
- wake.ts # wakeableSleep with fs.watch for instant message delivery
519
- shell.ts # exec() wrappers with AbortSignal support
625
+ index.ts # daemon entry point, main loop, subcommands
626
+ loop.ts # extracted tick logic (poll->reason->execute), testable with mocks
627
+ chat.ts # interactive chat UI (aoaoe-chat binary)
628
+ config.ts # config loader and CLI arg parser
629
+ config-watcher.ts # config hot-reload via fs.watch, safe field merge
630
+ types.ts # shared types (SessionSnapshot, Action, DaemonState, etc.)
631
+ poller.ts # aoe CLI + tmux capture-pane wrapper
632
+ executor.ts # maps action decisions to shell commands
633
+ console.ts # conversation log + file-based IPC
634
+ dashboard.ts # periodic CLI status table with task column
635
+ daemon-state.ts # shared IPC state file + interrupt flag
636
+ tui.ts # in-place terminal UI (alternate screen, scroll, sparklines, cards)
637
+ tui-history.ts # persisted TUI history (JSONL file with rotation, replay on startup)
638
+ input.ts # stdin readline + keypress handlers (all /commands live here)
639
+ init.ts # `aoaoe init`: auto-discover tools, sessions, generate config
640
+ notify.ts # webhook + Slack notification dispatcher for daemon events
641
+ health.ts # HTTP health check endpoint (GET /health JSON status)
642
+ colors.ts # shared ANSI color/style constants
643
+ context.ts # discoverContextFiles, resolveProjectDir, loadSessionContext
644
+ activity.ts # detect human keystrokes in tmux sessions
645
+ prompt-watcher.ts # reactive permission prompt clearing via tmux pipe-pane
646
+ task-manager.ts # task orchestration: definitions, persistent state
647
+ task-cli.ts # `aoaoe task` subcommand: list, start, stop, new, rm, edit
648
+ task-parser.ts # parse OpenCode TODO patterns, model, tokens, cost from tmux
649
+ message.ts # classifyMessages, formatUserMessages, shouldSkipSleep
650
+ wake.ts # wakeableSleep with fs.watch for instant message delivery
651
+ shell.ts # exec() wrappers with AbortSignal support
652
+ export.ts # timeline export (JSON/Markdown) from actions + history
653
+ tail.ts # `aoaoe tail`: live-stream daemon activity to another terminal
654
+ stats.ts # `aoaoe stats`: aggregate statistics + activity heatmap
655
+ replay.ts # `aoaoe replay`: play back tui-history.jsonl with timing
520
656
  reasoner/
521
- index.ts # common Reasoner interface + factory
522
- prompt.ts # system prompt + observation formatting
523
- parse.ts # response parsing, JSON extraction, action validation
524
- opencode.ts # OpenCode SDK backend
525
- claude-code.ts # Claude Code CLI backend
657
+ index.ts # common Reasoner interface + factory
658
+ prompt.ts # system prompt + observation formatting
659
+ parse.ts # response parsing, JSON extraction, action validation
660
+ opencode.ts # OpenCode SDK backend
661
+ claude-code.ts # Claude Code CLI backend
526
662
  ```
527
663
 
528
664
  ## Related Projects
@@ -5,7 +5,7 @@ import { writeFileSync, readFileSync, existsSync, unlinkSync, mkdirSync, renameS
5
5
  import { join } from "node:path";
6
6
  import { homedir } from "node:os";
7
7
  import { toDaemonState } from "./types.js";
8
- import { parseTasks, formatTaskList } from "./task-parser.js";
8
+ import { parseTasks, formatTaskList, parseContext } from "./task-parser.js";
9
9
  // default state directory — overridable via setStateDir() for test isolation
10
10
  let AOAOE_DIR = join(homedir(), ".aoaoe");
11
11
  let STATE_FILE = join(AOAOE_DIR, "daemon-state.json");
@@ -50,6 +50,8 @@ export function resetInternalState() {
50
50
  const sessionTasks = new Map();
51
51
  // cache parsed TODO summaries for unchanged sessions
52
52
  const todoCache = new Map();
53
+ // cache parsed context token usage for unchanged sessions
54
+ const contextCache = new Map();
53
55
  export function setSessionTask(sessionId, task) {
54
56
  // keep task text short for display
55
57
  sessionTasks.set(sessionId, task.length > 80 ? task.slice(0, 77) + "..." : task);
@@ -98,6 +100,14 @@ export function buildSessionStates(obs) {
98
100
  if (!currentIds.has(id))
99
101
  sessionTasks.delete(id);
100
102
  }
103
+ for (const id of todoCache.keys()) {
104
+ if (!currentIds.has(id))
105
+ todoCache.delete(id);
106
+ }
107
+ for (const id of contextCache.keys()) {
108
+ if (!currentIds.has(id))
109
+ contextCache.delete(id);
110
+ }
101
111
  // only re-parse TODO items for sessions that have new output
102
112
  const changedIds = new Set(obs.changes.map((c) => c.sessionId));
103
113
  return obs.sessions.map((snap) => {
@@ -115,6 +125,14 @@ export function buildSessionStates(obs) {
115
125
  else {
116
126
  todoSummary = todoCache.get(s.id);
117
127
  }
128
+ let contextTokens;
129
+ if (changedIds.has(s.id)) {
130
+ contextTokens = parseContext(snap.output);
131
+ contextCache.set(s.id, contextTokens);
132
+ }
133
+ else {
134
+ contextTokens = contextCache.get(s.id);
135
+ }
118
136
  return {
119
137
  id: s.id,
120
138
  title: s.title,
@@ -124,6 +142,7 @@ export function buildSessionStates(obs) {
124
142
  lastActivity: lastActivity && lastActivity.length > 100
125
143
  ? lastActivity.slice(0, 97) + "..."
126
144
  : lastActivity,
145
+ contextTokens,
127
146
  todoSummary,
128
147
  userActive: snap.userActive ?? false,
129
148
  };