aoaoe 1.0.0 → 2.0.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
@@ -4,7 +4,7 @@
4
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>
5
5
  <a href="https://www.npmjs.com/package/aoaoe"><img src="https://img.shields.io/npm/v/aoaoe" alt="npm version"></a>
6
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-2427-brightgreen" alt="tests">
7
+ <img src="https://img.shields.io/badge/tests-3332-brightgreen" alt="tests">
8
8
  <img src="https://img.shields.io/badge/node-%3E%3D20-blue" alt="Node.js >= 20">
9
9
  <img src="https://img.shields.io/badge/runtime%20deps-0-brightgreen" alt="zero runtime dependencies">
10
10
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
@@ -822,6 +822,28 @@ The daemon and chat UI communicate via files in `~/.aoaoe/`:
822
822
  | `chat.pid` | chat UI | daemon | Chat process PID for detection |
823
823
  | `actions.log` | daemon | -- | Persistent action history (JSONL) |
824
824
 
825
+ ## Intelligence Modules
826
+
827
+ aoaoe includes 55 intelligence modules that run every daemon tick without LLM calls. They handle observability, automation, and fleet management autonomously:
828
+
829
+ **Reasoning Pipeline** (7 gates, runs before every LLM call):
830
+ - Fleet rate limiter, observation cache, priority filter, context compressor, LLM call, approval workflow, cost tracker
831
+
832
+ **Per-Tick Autonomous Systems**:
833
+ - Session summarizer, conflict detector + auto-resolver, goal completion detector, cost budget enforcer
834
+ - Activity heatmap, budget predictor, task retry with backoff, adaptive poll controller
835
+ - Fleet SLA monitor, progress velocity tracker, recovery playbook, dependency scheduler
836
+ - Session graduation (trust ladder), fleet utilization tracker, anomaly detector
837
+ - Workflow engine (fan-out/fan-in stage orchestration)
838
+
839
+ **On-Demand Analytics** (via TUI commands):
840
+ - Audit trail + search, fleet snapshots + diff, lifecycle analytics, cost attribution
841
+ - Goal decomposition, difficulty scoring, smart nudge generation, template auto-detection
842
+ - Fleet-wide search, nudge effectiveness tracking, difficulty-based allocation
843
+ - Goal refinement from completed task patterns, fleet HTML export, session replay
844
+
845
+ See `AGENTS.md` for the full source layout with all 55 modules described.
846
+
825
847
  ## Project Structure
826
848
 
827
849
  ```
@@ -0,0 +1,42 @@
1
+ import type { ReasonerResult, Action } from "./types.js";
2
+ export interface ABTrialResult {
3
+ timestamp: number;
4
+ backendA: string;
5
+ backendB: string;
6
+ actionsA: Action[];
7
+ actionsB: Action[];
8
+ confidenceA?: string;
9
+ confidenceB?: string;
10
+ winner: "a" | "b" | "tie";
11
+ reason: string;
12
+ }
13
+ export interface ABStats {
14
+ totalTrials: number;
15
+ winsA: number;
16
+ winsB: number;
17
+ ties: number;
18
+ backendA: string;
19
+ backendB: string;
20
+ }
21
+ /**
22
+ * Compare two reasoner results and determine which is better.
23
+ * Heuristic: more specific actions > wait, higher confidence > lower,
24
+ * fewer redundant actions = better.
25
+ */
26
+ export declare function compareResults(resultA: ReasonerResult, resultB: ReasonerResult, backendA: string, backendB: string, now?: number): ABTrialResult;
27
+ /**
28
+ * Track A/B trial results over time.
29
+ */
30
+ export declare class ABReasoningTracker {
31
+ private trials;
32
+ private backendA;
33
+ private backendB;
34
+ constructor(backendA: string, backendB: string);
35
+ /** Record a trial result. */
36
+ recordTrial(result: ABTrialResult): void;
37
+ /** Get aggregate stats. */
38
+ getStats(): ABStats;
39
+ /** Format stats for TUI display. */
40
+ formatStats(): string[];
41
+ }
42
+ //# sourceMappingURL=ab-reasoning.d.ts.map
@@ -0,0 +1,91 @@
1
+ // ab-reasoning.ts — run two reasoner backends on the same observation,
2
+ // compare their outputs, and track which performs better over time.
3
+ /**
4
+ * Compare two reasoner results and determine which is better.
5
+ * Heuristic: more specific actions > wait, higher confidence > lower,
6
+ * fewer redundant actions = better.
7
+ */
8
+ export function compareResults(resultA, resultB, backendA, backendB, now = Date.now()) {
9
+ let scoreA = 0;
10
+ let scoreB = 0;
11
+ // prefer non-wait actions over wait
12
+ const nonWaitA = resultA.actions.filter((a) => a.action !== "wait").length;
13
+ const nonWaitB = resultB.actions.filter((a) => a.action !== "wait").length;
14
+ if (nonWaitA > nonWaitB)
15
+ scoreA += 2;
16
+ else if (nonWaitB > nonWaitA)
17
+ scoreB += 2;
18
+ // prefer higher confidence
19
+ const confOrder = { high: 3, medium: 2, low: 1 };
20
+ const confA = confOrder[resultA.confidence ?? "medium"] ?? 2;
21
+ const confB = confOrder[resultB.confidence ?? "medium"] ?? 2;
22
+ if (confA > confB)
23
+ scoreA += 1;
24
+ else if (confB > confA)
25
+ scoreB += 1;
26
+ // prefer fewer total actions (more focused)
27
+ if (resultA.actions.length > 0 && resultB.actions.length > 0) {
28
+ if (resultA.actions.length < resultB.actions.length)
29
+ scoreA += 1;
30
+ else if (resultB.actions.length < resultA.actions.length)
31
+ scoreB += 1;
32
+ }
33
+ const winner = scoreA > scoreB ? "a" : scoreB > scoreA ? "b" : "tie";
34
+ const reason = `A(${nonWaitA} actions, ${resultA.confidence ?? "?"}) vs B(${nonWaitB} actions, ${resultB.confidence ?? "?"})`;
35
+ return {
36
+ timestamp: now,
37
+ backendA,
38
+ backendB,
39
+ actionsA: resultA.actions,
40
+ actionsB: resultB.actions,
41
+ confidenceA: resultA.confidence,
42
+ confidenceB: resultB.confidence,
43
+ winner,
44
+ reason,
45
+ };
46
+ }
47
+ /**
48
+ * Track A/B trial results over time.
49
+ */
50
+ export class ABReasoningTracker {
51
+ trials = [];
52
+ backendA;
53
+ backendB;
54
+ constructor(backendA, backendB) {
55
+ this.backendA = backendA;
56
+ this.backendB = backendB;
57
+ }
58
+ /** Record a trial result. */
59
+ recordTrial(result) {
60
+ this.trials.push(result);
61
+ }
62
+ /** Get aggregate stats. */
63
+ getStats() {
64
+ return {
65
+ totalTrials: this.trials.length,
66
+ winsA: this.trials.filter((t) => t.winner === "a").length,
67
+ winsB: this.trials.filter((t) => t.winner === "b").length,
68
+ ties: this.trials.filter((t) => t.winner === "tie").length,
69
+ backendA: this.backendA,
70
+ backendB: this.backendB,
71
+ };
72
+ }
73
+ /** Format stats for TUI display. */
74
+ formatStats() {
75
+ const s = this.getStats();
76
+ if (s.totalTrials === 0)
77
+ return [" (no A/B trials recorded yet)"];
78
+ const pctA = s.totalTrials > 0 ? Math.round((s.winsA / s.totalTrials) * 100) : 0;
79
+ const pctB = s.totalTrials > 0 ? Math.round((s.winsB / s.totalTrials) * 100) : 0;
80
+ return [
81
+ ` A/B Reasoning: ${s.totalTrials} trials`,
82
+ ` ${s.backendA}: ${s.winsA} wins (${pctA}%)`,
83
+ ` ${s.backendB}: ${s.winsB} wins (${pctB}%)`,
84
+ ` Ties: ${s.ties}`,
85
+ s.winsA > s.winsB ? ` → ${s.backendA} is performing better` :
86
+ s.winsB > s.winsA ? ` → ${s.backendB} is performing better` :
87
+ ` → Both backends performing equally`,
88
+ ];
89
+ }
90
+ }
91
+ //# sourceMappingURL=ab-reasoning.js.map
@@ -0,0 +1,42 @@
1
+ export type AlertSeverity = "info" | "warning" | "critical";
2
+ export type AlertCondition = (ctx: AlertContext) => boolean;
3
+ export interface AlertContext {
4
+ fleetHealth: number;
5
+ activeSessions: number;
6
+ errorSessions: number;
7
+ totalCostUsd: number;
8
+ hourlyCostRate: number;
9
+ stuckSessions: number;
10
+ idleMinutes: Map<string, number>;
11
+ }
12
+ export interface AlertRule {
13
+ name: string;
14
+ description: string;
15
+ severity: AlertSeverity;
16
+ condition: AlertCondition;
17
+ cooldownMs: number;
18
+ lastFiredAt: number;
19
+ }
20
+ export interface FiredAlert {
21
+ ruleName: string;
22
+ severity: AlertSeverity;
23
+ message: string;
24
+ timestamp: number;
25
+ }
26
+ /**
27
+ * Built-in alert rules.
28
+ */
29
+ export declare function defaultAlertRules(): AlertRule[];
30
+ /**
31
+ * Evaluate all alert rules against current fleet state.
32
+ */
33
+ export declare function evaluateAlertRules(rules: AlertRule[], ctx: AlertContext, now?: number): FiredAlert[];
34
+ /**
35
+ * Format fired alerts for TUI display.
36
+ */
37
+ export declare function formatFiredAlerts(alerts: FiredAlert[]): string[];
38
+ /**
39
+ * Format all rules and their status for TUI display.
40
+ */
41
+ export declare function formatAlertRules(rules: AlertRule[], now?: number): string[];
42
+ //# sourceMappingURL=alert-rules.d.ts.map
@@ -0,0 +1,94 @@
1
+ // alert-rules.ts — custom fleet health alerting rules beyond SLA threshold.
2
+ // define conditions that trigger alerts when met, with configurable
3
+ // severity, cooldown, and notification routing.
4
+ /**
5
+ * Built-in alert rules.
6
+ */
7
+ export function defaultAlertRules() {
8
+ return [
9
+ {
10
+ name: "fleet-health-critical",
11
+ description: "Fleet health dropped below 30",
12
+ severity: "critical",
13
+ condition: (ctx) => ctx.fleetHealth < 30,
14
+ cooldownMs: 10 * 60_000,
15
+ lastFiredAt: 0,
16
+ },
17
+ {
18
+ name: "high-error-rate",
19
+ description: "More than 50% of sessions in error state",
20
+ severity: "critical",
21
+ condition: (ctx) => ctx.activeSessions > 0 && (ctx.errorSessions / ctx.activeSessions) > 0.5,
22
+ cooldownMs: 5 * 60_000,
23
+ lastFiredAt: 0,
24
+ },
25
+ {
26
+ name: "cost-spike",
27
+ description: "Hourly cost rate exceeds $5",
28
+ severity: "warning",
29
+ condition: (ctx) => ctx.hourlyCostRate > 5,
30
+ cooldownMs: 15 * 60_000,
31
+ lastFiredAt: 0,
32
+ },
33
+ {
34
+ name: "all-stuck",
35
+ description: "All active sessions are stuck",
36
+ severity: "critical",
37
+ condition: (ctx) => ctx.activeSessions > 0 && ctx.stuckSessions === ctx.activeSessions,
38
+ cooldownMs: 10 * 60_000,
39
+ lastFiredAt: 0,
40
+ },
41
+ {
42
+ name: "no-active-sessions",
43
+ description: "No active sessions running",
44
+ severity: "info",
45
+ condition: (ctx) => ctx.activeSessions === 0,
46
+ cooldownMs: 30 * 60_000,
47
+ lastFiredAt: 0,
48
+ },
49
+ ];
50
+ }
51
+ /**
52
+ * Evaluate all alert rules against current fleet state.
53
+ */
54
+ export function evaluateAlertRules(rules, ctx, now = Date.now()) {
55
+ const fired = [];
56
+ for (const rule of rules) {
57
+ if (now - rule.lastFiredAt < rule.cooldownMs)
58
+ continue;
59
+ if (rule.condition(ctx)) {
60
+ rule.lastFiredAt = now;
61
+ fired.push({
62
+ ruleName: rule.name,
63
+ severity: rule.severity,
64
+ message: rule.description,
65
+ timestamp: now,
66
+ });
67
+ }
68
+ }
69
+ return fired;
70
+ }
71
+ /**
72
+ * Format fired alerts for TUI display.
73
+ */
74
+ export function formatFiredAlerts(alerts) {
75
+ if (alerts.length === 0)
76
+ return [" ✅ no alerts fired"];
77
+ const icons = { info: "ℹ", warning: "⚠", critical: "🚨" };
78
+ return alerts.map((a) => ` ${icons[a.severity]} [${a.severity}] ${a.ruleName}: ${a.message}`);
79
+ }
80
+ /**
81
+ * Format all rules and their status for TUI display.
82
+ */
83
+ export function formatAlertRules(rules, now = Date.now()) {
84
+ const lines = [];
85
+ lines.push(` Alert rules (${rules.length}):`);
86
+ for (const r of rules) {
87
+ const cooldownRemaining = Math.max(0, r.cooldownMs - (now - r.lastFiredAt));
88
+ const cooldownStr = cooldownRemaining > 0 ? ` (cooldown: ${Math.round(cooldownRemaining / 60_000)}m)` : "";
89
+ const icon = r.severity === "critical" ? "🚨" : r.severity === "warning" ? "⚠" : "ℹ";
90
+ lines.push(` ${icon} ${r.name}: ${r.description}${cooldownStr}`);
91
+ }
92
+ return lines;
93
+ }
94
+ //# sourceMappingURL=alert-rules.js.map
@@ -0,0 +1,24 @@
1
+ export declare const CLI_COMMANDS: readonly ["init", "tasks", "progress", "health", "summary", "supervisor", "incident", "runbook", "adopt", "doctor", "stats", "replay", "export", "tail", "web", "sync", "test-context", "task", "config"];
2
+ export declare const CLI_FLAGS: readonly ["--config", "--verbose", "--dry-run", "--observe", "--confirm", "--json", "--ndjson", "--watch", "--changes-only", "--heartbeat", "--follow", "--help", "--version"];
3
+ export declare const TUI_COMMANDS: readonly ["/supervisor", "/incident", "/runbook", "/progress", "/health", "/prompt-template", "/pin-save", "/pin-load", "/pin-presets", "/activity", "/conflicts", "/heatmap", "/audit", "/audit-stats", "/audit-search", "/fleet-snap", "/budget-predict", "/retries", "/fleet-forecast", "/priority", "/escalations", "/poll-status", "/drift", "/goal-progress", "/pool", "/reasoner-cost", "/anomaly", "/sla", "/velocity", "/schedule", "/cost-summary", "/session-report", "/cache", "/rate-limit", "/recovery", "/lifecycle", "/cost-report", "/decompose", "/memory", "/dep-graph", "/approvals", "/approve", "/reject", "/fleet-diff", "/template", "/difficulty", "/smart-nudge", "/utilization", "/detect-template", "/fleet-search", "/nudge-stats", "/allocation", "/graduation", "/refine", "/export", "/clear"];
4
+ /**
5
+ * Generate bash completion script.
6
+ */
7
+ export declare function generateBashCompletion(): string;
8
+ /**
9
+ * Generate zsh completion script.
10
+ */
11
+ export declare function generateZshCompletion(): string;
12
+ /**
13
+ * Generate fish completion script.
14
+ */
15
+ export declare function generateFishCompletion(): string;
16
+ /**
17
+ * Generate completion script for the specified shell.
18
+ */
19
+ export declare function generateCompletion(shell: "bash" | "zsh" | "fish"): string;
20
+ /**
21
+ * List all available commands for help display.
22
+ */
23
+ export declare function formatCommandList(): string[];
24
+ //# sourceMappingURL=cli-completions.d.ts.map
@@ -0,0 +1,114 @@
1
+ // cli-completions.ts — shell autocomplete for all aoaoe commands and TUI slash commands.
2
+ // generates completion scripts for bash, zsh, and fish.
3
+ export const CLI_COMMANDS = [
4
+ "init", "tasks", "progress", "health", "summary", "supervisor",
5
+ "incident", "runbook", "adopt", "doctor", "stats", "replay",
6
+ "export", "tail", "web", "sync", "test-context",
7
+ "task", "config",
8
+ ];
9
+ export const CLI_FLAGS = [
10
+ "--config", "--verbose", "--dry-run", "--observe", "--confirm",
11
+ "--json", "--ndjson", "--watch", "--changes-only", "--heartbeat", "--follow",
12
+ "--help", "--version",
13
+ ];
14
+ export const TUI_COMMANDS = [
15
+ "/supervisor", "/incident", "/runbook", "/progress", "/health",
16
+ "/prompt-template", "/pin-save", "/pin-load", "/pin-presets",
17
+ "/activity", "/conflicts", "/heatmap", "/audit", "/audit-stats",
18
+ "/audit-search", "/fleet-snap", "/budget-predict", "/retries",
19
+ "/fleet-forecast", "/priority", "/escalations", "/poll-status",
20
+ "/drift", "/goal-progress", "/pool", "/reasoner-cost",
21
+ "/anomaly", "/sla", "/velocity", "/schedule", "/cost-summary",
22
+ "/session-report", "/cache", "/rate-limit", "/recovery",
23
+ "/lifecycle", "/cost-report", "/decompose", "/memory",
24
+ "/dep-graph", "/approvals", "/approve", "/reject", "/fleet-diff",
25
+ "/template", "/difficulty", "/smart-nudge", "/utilization",
26
+ "/detect-template", "/fleet-search", "/nudge-stats", "/allocation",
27
+ "/graduation", "/refine", "/export", "/clear",
28
+ ];
29
+ /**
30
+ * Generate bash completion script.
31
+ */
32
+ export function generateBashCompletion() {
33
+ const cmds = CLI_COMMANDS.join(" ");
34
+ const flags = CLI_FLAGS.join(" ");
35
+ return `# aoaoe bash completion
36
+ # Add to ~/.bashrc: eval "$(aoaoe completions bash)"
37
+ _aoaoe() {
38
+ local cur prev
39
+ cur="\${COMP_WORDS[COMP_CWORD]}"
40
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
41
+
42
+ if [[ "\${cur}" == --* ]]; then
43
+ COMPREPLY=($(compgen -W "${flags}" -- "\${cur}"))
44
+ elif [[ "\${COMP_CWORD}" -eq 1 ]]; then
45
+ COMPREPLY=($(compgen -W "${cmds}" -- "\${cur}"))
46
+ fi
47
+ }
48
+ complete -F _aoaoe aoaoe
49
+ `;
50
+ }
51
+ /**
52
+ * Generate zsh completion script.
53
+ */
54
+ export function generateZshCompletion() {
55
+ const cmdList = CLI_COMMANDS.map((c) => `'${c}'`).join(" ");
56
+ const flagList = CLI_FLAGS.map((f) => `'${f}'`).join(" ");
57
+ return `# aoaoe zsh completion
58
+ # Add to ~/.zshrc: eval "$(aoaoe completions zsh)"
59
+ _aoaoe() {
60
+ local -a commands flags
61
+ commands=(${cmdList})
62
+ flags=(${flagList})
63
+
64
+ if (( CURRENT == 2 )); then
65
+ _describe 'command' commands
66
+ elif [[ "\${words[CURRENT]}" == --* ]]; then
67
+ _describe 'flag' flags
68
+ fi
69
+ }
70
+ compdef _aoaoe aoaoe
71
+ `;
72
+ }
73
+ /**
74
+ * Generate fish completion script.
75
+ */
76
+ export function generateFishCompletion() {
77
+ const lines = [
78
+ "# aoaoe fish completion",
79
+ "# Add to ~/.config/fish/completions/aoaoe.fish",
80
+ ];
81
+ for (const cmd of CLI_COMMANDS) {
82
+ lines.push(`complete -c aoaoe -n '__fish_use_subcommand' -a '${cmd}'`);
83
+ }
84
+ for (const flag of CLI_FLAGS) {
85
+ lines.push(`complete -c aoaoe -l '${flag.replace(/^--/, "")}'`);
86
+ }
87
+ return lines.join("\n") + "\n";
88
+ }
89
+ /**
90
+ * Generate completion script for the specified shell.
91
+ */
92
+ export function generateCompletion(shell) {
93
+ switch (shell) {
94
+ case "bash": return generateBashCompletion();
95
+ case "zsh": return generateZshCompletion();
96
+ case "fish": return generateFishCompletion();
97
+ }
98
+ }
99
+ /**
100
+ * List all available commands for help display.
101
+ */
102
+ export function formatCommandList() {
103
+ const lines = [];
104
+ lines.push(` CLI commands (${CLI_COMMANDS.length}):`);
105
+ lines.push(` ${CLI_COMMANDS.join(", ")}`);
106
+ lines.push("");
107
+ lines.push(` TUI slash commands (${TUI_COMMANDS.length}):`);
108
+ // group in rows of 6
109
+ for (let i = 0; i < TUI_COMMANDS.length; i += 6) {
110
+ lines.push(` ${TUI_COMMANDS.slice(i, i + 6).join(" ")}`);
111
+ }
112
+ return lines;
113
+ }
114
+ //# sourceMappingURL=cli-completions.js.map
package/dist/config.d.ts CHANGED
@@ -91,6 +91,9 @@ export declare function parseCliArgs(argv: string[]): {
91
91
  replaySpeed?: number;
92
92
  replayLast?: string;
93
93
  registerTitle?: string;
94
+ runService: boolean;
95
+ runCompletions: boolean;
96
+ completionsShell?: string;
94
97
  };
95
98
  export declare function printHelp(): void;
96
99
  //# sourceMappingURL=config.d.ts.map
package/dist/config.js CHANGED
@@ -359,7 +359,7 @@ export function parseCliArgs(argv) {
359
359
  let initForce = false;
360
360
  let runTaskCli = false;
361
361
  let registerTitle;
362
- const defaults = { overrides, help: false, version: false, register: false, testContext: false, runTest: false, showTasks: false, showTasksJson: false, runProgress: false, progressSince: undefined, progressJson: false, runHealth: false, healthJson: false, runSummary: false, runAdopt: false, adoptTemplate: undefined, showHistory: false, showStatus: false, runRunbook: false, runbookJson: false, runbookSection: undefined, runIncident: false, incidentSince: undefined, incidentLimit: undefined, incidentJson: false, incidentNdjson: false, incidentWatch: false, incidentChangesOnly: false, incidentHeartbeatSec: undefined, incidentIntervalMs: undefined, runSupervisor: false, supervisorAll: false, supervisorSince: undefined, supervisorLimit: undefined, supervisorJson: false, supervisorNdjson: false, supervisorWatch: false, supervisorChangesOnly: false, supervisorHeartbeatSec: undefined, supervisorIntervalMs: undefined, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runDoctor: false, runBackup: false, backupOutput: undefined, runRestore: false, restoreInput: undefined, runSync: false, syncAction: undefined, syncRemote: undefined, runWeb: false, webPort: undefined, runLogs: false, logsActions: false, logsGrep: undefined, logsCount: undefined, runExport: false, exportFormat: undefined, exportOutput: undefined, exportLast: undefined, exportTasks: false, runInit: false, initForce: false, runTaskCli: false, runTail: false, tailFollow: false, tailCount: undefined, runStats: false, statsLast: undefined, runReplay: false, replaySpeed: undefined, replayLast: undefined };
362
+ const defaults = { overrides, help: false, version: false, register: false, testContext: false, runTest: false, showTasks: false, showTasksJson: false, runProgress: false, progressSince: undefined, progressJson: false, runHealth: false, healthJson: false, runSummary: false, runAdopt: false, adoptTemplate: undefined, showHistory: false, showStatus: false, runRunbook: false, runbookJson: false, runbookSection: undefined, runIncident: false, incidentSince: undefined, incidentLimit: undefined, incidentJson: false, incidentNdjson: false, incidentWatch: false, incidentChangesOnly: false, incidentHeartbeatSec: undefined, incidentIntervalMs: undefined, runSupervisor: false, supervisorAll: false, supervisorSince: undefined, supervisorLimit: undefined, supervisorJson: false, supervisorNdjson: false, supervisorWatch: false, supervisorChangesOnly: false, supervisorHeartbeatSec: undefined, supervisorIntervalMs: undefined, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runDoctor: false, runBackup: false, backupOutput: undefined, runRestore: false, restoreInput: undefined, runSync: false, syncAction: undefined, syncRemote: undefined, runWeb: false, webPort: undefined, runLogs: false, logsActions: false, logsGrep: undefined, logsCount: undefined, runExport: false, exportFormat: undefined, exportOutput: undefined, exportLast: undefined, exportTasks: false, runInit: false, initForce: false, runTaskCli: false, runTail: false, tailFollow: false, tailCount: undefined, runStats: false, statsLast: undefined, runReplay: false, replaySpeed: undefined, replayLast: undefined, runService: false, runCompletions: false, completionsShell: undefined };
363
363
  // check for subcommand as first non-flag arg
364
364
  if (argv[2] === "test-context") {
365
365
  return { ...defaults, testContext: true };
@@ -573,6 +573,13 @@ export function parseCliArgs(argv) {
573
573
  if (argv[2] === "doctor") {
574
574
  return { ...defaults, runDoctor: true };
575
575
  }
576
+ if (argv[2] === "service") {
577
+ return { ...defaults, runService: true };
578
+ }
579
+ if (argv[2] === "completions") {
580
+ const shell = argv[3] ?? "bash";
581
+ return { ...defaults, runCompletions: true, completionsShell: shell };
582
+ }
576
583
  if (argv[2] === "backup") {
577
584
  const output = argv[3] && !argv[3].startsWith("-") ? argv[3] : undefined;
578
585
  return { ...defaults, runBackup: true, backupOutput: output };
@@ -0,0 +1,34 @@
1
+ export interface FederationPeer {
2
+ name: string;
3
+ url: string;
4
+ lastSeenAt?: number;
5
+ status: "online" | "offline" | "unknown";
6
+ }
7
+ export interface FederatedFleetState {
8
+ peer: string;
9
+ sessions: number;
10
+ activeTasks: number;
11
+ fleetHealth: number;
12
+ totalCostUsd: number;
13
+ lastUpdatedAt: number;
14
+ }
15
+ export interface FederationOverview {
16
+ peers: FederatedFleetState[];
17
+ totalSessions: number;
18
+ totalActiveTasks: number;
19
+ averageHealth: number;
20
+ totalCostUsd: number;
21
+ }
22
+ /**
23
+ * Fetch fleet state from a peer daemon's health endpoint.
24
+ */
25
+ export declare function fetchPeerState(peer: FederationPeer, timeoutMs?: number): Promise<FederatedFleetState | null>;
26
+ /**
27
+ * Aggregate fleet state from all peers into an overview.
28
+ */
29
+ export declare function aggregateFederation(states: FederatedFleetState[]): FederationOverview;
30
+ /**
31
+ * Format federation overview for TUI display.
32
+ */
33
+ export declare function formatFederationOverview(overview: FederationOverview): string[];
34
+ //# sourceMappingURL=fleet-federation.d.ts.map
@@ -0,0 +1,55 @@
1
+ // fleet-federation.ts — coordinate across multiple aoaoe daemons via HTTP.
2
+ // each daemon exposes a lightweight status endpoint; the federation client
3
+ // aggregates fleet state across hosts for unified monitoring.
4
+ /**
5
+ * Fetch fleet state from a peer daemon's health endpoint.
6
+ */
7
+ export async function fetchPeerState(peer, timeoutMs = 5000) {
8
+ try {
9
+ const controller = new AbortController();
10
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
11
+ const response = await fetch(`${peer.url}/health`, { signal: controller.signal });
12
+ clearTimeout(timer);
13
+ if (!response.ok)
14
+ return null;
15
+ const data = await response.json();
16
+ return {
17
+ peer: peer.name,
18
+ sessions: data.sessions ?? 0,
19
+ activeTasks: data.activeTasks ?? 0,
20
+ fleetHealth: data.fleetHealth ?? 0,
21
+ totalCostUsd: data.totalCostUsd ?? 0,
22
+ lastUpdatedAt: Date.now(),
23
+ };
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ /**
30
+ * Aggregate fleet state from all peers into an overview.
31
+ */
32
+ export function aggregateFederation(states) {
33
+ const totalSessions = states.reduce((s, p) => s + p.sessions, 0);
34
+ const totalActiveTasks = states.reduce((s, p) => s + p.activeTasks, 0);
35
+ const totalCost = states.reduce((s, p) => s + p.totalCostUsd, 0);
36
+ const avgHealth = states.length > 0
37
+ ? Math.round(states.reduce((s, p) => s + p.fleetHealth, 0) / states.length)
38
+ : 0;
39
+ return { peers: states, totalSessions, totalActiveTasks, averageHealth: avgHealth, totalCostUsd: totalCost };
40
+ }
41
+ /**
42
+ * Format federation overview for TUI display.
43
+ */
44
+ export function formatFederationOverview(overview) {
45
+ if (overview.peers.length === 0)
46
+ return [" (no federation peers configured)"];
47
+ const lines = [];
48
+ lines.push(` Federation: ${overview.peers.length} peers, ${overview.totalSessions} sessions, health ${overview.averageHealth}/100, $${overview.totalCostUsd.toFixed(2)} total`);
49
+ for (const p of overview.peers) {
50
+ const age = Math.round((Date.now() - p.lastUpdatedAt) / 60_000);
51
+ lines.push(` ${p.peer}: ${p.sessions} sessions, ${p.activeTasks} active, health ${p.fleetHealth}/100, $${p.totalCostUsd.toFixed(2)} (${age}m ago)`);
52
+ }
53
+ return lines;
54
+ }
55
+ //# sourceMappingURL=fleet-federation.js.map