agentflow-core 0.6.1 → 0.6.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.
@@ -321,18 +321,36 @@ function auditWorkers(config) {
321
321
  return null;
322
322
  }
323
323
  }
324
+ function readCmdline(pid) {
325
+ try {
326
+ return readFileSync(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ").trim();
327
+ } catch {
328
+ return "";
329
+ }
330
+ }
324
331
  function getOsProcesses(processName) {
325
332
  try {
326
- const raw = execSync(`ps aux`, { encoding: "utf8", timeout: 5e3 });
327
- return raw.split("\n").filter((line) => line.includes(processName) && !line.includes("process-audit") && !line.includes("grep")).map((line) => {
328
- const parts = line.trim().split(/\s+/);
329
- return {
330
- pid: parseInt(parts[1] ?? "0", 10),
331
- cpu: parts[2] ?? "0",
332
- mem: parts[3] ?? "0",
333
- command: parts.slice(10).join(" ")
334
- };
335
- }).filter((p) => !isNaN(p.pid) && p.pid > 0);
333
+ const raw = execSync(
334
+ `ps -eo pid,pcpu,pmem,etime,lstart,args --no-headers`,
335
+ { encoding: "utf8", timeout: 5e3 }
336
+ );
337
+ const results = [];
338
+ for (const line of raw.split("\n")) {
339
+ if (!line.includes(processName)) continue;
340
+ if (line.includes("process-audit") || line.includes(" grep ")) continue;
341
+ const trimmed = line.trim();
342
+ const parts = trimmed.split(/\s+/);
343
+ const pid = parseInt(parts[0] ?? "0", 10);
344
+ if (isNaN(pid) || pid <= 0) continue;
345
+ const cpu = parts[1] ?? "0";
346
+ const mem = parts[2] ?? "0";
347
+ const elapsed = parts[3] ?? "";
348
+ const started = parts.slice(4, 9).join(" ");
349
+ const command = parts.slice(9).join(" ");
350
+ const cmdline = readCmdline(pid);
351
+ results.push({ pid, cpu, mem, elapsed, started, command, cmdline });
352
+ }
353
+ return results;
336
354
  } catch {
337
355
  return [];
338
356
  }
@@ -388,7 +406,11 @@ function auditProcesses(config) {
388
406
  }
389
407
  }
390
408
  if (systemd?.mainPid) knownPids.add(systemd.mainPid);
391
- const orphans = osProcesses.filter((p) => !knownPids.has(p.pid));
409
+ const selfPid = process.pid;
410
+ const selfPpid = process.ppid;
411
+ const orphans = osProcesses.filter(
412
+ (p) => !knownPids.has(p.pid) && p.pid !== selfPid && p.pid !== selfPpid
413
+ );
392
414
  const problems = [];
393
415
  if (pidFile?.stale) problems.push(`Stale PID file: ${pidFile.reason}`);
394
416
  if (systemd?.crashLooping) problems.push("Systemd unit is crash-looping (auto-restart)");
@@ -439,14 +461,16 @@ function formatAuditReport(result) {
439
461
  lines.push(`
440
462
  OS Processes (${result.osProcesses.length} total)`);
441
463
  for (const p of result.osProcesses) {
442
- lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} ${p.command.substring(0, 55)}`);
464
+ 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)}`);
443
465
  }
444
466
  }
445
467
  if (result.orphans.length > 0) {
446
468
  lines.push(`
447
469
  \u26A0\uFE0F ${result.orphans.length} ORPHAN PROCESS(ES):`);
448
470
  for (const p of result.orphans) {
449
- lines.push(` PID ${p.pid} \u2014 not tracked by PID file or workers registry`);
471
+ lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed}`);
472
+ lines.push(` Started: ${p.started}`);
473
+ lines.push(` Command: ${p.cmdline || p.command}`);
450
474
  }
451
475
  }
452
476
  lines.push("");
@@ -1061,7 +1085,9 @@ function render(config) {
1061
1085
  auditResult = auditProcesses(cachedAuditConfig);
1062
1086
  cachedAuditResult = auditResult;
1063
1087
  lastAuditTime = now;
1064
- } catch {
1088
+ } catch (err) {
1089
+ process.stderr.write(`[agentflow] process audit error: ${err instanceof Error ? err.message : err}
1090
+ `);
1065
1091
  }
1066
1092
  }
1067
1093
  } else {
@@ -1181,6 +1207,15 @@ function render(config) {
1181
1207
  writeLine(L, ` ${C.red}\u2022${C.reset} ${C.dim}${p}${C.reset}`);
1182
1208
  }
1183
1209
  }
1210
+ if (ar.orphans.length > 0) {
1211
+ for (const o of ar.orphans.slice(0, 5)) {
1212
+ const cmd = (o.cmdline || o.command).substring(0, detailWidth);
1213
+ 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}`);
1214
+ }
1215
+ if (ar.orphans.length > 5) {
1216
+ writeLine(L, ` ${C.dim}... +${ar.orphans.length - 5} more orphans${C.reset}`);
1217
+ }
1218
+ }
1184
1219
  }
1185
1220
  writeLine(L, "");
1186
1221
  writeLine(
package/dist/cli.cjs CHANGED
@@ -360,18 +360,36 @@ function auditWorkers(config) {
360
360
  return null;
361
361
  }
362
362
  }
363
+ function readCmdline(pid) {
364
+ try {
365
+ return (0, import_node_fs.readFileSync)(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ").trim();
366
+ } catch {
367
+ return "";
368
+ }
369
+ }
363
370
  function getOsProcesses(processName) {
364
371
  try {
365
- const raw = (0, import_node_child_process.execSync)(`ps aux`, { encoding: "utf8", timeout: 5e3 });
366
- return raw.split("\n").filter((line) => line.includes(processName) && !line.includes("process-audit") && !line.includes("grep")).map((line) => {
367
- const parts = line.trim().split(/\s+/);
368
- return {
369
- pid: parseInt(parts[1] ?? "0", 10),
370
- cpu: parts[2] ?? "0",
371
- mem: parts[3] ?? "0",
372
- command: parts.slice(10).join(" ")
373
- };
374
- }).filter((p) => !isNaN(p.pid) && p.pid > 0);
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
+ );
376
+ const results = [];
377
+ for (const line of raw.split("\n")) {
378
+ if (!line.includes(processName)) continue;
379
+ if (line.includes("process-audit") || line.includes(" grep ")) continue;
380
+ const trimmed = line.trim();
381
+ const parts = trimmed.split(/\s+/);
382
+ const pid = parseInt(parts[0] ?? "0", 10);
383
+ if (isNaN(pid) || pid <= 0) continue;
384
+ const cpu = parts[1] ?? "0";
385
+ const mem = parts[2] ?? "0";
386
+ const elapsed = parts[3] ?? "";
387
+ const started = parts.slice(4, 9).join(" ");
388
+ const command = parts.slice(9).join(" ");
389
+ const cmdline = readCmdline(pid);
390
+ results.push({ pid, cpu, mem, elapsed, started, command, cmdline });
391
+ }
392
+ return results;
375
393
  } catch {
376
394
  return [];
377
395
  }
@@ -427,7 +445,11 @@ function auditProcesses(config) {
427
445
  }
428
446
  }
429
447
  if (systemd?.mainPid) knownPids.add(systemd.mainPid);
430
- const orphans = osProcesses.filter((p) => !knownPids.has(p.pid));
448
+ const selfPid = process.pid;
449
+ const selfPpid = process.ppid;
450
+ const orphans = osProcesses.filter(
451
+ (p) => !knownPids.has(p.pid) && p.pid !== selfPid && p.pid !== selfPpid
452
+ );
431
453
  const problems = [];
432
454
  if (pidFile?.stale) problems.push(`Stale PID file: ${pidFile.reason}`);
433
455
  if (systemd?.crashLooping) problems.push("Systemd unit is crash-looping (auto-restart)");
@@ -478,14 +500,16 @@ function formatAuditReport(result) {
478
500
  lines.push(`
479
501
  OS Processes (${result.osProcesses.length} total)`);
480
502
  for (const p of result.osProcesses) {
481
- lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} ${p.command.substring(0, 55)}`);
503
+ 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)}`);
482
504
  }
483
505
  }
484
506
  if (result.orphans.length > 0) {
485
507
  lines.push(`
486
508
  \u26A0\uFE0F ${result.orphans.length} ORPHAN PROCESS(ES):`);
487
509
  for (const p of result.orphans) {
488
- lines.push(` PID ${p.pid} \u2014 not tracked by PID file or workers registry`);
510
+ lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed}`);
511
+ lines.push(` Started: ${p.started}`);
512
+ lines.push(` Command: ${p.cmdline || p.command}`);
489
513
  }
490
514
  }
491
515
  lines.push("");
@@ -1098,7 +1122,9 @@ function render(config) {
1098
1122
  auditResult = auditProcesses(cachedAuditConfig);
1099
1123
  cachedAuditResult = auditResult;
1100
1124
  lastAuditTime = now;
1101
- } catch {
1125
+ } catch (err) {
1126
+ process.stderr.write(`[agentflow] process audit error: ${err instanceof Error ? err.message : err}
1127
+ `);
1102
1128
  }
1103
1129
  }
1104
1130
  } else {
@@ -1218,6 +1244,15 @@ function render(config) {
1218
1244
  writeLine(L, ` ${C.red}\u2022${C.reset} ${C.dim}${p}${C.reset}`);
1219
1245
  }
1220
1246
  }
1247
+ if (ar.orphans.length > 0) {
1248
+ for (const o of ar.orphans.slice(0, 5)) {
1249
+ const cmd = (o.cmdline || o.command).substring(0, detailWidth);
1250
+ 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}`);
1251
+ }
1252
+ if (ar.orphans.length > 5) {
1253
+ writeLine(L, ` ${C.dim}... +${ar.orphans.length - 5} more orphans${C.reset}`);
1254
+ }
1255
+ }
1221
1256
  }
1222
1257
  writeLine(L, "");
1223
1258
  writeLine(
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  startWatch,
10
10
  toAsciiTree,
11
11
  toTimeline
12
- } from "./chunk-BOSYI5YM.js";
12
+ } from "./chunk-BXZC5ZMJ.js";
13
13
  import "./chunk-DY7YHFIB.js";
14
14
 
15
15
  // src/cli.ts
package/dist/index.cjs CHANGED
@@ -809,18 +809,36 @@ function auditWorkers(config) {
809
809
  return null;
810
810
  }
811
811
  }
812
+ function readCmdline(pid) {
813
+ try {
814
+ return (0, import_node_fs.readFileSync)(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ").trim();
815
+ } catch {
816
+ return "";
817
+ }
818
+ }
812
819
  function getOsProcesses(processName) {
813
820
  try {
814
- const raw = (0, import_node_child_process.execSync)(`ps aux`, { encoding: "utf8", timeout: 5e3 });
815
- return raw.split("\n").filter((line) => line.includes(processName) && !line.includes("process-audit") && !line.includes("grep")).map((line) => {
816
- const parts = line.trim().split(/\s+/);
817
- return {
818
- pid: parseInt(parts[1] ?? "0", 10),
819
- cpu: parts[2] ?? "0",
820
- mem: parts[3] ?? "0",
821
- command: parts.slice(10).join(" ")
822
- };
823
- }).filter((p) => !isNaN(p.pid) && p.pid > 0);
821
+ const raw = (0, import_node_child_process.execSync)(
822
+ `ps -eo pid,pcpu,pmem,etime,lstart,args --no-headers`,
823
+ { encoding: "utf8", timeout: 5e3 }
824
+ );
825
+ const results = [];
826
+ for (const line of raw.split("\n")) {
827
+ if (!line.includes(processName)) continue;
828
+ if (line.includes("process-audit") || line.includes(" grep ")) continue;
829
+ const trimmed = line.trim();
830
+ const parts = trimmed.split(/\s+/);
831
+ const pid = parseInt(parts[0] ?? "0", 10);
832
+ if (isNaN(pid) || pid <= 0) continue;
833
+ const cpu = parts[1] ?? "0";
834
+ const mem = parts[2] ?? "0";
835
+ const elapsed = parts[3] ?? "";
836
+ const started = parts.slice(4, 9).join(" ");
837
+ const command = parts.slice(9).join(" ");
838
+ const cmdline = readCmdline(pid);
839
+ results.push({ pid, cpu, mem, elapsed, started, command, cmdline });
840
+ }
841
+ return results;
824
842
  } catch {
825
843
  return [];
826
844
  }
@@ -876,7 +894,11 @@ function auditProcesses(config) {
876
894
  }
877
895
  }
878
896
  if (systemd?.mainPid) knownPids.add(systemd.mainPid);
879
- const orphans = osProcesses.filter((p) => !knownPids.has(p.pid));
897
+ const selfPid = process.pid;
898
+ const selfPpid = process.ppid;
899
+ const orphans = osProcesses.filter(
900
+ (p) => !knownPids.has(p.pid) && p.pid !== selfPid && p.pid !== selfPpid
901
+ );
880
902
  const problems = [];
881
903
  if (pidFile?.stale) problems.push(`Stale PID file: ${pidFile.reason}`);
882
904
  if (systemd?.crashLooping) problems.push("Systemd unit is crash-looping (auto-restart)");
@@ -927,14 +949,16 @@ function formatAuditReport(result) {
927
949
  lines.push(`
928
950
  OS Processes (${result.osProcesses.length} total)`);
929
951
  for (const p of result.osProcesses) {
930
- lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} ${p.command.substring(0, 55)}`);
952
+ 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)}`);
931
953
  }
932
954
  }
933
955
  if (result.orphans.length > 0) {
934
956
  lines.push(`
935
957
  \u26A0\uFE0F ${result.orphans.length} ORPHAN PROCESS(ES):`);
936
958
  for (const p of result.orphans) {
937
- lines.push(` PID ${p.pid} \u2014 not tracked by PID file or workers registry`);
959
+ lines.push(` PID ${String(p.pid).padEnd(8)} CPU=${p.cpu.padEnd(6)} MEM=${p.mem.padEnd(6)} Up=${p.elapsed}`);
960
+ lines.push(` Started: ${p.started}`);
961
+ lines.push(` Command: ${p.cmdline || p.command}`);
938
962
  }
939
963
  }
940
964
  lines.push("");
@@ -1547,7 +1571,9 @@ function render(config) {
1547
1571
  auditResult = auditProcesses(cachedAuditConfig);
1548
1572
  cachedAuditResult = auditResult;
1549
1573
  lastAuditTime = now;
1550
- } catch {
1574
+ } catch (err) {
1575
+ process.stderr.write(`[agentflow] process audit error: ${err instanceof Error ? err.message : err}
1576
+ `);
1551
1577
  }
1552
1578
  }
1553
1579
  } else {
@@ -1667,6 +1693,15 @@ function render(config) {
1667
1693
  writeLine(L, ` ${C.red}\u2022${C.reset} ${C.dim}${p}${C.reset}`);
1668
1694
  }
1669
1695
  }
1696
+ if (ar.orphans.length > 0) {
1697
+ for (const o of ar.orphans.slice(0, 5)) {
1698
+ const cmd = (o.cmdline || o.command).substring(0, detailWidth);
1699
+ 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}`);
1700
+ }
1701
+ if (ar.orphans.length > 5) {
1702
+ writeLine(L, ` ${C.dim}... +${ar.orphans.length - 5} more orphans${C.reset}`);
1703
+ }
1704
+ }
1670
1705
  }
1671
1706
  writeLine(L, "");
1672
1707
  writeLine(
package/dist/index.d.cts CHANGED
@@ -542,7 +542,13 @@ interface OsProcess {
542
542
  pid: number;
543
543
  cpu: string;
544
544
  mem: string;
545
+ /** Elapsed time since process started (e.g. "2:31:05", "03:14"). */
546
+ elapsed: string;
547
+ /** Process start time (e.g. "Mar18", "17:37"). */
548
+ started: string;
545
549
  command: string;
550
+ /** Full command line from /proc (Linux only). */
551
+ cmdline: string;
546
552
  }
547
553
  interface ProcessAuditResult {
548
554
  pidFile: PidFileResult | null;
package/dist/index.d.ts CHANGED
@@ -542,7 +542,13 @@ interface OsProcess {
542
542
  pid: number;
543
543
  cpu: string;
544
544
  mem: string;
545
+ /** Elapsed time since process started (e.g. "2:31:05", "03:14"). */
546
+ elapsed: string;
547
+ /** Process start time (e.g. "Mar18", "17:37"). */
548
+ started: string;
545
549
  command: string;
550
+ /** Full command line from /proc (Linux only). */
551
+ cmdline: string;
546
552
  }
547
553
  interface ProcessAuditResult {
548
554
  pidFile: PidFileResult | null;
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  stitchTrace,
24
24
  toAsciiTree,
25
25
  toTimeline
26
- } from "./chunk-BOSYI5YM.js";
26
+ } from "./chunk-BXZC5ZMJ.js";
27
27
  import {
28
28
  graphToJson,
29
29
  loadGraph
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentflow-core",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Monitor any AI agent system. Auto-detects failures, sends alerts, audits OS processes. Zero config, zero dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",