agentflow-core 0.1.3 → 0.2.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
@@ -235,6 +235,58 @@ function createGraphBuilder(config) {
235
235
  return builder;
236
236
  }
237
237
 
238
+ // src/loader.ts
239
+ function toNodesMap(raw) {
240
+ if (raw instanceof Map) return raw;
241
+ if (Array.isArray(raw)) {
242
+ return new Map(raw);
243
+ }
244
+ if (raw !== null && typeof raw === "object") {
245
+ return new Map(Object.entries(raw));
246
+ }
247
+ return /* @__PURE__ */ new Map();
248
+ }
249
+ function loadGraph(input) {
250
+ const raw = typeof input === "string" ? JSON.parse(input) : input;
251
+ const nodes = toNodesMap(raw.nodes);
252
+ return {
253
+ id: raw.id ?? "",
254
+ rootNodeId: raw.rootNodeId ?? raw.rootId ?? "",
255
+ nodes,
256
+ edges: raw.edges ?? [],
257
+ startTime: raw.startTime ?? 0,
258
+ endTime: raw.endTime ?? null,
259
+ status: raw.status ?? "completed",
260
+ trigger: raw.trigger ?? "unknown",
261
+ agentId: raw.agentId ?? "unknown",
262
+ events: raw.events ?? [],
263
+ traceId: raw.traceId,
264
+ spanId: raw.spanId,
265
+ parentSpanId: raw.parentSpanId
266
+ };
267
+ }
268
+ function graphToJson(graph) {
269
+ const nodesObj = {};
270
+ for (const [id, node] of graph.nodes) {
271
+ nodesObj[id] = node;
272
+ }
273
+ return {
274
+ id: graph.id,
275
+ rootNodeId: graph.rootNodeId,
276
+ nodes: nodesObj,
277
+ edges: graph.edges,
278
+ startTime: graph.startTime,
279
+ endTime: graph.endTime,
280
+ status: graph.status,
281
+ trigger: graph.trigger,
282
+ agentId: graph.agentId,
283
+ events: graph.events,
284
+ traceId: graph.traceId,
285
+ spanId: graph.spanId,
286
+ parentSpanId: graph.parentSpanId
287
+ };
288
+ }
289
+
238
290
  // src/runner.ts
239
291
  function globToRegex(pattern) {
240
292
  const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
@@ -267,27 +319,6 @@ function deriveAgentId(command) {
267
319
  function fileTimestamp() {
268
320
  return (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").replace(/\.\d+Z$/, "");
269
321
  }
270
- function graphToJson(graph) {
271
- const nodesObj = {};
272
- for (const [id, node] of graph.nodes) {
273
- nodesObj[id] = node;
274
- }
275
- return {
276
- id: graph.id,
277
- rootNodeId: graph.rootNodeId,
278
- nodes: nodesObj,
279
- edges: graph.edges,
280
- startTime: graph.startTime,
281
- endTime: graph.endTime,
282
- status: graph.status,
283
- trigger: graph.trigger,
284
- agentId: graph.agentId,
285
- events: graph.events,
286
- traceId: graph.traceId,
287
- spanId: graph.spanId,
288
- parentSpanId: graph.parentSpanId
289
- };
290
- }
291
322
  async function runTraced(config) {
292
323
  const {
293
324
  command,
@@ -404,8 +435,442 @@ async function runTraced(config) {
404
435
  };
405
436
  }
406
437
 
407
- // src/cli.ts
438
+ // src/live.ts
439
+ var import_node_fs2 = require("fs");
440
+ var import_node_path2 = require("path");
441
+
442
+ // src/graph-query.ts
443
+ function getFailures(graph) {
444
+ const failureStatuses = /* @__PURE__ */ new Set(["failed", "hung", "timeout"]);
445
+ return [...graph.nodes.values()].filter((node) => failureStatuses.has(node.status));
446
+ }
447
+ function getHungNodes(graph) {
448
+ return [...graph.nodes.values()].filter(
449
+ (node) => node.status === "running" && node.endTime === null
450
+ );
451
+ }
452
+ function getDuration(graph) {
453
+ const end = graph.endTime ?? Date.now();
454
+ return end - graph.startTime;
455
+ }
456
+ function getDepth(graph) {
457
+ const root = graph.nodes.get(graph.rootNodeId);
458
+ if (!root) return -1;
459
+ function dfs(node, depth) {
460
+ if (node.children.length === 0) return depth;
461
+ let maxDepth = depth;
462
+ for (const childId of node.children) {
463
+ const child = graph.nodes.get(childId);
464
+ if (!child) continue;
465
+ const childDepth = dfs(child, depth + 1);
466
+ if (childDepth > maxDepth) maxDepth = childDepth;
467
+ }
468
+ return maxDepth;
469
+ }
470
+ return dfs(root, 0);
471
+ }
472
+ function getStats(graph) {
473
+ const byStatus = {
474
+ running: 0,
475
+ completed: 0,
476
+ failed: 0,
477
+ hung: 0,
478
+ timeout: 0
479
+ };
480
+ const byType = {
481
+ agent: 0,
482
+ tool: 0,
483
+ subagent: 0,
484
+ wait: 0,
485
+ decision: 0,
486
+ custom: 0
487
+ };
488
+ let failureCount = 0;
489
+ let hungCount = 0;
490
+ for (const node of graph.nodes.values()) {
491
+ byStatus[node.status]++;
492
+ byType[node.type]++;
493
+ if (node.status === "failed" || node.status === "timeout" || node.status === "hung") {
494
+ failureCount++;
495
+ }
496
+ if (node.status === "running" && node.endTime === null) {
497
+ hungCount++;
498
+ }
499
+ }
500
+ return {
501
+ totalNodes: graph.nodes.size,
502
+ byStatus,
503
+ byType,
504
+ depth: getDepth(graph),
505
+ duration: getDuration(graph),
506
+ failureCount,
507
+ hungCount
508
+ };
509
+ }
510
+
511
+ // src/graph-stitch.ts
512
+ function groupByTraceId(graphs) {
513
+ const groups = /* @__PURE__ */ new Map();
514
+ for (const g of graphs) {
515
+ if (!g.traceId) continue;
516
+ const arr = groups.get(g.traceId) ?? [];
517
+ arr.push(g);
518
+ groups.set(g.traceId, arr);
519
+ }
520
+ return groups;
521
+ }
522
+ function stitchTrace(graphs) {
523
+ if (graphs.length === 0) throw new Error("No graphs to stitch");
524
+ const traceId = graphs[0].traceId ?? "";
525
+ const graphsBySpan = /* @__PURE__ */ new Map();
526
+ const childMap = /* @__PURE__ */ new Map();
527
+ let rootGraph = null;
528
+ for (const g of graphs) {
529
+ if (g.spanId) graphsBySpan.set(g.spanId, g);
530
+ if (!g.parentSpanId) {
531
+ if (!rootGraph || g.startTime < rootGraph.startTime) rootGraph = g;
532
+ }
533
+ if (g.parentSpanId) {
534
+ const siblings = childMap.get(g.parentSpanId) ?? [];
535
+ if (g.spanId) siblings.push(g.spanId);
536
+ childMap.set(g.parentSpanId, siblings);
537
+ }
538
+ }
539
+ if (!rootGraph) rootGraph = graphs[0];
540
+ let status = "completed";
541
+ let endTime = 0;
542
+ let startTime = Infinity;
543
+ for (const g of graphs) {
544
+ startTime = Math.min(startTime, g.startTime);
545
+ if (g.status === "failed") status = "failed";
546
+ else if (g.status === "running" && status !== "failed") status = "running";
547
+ if (g.endTime === null) endTime = null;
548
+ else if (endTime !== null) endTime = Math.max(endTime, g.endTime);
549
+ }
550
+ const frozenChildMap = /* @__PURE__ */ new Map();
551
+ for (const [k, v] of childMap) frozenChildMap.set(k, Object.freeze([...v]));
552
+ return Object.freeze({
553
+ traceId,
554
+ graphs: graphsBySpan,
555
+ rootGraph,
556
+ childMap: frozenChildMap,
557
+ startTime,
558
+ endTime,
559
+ status
560
+ });
561
+ }
562
+ function getTraceTree(trace) {
563
+ const result = [];
564
+ function walk(spanId) {
565
+ const graph = trace.graphs.get(spanId);
566
+ if (graph) result.push(graph);
567
+ const children = trace.childMap.get(spanId) ?? [];
568
+ for (const childSpan of children) walk(childSpan);
569
+ }
570
+ if (trace.rootGraph.spanId) walk(trace.rootGraph.spanId);
571
+ else result.push(trace.rootGraph);
572
+ return result;
573
+ }
574
+
575
+ // src/live.ts
576
+ var C = {
577
+ reset: "\x1B[0m",
578
+ bold: "\x1B[1m",
579
+ dim: "\x1B[90m",
580
+ under: "\x1B[4m",
581
+ red: "\x1B[31m",
582
+ green: "\x1B[32m",
583
+ yellow: "\x1B[33m",
584
+ blue: "\x1B[34m",
585
+ magenta: "\x1B[35m",
586
+ cyan: "\x1B[36m",
587
+ white: "\x1B[37m"
588
+ };
408
589
  function parseArgs(argv) {
590
+ const config = {
591
+ tracesDir: "./traces",
592
+ refreshMs: 3e3
593
+ };
594
+ const args = argv.slice(0);
595
+ if (args[0] === "live") args.shift();
596
+ let i = 0;
597
+ while (i < args.length) {
598
+ const arg = args[i];
599
+ if (arg === "--help" || arg === "-h") {
600
+ printUsage();
601
+ process.exit(0);
602
+ } else if (arg === "--refresh" || arg === "-r") {
603
+ i++;
604
+ const val = parseInt(args[i] ?? "", 10);
605
+ if (!isNaN(val) && val > 0) config.refreshMs = val * 1e3;
606
+ i++;
607
+ } else if (arg === "--traces-dir" || arg === "-t") {
608
+ i++;
609
+ config.tracesDir = args[i] ?? config.tracesDir;
610
+ i++;
611
+ } else if (!arg.startsWith("-")) {
612
+ config.tracesDir = arg;
613
+ i++;
614
+ } else {
615
+ i++;
616
+ }
617
+ }
618
+ config.tracesDir = (0, import_node_path2.resolve)(config.tracesDir);
619
+ return config;
620
+ }
621
+ function printUsage() {
622
+ console.log(`
623
+ AgentFlow Live Monitor \u2014 real-time terminal dashboard for agent systems.
624
+
625
+ Usage:
626
+ agentflow live [traces-dir] [options]
627
+
628
+ Arguments:
629
+ traces-dir Path to the traces directory (default: ./traces)
630
+
631
+ Options:
632
+ -r, --refresh <secs> Refresh interval in seconds (default: 3)
633
+ -t, --traces-dir <path> Explicit traces directory path
634
+ -h, --help Show this help message
635
+
636
+ Examples:
637
+ agentflow live
638
+ agentflow live ./my-traces --refresh 5
639
+ agentflow live /var/log/agentflow/traces -r 10
640
+ `.trim());
641
+ }
642
+ function listTraceFiles(tracesDir) {
643
+ try {
644
+ return (0, import_node_fs2.readdirSync)(tracesDir).filter((f) => f.endsWith(".json")).map((f) => {
645
+ const fp = (0, import_node_path2.join)(tracesDir, f);
646
+ const stat = (0, import_node_fs2.statSync)(fp);
647
+ return { filename: f, path: fp, mtime: stat.mtime.getTime() };
648
+ }).sort((a, b) => b.mtime - a.mtime);
649
+ } catch {
650
+ return [];
651
+ }
652
+ }
653
+ function safeLoadTrace(fp) {
654
+ try {
655
+ return loadGraph((0, import_node_fs2.readFileSync)(fp, "utf8"));
656
+ } catch {
657
+ return null;
658
+ }
659
+ }
660
+ function analyze(trace) {
661
+ try {
662
+ const stats = getStats(trace);
663
+ const fails = getFailures(trace);
664
+ const hung = getHungNodes(trace);
665
+ return {
666
+ agentId: trace.agentId,
667
+ trigger: trace.trigger,
668
+ traceId: trace.traceId,
669
+ spanId: trace.spanId,
670
+ parentSpanId: trace.parentSpanId,
671
+ nodes: stats.totalNodes,
672
+ success: fails.length === 0 && hung.length === 0,
673
+ failures: fails.length,
674
+ hung: hung.length
675
+ };
676
+ } catch {
677
+ return null;
678
+ }
679
+ }
680
+ function getDistributedDepth(dt, spanId) {
681
+ if (!spanId) return 0;
682
+ const graph = dt.graphs.get(spanId);
683
+ if (!graph || !graph.parentSpanId) return 0;
684
+ return 1 + getDistributedDepth(dt, graph.parentSpanId);
685
+ }
686
+ var prevFileCount = 0;
687
+ var newExecCount = 0;
688
+ var sessionStart = Date.now();
689
+ function render(config) {
690
+ const files = listTraceFiles(config.tracesDir);
691
+ if (files.length > prevFileCount && prevFileCount > 0) {
692
+ newExecCount += files.length - prevFileCount;
693
+ }
694
+ prevFileCount = files.length;
695
+ const allTraces = [];
696
+ const agents = {};
697
+ for (const f of files.slice(0, 200)) {
698
+ const trace = safeLoadTrace(f.path);
699
+ if (!trace) continue;
700
+ allTraces.push(trace);
701
+ const a = analyze(trace);
702
+ if (!a) continue;
703
+ if (!agents[a.agentId]) {
704
+ agents[a.agentId] = { name: a.agentId, total: 0, ok: 0, fail: 0, lastTs: 0 };
705
+ }
706
+ const ag = agents[a.agentId];
707
+ ag.total++;
708
+ a.success ? ag.ok++ : ag.fail++;
709
+ if (f.mtime > ag.lastTs) ag.lastTs = f.mtime;
710
+ }
711
+ const agentList = Object.values(agents).sort((a, b) => b.total - a.total);
712
+ const totExec = agentList.reduce((s, a) => s + a.total, 0);
713
+ const totFail = agentList.reduce((s, a) => s + a.fail, 0);
714
+ const sysRate = totExec > 0 ? ((totExec - totFail) / totExec * 100).toFixed(1) : "100.0";
715
+ const recent = [];
716
+ for (const f of files.slice(0, 15)) {
717
+ const trace = safeLoadTrace(f.path);
718
+ if (!trace) continue;
719
+ const a = analyze(trace);
720
+ if (a) recent.push({ ...a, ts: f.mtime });
721
+ }
722
+ const now = Date.now();
723
+ const buckets = new Array(12).fill(0);
724
+ const failBuckets = new Array(12).fill(0);
725
+ for (const f of files) {
726
+ const age = now - f.mtime;
727
+ if (age > 36e5) continue;
728
+ const idx = 11 - Math.floor(age / 3e5);
729
+ if (idx >= 0 && idx < 12) {
730
+ const trace = safeLoadTrace(f.path);
731
+ if (!trace) continue;
732
+ const a = analyze(trace);
733
+ if (!a) continue;
734
+ buckets[idx]++;
735
+ if (!a.success) failBuckets[idx]++;
736
+ }
737
+ }
738
+ const maxBucket = Math.max(...buckets, 1);
739
+ const sparkChars = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
740
+ const spark = buckets.map((v, i) => {
741
+ const level = Math.round(v / maxBucket * 8);
742
+ return (failBuckets[i] > 0 ? C.red : C.green) + sparkChars[level] + C.reset;
743
+ }).join("");
744
+ const traceGroups = groupByTraceId(allTraces);
745
+ const distributedTraces = [];
746
+ for (const [_traceId, graphs] of traceGroups) {
747
+ if (graphs.length > 1) {
748
+ try {
749
+ distributedTraces.push(stitchTrace(graphs));
750
+ } catch {
751
+ }
752
+ }
753
+ }
754
+ distributedTraces.sort((a, b) => b.startTime - a.startTime);
755
+ const upSec = Math.floor((Date.now() - sessionStart) / 1e3);
756
+ const upMin = Math.floor(upSec / 60);
757
+ const upStr = upMin > 0 ? `${upMin}m ${upSec % 60}s` : `${upSec}s`;
758
+ const time = (/* @__PURE__ */ new Date()).toLocaleTimeString();
759
+ process.stdout.write("\x1B[2J\x1B[H");
760
+ console.log(`${C.bold}${C.cyan}\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\u2550\u2550\u2550\u2550\u2557${C.reset}`);
761
+ console.log(`${C.bold}${C.cyan}\u2551${C.reset} ${C.bold}${C.white}AGENTFLOW LIVE${C.reset} ${C.green}\u25CF LIVE${C.reset} ${C.dim}${time}${C.reset} ${C.bold}${C.cyan}\u2551${C.reset}`);
762
+ const metaLine = `Refresh: ${config.refreshMs / 1e3}s \xB7 Up: ${upStr}`;
763
+ const pad1 = Math.max(0, 64 - metaLine.length);
764
+ console.log(`${C.bold}${C.cyan}\u2551${C.reset} ${C.dim}${metaLine}${C.reset}${" ".repeat(pad1)}${C.bold}${C.cyan}\u2551${C.reset}`);
765
+ console.log(`${C.bold}${C.cyan}\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\u2550\u2550\u2550\u2550\u255D${C.reset}`);
766
+ const sc = totFail === 0 ? C.green : C.yellow;
767
+ console.log("");
768
+ console.log(` ${C.bold}Agents${C.reset} ${sc}${agentList.length}${C.reset} ${C.bold}Executions${C.reset} ${sc}${totExec}${C.reset} ${C.bold}Success${C.reset} ${sc}${sysRate}%${C.reset} ${C.bold}Traces${C.reset} ${sc}${files.length}${C.reset} ${C.bold}New${C.reset} ${C.yellow}+${newExecCount}${C.reset} ${C.bold}Distributed${C.reset} ${C.magenta}${distributedTraces.length}${C.reset}`);
769
+ console.log("");
770
+ console.log(` ${C.bold}Activity (1h)${C.reset} ${spark} ${C.dim}\u2190 now${C.reset}`);
771
+ console.log("");
772
+ console.log(` ${C.bold}${C.under}Agent Runs OK Fail Rate Last Active${C.reset}`);
773
+ for (const ag of agentList) {
774
+ const rate = (ag.ok / ag.total * 100).toFixed(0);
775
+ const lastTime = new Date(ag.lastTs).toLocaleTimeString();
776
+ const isRecent = Date.now() - ag.lastTs < 3e5;
777
+ let status;
778
+ if (ag.fail > 0) status = `${C.red}\u25CF${C.reset}`;
779
+ else if (isRecent) status = `${C.green}\u25CF${C.reset}`;
780
+ else status = `${C.dim}\u25CB${C.reset}`;
781
+ const name = ag.name.padEnd(28);
782
+ const runs = String(ag.total).padStart(5);
783
+ const ok = String(ag.ok).padStart(5);
784
+ const fail = ag.fail > 0 ? `${C.red}${String(ag.fail).padStart(4)}${C.reset}` : String(ag.fail).padStart(4);
785
+ const rateStr = (rate + "%").padStart(5);
786
+ const activeStr = isRecent ? `${C.green}${lastTime}${C.reset}` : `${C.dim}${lastTime}${C.reset}`;
787
+ console.log(` ${status} ${name}${runs}${ok}${fail} ${rateStr} ${activeStr}`);
788
+ }
789
+ if (distributedTraces.length > 0) {
790
+ console.log("");
791
+ console.log(` ${C.bold}${C.under}Distributed Traces (multi-agent workflows)${C.reset}`);
792
+ for (const dt of distributedTraces.slice(0, 5)) {
793
+ const traceTime = new Date(dt.startTime).toLocaleTimeString();
794
+ const statusIcon = dt.status === "completed" ? `${C.green}\u2713${C.reset}` : dt.status === "failed" ? `${C.red}\u2717${C.reset}` : `${C.yellow}\u23F3${C.reset}`;
795
+ const dur = dt.endTime ? `${dt.endTime - dt.startTime}ms` : "running";
796
+ const tid = dt.traceId.slice(0, 8);
797
+ console.log(` ${statusIcon} ${C.magenta}trace:${tid}${C.reset} ${C.dim}${traceTime}${C.reset} ${C.dim}${dur}${C.reset} ${C.dim}(${dt.graphs.size} agents)${C.reset}`);
798
+ const tree = getTraceTree(dt);
799
+ for (let i = 0; i < tree.length; i++) {
800
+ const g = tree[i];
801
+ const depth = getDistributedDepth(dt, g.spanId);
802
+ const indent = " " + "\u2502 ".repeat(Math.max(0, depth - 1));
803
+ const isLast = i === tree.length - 1 || getDistributedDepth(dt, tree[i + 1]?.spanId) <= depth;
804
+ const connector = depth === 0 ? " " : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
805
+ const gStatus = g.status === "completed" ? `${C.green}\u2713${C.reset}` : g.status === "failed" ? `${C.red}\u2717${C.reset}` : `${C.yellow}\u23F3${C.reset}`;
806
+ const gDur = g.endTime ? `${g.endTime - g.startTime}ms` : "running";
807
+ console.log(`${indent}${connector}${gStatus} ${C.bold}${g.agentId}${C.reset} ${C.dim}[${g.trigger}] ${gDur}${C.reset}`);
808
+ }
809
+ }
810
+ }
811
+ console.log("");
812
+ console.log(` ${C.bold}${C.under}Recent Executions${C.reset}`);
813
+ for (const ex of recent.slice(0, 8)) {
814
+ const icon = ex.success ? `${C.green}\u2713${C.reset}` : `${C.red}\u2717${C.reset}`;
815
+ const t = new Date(ex.ts).toLocaleTimeString();
816
+ const agent = ex.agentId.padEnd(28);
817
+ const age = Math.floor((Date.now() - ex.ts) / 1e3);
818
+ const ageStr = age < 60 ? age + "s ago" : Math.floor(age / 60) + "m ago";
819
+ const traceTag = ex.traceId ? ` ${C.magenta}\u29EB${C.reset}` : "";
820
+ console.log(` ${icon} ${agent} ${C.dim}${t} ${ageStr.padStart(8)} ${ex.nodes} nodes${C.reset}${traceTag}`);
821
+ }
822
+ if (files.length === 0) {
823
+ console.log(` ${C.dim}No trace files found. Waiting for traces in:${C.reset}`);
824
+ console.log(` ${C.dim}${config.tracesDir}${C.reset}`);
825
+ }
826
+ console.log("");
827
+ console.log(` ${C.dim}Watching: ${config.tracesDir}${C.reset}`);
828
+ console.log(` ${C.dim}Press Ctrl+C to exit${C.reset}`);
829
+ }
830
+ function startLive(argv) {
831
+ const config = parseArgs(argv);
832
+ if (!(0, import_node_fs2.existsSync)(config.tracesDir)) {
833
+ console.error(`Traces directory does not exist: ${config.tracesDir}`);
834
+ console.error("Create it or specify a different path: agentflow live <traces-dir>");
835
+ process.exit(1);
836
+ }
837
+ render(config);
838
+ let debounce = null;
839
+ try {
840
+ (0, import_node_fs2.watch)(config.tracesDir, () => {
841
+ if (debounce) clearTimeout(debounce);
842
+ debounce = setTimeout(() => render(config), 500);
843
+ });
844
+ } catch {
845
+ }
846
+ setInterval(() => render(config), config.refreshMs);
847
+ process.on("SIGINT", () => {
848
+ console.log("\n" + C.dim + "Monitor stopped." + C.reset);
849
+ process.exit(0);
850
+ });
851
+ }
852
+
853
+ // src/cli.ts
854
+ function printHelp() {
855
+ console.log(`
856
+ AgentFlow CLI \u2014 execution tracing and live monitoring for AI agent systems.
857
+
858
+ Usage:
859
+ agentflow <command> [options]
860
+
861
+ Commands:
862
+ run [options] -- <cmd> Wrap a command with automatic execution tracing
863
+ live [traces-dir] [options] Real-time terminal monitor for trace files
864
+
865
+ Run \`agentflow <command> --help\` for command-specific options.
866
+
867
+ Examples:
868
+ agentflow run --traces-dir ./traces -- python -m myagent process
869
+ agentflow live ./traces
870
+ agentflow live ./traces --refresh 5
871
+ `.trim());
872
+ }
873
+ function parseRunArgs(argv) {
409
874
  const result = {
410
875
  tracesDir: "./traces",
411
876
  watchDirs: [],
@@ -463,9 +928,9 @@ function parseArgs(argv) {
463
928
  result.command = commandArgs;
464
929
  return result;
465
930
  }
466
- function printUsage() {
931
+ function printRunUsage() {
467
932
  console.log(`
468
- AgentFlow CLI \u2014 Wrap any command with automatic execution tracing.
933
+ AgentFlow Run \u2014 wrap any command with automatic execution tracing.
469
934
 
470
935
  Usage:
471
936
  agentflow run [options] -- <command>
@@ -479,21 +944,20 @@ Options:
479
944
  --help Show this help message
480
945
 
481
946
  Examples:
482
- agentflow run -- python -m alfred process
483
- agentflow run --watch-dir /home/trader/.alfred/data -- python -m alfred process
484
- agentflow run --traces-dir ./my-traces --agent-id alfred -- node worker.js
947
+ agentflow run -- python -m myagent process
948
+ agentflow run --watch-dir ./data -- python worker.py
949
+ agentflow run --traces-dir ./my-traces --agent-id recon -- node agent.js
485
950
  `.trim());
486
951
  }
487
- async function main() {
488
- const argv = process.argv.slice(2);
489
- if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
490
- printUsage();
952
+ async function runCommand(argv) {
953
+ if (argv.includes("--help") || argv.includes("-h")) {
954
+ printRunUsage();
491
955
  process.exit(0);
492
956
  }
493
- const parsed = parseArgs(argv);
957
+ const parsed = parseRunArgs(argv);
494
958
  if (parsed.command.length === 0) {
495
959
  console.error("Error: No command specified. Use -- to separate agentflow flags from the command.");
496
- console.error("Example: agentflow run -- python -m alfred process");
960
+ console.error("Example: agentflow run -- python -m myagent process");
497
961
  process.exit(1);
498
962
  }
499
963
  const commandStr = parsed.command.join(" ");
@@ -539,4 +1003,28 @@ async function main() {
539
1003
  process.exit(1);
540
1004
  }
541
1005
  }
1006
+ async function main() {
1007
+ const argv = process.argv.slice(2);
1008
+ if (argv.length === 0 || argv[0] !== "run" && argv[0] !== "live" && (argv.includes("--help") || argv.includes("-h"))) {
1009
+ printHelp();
1010
+ process.exit(0);
1011
+ }
1012
+ const subcommand = argv[0];
1013
+ switch (subcommand) {
1014
+ case "run":
1015
+ await runCommand(argv);
1016
+ break;
1017
+ case "live":
1018
+ startLive(argv);
1019
+ break;
1020
+ default:
1021
+ if (!subcommand?.startsWith("-")) {
1022
+ startLive(["live", ...argv]);
1023
+ } else {
1024
+ printHelp();
1025
+ process.exit(1);
1026
+ }
1027
+ break;
1028
+ }
1029
+ }
542
1030
  main();
package/dist/cli.js CHANGED
@@ -1,11 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- runTraced
4
- } from "./chunk-DGLK6IBP.js";
3
+ runTraced,
4
+ startLive
5
+ } from "./chunk-TRKBUPIN.js";
5
6
 
6
7
  // src/cli.ts
7
8
  import { basename } from "path";
8
- function parseArgs(argv) {
9
+ function printHelp() {
10
+ console.log(`
11
+ AgentFlow CLI \u2014 execution tracing and live monitoring for AI agent systems.
12
+
13
+ Usage:
14
+ agentflow <command> [options]
15
+
16
+ Commands:
17
+ run [options] -- <cmd> Wrap a command with automatic execution tracing
18
+ live [traces-dir] [options] Real-time terminal monitor for trace files
19
+
20
+ Run \`agentflow <command> --help\` for command-specific options.
21
+
22
+ Examples:
23
+ agentflow run --traces-dir ./traces -- python -m myagent process
24
+ agentflow live ./traces
25
+ agentflow live ./traces --refresh 5
26
+ `.trim());
27
+ }
28
+ function parseRunArgs(argv) {
9
29
  const result = {
10
30
  tracesDir: "./traces",
11
31
  watchDirs: [],
@@ -63,9 +83,9 @@ function parseArgs(argv) {
63
83
  result.command = commandArgs;
64
84
  return result;
65
85
  }
66
- function printUsage() {
86
+ function printRunUsage() {
67
87
  console.log(`
68
- AgentFlow CLI \u2014 Wrap any command with automatic execution tracing.
88
+ AgentFlow Run \u2014 wrap any command with automatic execution tracing.
69
89
 
70
90
  Usage:
71
91
  agentflow run [options] -- <command>
@@ -79,21 +99,20 @@ Options:
79
99
  --help Show this help message
80
100
 
81
101
  Examples:
82
- agentflow run -- python -m alfred process
83
- agentflow run --watch-dir /home/trader/.alfred/data -- python -m alfred process
84
- agentflow run --traces-dir ./my-traces --agent-id alfred -- node worker.js
102
+ agentflow run -- python -m myagent process
103
+ agentflow run --watch-dir ./data -- python worker.py
104
+ agentflow run --traces-dir ./my-traces --agent-id recon -- node agent.js
85
105
  `.trim());
86
106
  }
87
- async function main() {
88
- const argv = process.argv.slice(2);
89
- if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
90
- printUsage();
107
+ async function runCommand(argv) {
108
+ if (argv.includes("--help") || argv.includes("-h")) {
109
+ printRunUsage();
91
110
  process.exit(0);
92
111
  }
93
- const parsed = parseArgs(argv);
112
+ const parsed = parseRunArgs(argv);
94
113
  if (parsed.command.length === 0) {
95
114
  console.error("Error: No command specified. Use -- to separate agentflow flags from the command.");
96
- console.error("Example: agentflow run -- python -m alfred process");
115
+ console.error("Example: agentflow run -- python -m myagent process");
97
116
  process.exit(1);
98
117
  }
99
118
  const commandStr = parsed.command.join(" ");
@@ -139,4 +158,28 @@ async function main() {
139
158
  process.exit(1);
140
159
  }
141
160
  }
161
+ async function main() {
162
+ const argv = process.argv.slice(2);
163
+ if (argv.length === 0 || argv[0] !== "run" && argv[0] !== "live" && (argv.includes("--help") || argv.includes("-h"))) {
164
+ printHelp();
165
+ process.exit(0);
166
+ }
167
+ const subcommand = argv[0];
168
+ switch (subcommand) {
169
+ case "run":
170
+ await runCommand(argv);
171
+ break;
172
+ case "live":
173
+ startLive(argv);
174
+ break;
175
+ default:
176
+ if (!subcommand?.startsWith("-")) {
177
+ startLive(["live", ...argv]);
178
+ } else {
179
+ printHelp();
180
+ process.exit(1);
181
+ }
182
+ break;
183
+ }
184
+ }
142
185
  main();