agentflow-core 0.4.0 → 0.5.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.
@@ -209,6 +209,7 @@ function getTraceTree(trace) {
209
209
  // src/live.ts
210
210
  import { existsSync, readdirSync, readFileSync, statSync, watch } from "fs";
211
211
  import { basename, join, resolve } from "path";
212
+ import { execSync } from "child_process";
212
213
  var C = {
213
214
  reset: "\x1B[0m",
214
215
  bold: "\x1B[1m",
@@ -456,11 +457,22 @@ function processJsonFile(file) {
456
457
  const status2 = findStatus(w);
457
458
  const ts2 = findTimestamp(w) || findTimestamp(obj) || file.mtime;
458
459
  const pid = w.pid;
459
- const detail2 = pid ? `pid: ${pid}` : extractDetail(w);
460
+ let validatedStatus = status2;
461
+ let pidAlive = true;
462
+ if (pid && (status2 === "running" || status2 === "ok")) {
463
+ try {
464
+ execSync(`kill -0 ${pid} 2>/dev/null`, { stdio: "ignore" });
465
+ } catch {
466
+ pidAlive = false;
467
+ validatedStatus = "error";
468
+ }
469
+ }
470
+ const pidLabel = pid ? pidAlive ? `pid: ${pid}` : `pid: ${pid} (dead)` : "";
471
+ const detail2 = pidLabel || extractDetail(w);
460
472
  records.push({
461
473
  id: name,
462
474
  source: "workers",
463
- status: status2,
475
+ status: validatedStatus,
464
476
  lastActive: ts2,
465
477
  detail: detail2,
466
478
  file: file.filename
@@ -651,8 +663,30 @@ function render(config) {
651
663
  if (r.traceData) allTraces.push(r.traceData);
652
664
  }
653
665
  }
654
- const byFile = /* @__PURE__ */ new Map();
666
+ const deduped = [];
667
+ const seenAgents = /* @__PURE__ */ new Map();
655
668
  for (const r of allRecords) {
669
+ if (r.source === "jobs" || r.source === "workers" || r.source === "state") {
670
+ deduped.push(r);
671
+ continue;
672
+ }
673
+ const key = `${r.source}:${r.id}`;
674
+ const existing = seenAgents.get(key);
675
+ if (!existing || r.lastActive > existing.lastActive) {
676
+ seenAgents.set(key, r);
677
+ }
678
+ }
679
+ for (const r of seenAgents.values()) deduped.push(r);
680
+ const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
681
+ const now = Date.now();
682
+ const filtered = deduped.filter((r) => {
683
+ if (r.source === "jobs" || r.source === "workers") return true;
684
+ if (r.status === "running") return true;
685
+ return now - r.lastActive < STALE_THRESHOLD_MS;
686
+ });
687
+ const activeRecords = filtered;
688
+ const byFile = /* @__PURE__ */ new Map();
689
+ for (const r of activeRecords) {
656
690
  const arr = byFile.get(r.file) ?? [];
657
691
  arr.push(r);
658
692
  byFile.set(r.file, arr);
@@ -699,15 +733,14 @@ function render(config) {
699
733
  }
700
734
  }
701
735
  groups.sort((a, b) => b.lastTs - a.lastTs);
702
- const totExec = allRecords.length;
703
- const totFail = allRecords.filter((r) => r.status === "error").length;
704
- const totRunning = allRecords.filter((r) => r.status === "running").length;
705
- const uniqueAgents = new Set(allRecords.map((r) => r.id)).size;
736
+ const totExec = activeRecords.length;
737
+ const totFail = activeRecords.filter((r) => r.status === "error").length;
738
+ const totRunning = activeRecords.filter((r) => r.status === "running").length;
739
+ const uniqueAgents = new Set(activeRecords.map((r) => r.id)).size;
706
740
  const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
707
- const now = Date.now();
708
741
  const buckets = new Array(12).fill(0);
709
742
  const failBuckets = new Array(12).fill(0);
710
- for (const r of allRecords) {
743
+ for (const r of activeRecords) {
711
744
  const age = now - r.lastActive;
712
745
  if (age > 36e5 || age < 0) continue;
713
746
  const idx = 11 - Math.floor(age / 3e5);
@@ -881,7 +914,7 @@ function render(config) {
881
914
  }
882
915
  }
883
916
  }
884
- const recentRecords = allRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
917
+ const recentRecords = activeRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
885
918
  if (recentRecords.length > 0) {
886
919
  writeLine(L, "");
887
920
  writeLine(L, ` ${C.bold}${C.under}Recent Activity${C.reset}`);
package/dist/cli.cjs CHANGED
@@ -98,6 +98,7 @@ var import_path3 = require("path");
98
98
  // src/live.ts
99
99
  var import_node_fs = require("fs");
100
100
  var import_node_path = require("path");
101
+ var import_node_child_process = require("child_process");
101
102
 
102
103
  // src/graph-query.ts
103
104
  function getChildren(graph, nodeId) {
@@ -491,11 +492,22 @@ function processJsonFile(file) {
491
492
  const status2 = findStatus(w);
492
493
  const ts2 = findTimestamp(w) || findTimestamp(obj) || file.mtime;
493
494
  const pid = w.pid;
494
- const detail2 = pid ? `pid: ${pid}` : extractDetail(w);
495
+ let validatedStatus = status2;
496
+ let pidAlive = true;
497
+ if (pid && (status2 === "running" || status2 === "ok")) {
498
+ try {
499
+ (0, import_node_child_process.execSync)(`kill -0 ${pid} 2>/dev/null`, { stdio: "ignore" });
500
+ } catch {
501
+ pidAlive = false;
502
+ validatedStatus = "error";
503
+ }
504
+ }
505
+ const pidLabel = pid ? pidAlive ? `pid: ${pid}` : `pid: ${pid} (dead)` : "";
506
+ const detail2 = pidLabel || extractDetail(w);
495
507
  records.push({
496
508
  id: name,
497
509
  source: "workers",
498
- status: status2,
510
+ status: validatedStatus,
499
511
  lastActive: ts2,
500
512
  detail: detail2,
501
513
  file: file.filename
@@ -686,8 +698,30 @@ function render(config) {
686
698
  if (r.traceData) allTraces.push(r.traceData);
687
699
  }
688
700
  }
689
- const byFile = /* @__PURE__ */ new Map();
701
+ const deduped = [];
702
+ const seenAgents = /* @__PURE__ */ new Map();
690
703
  for (const r of allRecords) {
704
+ if (r.source === "jobs" || r.source === "workers" || r.source === "state") {
705
+ deduped.push(r);
706
+ continue;
707
+ }
708
+ const key = `${r.source}:${r.id}`;
709
+ const existing = seenAgents.get(key);
710
+ if (!existing || r.lastActive > existing.lastActive) {
711
+ seenAgents.set(key, r);
712
+ }
713
+ }
714
+ for (const r of seenAgents.values()) deduped.push(r);
715
+ const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
716
+ const now = Date.now();
717
+ const filtered = deduped.filter((r) => {
718
+ if (r.source === "jobs" || r.source === "workers") return true;
719
+ if (r.status === "running") return true;
720
+ return now - r.lastActive < STALE_THRESHOLD_MS;
721
+ });
722
+ const activeRecords = filtered;
723
+ const byFile = /* @__PURE__ */ new Map();
724
+ for (const r of activeRecords) {
691
725
  const arr = byFile.get(r.file) ?? [];
692
726
  arr.push(r);
693
727
  byFile.set(r.file, arr);
@@ -734,15 +768,14 @@ function render(config) {
734
768
  }
735
769
  }
736
770
  groups.sort((a, b) => b.lastTs - a.lastTs);
737
- const totExec = allRecords.length;
738
- const totFail = allRecords.filter((r) => r.status === "error").length;
739
- const totRunning = allRecords.filter((r) => r.status === "running").length;
740
- const uniqueAgents = new Set(allRecords.map((r) => r.id)).size;
771
+ const totExec = activeRecords.length;
772
+ const totFail = activeRecords.filter((r) => r.status === "error").length;
773
+ const totRunning = activeRecords.filter((r) => r.status === "running").length;
774
+ const uniqueAgents = new Set(activeRecords.map((r) => r.id)).size;
741
775
  const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
742
- const now = Date.now();
743
776
  const buckets = new Array(12).fill(0);
744
777
  const failBuckets = new Array(12).fill(0);
745
- for (const r of allRecords) {
778
+ for (const r of activeRecords) {
746
779
  const age = now - r.lastActive;
747
780
  if (age > 36e5 || age < 0) continue;
748
781
  const idx = 11 - Math.floor(age / 3e5);
@@ -916,7 +949,7 @@ function render(config) {
916
949
  }
917
950
  }
918
951
  }
919
- const recentRecords = allRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
952
+ const recentRecords = activeRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
920
953
  if (recentRecords.length > 0) {
921
954
  writeLine(L, "");
922
955
  writeLine(L, ` ${C.bold}${C.under}Recent Activity${C.reset}`);
@@ -982,7 +1015,7 @@ function startLive(argv) {
982
1015
  }
983
1016
 
984
1017
  // src/runner.ts
985
- var import_node_child_process = require("child_process");
1018
+ var import_node_child_process2 = require("child_process");
986
1019
  var import_node_fs2 = require("fs");
987
1020
  var import_node_path2 = require("path");
988
1021
 
@@ -1286,7 +1319,7 @@ async function runTraced(config) {
1286
1319
  const execArgs = command.slice(1);
1287
1320
  process.env.AGENTFLOW_TRACE_ID = traceId;
1288
1321
  process.env.AGENTFLOW_PARENT_SPAN_ID = spanId;
1289
- const result = (0, import_node_child_process.spawnSync)(execCmd, execArgs, { stdio: "inherit" });
1322
+ const result = (0, import_node_child_process2.spawnSync)(execCmd, execArgs, { stdio: "inherit" });
1290
1323
  delete process.env.AGENTFLOW_TRACE_ID;
1291
1324
  delete process.env.AGENTFLOW_PARENT_SPAN_ID;
1292
1325
  const exitCode = result.status ?? 1;
@@ -1792,7 +1825,7 @@ var import_node_os = require("os");
1792
1825
  var import_node_path3 = require("path");
1793
1826
 
1794
1827
  // src/watch-alerts.ts
1795
- var import_node_child_process2 = require("child_process");
1828
+ var import_node_child_process3 = require("child_process");
1796
1829
  var import_node_http = require("http");
1797
1830
  var import_node_https = require("https");
1798
1831
  function formatAlertMessage(payload) {
@@ -1902,7 +1935,7 @@ function sendCommand(payload, cmd) {
1902
1935
  AGENTFLOW_ALERT_FILE: payload.file,
1903
1936
  AGENTFLOW_ALERT_TIMESTAMP: String(payload.timestamp)
1904
1937
  };
1905
- (0, import_node_child_process2.exec)(cmd, { env, timeout: 3e4 }, (err) => {
1938
+ (0, import_node_child_process3.exec)(cmd, { env, timeout: 3e4 }, (err) => {
1906
1939
  if (err) reject(err);
1907
1940
  else resolve6();
1908
1941
  });
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  startWatch,
7
7
  toAsciiTree,
8
8
  toTimeline
9
- } from "./chunk-DHCTDCDI.js";
9
+ } from "./chunk-T2BYYGA4.js";
10
10
  import "./chunk-DY7YHFIB.js";
11
11
 
12
12
  // src/cli.ts
package/dist/index.cjs CHANGED
@@ -638,6 +638,7 @@ function withGuards(builder, config) {
638
638
  // src/live.ts
639
639
  var import_node_fs = require("fs");
640
640
  var import_node_path = require("path");
641
+ var import_node_child_process = require("child_process");
641
642
 
642
643
  // src/loader.ts
643
644
  function toNodesMap(raw) {
@@ -939,11 +940,22 @@ function processJsonFile(file) {
939
940
  const status2 = findStatus(w);
940
941
  const ts2 = findTimestamp(w) || findTimestamp(obj) || file.mtime;
941
942
  const pid = w.pid;
942
- const detail2 = pid ? `pid: ${pid}` : extractDetail(w);
943
+ let validatedStatus = status2;
944
+ let pidAlive = true;
945
+ if (pid && (status2 === "running" || status2 === "ok")) {
946
+ try {
947
+ (0, import_node_child_process.execSync)(`kill -0 ${pid} 2>/dev/null`, { stdio: "ignore" });
948
+ } catch {
949
+ pidAlive = false;
950
+ validatedStatus = "error";
951
+ }
952
+ }
953
+ const pidLabel = pid ? pidAlive ? `pid: ${pid}` : `pid: ${pid} (dead)` : "";
954
+ const detail2 = pidLabel || extractDetail(w);
943
955
  records.push({
944
956
  id: name,
945
957
  source: "workers",
946
- status: status2,
958
+ status: validatedStatus,
947
959
  lastActive: ts2,
948
960
  detail: detail2,
949
961
  file: file.filename
@@ -1134,8 +1146,30 @@ function render(config) {
1134
1146
  if (r.traceData) allTraces.push(r.traceData);
1135
1147
  }
1136
1148
  }
1137
- const byFile = /* @__PURE__ */ new Map();
1149
+ const deduped = [];
1150
+ const seenAgents = /* @__PURE__ */ new Map();
1138
1151
  for (const r of allRecords) {
1152
+ if (r.source === "jobs" || r.source === "workers" || r.source === "state") {
1153
+ deduped.push(r);
1154
+ continue;
1155
+ }
1156
+ const key = `${r.source}:${r.id}`;
1157
+ const existing = seenAgents.get(key);
1158
+ if (!existing || r.lastActive > existing.lastActive) {
1159
+ seenAgents.set(key, r);
1160
+ }
1161
+ }
1162
+ for (const r of seenAgents.values()) deduped.push(r);
1163
+ const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
1164
+ const now = Date.now();
1165
+ const filtered = deduped.filter((r) => {
1166
+ if (r.source === "jobs" || r.source === "workers") return true;
1167
+ if (r.status === "running") return true;
1168
+ return now - r.lastActive < STALE_THRESHOLD_MS;
1169
+ });
1170
+ const activeRecords = filtered;
1171
+ const byFile = /* @__PURE__ */ new Map();
1172
+ for (const r of activeRecords) {
1139
1173
  const arr = byFile.get(r.file) ?? [];
1140
1174
  arr.push(r);
1141
1175
  byFile.set(r.file, arr);
@@ -1182,15 +1216,14 @@ function render(config) {
1182
1216
  }
1183
1217
  }
1184
1218
  groups.sort((a, b) => b.lastTs - a.lastTs);
1185
- const totExec = allRecords.length;
1186
- const totFail = allRecords.filter((r) => r.status === "error").length;
1187
- const totRunning = allRecords.filter((r) => r.status === "running").length;
1188
- const uniqueAgents = new Set(allRecords.map((r) => r.id)).size;
1219
+ const totExec = activeRecords.length;
1220
+ const totFail = activeRecords.filter((r) => r.status === "error").length;
1221
+ const totRunning = activeRecords.filter((r) => r.status === "running").length;
1222
+ const uniqueAgents = new Set(activeRecords.map((r) => r.id)).size;
1189
1223
  const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
1190
- const now = Date.now();
1191
1224
  const buckets = new Array(12).fill(0);
1192
1225
  const failBuckets = new Array(12).fill(0);
1193
- for (const r of allRecords) {
1226
+ for (const r of activeRecords) {
1194
1227
  const age = now - r.lastActive;
1195
1228
  if (age > 36e5 || age < 0) continue;
1196
1229
  const idx = 11 - Math.floor(age / 3e5);
@@ -1364,7 +1397,7 @@ function render(config) {
1364
1397
  }
1365
1398
  }
1366
1399
  }
1367
- const recentRecords = allRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
1400
+ const recentRecords = activeRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
1368
1401
  if (recentRecords.length > 0) {
1369
1402
  writeLine(L, "");
1370
1403
  writeLine(L, ` ${C.bold}${C.under}Recent Activity${C.reset}`);
@@ -1430,7 +1463,7 @@ function startLive(argv) {
1430
1463
  }
1431
1464
 
1432
1465
  // src/runner.ts
1433
- var import_node_child_process = require("child_process");
1466
+ var import_node_child_process2 = require("child_process");
1434
1467
  var import_node_fs2 = require("fs");
1435
1468
  var import_node_path2 = require("path");
1436
1469
  function globToRegex(pattern) {
@@ -1505,7 +1538,7 @@ async function runTraced(config) {
1505
1538
  const execArgs = command.slice(1);
1506
1539
  process.env.AGENTFLOW_TRACE_ID = traceId;
1507
1540
  process.env.AGENTFLOW_PARENT_SPAN_ID = spanId;
1508
- const result = (0, import_node_child_process.spawnSync)(execCmd, execArgs, { stdio: "inherit" });
1541
+ const result = (0, import_node_child_process2.spawnSync)(execCmd, execArgs, { stdio: "inherit" });
1509
1542
  delete process.env.AGENTFLOW_TRACE_ID;
1510
1543
  delete process.env.AGENTFLOW_PARENT_SPAN_ID;
1511
1544
  const exitCode = result.status ?? 1;
@@ -1818,7 +1851,7 @@ var import_node_os = require("os");
1818
1851
  var import_node_path3 = require("path");
1819
1852
 
1820
1853
  // src/watch-alerts.ts
1821
- var import_node_child_process2 = require("child_process");
1854
+ var import_node_child_process3 = require("child_process");
1822
1855
  var import_node_http = require("http");
1823
1856
  var import_node_https = require("https");
1824
1857
  function formatAlertMessage(payload) {
@@ -1928,7 +1961,7 @@ function sendCommand(payload, cmd) {
1928
1961
  AGENTFLOW_ALERT_FILE: payload.file,
1929
1962
  AGENTFLOW_ALERT_TIMESTAMP: String(payload.timestamp)
1930
1963
  };
1931
- (0, import_node_child_process2.exec)(cmd, { env, timeout: 3e4 }, (err) => {
1964
+ (0, import_node_child_process3.exec)(cmd, { env, timeout: 3e4 }, (err) => {
1932
1965
  if (err) reject(err);
1933
1966
  else resolve4();
1934
1967
  });
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  stitchTrace,
21
21
  toAsciiTree,
22
22
  toTimeline
23
- } from "./chunk-DHCTDCDI.js";
23
+ } from "./chunk-T2BYYGA4.js";
24
24
  import {
25
25
  graphToJson,
26
26
  loadGraph
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentflow-core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Monitor any AI agent system. Auto-detects failures, sends alerts. Zero config, zero dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",