agentflow-core 0.1.4 → 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
@@ -236,6 +236,35 @@ function createGraphBuilder(config) {
236
236
  }
237
237
 
238
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
+ }
239
268
  function graphToJson(graph) {
240
269
  const nodesObj = {};
241
270
  for (const [id, node] of graph.nodes) {
@@ -406,8 +435,442 @@ async function runTraced(config) {
406
435
  };
407
436
  }
408
437
 
409
- // 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
+ };
410
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) {
411
874
  const result = {
412
875
  tracesDir: "./traces",
413
876
  watchDirs: [],
@@ -465,9 +928,9 @@ function parseArgs(argv) {
465
928
  result.command = commandArgs;
466
929
  return result;
467
930
  }
468
- function printUsage() {
931
+ function printRunUsage() {
469
932
  console.log(`
470
- AgentFlow CLI \u2014 Wrap any command with automatic execution tracing.
933
+ AgentFlow Run \u2014 wrap any command with automatic execution tracing.
471
934
 
472
935
  Usage:
473
936
  agentflow run [options] -- <command>
@@ -481,21 +944,20 @@ Options:
481
944
  --help Show this help message
482
945
 
483
946
  Examples:
484
- agentflow run -- python -m alfred process
485
- agentflow run --watch-dir /home/trader/.alfred/data -- python -m alfred process
486
- 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
487
950
  `.trim());
488
951
  }
489
- async function main() {
490
- const argv = process.argv.slice(2);
491
- if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
492
- printUsage();
952
+ async function runCommand(argv) {
953
+ if (argv.includes("--help") || argv.includes("-h")) {
954
+ printRunUsage();
493
955
  process.exit(0);
494
956
  }
495
- const parsed = parseArgs(argv);
957
+ const parsed = parseRunArgs(argv);
496
958
  if (parsed.command.length === 0) {
497
959
  console.error("Error: No command specified. Use -- to separate agentflow flags from the command.");
498
- console.error("Example: agentflow run -- python -m alfred process");
960
+ console.error("Example: agentflow run -- python -m myagent process");
499
961
  process.exit(1);
500
962
  }
501
963
  const commandStr = parsed.command.join(" ");
@@ -541,4 +1003,28 @@ async function main() {
541
1003
  process.exit(1);
542
1004
  }
543
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
+ }
544
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-TT5DLU73.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();