agentflow-core 0.4.0 → 0.5.1
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/{chunk-DHCTDCDI.js → chunk-LPTCBS77.js} +85 -16
- package/dist/cli.cjs +89 -20
- package/dist/cli.js +1 -1
- package/dist/index.cjs +89 -20
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -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",
|
|
@@ -276,11 +277,29 @@ Examples:
|
|
|
276
277
|
`.trim()
|
|
277
278
|
);
|
|
278
279
|
}
|
|
280
|
+
var dirMtimeCache = /* @__PURE__ */ new Map();
|
|
281
|
+
var dirFileCache = /* @__PURE__ */ new Map();
|
|
279
282
|
function scanFiles(dirs, recursive) {
|
|
280
283
|
const results = [];
|
|
281
284
|
const seen = /* @__PURE__ */ new Set();
|
|
282
285
|
function scanDir(d, topLevel) {
|
|
283
286
|
try {
|
|
287
|
+
const dirStat = statSync(d);
|
|
288
|
+
const dirMtime = dirStat.mtime.getTime();
|
|
289
|
+
const cachedMtime = dirMtimeCache.get(d);
|
|
290
|
+
if (cachedMtime === dirMtime) {
|
|
291
|
+
const cached = dirFileCache.get(d);
|
|
292
|
+
if (cached) {
|
|
293
|
+
for (const f of cached) {
|
|
294
|
+
if (!seen.has(f.path)) {
|
|
295
|
+
seen.add(f.path);
|
|
296
|
+
results.push(f);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const dirResults = [];
|
|
284
303
|
for (const f of readdirSync(d)) {
|
|
285
304
|
if (f.startsWith(".")) continue;
|
|
286
305
|
const fp = join(d, f);
|
|
@@ -298,12 +317,18 @@ function scanFiles(dirs, recursive) {
|
|
|
298
317
|
if (!stat.isFile()) continue;
|
|
299
318
|
if (f.endsWith(".json")) {
|
|
300
319
|
seen.add(fp);
|
|
301
|
-
|
|
320
|
+
const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".json" };
|
|
321
|
+
results.push(entry);
|
|
322
|
+
dirResults.push(entry);
|
|
302
323
|
} else if (f.endsWith(".jsonl")) {
|
|
303
324
|
seen.add(fp);
|
|
304
|
-
|
|
325
|
+
const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".jsonl" };
|
|
326
|
+
results.push(entry);
|
|
327
|
+
dirResults.push(entry);
|
|
305
328
|
}
|
|
306
329
|
}
|
|
330
|
+
dirMtimeCache.set(d, dirMtime);
|
|
331
|
+
dirFileCache.set(d, dirResults);
|
|
307
332
|
} catch {
|
|
308
333
|
}
|
|
309
334
|
}
|
|
@@ -456,11 +481,22 @@ function processJsonFile(file) {
|
|
|
456
481
|
const status2 = findStatus(w);
|
|
457
482
|
const ts2 = findTimestamp(w) || findTimestamp(obj) || file.mtime;
|
|
458
483
|
const pid = w.pid;
|
|
459
|
-
|
|
484
|
+
let validatedStatus = status2;
|
|
485
|
+
let pidAlive = true;
|
|
486
|
+
if (pid && (status2 === "running" || status2 === "ok")) {
|
|
487
|
+
try {
|
|
488
|
+
execSync(`kill -0 ${pid} 2>/dev/null`, { stdio: "ignore" });
|
|
489
|
+
} catch {
|
|
490
|
+
pidAlive = false;
|
|
491
|
+
validatedStatus = "error";
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const pidLabel = pid ? pidAlive ? `pid: ${pid}` : `pid: ${pid} (dead)` : "";
|
|
495
|
+
const detail2 = pidLabel || extractDetail(w);
|
|
460
496
|
records.push({
|
|
461
497
|
id: name,
|
|
462
498
|
source: "workers",
|
|
463
|
-
status:
|
|
499
|
+
status: validatedStatus,
|
|
464
500
|
lastActive: ts2,
|
|
465
501
|
detail: detail2,
|
|
466
502
|
file: file.filename
|
|
@@ -636,23 +672,57 @@ var prevFileCount = 0;
|
|
|
636
672
|
var newExecCount = 0;
|
|
637
673
|
var sessionStart = Date.now();
|
|
638
674
|
var firstRender = true;
|
|
675
|
+
var fileCache = /* @__PURE__ */ new Map();
|
|
676
|
+
function getRecordsCached(f) {
|
|
677
|
+
const cached = fileCache.get(f.path);
|
|
678
|
+
if (cached && cached.mtime === f.mtime) return cached;
|
|
679
|
+
const records = f.ext === ".jsonl" ? processJsonlFile(f) : processJsonFile(f);
|
|
680
|
+
const traces = records.filter((r) => r.traceData).map((r) => r.traceData);
|
|
681
|
+
const entry = { mtime: f.mtime, records, traces };
|
|
682
|
+
fileCache.set(f.path, entry);
|
|
683
|
+
return entry;
|
|
684
|
+
}
|
|
639
685
|
function render(config) {
|
|
640
686
|
const files = scanFiles(config.dirs, config.recursive);
|
|
641
687
|
if (files.length > prevFileCount && prevFileCount > 0) {
|
|
642
688
|
newExecCount += files.length - prevFileCount;
|
|
643
689
|
}
|
|
644
690
|
prevFileCount = files.length;
|
|
691
|
+
const currentPaths = new Set(files.map((f) => f.path));
|
|
692
|
+
for (const key of fileCache.keys()) {
|
|
693
|
+
if (!currentPaths.has(key)) fileCache.delete(key);
|
|
694
|
+
}
|
|
645
695
|
const allRecords = [];
|
|
646
696
|
const allTraces = [];
|
|
647
697
|
for (const f of files.slice(0, 300)) {
|
|
648
|
-
const records
|
|
649
|
-
for (const r of records)
|
|
650
|
-
|
|
651
|
-
|
|
698
|
+
const { records, traces } = getRecordsCached(f);
|
|
699
|
+
for (const r of records) allRecords.push(r);
|
|
700
|
+
for (const t of traces) allTraces.push(t);
|
|
701
|
+
}
|
|
702
|
+
const deduped = [];
|
|
703
|
+
const seenAgents = /* @__PURE__ */ new Map();
|
|
704
|
+
for (const r of allRecords) {
|
|
705
|
+
if (r.source === "jobs" || r.source === "workers" || r.source === "state") {
|
|
706
|
+
deduped.push(r);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
const key = `${r.source}:${r.id}`;
|
|
710
|
+
const existing = seenAgents.get(key);
|
|
711
|
+
if (!existing || r.lastActive > existing.lastActive) {
|
|
712
|
+
seenAgents.set(key, r);
|
|
652
713
|
}
|
|
653
714
|
}
|
|
715
|
+
for (const r of seenAgents.values()) deduped.push(r);
|
|
716
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
|
|
717
|
+
const now = Date.now();
|
|
718
|
+
const filtered = deduped.filter((r) => {
|
|
719
|
+
if (r.source === "jobs" || r.source === "workers") return true;
|
|
720
|
+
if (r.status === "running") return true;
|
|
721
|
+
return now - r.lastActive < STALE_THRESHOLD_MS;
|
|
722
|
+
});
|
|
723
|
+
const activeRecords = filtered;
|
|
654
724
|
const byFile = /* @__PURE__ */ new Map();
|
|
655
|
-
for (const r of
|
|
725
|
+
for (const r of activeRecords) {
|
|
656
726
|
const arr = byFile.get(r.file) ?? [];
|
|
657
727
|
arr.push(r);
|
|
658
728
|
byFile.set(r.file, arr);
|
|
@@ -699,15 +769,14 @@ function render(config) {
|
|
|
699
769
|
}
|
|
700
770
|
}
|
|
701
771
|
groups.sort((a, b) => b.lastTs - a.lastTs);
|
|
702
|
-
const totExec =
|
|
703
|
-
const totFail =
|
|
704
|
-
const totRunning =
|
|
705
|
-
const uniqueAgents = new Set(
|
|
772
|
+
const totExec = activeRecords.length;
|
|
773
|
+
const totFail = activeRecords.filter((r) => r.status === "error").length;
|
|
774
|
+
const totRunning = activeRecords.filter((r) => r.status === "running").length;
|
|
775
|
+
const uniqueAgents = new Set(activeRecords.map((r) => r.id)).size;
|
|
706
776
|
const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
|
|
707
|
-
const now = Date.now();
|
|
708
777
|
const buckets = new Array(12).fill(0);
|
|
709
778
|
const failBuckets = new Array(12).fill(0);
|
|
710
|
-
for (const r of
|
|
779
|
+
for (const r of activeRecords) {
|
|
711
780
|
const age = now - r.lastActive;
|
|
712
781
|
if (age > 36e5 || age < 0) continue;
|
|
713
782
|
const idx = 11 - Math.floor(age / 3e5);
|
|
@@ -881,7 +950,7 @@ function render(config) {
|
|
|
881
950
|
}
|
|
882
951
|
}
|
|
883
952
|
}
|
|
884
|
-
const recentRecords =
|
|
953
|
+
const recentRecords = activeRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
|
|
885
954
|
if (recentRecords.length > 0) {
|
|
886
955
|
writeLine(L, "");
|
|
887
956
|
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) {
|
|
@@ -311,11 +312,29 @@ Examples:
|
|
|
311
312
|
`.trim()
|
|
312
313
|
);
|
|
313
314
|
}
|
|
315
|
+
var dirMtimeCache = /* @__PURE__ */ new Map();
|
|
316
|
+
var dirFileCache = /* @__PURE__ */ new Map();
|
|
314
317
|
function scanFiles(dirs, recursive) {
|
|
315
318
|
const results = [];
|
|
316
319
|
const seen = /* @__PURE__ */ new Set();
|
|
317
320
|
function scanDir(d, topLevel) {
|
|
318
321
|
try {
|
|
322
|
+
const dirStat = (0, import_node_fs.statSync)(d);
|
|
323
|
+
const dirMtime = dirStat.mtime.getTime();
|
|
324
|
+
const cachedMtime = dirMtimeCache.get(d);
|
|
325
|
+
if (cachedMtime === dirMtime) {
|
|
326
|
+
const cached = dirFileCache.get(d);
|
|
327
|
+
if (cached) {
|
|
328
|
+
for (const f of cached) {
|
|
329
|
+
if (!seen.has(f.path)) {
|
|
330
|
+
seen.add(f.path);
|
|
331
|
+
results.push(f);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const dirResults = [];
|
|
319
338
|
for (const f of (0, import_node_fs.readdirSync)(d)) {
|
|
320
339
|
if (f.startsWith(".")) continue;
|
|
321
340
|
const fp = (0, import_node_path.join)(d, f);
|
|
@@ -333,12 +352,18 @@ function scanFiles(dirs, recursive) {
|
|
|
333
352
|
if (!stat.isFile()) continue;
|
|
334
353
|
if (f.endsWith(".json")) {
|
|
335
354
|
seen.add(fp);
|
|
336
|
-
|
|
355
|
+
const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".json" };
|
|
356
|
+
results.push(entry);
|
|
357
|
+
dirResults.push(entry);
|
|
337
358
|
} else if (f.endsWith(".jsonl")) {
|
|
338
359
|
seen.add(fp);
|
|
339
|
-
|
|
360
|
+
const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".jsonl" };
|
|
361
|
+
results.push(entry);
|
|
362
|
+
dirResults.push(entry);
|
|
340
363
|
}
|
|
341
364
|
}
|
|
365
|
+
dirMtimeCache.set(d, dirMtime);
|
|
366
|
+
dirFileCache.set(d, dirResults);
|
|
342
367
|
} catch {
|
|
343
368
|
}
|
|
344
369
|
}
|
|
@@ -491,11 +516,22 @@ function processJsonFile(file) {
|
|
|
491
516
|
const status2 = findStatus(w);
|
|
492
517
|
const ts2 = findTimestamp(w) || findTimestamp(obj) || file.mtime;
|
|
493
518
|
const pid = w.pid;
|
|
494
|
-
|
|
519
|
+
let validatedStatus = status2;
|
|
520
|
+
let pidAlive = true;
|
|
521
|
+
if (pid && (status2 === "running" || status2 === "ok")) {
|
|
522
|
+
try {
|
|
523
|
+
(0, import_node_child_process.execSync)(`kill -0 ${pid} 2>/dev/null`, { stdio: "ignore" });
|
|
524
|
+
} catch {
|
|
525
|
+
pidAlive = false;
|
|
526
|
+
validatedStatus = "error";
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
const pidLabel = pid ? pidAlive ? `pid: ${pid}` : `pid: ${pid} (dead)` : "";
|
|
530
|
+
const detail2 = pidLabel || extractDetail(w);
|
|
495
531
|
records.push({
|
|
496
532
|
id: name,
|
|
497
533
|
source: "workers",
|
|
498
|
-
status:
|
|
534
|
+
status: validatedStatus,
|
|
499
535
|
lastActive: ts2,
|
|
500
536
|
detail: detail2,
|
|
501
537
|
file: file.filename
|
|
@@ -671,23 +707,57 @@ var prevFileCount = 0;
|
|
|
671
707
|
var newExecCount = 0;
|
|
672
708
|
var sessionStart = Date.now();
|
|
673
709
|
var firstRender = true;
|
|
710
|
+
var fileCache = /* @__PURE__ */ new Map();
|
|
711
|
+
function getRecordsCached(f) {
|
|
712
|
+
const cached = fileCache.get(f.path);
|
|
713
|
+
if (cached && cached.mtime === f.mtime) return cached;
|
|
714
|
+
const records = f.ext === ".jsonl" ? processJsonlFile(f) : processJsonFile(f);
|
|
715
|
+
const traces = records.filter((r) => r.traceData).map((r) => r.traceData);
|
|
716
|
+
const entry = { mtime: f.mtime, records, traces };
|
|
717
|
+
fileCache.set(f.path, entry);
|
|
718
|
+
return entry;
|
|
719
|
+
}
|
|
674
720
|
function render(config) {
|
|
675
721
|
const files = scanFiles(config.dirs, config.recursive);
|
|
676
722
|
if (files.length > prevFileCount && prevFileCount > 0) {
|
|
677
723
|
newExecCount += files.length - prevFileCount;
|
|
678
724
|
}
|
|
679
725
|
prevFileCount = files.length;
|
|
726
|
+
const currentPaths = new Set(files.map((f) => f.path));
|
|
727
|
+
for (const key of fileCache.keys()) {
|
|
728
|
+
if (!currentPaths.has(key)) fileCache.delete(key);
|
|
729
|
+
}
|
|
680
730
|
const allRecords = [];
|
|
681
731
|
const allTraces = [];
|
|
682
732
|
for (const f of files.slice(0, 300)) {
|
|
683
|
-
const records
|
|
684
|
-
for (const r of records)
|
|
685
|
-
|
|
686
|
-
|
|
733
|
+
const { records, traces } = getRecordsCached(f);
|
|
734
|
+
for (const r of records) allRecords.push(r);
|
|
735
|
+
for (const t of traces) allTraces.push(t);
|
|
736
|
+
}
|
|
737
|
+
const deduped = [];
|
|
738
|
+
const seenAgents = /* @__PURE__ */ new Map();
|
|
739
|
+
for (const r of allRecords) {
|
|
740
|
+
if (r.source === "jobs" || r.source === "workers" || r.source === "state") {
|
|
741
|
+
deduped.push(r);
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
const key = `${r.source}:${r.id}`;
|
|
745
|
+
const existing = seenAgents.get(key);
|
|
746
|
+
if (!existing || r.lastActive > existing.lastActive) {
|
|
747
|
+
seenAgents.set(key, r);
|
|
687
748
|
}
|
|
688
749
|
}
|
|
750
|
+
for (const r of seenAgents.values()) deduped.push(r);
|
|
751
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
|
|
752
|
+
const now = Date.now();
|
|
753
|
+
const filtered = deduped.filter((r) => {
|
|
754
|
+
if (r.source === "jobs" || r.source === "workers") return true;
|
|
755
|
+
if (r.status === "running") return true;
|
|
756
|
+
return now - r.lastActive < STALE_THRESHOLD_MS;
|
|
757
|
+
});
|
|
758
|
+
const activeRecords = filtered;
|
|
689
759
|
const byFile = /* @__PURE__ */ new Map();
|
|
690
|
-
for (const r of
|
|
760
|
+
for (const r of activeRecords) {
|
|
691
761
|
const arr = byFile.get(r.file) ?? [];
|
|
692
762
|
arr.push(r);
|
|
693
763
|
byFile.set(r.file, arr);
|
|
@@ -734,15 +804,14 @@ function render(config) {
|
|
|
734
804
|
}
|
|
735
805
|
}
|
|
736
806
|
groups.sort((a, b) => b.lastTs - a.lastTs);
|
|
737
|
-
const totExec =
|
|
738
|
-
const totFail =
|
|
739
|
-
const totRunning =
|
|
740
|
-
const uniqueAgents = new Set(
|
|
807
|
+
const totExec = activeRecords.length;
|
|
808
|
+
const totFail = activeRecords.filter((r) => r.status === "error").length;
|
|
809
|
+
const totRunning = activeRecords.filter((r) => r.status === "running").length;
|
|
810
|
+
const uniqueAgents = new Set(activeRecords.map((r) => r.id)).size;
|
|
741
811
|
const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
|
|
742
|
-
const now = Date.now();
|
|
743
812
|
const buckets = new Array(12).fill(0);
|
|
744
813
|
const failBuckets = new Array(12).fill(0);
|
|
745
|
-
for (const r of
|
|
814
|
+
for (const r of activeRecords) {
|
|
746
815
|
const age = now - r.lastActive;
|
|
747
816
|
if (age > 36e5 || age < 0) continue;
|
|
748
817
|
const idx = 11 - Math.floor(age / 3e5);
|
|
@@ -916,7 +985,7 @@ function render(config) {
|
|
|
916
985
|
}
|
|
917
986
|
}
|
|
918
987
|
}
|
|
919
|
-
const recentRecords =
|
|
988
|
+
const recentRecords = activeRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
|
|
920
989
|
if (recentRecords.length > 0) {
|
|
921
990
|
writeLine(L, "");
|
|
922
991
|
writeLine(L, ` ${C.bold}${C.under}Recent Activity${C.reset}`);
|
|
@@ -982,7 +1051,7 @@ function startLive(argv) {
|
|
|
982
1051
|
}
|
|
983
1052
|
|
|
984
1053
|
// src/runner.ts
|
|
985
|
-
var
|
|
1054
|
+
var import_node_child_process2 = require("child_process");
|
|
986
1055
|
var import_node_fs2 = require("fs");
|
|
987
1056
|
var import_node_path2 = require("path");
|
|
988
1057
|
|
|
@@ -1286,7 +1355,7 @@ async function runTraced(config) {
|
|
|
1286
1355
|
const execArgs = command.slice(1);
|
|
1287
1356
|
process.env.AGENTFLOW_TRACE_ID = traceId;
|
|
1288
1357
|
process.env.AGENTFLOW_PARENT_SPAN_ID = spanId;
|
|
1289
|
-
const result = (0,
|
|
1358
|
+
const result = (0, import_node_child_process2.spawnSync)(execCmd, execArgs, { stdio: "inherit" });
|
|
1290
1359
|
delete process.env.AGENTFLOW_TRACE_ID;
|
|
1291
1360
|
delete process.env.AGENTFLOW_PARENT_SPAN_ID;
|
|
1292
1361
|
const exitCode = result.status ?? 1;
|
|
@@ -1792,7 +1861,7 @@ var import_node_os = require("os");
|
|
|
1792
1861
|
var import_node_path3 = require("path");
|
|
1793
1862
|
|
|
1794
1863
|
// src/watch-alerts.ts
|
|
1795
|
-
var
|
|
1864
|
+
var import_node_child_process3 = require("child_process");
|
|
1796
1865
|
var import_node_http = require("http");
|
|
1797
1866
|
var import_node_https = require("https");
|
|
1798
1867
|
function formatAlertMessage(payload) {
|
|
@@ -1902,7 +1971,7 @@ function sendCommand(payload, cmd) {
|
|
|
1902
1971
|
AGENTFLOW_ALERT_FILE: payload.file,
|
|
1903
1972
|
AGENTFLOW_ALERT_TIMESTAMP: String(payload.timestamp)
|
|
1904
1973
|
};
|
|
1905
|
-
(0,
|
|
1974
|
+
(0, import_node_child_process3.exec)(cmd, { env, timeout: 3e4 }, (err) => {
|
|
1906
1975
|
if (err) reject(err);
|
|
1907
1976
|
else resolve6();
|
|
1908
1977
|
});
|
package/dist/cli.js
CHANGED
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) {
|
|
@@ -759,11 +760,29 @@ Examples:
|
|
|
759
760
|
`.trim()
|
|
760
761
|
);
|
|
761
762
|
}
|
|
763
|
+
var dirMtimeCache = /* @__PURE__ */ new Map();
|
|
764
|
+
var dirFileCache = /* @__PURE__ */ new Map();
|
|
762
765
|
function scanFiles(dirs, recursive) {
|
|
763
766
|
const results = [];
|
|
764
767
|
const seen = /* @__PURE__ */ new Set();
|
|
765
768
|
function scanDir(d, topLevel) {
|
|
766
769
|
try {
|
|
770
|
+
const dirStat = (0, import_node_fs.statSync)(d);
|
|
771
|
+
const dirMtime = dirStat.mtime.getTime();
|
|
772
|
+
const cachedMtime = dirMtimeCache.get(d);
|
|
773
|
+
if (cachedMtime === dirMtime) {
|
|
774
|
+
const cached = dirFileCache.get(d);
|
|
775
|
+
if (cached) {
|
|
776
|
+
for (const f of cached) {
|
|
777
|
+
if (!seen.has(f.path)) {
|
|
778
|
+
seen.add(f.path);
|
|
779
|
+
results.push(f);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
const dirResults = [];
|
|
767
786
|
for (const f of (0, import_node_fs.readdirSync)(d)) {
|
|
768
787
|
if (f.startsWith(".")) continue;
|
|
769
788
|
const fp = (0, import_node_path.join)(d, f);
|
|
@@ -781,12 +800,18 @@ function scanFiles(dirs, recursive) {
|
|
|
781
800
|
if (!stat.isFile()) continue;
|
|
782
801
|
if (f.endsWith(".json")) {
|
|
783
802
|
seen.add(fp);
|
|
784
|
-
|
|
803
|
+
const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".json" };
|
|
804
|
+
results.push(entry);
|
|
805
|
+
dirResults.push(entry);
|
|
785
806
|
} else if (f.endsWith(".jsonl")) {
|
|
786
807
|
seen.add(fp);
|
|
787
|
-
|
|
808
|
+
const entry = { filename: f, path: fp, mtime: stat.mtime.getTime(), ext: ".jsonl" };
|
|
809
|
+
results.push(entry);
|
|
810
|
+
dirResults.push(entry);
|
|
788
811
|
}
|
|
789
812
|
}
|
|
813
|
+
dirMtimeCache.set(d, dirMtime);
|
|
814
|
+
dirFileCache.set(d, dirResults);
|
|
790
815
|
} catch {
|
|
791
816
|
}
|
|
792
817
|
}
|
|
@@ -939,11 +964,22 @@ function processJsonFile(file) {
|
|
|
939
964
|
const status2 = findStatus(w);
|
|
940
965
|
const ts2 = findTimestamp(w) || findTimestamp(obj) || file.mtime;
|
|
941
966
|
const pid = w.pid;
|
|
942
|
-
|
|
967
|
+
let validatedStatus = status2;
|
|
968
|
+
let pidAlive = true;
|
|
969
|
+
if (pid && (status2 === "running" || status2 === "ok")) {
|
|
970
|
+
try {
|
|
971
|
+
(0, import_node_child_process.execSync)(`kill -0 ${pid} 2>/dev/null`, { stdio: "ignore" });
|
|
972
|
+
} catch {
|
|
973
|
+
pidAlive = false;
|
|
974
|
+
validatedStatus = "error";
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
const pidLabel = pid ? pidAlive ? `pid: ${pid}` : `pid: ${pid} (dead)` : "";
|
|
978
|
+
const detail2 = pidLabel || extractDetail(w);
|
|
943
979
|
records.push({
|
|
944
980
|
id: name,
|
|
945
981
|
source: "workers",
|
|
946
|
-
status:
|
|
982
|
+
status: validatedStatus,
|
|
947
983
|
lastActive: ts2,
|
|
948
984
|
detail: detail2,
|
|
949
985
|
file: file.filename
|
|
@@ -1119,23 +1155,57 @@ var prevFileCount = 0;
|
|
|
1119
1155
|
var newExecCount = 0;
|
|
1120
1156
|
var sessionStart = Date.now();
|
|
1121
1157
|
var firstRender = true;
|
|
1158
|
+
var fileCache = /* @__PURE__ */ new Map();
|
|
1159
|
+
function getRecordsCached(f) {
|
|
1160
|
+
const cached = fileCache.get(f.path);
|
|
1161
|
+
if (cached && cached.mtime === f.mtime) return cached;
|
|
1162
|
+
const records = f.ext === ".jsonl" ? processJsonlFile(f) : processJsonFile(f);
|
|
1163
|
+
const traces = records.filter((r) => r.traceData).map((r) => r.traceData);
|
|
1164
|
+
const entry = { mtime: f.mtime, records, traces };
|
|
1165
|
+
fileCache.set(f.path, entry);
|
|
1166
|
+
return entry;
|
|
1167
|
+
}
|
|
1122
1168
|
function render(config) {
|
|
1123
1169
|
const files = scanFiles(config.dirs, config.recursive);
|
|
1124
1170
|
if (files.length > prevFileCount && prevFileCount > 0) {
|
|
1125
1171
|
newExecCount += files.length - prevFileCount;
|
|
1126
1172
|
}
|
|
1127
1173
|
prevFileCount = files.length;
|
|
1174
|
+
const currentPaths = new Set(files.map((f) => f.path));
|
|
1175
|
+
for (const key of fileCache.keys()) {
|
|
1176
|
+
if (!currentPaths.has(key)) fileCache.delete(key);
|
|
1177
|
+
}
|
|
1128
1178
|
const allRecords = [];
|
|
1129
1179
|
const allTraces = [];
|
|
1130
1180
|
for (const f of files.slice(0, 300)) {
|
|
1131
|
-
const records
|
|
1132
|
-
for (const r of records)
|
|
1133
|
-
|
|
1134
|
-
|
|
1181
|
+
const { records, traces } = getRecordsCached(f);
|
|
1182
|
+
for (const r of records) allRecords.push(r);
|
|
1183
|
+
for (const t of traces) allTraces.push(t);
|
|
1184
|
+
}
|
|
1185
|
+
const deduped = [];
|
|
1186
|
+
const seenAgents = /* @__PURE__ */ new Map();
|
|
1187
|
+
for (const r of allRecords) {
|
|
1188
|
+
if (r.source === "jobs" || r.source === "workers" || r.source === "state") {
|
|
1189
|
+
deduped.push(r);
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1192
|
+
const key = `${r.source}:${r.id}`;
|
|
1193
|
+
const existing = seenAgents.get(key);
|
|
1194
|
+
if (!existing || r.lastActive > existing.lastActive) {
|
|
1195
|
+
seenAgents.set(key, r);
|
|
1135
1196
|
}
|
|
1136
1197
|
}
|
|
1198
|
+
for (const r of seenAgents.values()) deduped.push(r);
|
|
1199
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
|
|
1200
|
+
const now = Date.now();
|
|
1201
|
+
const filtered = deduped.filter((r) => {
|
|
1202
|
+
if (r.source === "jobs" || r.source === "workers") return true;
|
|
1203
|
+
if (r.status === "running") return true;
|
|
1204
|
+
return now - r.lastActive < STALE_THRESHOLD_MS;
|
|
1205
|
+
});
|
|
1206
|
+
const activeRecords = filtered;
|
|
1137
1207
|
const byFile = /* @__PURE__ */ new Map();
|
|
1138
|
-
for (const r of
|
|
1208
|
+
for (const r of activeRecords) {
|
|
1139
1209
|
const arr = byFile.get(r.file) ?? [];
|
|
1140
1210
|
arr.push(r);
|
|
1141
1211
|
byFile.set(r.file, arr);
|
|
@@ -1182,15 +1252,14 @@ function render(config) {
|
|
|
1182
1252
|
}
|
|
1183
1253
|
}
|
|
1184
1254
|
groups.sort((a, b) => b.lastTs - a.lastTs);
|
|
1185
|
-
const totExec =
|
|
1186
|
-
const totFail =
|
|
1187
|
-
const totRunning =
|
|
1188
|
-
const uniqueAgents = new Set(
|
|
1255
|
+
const totExec = activeRecords.length;
|
|
1256
|
+
const totFail = activeRecords.filter((r) => r.status === "error").length;
|
|
1257
|
+
const totRunning = activeRecords.filter((r) => r.status === "running").length;
|
|
1258
|
+
const uniqueAgents = new Set(activeRecords.map((r) => r.id)).size;
|
|
1189
1259
|
const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
|
|
1190
|
-
const now = Date.now();
|
|
1191
1260
|
const buckets = new Array(12).fill(0);
|
|
1192
1261
|
const failBuckets = new Array(12).fill(0);
|
|
1193
|
-
for (const r of
|
|
1262
|
+
for (const r of activeRecords) {
|
|
1194
1263
|
const age = now - r.lastActive;
|
|
1195
1264
|
if (age > 36e5 || age < 0) continue;
|
|
1196
1265
|
const idx = 11 - Math.floor(age / 3e5);
|
|
@@ -1364,7 +1433,7 @@ function render(config) {
|
|
|
1364
1433
|
}
|
|
1365
1434
|
}
|
|
1366
1435
|
}
|
|
1367
|
-
const recentRecords =
|
|
1436
|
+
const recentRecords = activeRecords.filter((r) => r.lastActive > 0).sort((a, b) => b.lastActive - a.lastActive).slice(0, 6);
|
|
1368
1437
|
if (recentRecords.length > 0) {
|
|
1369
1438
|
writeLine(L, "");
|
|
1370
1439
|
writeLine(L, ` ${C.bold}${C.under}Recent Activity${C.reset}`);
|
|
@@ -1430,7 +1499,7 @@ function startLive(argv) {
|
|
|
1430
1499
|
}
|
|
1431
1500
|
|
|
1432
1501
|
// src/runner.ts
|
|
1433
|
-
var
|
|
1502
|
+
var import_node_child_process2 = require("child_process");
|
|
1434
1503
|
var import_node_fs2 = require("fs");
|
|
1435
1504
|
var import_node_path2 = require("path");
|
|
1436
1505
|
function globToRegex(pattern) {
|
|
@@ -1505,7 +1574,7 @@ async function runTraced(config) {
|
|
|
1505
1574
|
const execArgs = command.slice(1);
|
|
1506
1575
|
process.env.AGENTFLOW_TRACE_ID = traceId;
|
|
1507
1576
|
process.env.AGENTFLOW_PARENT_SPAN_ID = spanId;
|
|
1508
|
-
const result = (0,
|
|
1577
|
+
const result = (0, import_node_child_process2.spawnSync)(execCmd, execArgs, { stdio: "inherit" });
|
|
1509
1578
|
delete process.env.AGENTFLOW_TRACE_ID;
|
|
1510
1579
|
delete process.env.AGENTFLOW_PARENT_SPAN_ID;
|
|
1511
1580
|
const exitCode = result.status ?? 1;
|
|
@@ -1818,7 +1887,7 @@ var import_node_os = require("os");
|
|
|
1818
1887
|
var import_node_path3 = require("path");
|
|
1819
1888
|
|
|
1820
1889
|
// src/watch-alerts.ts
|
|
1821
|
-
var
|
|
1890
|
+
var import_node_child_process3 = require("child_process");
|
|
1822
1891
|
var import_node_http = require("http");
|
|
1823
1892
|
var import_node_https = require("https");
|
|
1824
1893
|
function formatAlertMessage(payload) {
|
|
@@ -1928,7 +1997,7 @@ function sendCommand(payload, cmd) {
|
|
|
1928
1997
|
AGENTFLOW_ALERT_FILE: payload.file,
|
|
1929
1998
|
AGENTFLOW_ALERT_TIMESTAMP: String(payload.timestamp)
|
|
1930
1999
|
};
|
|
1931
|
-
(0,
|
|
2000
|
+
(0, import_node_child_process3.exec)(cmd, { env, timeout: 3e4 }, (err) => {
|
|
1932
2001
|
if (err) reject(err);
|
|
1933
2002
|
else resolve4();
|
|
1934
2003
|
});
|
package/dist/index.js
CHANGED
package/package.json
CHANGED