aoaoe 0.95.0 → 0.109.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-1509-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,94 @@ 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 (all sessions at a glance) |
260
+ | `/uptime` | Show session uptimes |
261
+ | `/auto-pin` | Toggle auto-pin on error |
262
+ | `/note N\|name text` | Attach a note to a session (no text = clear) |
263
+ | `/notes` | List all session notes |
264
+ | `/clip [N]` | Copy last N activity entries to clipboard (default 20) |
265
+ | `/diff N` | Show activity since bookmark N |
266
+ | `/mark` | Bookmark current activity position |
267
+ | `/jump N` | Jump to bookmark N |
268
+ | `/marks` | List all bookmarks |
269
+ | `/search <pattern>` | Filter activity entries by substring (no arg = clear) |
270
+ | Click session | Click an agent card to drill down (click again to go back) |
271
+ | Mouse wheel | Scroll activity (overview) or session output (drill-down) |
272
+ | PgUp / PgDn | Scroll through activity or session output |
273
+ | Home / End | Jump to oldest / return to live |
274
+
275
+ ### Info
276
+
277
+ | Command | What it does |
278
+ |---------|-------------|
279
+ | `/status` | Show daemon state |
280
+ | `/dashboard` | Show full dashboard |
281
+ | `/tasks` | Show task progress table |
282
+ | `/t ...` `/todo ...` `/idea ...` | Aliases for `/task ...` |
283
+ | `/task [sub] [args]` | Task management (list, start, stop, edit, new, rm) |
284
+ | `/task <session> :: <goal>` | Fast path: update/create task for an existing session and set its goal |
285
+ | `:<goal>` | Fastest path in drill-down: set goal for that session |
286
+ | `just type` (in drill-down) | Default behavior: update goal for the focused session |
287
+
288
+ ### Other
289
+
290
+ | Command | What it does |
291
+ |---------|-------------|
292
+ | `/verbose` | Toggle detailed logging |
293
+ | `/clear` | Clear the screen |
294
+ | `/help` | Show all commands |
295
+
296
+ ### TUI Features
297
+
298
+ - **Activity sparkline** -- 10-minute activity rate chart in the separator bar (Unicode blocks with color gradient)
299
+ - **Session cards** -- per-session status with pin `▲`, mute `◌`, note `✎` indicators
300
+ - **Sticky preferences** -- sort mode, compact, focus, bell, auto-pin, and tag filter persist across restarts (`~/.aoaoe/tui-prefs.json`)
301
+ - **Filter pipeline** -- mute, tag filter, and search compose: mute → tag → search
302
+ - **Activity heatmap** -- 24-hour colored block chart via `aoaoe stats`
303
+ - **Bookmarks** -- mark positions in the activity stream, jump back to them, diff since a bookmark
304
+ - **Clipboard export** -- `/clip` copies activity to system clipboard (macOS) or `~/.aoaoe/clip.txt`
305
+
198
306
  ## Chat UI Commands
199
307
 
200
- Once inside the chat UI (via `aoe` -> select "aoaoe"):
308
+ The chat UI (`aoaoe-chat`) runs inside an AoE tmux pane. Register it with `aoaoe register`, then access via `aoe` -> select "aoaoe".
201
309
 
202
310
  | Command | What it does |
203
311
  |---------|-------------|
@@ -491,38 +599,43 @@ The daemon and chat UI communicate via files in `~/.aoaoe/`:
491
599
 
492
600
  ```
493
601
  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
602
+ index.ts # daemon entry point, main loop, subcommands
603
+ loop.ts # extracted tick logic (poll->reason->execute), testable with mocks
604
+ chat.ts # interactive chat UI (aoaoe-chat binary)
605
+ config.ts # config loader and CLI arg parser
606
+ config-watcher.ts # config hot-reload via fs.watch, safe field merge
607
+ types.ts # shared types (SessionSnapshot, Action, DaemonState, etc.)
608
+ poller.ts # aoe CLI + tmux capture-pane wrapper
609
+ executor.ts # maps action decisions to shell commands
610
+ console.ts # conversation log + file-based IPC
611
+ dashboard.ts # periodic CLI status table with task column
612
+ daemon-state.ts # shared IPC state file + interrupt flag
613
+ tui.ts # in-place terminal UI (alternate screen, scroll, sparklines, cards)
614
+ tui-history.ts # persisted TUI history (JSONL file with rotation, replay on startup)
615
+ input.ts # stdin readline + keypress handlers (all /commands live here)
616
+ init.ts # `aoaoe init`: auto-discover tools, sessions, generate config
617
+ notify.ts # webhook + Slack notification dispatcher for daemon events
618
+ health.ts # HTTP health check endpoint (GET /health JSON status)
619
+ colors.ts # shared ANSI color/style constants
620
+ context.ts # discoverContextFiles, resolveProjectDir, loadSessionContext
621
+ activity.ts # detect human keystrokes in tmux sessions
622
+ prompt-watcher.ts # reactive permission prompt clearing via tmux pipe-pane
623
+ task-manager.ts # task orchestration: definitions, persistent state
624
+ task-cli.ts # `aoaoe task` subcommand: list, start, stop, new, rm, edit
625
+ task-parser.ts # parse OpenCode TODO patterns, model, tokens, cost from tmux
626
+ message.ts # classifyMessages, formatUserMessages, shouldSkipSleep
627
+ wake.ts # wakeableSleep with fs.watch for instant message delivery
628
+ shell.ts # exec() wrappers with AbortSignal support
629
+ export.ts # timeline export (JSON/Markdown) from actions + history
630
+ tail.ts # `aoaoe tail`: live-stream daemon activity to another terminal
631
+ stats.ts # `aoaoe stats`: aggregate statistics + activity heatmap
632
+ replay.ts # `aoaoe replay`: play back tui-history.jsonl with timing
520
633
  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
634
+ index.ts # common Reasoner interface + factory
635
+ prompt.ts # system prompt + observation formatting
636
+ parse.ts # response parsing, JSON extraction, action validation
637
+ opencode.ts # OpenCode SDK backend
638
+ claude-code.ts # Claude Code CLI backend
526
639
  ```
527
640
 
528
641
  ## 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
  };