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 +175 -39
- package/dist/daemon-state.js +20 -1
- package/dist/index.js +415 -13
- package/dist/init.js +1 -0
- package/dist/input.d.ts +41 -0
- package/dist/input.js +310 -5
- package/dist/task-cli.d.ts +3 -2
- package/dist/task-cli.js +125 -22
- package/dist/task-manager.d.ts +5 -0
- package/dist/task-manager.js +101 -5
- package/dist/task-parser.js +6 -3
- package/dist/tui.d.ts +198 -2
- package/dist/tui.js +626 -31
- package/dist/types.d.ts +5 -0
- package/dist/types.js +1 -0
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
-
[
|
|
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
|
-
{
|
|
175
|
-
|
|
176
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
495
|
-
loop.ts
|
|
496
|
-
chat.ts
|
|
497
|
-
config.ts
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
tui
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
task-
|
|
516
|
-
task-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
|
522
|
-
prompt.ts
|
|
523
|
-
parse.ts
|
|
524
|
-
opencode.ts
|
|
525
|
-
claude-code.ts
|
|
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
|
package/dist/daemon-state.js
CHANGED
|
@@ -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
|
};
|