openclaw-aegis 1.12.0 → 1.12.2
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/dist/cli/index.js +100 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2357,7 +2357,8 @@ var fs9 = __toESM(require("fs"));
|
|
|
2357
2357
|
var path3 = __toESM(require("path"));
|
|
2358
2358
|
function parseIncident(filePath) {
|
|
2359
2359
|
const id = path3.basename(filePath, ".jsonl");
|
|
2360
|
-
const
|
|
2360
|
+
const actualFile = fs9.statSync(filePath).isDirectory() ? path3.join(filePath, "events.jsonl") : filePath;
|
|
2361
|
+
const lines = fs9.readFileSync(actualFile, "utf-8").trim().split("\n").filter(Boolean);
|
|
2361
2362
|
const events = [];
|
|
2362
2363
|
for (const line of lines) {
|
|
2363
2364
|
try {
|
|
@@ -2387,7 +2388,10 @@ var incidentsCommand = new import_commander5.Command("incidents").description("B
|
|
|
2387
2388
|
console.log("No incidents recorded yet.");
|
|
2388
2389
|
return;
|
|
2389
2390
|
}
|
|
2390
|
-
const files = fs9.readdirSync(incidentsDir).filter((f) =>
|
|
2391
|
+
const files = fs9.readdirSync(incidentsDir).filter((f) => {
|
|
2392
|
+
const full = path3.join(incidentsDir, f);
|
|
2393
|
+
return f.endsWith(".jsonl") || fs9.statSync(full).isDirectory() && fs9.existsSync(path3.join(full, "events.jsonl"));
|
|
2394
|
+
}).sort().reverse();
|
|
2391
2395
|
if (files.length === 0) {
|
|
2392
2396
|
console.log("No incidents recorded yet.");
|
|
2393
2397
|
return;
|
|
@@ -3557,8 +3561,9 @@ function preflightValidation(configPath) {
|
|
|
3557
3561
|
} catch {
|
|
3558
3562
|
return { valid: false, errors: ["Config is not valid JSON"] };
|
|
3559
3563
|
}
|
|
3560
|
-
|
|
3561
|
-
|
|
3564
|
+
const gateway = parsed.gateway;
|
|
3565
|
+
if (!("port" in parsed) && !(gateway && "port" in gateway)) {
|
|
3566
|
+
errors.push("Missing required key: port (checked top-level and gateway.port)");
|
|
3562
3567
|
}
|
|
3563
3568
|
const poisonKeys = ["autoAck", "autoAckMessage"];
|
|
3564
3569
|
for (const key of poisonKeys) {
|
|
@@ -4473,7 +4478,8 @@ function createPatterns(backupManager) {
|
|
|
4473
4478
|
try {
|
|
4474
4479
|
const raw = fs17.readFileSync(ctx.configPath, "utf-8");
|
|
4475
4480
|
const parsed = JSON.parse(raw);
|
|
4476
|
-
|
|
4481
|
+
const gw = parsed.gateway;
|
|
4482
|
+
return !("port" in parsed) && !(gw && "port" in gw);
|
|
4477
4483
|
} catch {
|
|
4478
4484
|
return true;
|
|
4479
4485
|
}
|
|
@@ -6184,6 +6190,95 @@ var serveCommand = new import_commander6.Command("serve").description("Start the
|
|
|
6184
6190
|
const deadManSwitch = new DeadManSwitch(config, backupManager);
|
|
6185
6191
|
const diagnosisEngine = new DiagnosisEngine(backupManager);
|
|
6186
6192
|
const recovery = new RecoveryOrchestrator(config, diagnosisEngine, backupManager);
|
|
6193
|
+
for (const ch of config.alerts.channels) {
|
|
6194
|
+
switch (ch.type) {
|
|
6195
|
+
case "ntfy":
|
|
6196
|
+
alertDispatcher.addProvider(new NtfyProvider(ch));
|
|
6197
|
+
break;
|
|
6198
|
+
case "telegram":
|
|
6199
|
+
alertDispatcher.addProvider(new TelegramProvider(ch));
|
|
6200
|
+
break;
|
|
6201
|
+
case "whatsapp":
|
|
6202
|
+
alertDispatcher.addProvider(new WhatsAppProvider(ch));
|
|
6203
|
+
break;
|
|
6204
|
+
case "webhook":
|
|
6205
|
+
alertDispatcher.addProvider(new WebhookProvider(ch));
|
|
6206
|
+
break;
|
|
6207
|
+
case "slack":
|
|
6208
|
+
alertDispatcher.addProvider(new SlackProvider(ch));
|
|
6209
|
+
break;
|
|
6210
|
+
case "discord":
|
|
6211
|
+
alertDispatcher.addProvider(new DiscordProvider(ch));
|
|
6212
|
+
break;
|
|
6213
|
+
case "email":
|
|
6214
|
+
alertDispatcher.addProvider(new EmailProvider(ch));
|
|
6215
|
+
break;
|
|
6216
|
+
case "pushover":
|
|
6217
|
+
alertDispatcher.addProvider(new PushoverProvider(ch));
|
|
6218
|
+
break;
|
|
6219
|
+
}
|
|
6220
|
+
}
|
|
6221
|
+
let escalationActive = false;
|
|
6222
|
+
monitor.on("escalate", async (score) => {
|
|
6223
|
+
if (escalationActive) return;
|
|
6224
|
+
escalationActive = true;
|
|
6225
|
+
try {
|
|
6226
|
+
const incidentId = incidentLogger.startIncident();
|
|
6227
|
+
console.log(
|
|
6228
|
+
`[aegis] ESCALATION: band=${score.band} score=${score.total} incident=${incidentId}`
|
|
6229
|
+
);
|
|
6230
|
+
incidentLogger.log("escalation", {
|
|
6231
|
+
score: score.total,
|
|
6232
|
+
band: score.band,
|
|
6233
|
+
probes: score.probeResults
|
|
6234
|
+
});
|
|
6235
|
+
const alert = {
|
|
6236
|
+
severity: score.band === "critical" ? "critical" : "warning",
|
|
6237
|
+
title: `Gateway ${score.band.toUpperCase()}: health score ${score.total}`,
|
|
6238
|
+
body: `Aegis detected gateway health degradation.
|
|
6239
|
+
Band: ${score.band}
|
|
6240
|
+
Score: ${score.total}
|
|
6241
|
+
Failed probes: ${score.probeResults.filter((p) => !p.healthy).map((p) => p.name).join(", ") || "none"}`,
|
|
6242
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6243
|
+
incidentId: incidentId ?? void 0,
|
|
6244
|
+
healthScore: score
|
|
6245
|
+
};
|
|
6246
|
+
void alertDispatcher.dispatch(alert);
|
|
6247
|
+
const actions = await recovery.recover(score);
|
|
6248
|
+
incidentLogger.log("recovery_result", { actions });
|
|
6249
|
+
if (actions.some((a) => a.result === "success")) {
|
|
6250
|
+
console.log(`[aegis] Recovery succeeded after ${actions.length} action(s)`);
|
|
6251
|
+
incidentLogger.log("recovery_success", { actions });
|
|
6252
|
+
incidentLogger.endIncident();
|
|
6253
|
+
} else {
|
|
6254
|
+
console.log(`[aegis] Recovery FAILED \u2014 all ${actions.length} action(s) exhausted`);
|
|
6255
|
+
incidentLogger.log("recovery_failed", { actions });
|
|
6256
|
+
const failAlert = {
|
|
6257
|
+
severity: "critical",
|
|
6258
|
+
title: "Gateway recovery FAILED \u2014 manual intervention required",
|
|
6259
|
+
body: `Aegis exhausted all recovery actions.
|
|
6260
|
+
Actions attempted: ${actions.map((a) => `${a.level}/${a.action}=${a.result}`).join(", ")}`,
|
|
6261
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6262
|
+
incidentId: incidentId ?? void 0,
|
|
6263
|
+
recoveryActions: actions
|
|
6264
|
+
};
|
|
6265
|
+
void alertDispatcher.dispatch(failAlert);
|
|
6266
|
+
}
|
|
6267
|
+
} catch (err) {
|
|
6268
|
+
console.error(
|
|
6269
|
+
`[aegis] Escalation handler error: ${err instanceof Error ? err.message : String(err)}`
|
|
6270
|
+
);
|
|
6271
|
+
incidentLogger.log("escalation_error", {
|
|
6272
|
+
error: err instanceof Error ? err.message : String(err)
|
|
6273
|
+
});
|
|
6274
|
+
} finally {
|
|
6275
|
+
escalationActive = false;
|
|
6276
|
+
}
|
|
6277
|
+
});
|
|
6278
|
+
recovery.on("recovery", (event) => {
|
|
6279
|
+
console.log(`[aegis] Recovery event: ${event.type}`);
|
|
6280
|
+
incidentLogger.log("recovery_event", event);
|
|
6281
|
+
});
|
|
6187
6282
|
const intel = config.intelligence;
|
|
6188
6283
|
const anomalyDetector = new AnomalyDetector(monitor, {
|
|
6189
6284
|
minBaseline: intel.anomaly.minBaseline,
|