agentflow-core 0.7.0 → 0.8.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/dist/cli.cjs CHANGED
@@ -93,7 +93,7 @@ var init_loader = __esm({
93
93
  });
94
94
 
95
95
  // src/cli.ts
96
- var import_path3 = require("path");
96
+ var import_node_path7 = require("path");
97
97
 
98
98
  // src/live.ts
99
99
  var import_node_fs2 = require("fs");
@@ -191,7 +191,7 @@ function groupByTraceId(graphs) {
191
191
  }
192
192
  function stitchTrace(graphs) {
193
193
  if (graphs.length === 0) throw new Error("No graphs to stitch");
194
- const traceId = graphs[0].traceId ?? "";
194
+ const traceId = graphs[0]?.traceId ?? "";
195
195
  const graphsBySpan = /* @__PURE__ */ new Map();
196
196
  const childMap = /* @__PURE__ */ new Map();
197
197
  let rootGraph = null;
@@ -268,7 +268,7 @@ function pidMatchesName(pid, name) {
268
268
  function readPidFile(path) {
269
269
  try {
270
270
  const pid = parseInt((0, import_node_fs.readFileSync)(path, "utf8").trim(), 10);
271
- return isNaN(pid) ? null : pid;
271
+ return Number.isNaN(pid) ? null : pid;
272
272
  } catch {
273
273
  return null;
274
274
  }
@@ -312,11 +312,11 @@ function auditSystemd(config) {
312
312
  const [k, ...v] = line.split("=");
313
313
  if (k) props[k.trim()] = v.join("=").trim();
314
314
  }
315
- const activeState = props["ActiveState"] ?? "unknown";
316
- const subState = props["SubState"] ?? "unknown";
317
- const mainPid = parseInt(props["MainPID"] ?? "0", 10);
318
- const restarts = parseInt(props["NRestarts"] ?? "0", 10);
319
- const result = props["Result"] ?? "unknown";
315
+ const activeState = props.ActiveState ?? "unknown";
316
+ const subState = props.SubState ?? "unknown";
317
+ const mainPid = parseInt(props.MainPID ?? "0", 10);
318
+ const restarts = parseInt(props.NRestarts ?? "0", 10);
319
+ const result = props.Result ?? "unknown";
320
320
  return {
321
321
  unit,
322
322
  activeState,
@@ -369,10 +369,10 @@ function readCmdline(pid) {
369
369
  }
370
370
  function getOsProcesses(processName) {
371
371
  try {
372
- const raw = (0, import_node_child_process.execSync)(
373
- `ps -eo pid,pcpu,pmem,etime,lstart,args --no-headers`,
374
- { encoding: "utf8", timeout: 5e3 }
375
- );
372
+ const raw = (0, import_node_child_process.execSync)(`ps -eo pid,pcpu,pmem,etime,lstart,args --no-headers`, {
373
+ encoding: "utf8",
374
+ timeout: 5e3
375
+ });
376
376
  const results = [];
377
377
  for (const line of raw.split("\n")) {
378
378
  if (!line.includes(processName)) continue;
@@ -380,7 +380,7 @@ function getOsProcesses(processName) {
380
380
  const trimmed = line.trim();
381
381
  const parts = trimmed.split(/\s+/);
382
382
  const pid = parseInt(parts[0] ?? "0", 10);
383
- if (isNaN(pid) || pid <= 0) continue;
383
+ if (Number.isNaN(pid) || pid <= 0) continue;
384
384
  const cpu = parts[1] ?? "0";
385
385
  const mem = parts[2] ?? "0";
386
386
  const elapsed = parts[3] ?? "";
@@ -457,16 +457,45 @@ function auditProcesses(config) {
457
457
  }
458
458
  }
459
459
  if (systemd?.mainPid) knownPids.add(systemd.mainPid);
460
+ const childPids = /* @__PURE__ */ new Set();
461
+ for (const knownPid of knownPids) {
462
+ try {
463
+ const childrenRaw = (0, import_node_fs.readFileSync)(
464
+ `/proc/${knownPid}/task/${knownPid}/children`,
465
+ "utf8"
466
+ ).trim();
467
+ if (childrenRaw) {
468
+ for (const c of childrenRaw.split(/\s+/)) {
469
+ const cp = parseInt(c, 10);
470
+ if (!Number.isNaN(cp)) childPids.add(cp);
471
+ }
472
+ }
473
+ } catch {
474
+ }
475
+ }
476
+ for (const p of osProcesses) {
477
+ if (knownPids.has(p.pid)) continue;
478
+ try {
479
+ const statusContent = (0, import_node_fs.readFileSync)(`/proc/${p.pid}/status`, "utf8");
480
+ const ppidMatch = statusContent.match(/^PPid:\s+(\d+)/m);
481
+ if (ppidMatch) {
482
+ const ppid = parseInt(ppidMatch[1] ?? "0", 10);
483
+ if (knownPids.has(ppid)) childPids.add(p.pid);
484
+ }
485
+ } catch {
486
+ }
487
+ }
460
488
  const selfPid = process.pid;
461
489
  const selfPpid = process.ppid;
462
490
  const orphans = osProcesses.filter(
463
- (p) => !knownPids.has(p.pid) && p.pid !== selfPid && p.pid !== selfPpid
491
+ (p) => !knownPids.has(p.pid) && !childPids.has(p.pid) && p.pid !== selfPid && p.pid !== selfPpid
464
492
  );
465
493
  const problems = [];
466
494
  if (pidFile?.stale) problems.push(`Stale PID file: ${pidFile.reason}`);
467
495
  if (systemd?.crashLooping) problems.push("Systemd unit is crash-looping (auto-restart)");
468
496
  if (systemd?.failed) problems.push("Systemd unit has failed");
469
- if (systemd && systemd.restarts > 10) problems.push(`High systemd restart count: ${systemd.restarts}`);
497
+ if (systemd && systemd.restarts > 10)
498
+ problems.push(`High systemd restart count: ${systemd.restarts}`);
470
499
  if (pidFile?.pid && systemd?.mainPid && pidFile.pid !== systemd.mainPid) {
471
500
  problems.push(`PID mismatch: file says ${pidFile.pid}, systemd says ${systemd.mainPid}`);
472
501
  }
@@ -475,15 +504,24 @@ function auditProcesses(config) {
475
504
  if (w.stale) problems.push(`Worker "${w.name}" (pid ${w.pid}) declares running but is dead`);
476
505
  }
477
506
  }
478
- if (orphans.length > 0) problems.push(`${orphans.length} orphan process(es) not tracked by PID file or workers registry`);
507
+ if (orphans.length > 0)
508
+ problems.push(
509
+ `${orphans.length} orphan process(es) not tracked by PID file or workers registry`
510
+ );
479
511
  return { pidFile, systemd, workers, osProcesses, orphans, problems };
480
512
  }
481
513
  function formatAuditReport(result) {
482
514
  const lines = [];
483
515
  lines.push("");
484
- lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
485
- lines.push("\u2551 \u{1F50D} P R O C E S S A U D I T \u2551");
486
- lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
516
+ lines.push(
517
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"
518
+ );
519
+ lines.push(
520
+ "\u2551 \u{1F50D} P R O C E S S A U D I T \u2551"
521
+ );
522
+ lines.push(
523
+ "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
524
+ );
487
525
  if (result.pidFile) {
488
526
  const pf = result.pidFile;
489
527
  const icon = pf.pid && pf.alive && pf.matchesProcess ? "\u2705" : pf.stale ? "\u26A0\uFE0F " : "\u2139\uFE0F ";
@@ -501,25 +539,33 @@ function formatAuditReport(result) {
501
539
  }
502
540
  if (result.workers) {
503
541
  const w = result.workers;
504
- lines.push(`
505
- Workers (orchestrator pid ${w.orchestratorPid ?? "unknown"} ${w.orchestratorAlive ? "\u2705" : "\u274C"})`);
542
+ lines.push(
543
+ `
544
+ Workers (orchestrator pid ${w.orchestratorPid ?? "unknown"} ${w.orchestratorAlive ? "\u2705" : "\u274C"})`
545
+ );
506
546
  for (const worker of w.workers) {
507
547
  const icon = worker.declaredStatus === "running" && worker.alive ? "\u{1F7E2}" : worker.stale ? "\u{1F534} STALE" : "\u26AA";
508
- lines.push(` ${icon} ${worker.name.padEnd(14)} pid=${String(worker.pid ?? "-").padEnd(8)} status=${worker.declaredStatus}`);
548
+ lines.push(
549
+ ` ${icon} ${worker.name.padEnd(14)} pid=${String(worker.pid ?? "-").padEnd(8)} status=${worker.declaredStatus}`
550
+ );
509
551
  }
510
552
  }
511
553
  if (result.osProcesses.length > 0) {
512
554
  lines.push(`
513
555
  OS Processes (${result.osProcesses.length} total)`);
514
556
  for (const p of result.osProcesses) {
515
- lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed.padEnd(10)} ${p.command.substring(0, 50)}`);
557
+ lines.push(
558
+ ` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed.padEnd(10)} ${p.command.substring(0, 50)}`
559
+ );
516
560
  }
517
561
  }
518
562
  if (result.orphans.length > 0) {
519
563
  lines.push(`
520
564
  \u26A0\uFE0F ${result.orphans.length} ORPHAN PROCESS(ES):`);
521
565
  for (const p of result.orphans) {
522
- lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed}`);
566
+ lines.push(
567
+ ` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed}`
568
+ );
523
569
  lines.push(` Started: ${p.started}`);
524
570
  lines.push(` Command: ${p.cmdline || p.command}`);
525
571
  }
@@ -564,7 +610,7 @@ function parseArgs(argv) {
564
610
  } else if (arg === "--refresh" || arg === "-r") {
565
611
  i++;
566
612
  const v = parseInt(args[i] ?? "", 10);
567
- if (!isNaN(v) && v > 0) config.refreshMs = v * 1e3;
613
+ if (!Number.isNaN(v) && v > 0) config.refreshMs = v * 1e3;
568
614
  i++;
569
615
  } else if (arg === "--recursive" || arg === "-R") {
570
616
  config.recursive = true;
@@ -645,12 +691,22 @@ function scanFiles(dirs, recursive) {
645
691
  if (!stat.isFile()) continue;
646
692
  if (f.endsWith(".json")) {
647
693
  seen.add(fp);
648
- const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".json" };
694
+ const entry = {
695
+ filename: f,
696
+ path: fp,
697
+ mtime: stat.mtime.getTime(),
698
+ ext: ".json"
699
+ };
649
700
  results.push(entry);
650
701
  dirResults.push(entry);
651
702
  } else if (f.endsWith(".jsonl")) {
652
703
  seen.add(fp);
653
- const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".jsonl" };
704
+ const entry = {
705
+ filename: f,
706
+ path: fp,
707
+ mtime: stat.mtime.getTime(),
708
+ ext: ".jsonl"
709
+ };
654
710
  results.push(entry);
655
711
  dirResults.push(entry);
656
712
  }
@@ -712,7 +768,7 @@ function findTimestamp(obj) {
712
768
  if (typeof val === "number") return val > 1e12 ? val : val * 1e3;
713
769
  if (typeof val === "string") {
714
770
  const d = Date.parse(val);
715
- if (!isNaN(d)) return d;
771
+ if (!Number.isNaN(d)) return d;
716
772
  }
717
773
  }
718
774
  return 0;
@@ -744,7 +800,7 @@ function extractDetail(obj) {
744
800
  }
745
801
  return parts.join(" | ") || "";
746
802
  }
747
- function tryLoadTrace(fp, raw) {
803
+ function tryLoadTrace(_fp, raw) {
748
804
  if (typeof raw !== "object" || raw === null) return null;
749
805
  const obj = raw;
750
806
  if (!("nodes" in obj)) return null;
@@ -995,7 +1051,8 @@ function writeLine(lines, text) {
995
1051
  }
996
1052
  function flushLines(lines) {
997
1053
  process.stdout.write("\x1B[H");
998
- process.stdout.write(lines.join("\n") + "\n");
1054
+ process.stdout.write(`${lines.join("\n")}
1055
+ `);
999
1056
  process.stdout.write("\x1B[J");
1000
1057
  }
1001
1058
  var prevFileCount = 0;
@@ -1089,7 +1146,7 @@ function render(config) {
1089
1146
  const status = fail > 0 ? "error" : running > 0 ? "running" : ok > 0 ? "ok" : "unknown";
1090
1147
  groups.push({
1091
1148
  name: groupName,
1092
- source: records[0].source,
1149
+ source: records[0]?.source ?? "trace",
1093
1150
  status,
1094
1151
  lastTs,
1095
1152
  detail: `${records.length} agents`,
@@ -1135,8 +1192,10 @@ function render(config) {
1135
1192
  cachedAuditResult = auditResult;
1136
1193
  lastAuditTime = now;
1137
1194
  } catch (err) {
1138
- process.stderr.write(`[agentflow] process audit error: ${err instanceof Error ? err.message : err}
1139
- `);
1195
+ process.stderr.write(
1196
+ `[agentflow] process audit error: ${err instanceof Error ? err.message : err}
1197
+ `
1198
+ );
1140
1199
  }
1141
1200
  }
1142
1201
  } else {
@@ -1193,7 +1252,7 @@ function render(config) {
1193
1252
  return new Date(ts).toLocaleTimeString();
1194
1253
  }
1195
1254
  function truncate(s, max) {
1196
- return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
1255
+ return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
1197
1256
  }
1198
1257
  const termWidth = process.stdout.columns || 120;
1199
1258
  const detailWidth = Math.max(20, termWidth - 60);
@@ -1234,7 +1293,8 @@ function render(config) {
1234
1293
  if (ar.systemd) {
1235
1294
  const si = ar.systemd.activeState === "active" ? `${C.green}\u25CF${C.reset}` : ar.systemd.crashLooping ? `${C.yellow}\u25CF${C.reset}` : ar.systemd.failed ? `${C.red}\u25CF${C.reset}` : `${C.dim}\u25CB${C.reset}`;
1236
1295
  sysdLabel = ` ${C.bold}Systemd${C.reset} ${si} ${ar.systemd.activeState}`;
1237
- if (ar.systemd.restarts > 0) sysdLabel += ` ${C.dim}(${ar.systemd.restarts} restarts)${C.reset}`;
1296
+ if (ar.systemd.restarts > 0)
1297
+ sysdLabel += ` ${C.dim}(${ar.systemd.restarts} restarts)${C.reset}`;
1238
1298
  }
1239
1299
  let pidLabel = "";
1240
1300
  if (ar.pidFile?.pid) {
@@ -1243,7 +1303,10 @@ function render(config) {
1243
1303
  }
1244
1304
  writeLine(L, "");
1245
1305
  writeLine(L, ` ${C.bold}${C.under}Process Health${C.reset}`);
1246
- writeLine(L, ` ${healthIcon} ${healthLabel}${pidLabel}${sysdLabel} ${C.bold}Procs${C.reset} ${C.dim}${ar.osProcesses.length}${C.reset} ${ar.orphans.length > 0 ? `${C.red}Orphans ${ar.orphans.length}${C.reset}` : `${C.dim}Orphans 0${C.reset}`}`);
1306
+ writeLine(
1307
+ L,
1308
+ ` ${healthIcon} ${healthLabel}${pidLabel}${sysdLabel} ${C.bold}Procs${C.reset} ${C.dim}${ar.osProcesses.length}${C.reset} ${ar.orphans.length > 0 ? `${C.red}Orphans ${ar.orphans.length}${C.reset}` : `${C.dim}Orphans 0${C.reset}`}`
1309
+ );
1247
1310
  if (workerParts.length > 0) {
1248
1311
  writeLine(L, ` ${C.dim}Workers${C.reset} ${workerParts.join(" ")}`);
1249
1312
  }
@@ -1255,7 +1318,10 @@ function render(config) {
1255
1318
  if (ar.orphans.length > 0) {
1256
1319
  for (const o of ar.orphans.slice(0, 5)) {
1257
1320
  const cmd = (o.cmdline || o.command).substring(0, detailWidth);
1258
- writeLine(L, ` ${C.red}?${C.reset} ${C.dim}pid=${o.pid} cpu=${o.cpu} mem=${o.mem} up=${o.elapsed}${C.reset} ${C.dim}${cmd}${C.reset}`);
1321
+ writeLine(
1322
+ L,
1323
+ ` ${C.red}?${C.reset} ${C.dim}pid=${o.pid} cpu=${o.cpu} mem=${o.mem} up=${o.elapsed}${C.reset} ${C.dim}${cmd}${C.reset}`
1324
+ );
1259
1325
  }
1260
1326
  if (ar.orphans.length > 5) {
1261
1327
  writeLine(L, ` ${C.dim}... +${ar.orphans.length - 5} more orphans${C.reset}`);
@@ -1329,7 +1395,7 @@ function render(config) {
1329
1395
  for (let i = 0; i < Math.min(tree.length, 6); i++) {
1330
1396
  const tg = tree[i];
1331
1397
  const depth = getDistDepth(dt, tg.spanId);
1332
- const indent = " " + "\u2502 ".repeat(Math.max(0, depth - 1));
1398
+ const indent = ` ${"\u2502 ".repeat(Math.max(0, depth - 1))}`;
1333
1399
  const isLast = i === tree.length - 1 || getDistDepth(dt, tree[i + 1]?.spanId) <= depth;
1334
1400
  const conn = depth === 0 ? " " : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
1335
1401
  const gs = tg.status === "completed" ? `${C.green}\u2713${C.reset}` : tg.status === "failed" ? `${C.red}\u2717${C.reset}` : `${C.yellow}\u23F3${C.reset}`;
@@ -1350,7 +1416,7 @@ function render(config) {
1350
1416
  const t = new Date(r.lastActive).toLocaleTimeString();
1351
1417
  const agent = truncate(r.id, 26).padEnd(26);
1352
1418
  const age = Math.floor((Date.now() - r.lastActive) / 1e3);
1353
- const ageStr = age < 60 ? age + "s ago" : age < 3600 ? Math.floor(age / 60) + "m ago" : Math.floor(age / 3600) + "h ago";
1419
+ const ageStr = age < 60 ? `${age}s ago` : age < 3600 ? `${Math.floor(age / 60)}m ago` : `${Math.floor(age / 3600)}h ago`;
1354
1420
  const det = truncate(r.detail, detailWidth);
1355
1421
  writeLine(
1356
1422
  L,
@@ -1415,7 +1481,7 @@ function startLive(argv) {
1415
1481
  };
1416
1482
  process.on("SIGINT", () => {
1417
1483
  cleanup();
1418
- console.log(C.dim + "Monitor stopped." + C.reset);
1484
+ console.log(`${C.dim}Monitor stopped.${C.reset}`);
1419
1485
  process.exit(0);
1420
1486
  });
1421
1487
  process.on("SIGTERM", () => {
@@ -1430,7 +1496,7 @@ var import_node_fs3 = require("fs");
1430
1496
  var import_node_path3 = require("path");
1431
1497
 
1432
1498
  // src/graph-builder.ts
1433
- var import_crypto = require("crypto");
1499
+ var import_node_crypto = require("crypto");
1434
1500
  function deepFreeze(obj) {
1435
1501
  if (obj === null || typeof obj !== "object") return obj;
1436
1502
  if (obj instanceof Map) {
@@ -1461,8 +1527,8 @@ function createGraphBuilder(config) {
1461
1527
  const generateId = config?.idGenerator ?? createCounterIdGenerator();
1462
1528
  const agentId = config?.agentId ?? "unknown";
1463
1529
  const trigger = config?.trigger ?? "manual";
1464
- const spanId = (0, import_crypto.randomUUID)();
1465
- const traceId = config?.traceId ?? (typeof process !== "undefined" ? process.env?.AGENTFLOW_TRACE_ID : void 0) ?? (0, import_crypto.randomUUID)();
1530
+ const spanId = (0, import_node_crypto.randomUUID)();
1531
+ const traceId = config?.traceId ?? (typeof process !== "undefined" ? process.env?.AGENTFLOW_TRACE_ID : void 0) ?? (0, import_node_crypto.randomUUID)();
1466
1532
  const parentSpanId = config?.parentSpanId ?? (typeof process !== "undefined" ? process.env?.AGENTFLOW_PARENT_SPAN_ID : void 0) ?? null;
1467
1533
  const graphId = generateId();
1468
1534
  const startTime = Date.now();
@@ -1682,7 +1748,7 @@ function agentIdFromFilename(filePath) {
1682
1748
  const cleaned = base.replace(/-state$/, "");
1683
1749
  return `alfred-${cleaned}`;
1684
1750
  }
1685
- function deriveAgentId(command) {
1751
+ function deriveAgentId(_command) {
1686
1752
  return "orchestrator";
1687
1753
  }
1688
1754
  function fileTimestamp() {
@@ -1792,14 +1858,18 @@ async function runTraced(config) {
1792
1858
  const filename = `${graph.agentId}-${ts}.json`;
1793
1859
  const outPath = (0, import_node_path3.join)(resolvedTracesDir, filename);
1794
1860
  const resolvedOut = (0, import_node_path3.resolve)(outPath);
1795
- if (!resolvedOut.startsWith(resolvedTracesDir + "/") && resolvedOut !== resolvedTracesDir) {
1796
- throw new Error(`Path traversal detected: agentId "${graph.agentId}" escapes traces directory`);
1861
+ if (!resolvedOut.startsWith(`${resolvedTracesDir}/`) && resolvedOut !== resolvedTracesDir) {
1862
+ throw new Error(
1863
+ `Path traversal detected: agentId "${graph.agentId}" escapes traces directory`
1864
+ );
1797
1865
  }
1798
1866
  (0, import_node_fs3.writeFileSync)(outPath, JSON.stringify(graphToJson(graph), null, 2), "utf-8");
1799
1867
  tracePaths.push(outPath);
1800
1868
  }
1801
1869
  if (tracePaths.length > 0) {
1802
- console.log(`\u{1F50D} Run "agentflow trace show ${orchestratorGraph.id} --traces-dir ${resolvedTracesDir}" to inspect`);
1870
+ console.log(
1871
+ `\u{1F50D} Run "agentflow trace show ${orchestratorGraph.id} --traces-dir ${resolvedTracesDir}" to inspect`
1872
+ );
1803
1873
  }
1804
1874
  return {
1805
1875
  exitCode,
@@ -1812,11 +1882,11 @@ async function runTraced(config) {
1812
1882
  }
1813
1883
 
1814
1884
  // src/trace-cli.ts
1815
- var import_path2 = require("path");
1885
+ var import_node_path5 = require("path");
1816
1886
 
1817
1887
  // src/trace-store.ts
1818
1888
  var import_promises = require("fs/promises");
1819
- var import_path = require("path");
1889
+ var import_node_path4 = require("path");
1820
1890
  init_loader();
1821
1891
  function createTraceStore(dir) {
1822
1892
  async function ensureDir() {
@@ -1834,7 +1904,7 @@ function createTraceStore(dir) {
1834
1904
  for (const file of files) {
1835
1905
  if (!file.endsWith(".json")) continue;
1836
1906
  try {
1837
- const content = await (0, import_promises.readFile)((0, import_path.join)(dir, file), "utf-8");
1907
+ const content = await (0, import_promises.readFile)((0, import_node_path4.join)(dir, file), "utf-8");
1838
1908
  const graph = loadGraph(content);
1839
1909
  graphs.push(graph);
1840
1910
  } catch {
@@ -1846,10 +1916,10 @@ function createTraceStore(dir) {
1846
1916
  async save(graph) {
1847
1917
  await ensureDir();
1848
1918
  const json = graphToJson(graph);
1849
- const filePath = (0, import_path.join)(dir, `${graph.id}.json`);
1850
- const resolvedBase = (0, import_path.resolve)(dir);
1851
- const resolvedPath = (0, import_path.resolve)(filePath);
1852
- if (!resolvedPath.startsWith(resolvedBase + "/") && resolvedPath !== resolvedBase) {
1919
+ const filePath = (0, import_node_path4.join)(dir, `${graph.id}.json`);
1920
+ const resolvedBase = (0, import_node_path4.resolve)(dir);
1921
+ const resolvedPath = (0, import_node_path4.resolve)(filePath);
1922
+ if (!resolvedPath.startsWith(`${resolvedBase}/`) && resolvedPath !== resolvedBase) {
1853
1923
  throw new Error(`Path traversal detected: "${graph.id}" escapes base directory`);
1854
1924
  }
1855
1925
  await (0, import_promises.writeFile)(filePath, JSON.stringify(json, null, 2), "utf-8");
@@ -1857,7 +1927,7 @@ function createTraceStore(dir) {
1857
1927
  },
1858
1928
  async get(graphId) {
1859
1929
  await ensureDir();
1860
- const filePath = (0, import_path.join)(dir, `${graphId}.json`);
1930
+ const filePath = (0, import_node_path4.join)(dir, `${graphId}.json`);
1861
1931
  try {
1862
1932
  const content = await (0, import_promises.readFile)(filePath, "utf-8");
1863
1933
  return loadGraph(content);
@@ -1979,7 +2049,8 @@ function toAsciiTree(graph) {
1979
2049
  const children = getChildren(graph, nodeId);
1980
2050
  const childPrefix = isRoot ? "" : prefix + (isLast ? " " : "\u2502 ");
1981
2051
  for (let i = 0; i < children.length; i++) {
1982
- renderNode(children[i].id, childPrefix, i === children.length - 1, false);
2052
+ const childId = children[i]?.id;
2053
+ if (childId) renderNode(childId, childPrefix, i === children.length - 1, false);
1983
2054
  }
1984
2055
  }
1985
2056
  renderNode(graph.rootNodeId, "", true, true);
@@ -2053,9 +2124,9 @@ function toTimeline(graph) {
2053
2124
  function getTracesDir(argv) {
2054
2125
  const idx = argv.indexOf("--traces-dir");
2055
2126
  if (idx !== -1 && argv[idx + 1]) {
2056
- return (0, import_path2.resolve)(argv[idx + 1]);
2127
+ return (0, import_node_path5.resolve)(argv[idx + 1]);
2057
2128
  }
2058
- return (0, import_path2.resolve)("./traces");
2129
+ return (0, import_node_path5.resolve)("./traces");
2059
2130
  }
2060
2131
  function getFlag(argv, name) {
2061
2132
  const idx = argv.indexOf(name);
@@ -2241,7 +2312,7 @@ async function handleTrace(argv) {
2241
2312
  // src/watch.ts
2242
2313
  var import_node_fs5 = require("fs");
2243
2314
  var import_node_os = require("os");
2244
- var import_node_path4 = require("path");
2315
+ var import_node_path6 = require("path");
2245
2316
 
2246
2317
  // src/watch-alerts.ts
2247
2318
  var import_node_child_process3 = require("child_process");
@@ -2367,10 +2438,10 @@ function parseDuration(input) {
2367
2438
  const match = input.match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i);
2368
2439
  if (!match) {
2369
2440
  const n = parseInt(input, 10);
2370
- return isNaN(n) ? 0 : n * 1e3;
2441
+ return Number.isNaN(n) ? 0 : n * 1e3;
2371
2442
  }
2372
2443
  const value = parseFloat(match[1]);
2373
- switch (match[2].toLowerCase()) {
2444
+ switch (match[2]?.toLowerCase()) {
2374
2445
  case "s":
2375
2446
  return value * 1e3;
2376
2447
  case "m":
@@ -2397,7 +2468,7 @@ function loadWatchState(filePath) {
2397
2468
  }
2398
2469
  }
2399
2470
  function saveWatchState(filePath, state) {
2400
- const tmp = filePath + ".tmp";
2471
+ const tmp = `${filePath}.tmp`;
2401
2472
  try {
2402
2473
  (0, import_node_fs4.writeFileSync)(tmp, JSON.stringify(state, null, 2), "utf8");
2403
2474
  (0, import_node_fs4.renameSync)(tmp, filePath);
@@ -2598,8 +2669,8 @@ function parseWatchArgs(argv) {
2598
2669
  i++;
2599
2670
  const val = args[i] ?? "";
2600
2671
  if (val === "telegram") {
2601
- const botToken = process.env["AGENTFLOW_TELEGRAM_BOT_TOKEN"] ?? "";
2602
- const chatId = process.env["AGENTFLOW_TELEGRAM_CHAT_ID"] ?? "";
2672
+ const botToken = process.env.AGENTFLOW_TELEGRAM_BOT_TOKEN ?? "";
2673
+ const chatId = process.env.AGENTFLOW_TELEGRAM_CHAT_ID ?? "";
2603
2674
  if (botToken && chatId) {
2604
2675
  notifyChannels.push({ type: "telegram", botToken, chatId });
2605
2676
  } else {
@@ -2616,7 +2687,7 @@ function parseWatchArgs(argv) {
2616
2687
  } else if (arg === "--poll") {
2617
2688
  i++;
2618
2689
  const v = parseInt(args[i] ?? "", 10);
2619
- if (!isNaN(v) && v > 0) pollIntervalMs = v * 1e3;
2690
+ if (!Number.isNaN(v) && v > 0) pollIntervalMs = v * 1e3;
2620
2691
  i++;
2621
2692
  } else if (arg === "--cooldown") {
2622
2693
  i++;
@@ -2631,20 +2702,20 @@ function parseWatchArgs(argv) {
2631
2702
  recursive = true;
2632
2703
  i++;
2633
2704
  } else if (!arg.startsWith("-")) {
2634
- dirs.push((0, import_node_path4.resolve)(arg));
2705
+ dirs.push((0, import_node_path6.resolve)(arg));
2635
2706
  i++;
2636
2707
  } else {
2637
2708
  i++;
2638
2709
  }
2639
2710
  }
2640
- if (dirs.length === 0) dirs.push((0, import_node_path4.resolve)("."));
2711
+ if (dirs.length === 0) dirs.push((0, import_node_path6.resolve)("."));
2641
2712
  if (alertConditions.length === 0) {
2642
2713
  alertConditions.push({ type: "error" });
2643
2714
  alertConditions.push({ type: "recovery" });
2644
2715
  }
2645
2716
  notifyChannels.unshift({ type: "stdout" });
2646
2717
  if (!stateFilePath) {
2647
- stateFilePath = (0, import_node_path4.join)(dirs[0], ".agentflow-watch-state.json");
2718
+ stateFilePath = (0, import_node_path6.join)(dirs[0], ".agentflow-watch-state.json");
2648
2719
  }
2649
2720
  return {
2650
2721
  dirs,
@@ -2652,7 +2723,7 @@ function parseWatchArgs(argv) {
2652
2723
  pollIntervalMs,
2653
2724
  alertConditions,
2654
2725
  notifyChannels,
2655
- stateFilePath: (0, import_node_path4.resolve)(stateFilePath),
2726
+ stateFilePath: (0, import_node_path6.resolve)(stateFilePath),
2656
2727
  cooldownMs
2657
2728
  };
2658
2729
  }
@@ -2732,7 +2803,7 @@ agentflow watch started`);
2732
2803
  console.log(` Poll: ${config.pollIntervalMs / 1e3}s`);
2733
2804
  console.log(` Alert on: ${condLabels.join(", ")}`);
2734
2805
  console.log(
2735
- ` Notify: stdout${channelLabels.length > 0 ? ", " + channelLabels.join(", ") : ""}`
2806
+ ` Notify: stdout${channelLabels.length > 0 ? `, ${channelLabels.join(", ")}` : ""}`
2736
2807
  );
2737
2808
  console.log(` Cooldown: ${Math.floor(config.cooldownMs / 6e4)}m`);
2738
2809
  console.log(` State: ${config.stateFilePath}`);
@@ -2936,11 +3007,11 @@ async function runCommand(argv) {
2936
3007
  if (result.tracePaths.length > 0) {
2937
3008
  console.log("\u{1F4DD} Traces saved:");
2938
3009
  const orchPath = result.tracePaths[0];
2939
- const orchName = (0, import_path3.basename)(orchPath, ".json").split("-")[0] ?? "orchestrator";
3010
+ const orchName = (0, import_node_path7.basename)(orchPath, ".json").split("-")[0] ?? "orchestrator";
2940
3011
  console.log(` ${orchName.padEnd(14)} \u2192 ${orchPath}`);
2941
3012
  for (let i = 1; i < result.tracePaths.length; i++) {
2942
3013
  const tPath = result.tracePaths[i];
2943
- const name = (0, import_path3.basename)(tPath, ".json").replace(/-\d{4}-.*$/, "");
3014
+ const name = (0, import_node_path7.basename)(tPath, ".json").replace(/-\d{4}-.*$/, "");
2944
3015
  const isLast = i === result.tracePaths.length - 1;
2945
3016
  const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
2946
3017
  console.log(` ${prefix} ${name.padEnd(12)} \u2192 ${tPath} (state changed)`);
@@ -2989,7 +3060,7 @@ function parseAuditArgs(argv) {
2989
3060
  systemdUnit = null;
2990
3061
  i++;
2991
3062
  } else if (!arg.startsWith("-")) {
2992
- discoverDirs.push((0, import_path3.resolve)(arg));
3063
+ discoverDirs.push((0, import_node_path7.resolve)(arg));
2993
3064
  i++;
2994
3065
  } else {
2995
3066
  i++;
@@ -2998,12 +3069,16 @@ function parseAuditArgs(argv) {
2998
3069
  if (!processName && !pidFile && !workersFile && discoverDirs.length > 0) {
2999
3070
  const discovered = discoverProcessConfig(discoverDirs);
3000
3071
  if (discovered) {
3001
- console.log(`Auto-discovered: process="${discovered.processName}"${discovered.pidFile ? ` pid-file=${discovered.pidFile}` : ""}${discovered.workersFile ? ` workers=${discovered.workersFile}` : ""}`);
3072
+ console.log(
3073
+ `Auto-discovered: process="${discovered.processName}"${discovered.pidFile ? ` pid-file=${discovered.pidFile}` : ""}${discovered.workersFile ? ` workers=${discovered.workersFile}` : ""}`
3074
+ );
3002
3075
  return { ...discovered, systemdUnit };
3003
3076
  }
3004
3077
  }
3005
3078
  if (!processName) {
3006
- console.error("Error: --process <name> is required, or provide directories for auto-discovery.");
3079
+ console.error(
3080
+ "Error: --process <name> is required, or provide directories for auto-discovery."
3081
+ );
3007
3082
  console.error("Examples:");
3008
3083
  console.error(" agentflow audit --process alfred --pid-file ./data/alfred.pid");
3009
3084
  console.error(" agentflow audit ./data # auto-discovers *.pid and workers.json");
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  startWatch,
10
10
  toAsciiTree,
11
11
  toTimeline
12
- } from "./chunk-5PRHVYYD.js";
12
+ } from "./chunk-6X5HU5LB.js";
13
13
  import "./chunk-DY7YHFIB.js";
14
14
 
15
15
  // src/cli.ts
@@ -414,12 +414,16 @@ function parseAuditArgs(argv) {
414
414
  if (!processName && !pidFile && !workersFile && discoverDirs.length > 0) {
415
415
  const discovered = discoverProcessConfig(discoverDirs);
416
416
  if (discovered) {
417
- console.log(`Auto-discovered: process="${discovered.processName}"${discovered.pidFile ? ` pid-file=${discovered.pidFile}` : ""}${discovered.workersFile ? ` workers=${discovered.workersFile}` : ""}`);
417
+ console.log(
418
+ `Auto-discovered: process="${discovered.processName}"${discovered.pidFile ? ` pid-file=${discovered.pidFile}` : ""}${discovered.workersFile ? ` workers=${discovered.workersFile}` : ""}`
419
+ );
418
420
  return { ...discovered, systemdUnit };
419
421
  }
420
422
  }
421
423
  if (!processName) {
422
- console.error("Error: --process <name> is required, or provide directories for auto-discovery.");
424
+ console.error(
425
+ "Error: --process <name> is required, or provide directories for auto-discovery."
426
+ );
423
427
  console.error("Examples:");
424
428
  console.error(" agentflow audit --process alfred --pid-file ./data/alfred.pid");
425
429
  console.error(" agentflow audit ./data # auto-discovers *.pid and workers.json");