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 +23 -1
- package/dist/ab-reasoning.d.ts +42 -0
- package/dist/ab-reasoning.js +91 -0
- package/dist/alert-rules.d.ts +42 -0
- package/dist/alert-rules.js +94 -0
- package/dist/cli-completions.d.ts +24 -0
- package/dist/cli-completions.js +114 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +8 -1
- package/dist/fleet-federation.d.ts +34 -0
- package/dist/fleet-federation.js +55 -0
- package/dist/index.js +281 -1
- package/dist/input.d.ts +42 -0
- package/dist/input.js +130 -0
- package/dist/multi-reasoner.d.ts +36 -0
- package/dist/multi-reasoner.js +87 -0
- package/dist/output-archival.d.ts +23 -0
- package/dist/output-archival.js +72 -0
- package/dist/runbook-generator.d.ts +21 -0
- package/dist/runbook-generator.js +104 -0
- package/dist/service-generator.d.ts +32 -0
- package/dist/service-generator.js +132 -0
- package/dist/session-checkpoint.d.ts +55 -0
- package/dist/session-checkpoint.js +69 -0
- package/dist/session-replay.d.ts +25 -0
- package/dist/session-replay.js +103 -0
- package/dist/token-quota.d.ts +45 -0
- package/dist/token-quota.js +76 -0
- package/dist/workflow-chain.d.ts +33 -0
- package/dist/workflow-chain.js +69 -0
- package/dist/workflow-cost-forecast.d.ts +22 -0
- package/dist/workflow-cost-forecast.js +55 -0
- package/dist/workflow-engine.d.ts +48 -0
- package/dist/workflow-engine.js +91 -0
- package/dist/workflow-templates.d.ts +25 -0
- package/dist/workflow-templates.js +92 -0
- package/package.json +1 -1
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-
|
|
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
|