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 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 lines = fs9.readFileSync(filePath, "utf-8").trim().split("\n").filter(Boolean);
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) => f.endsWith(".jsonl")).sort().reverse();
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
- if (!("port" in parsed)) {
3561
- errors.push("Missing required key: port");
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
- return !("port" in parsed);
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,