agentflow-core 0.3.3 → 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.
package/dist/cli.js CHANGED
@@ -1,14 +1,211 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ createTraceStore,
3
4
  runTraced,
4
5
  startLive,
5
- startWatch
6
- } from "./chunk-M5CGDXAO.js";
6
+ startWatch,
7
+ toAsciiTree,
8
+ toTimeline
9
+ } from "./chunk-T2BYYGA4.js";
10
+ import "./chunk-DY7YHFIB.js";
7
11
 
8
12
  // src/cli.ts
9
13
  import { basename } from "path";
14
+
15
+ // src/trace-cli.ts
16
+ import { resolve } from "path";
17
+ function getTracesDir(argv) {
18
+ const idx = argv.indexOf("--traces-dir");
19
+ if (idx !== -1 && argv[idx + 1]) {
20
+ return resolve(argv[idx + 1]);
21
+ }
22
+ return resolve("./traces");
23
+ }
24
+ function getFlag(argv, name) {
25
+ const idx = argv.indexOf(name);
26
+ if (idx !== -1 && argv[idx + 1]) {
27
+ return argv[idx + 1];
28
+ }
29
+ return void 0;
30
+ }
31
+ function printTraceHelp() {
32
+ console.log(
33
+ `
34
+ AgentFlow Trace \u2014 inspect saved execution traces.
35
+
36
+ Usage:
37
+ agentflow trace <command> [options]
38
+
39
+ Commands:
40
+ list [--status <status>] [--limit <n>] List saved traces
41
+ show <graph-id> Show trace as ASCII tree
42
+ timeline <graph-id> Show trace as timeline waterfall
43
+ stuck Show all stuck/hung/timeout spans
44
+ loops [--threshold <n>] Detect reasoning loops
45
+
46
+ Options:
47
+ --traces-dir <path> Directory containing trace files (default: ./traces)
48
+
49
+ Examples:
50
+ agentflow trace list --status failed --limit 10
51
+ agentflow trace show abc-123
52
+ agentflow trace timeline abc-123
53
+ agentflow trace stuck
54
+ agentflow trace loops --threshold 10
55
+ `.trim()
56
+ );
57
+ }
58
+ async function traceList(argv) {
59
+ const dir = getTracesDir(argv);
60
+ const store = createTraceStore(dir);
61
+ const status = getFlag(argv, "--status");
62
+ const limitStr = getFlag(argv, "--limit");
63
+ const limit = limitStr ? Number.parseInt(limitStr, 10) : void 0;
64
+ const graphs = await store.list({ status, limit });
65
+ if (graphs.length === 0) {
66
+ console.log("No traces found.");
67
+ return;
68
+ }
69
+ console.log(`Found ${graphs.length} trace(s) in ${dir}:
70
+ `);
71
+ for (const g of graphs) {
72
+ const duration = g.endTime ? `${((g.endTime - g.startTime) / 1e3).toFixed(1)}s` : "running";
73
+ const date = new Date(g.startTime).toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
74
+ const icon = g.status === "completed" ? "\u2713" : g.status === "failed" ? "\u2717" : "\u231B";
75
+ console.log(
76
+ ` ${icon} ${g.id} ${g.status.padEnd(10)} ${duration.padEnd(8)} ${date} ${g.agentId}`
77
+ );
78
+ }
79
+ }
80
+ async function traceShow(argv) {
81
+ const dir = getTracesDir(argv);
82
+ const store = createTraceStore(dir);
83
+ const showIdx = argv.indexOf("show");
84
+ const graphId = showIdx !== -1 ? argv[showIdx + 1] : void 0;
85
+ if (!graphId || graphId.startsWith("--")) {
86
+ console.error("Usage: agentflow trace show <graph-id>");
87
+ process.exit(1);
88
+ }
89
+ let graph = await store.get(graphId);
90
+ if (!graph) {
91
+ const { readFile } = await import("fs/promises");
92
+ const { join } = await import("path");
93
+ const fname = graphId.endsWith(".json") ? graphId : `${graphId}.json`;
94
+ try {
95
+ const { loadGraph } = await import("./loader-LYRR6LMM.js");
96
+ const content = await readFile(join(dir, fname), "utf-8");
97
+ graph = loadGraph(content);
98
+ } catch {
99
+ }
100
+ }
101
+ if (!graph) {
102
+ console.error(`Trace "${graphId}" not found in ${dir}`);
103
+ process.exit(1);
104
+ }
105
+ console.log(`Trace: ${graph.id} (${graph.status})
106
+ `);
107
+ console.log(toAsciiTree(graph));
108
+ }
109
+ async function traceTimeline(argv) {
110
+ const dir = getTracesDir(argv);
111
+ const store = createTraceStore(dir);
112
+ const timelineIdx = argv.indexOf("timeline");
113
+ const graphId = timelineIdx !== -1 ? argv[timelineIdx + 1] : void 0;
114
+ if (!graphId || graphId.startsWith("--")) {
115
+ console.error("Usage: agentflow trace timeline <graph-id>");
116
+ process.exit(1);
117
+ }
118
+ let graph = await store.get(graphId);
119
+ if (!graph) {
120
+ const { readFile } = await import("fs/promises");
121
+ const { join } = await import("path");
122
+ const fname = graphId.endsWith(".json") ? graphId : `${graphId}.json`;
123
+ try {
124
+ const { loadGraph } = await import("./loader-LYRR6LMM.js");
125
+ const content = await readFile(join(dir, fname), "utf-8");
126
+ graph = loadGraph(content);
127
+ } catch {
128
+ }
129
+ }
130
+ if (!graph) {
131
+ console.error(`Trace "${graphId}" not found in ${dir}`);
132
+ process.exit(1);
133
+ }
134
+ console.log(`Trace: ${graph.id} (${graph.status})
135
+ `);
136
+ console.log(toTimeline(graph));
137
+ }
138
+ async function traceStuck(argv) {
139
+ const dir = getTracesDir(argv);
140
+ const store = createTraceStore(dir);
141
+ const stuck = await store.getStuckSpans();
142
+ if (stuck.length === 0) {
143
+ console.log("No stuck spans found.");
144
+ return;
145
+ }
146
+ console.log(`Found ${stuck.length} stuck span(s):
147
+ `);
148
+ for (const node of stuck) {
149
+ const elapsed = Date.now() - node.startTime;
150
+ const icon = node.status === "timeout" ? "\u231B" : node.status === "hung" ? "\u231B" : "\u231B";
151
+ console.log(
152
+ ` ${icon} ${node.id} ${node.type.padEnd(10)} ${node.name.padEnd(20)} ${node.status.padEnd(8)} ${(elapsed / 1e3).toFixed(0)}s`
153
+ );
154
+ }
155
+ }
156
+ async function traceLoops(argv) {
157
+ const dir = getTracesDir(argv);
158
+ const store = createTraceStore(dir);
159
+ const thresholdStr = getFlag(argv, "--threshold");
160
+ const threshold = thresholdStr ? Number.parseInt(thresholdStr, 10) : void 0;
161
+ const loops = await store.getReasoningLoops(threshold);
162
+ if (loops.length === 0) {
163
+ console.log("No reasoning loops detected.");
164
+ return;
165
+ }
166
+ console.log(`Found reasoning loops in ${loops.length} trace(s):
167
+ `);
168
+ for (const { graphId, nodes } of loops) {
169
+ console.log(` Graph: ${graphId}`);
170
+ for (const node of nodes) {
171
+ console.log(` - ${node.id} (${node.type}: ${node.name})`);
172
+ }
173
+ console.log("");
174
+ }
175
+ }
176
+ async function handleTrace(argv) {
177
+ if (argv.includes("--help") || argv.includes("-h")) {
178
+ printTraceHelp();
179
+ return;
180
+ }
181
+ const traceIdx = argv.indexOf("trace");
182
+ const subcommand = traceIdx !== -1 ? argv[traceIdx + 1] : void 0;
183
+ switch (subcommand) {
184
+ case "list":
185
+ await traceList(argv);
186
+ break;
187
+ case "show":
188
+ await traceShow(argv);
189
+ break;
190
+ case "timeline":
191
+ await traceTimeline(argv);
192
+ break;
193
+ case "stuck":
194
+ await traceStuck(argv);
195
+ break;
196
+ case "loops":
197
+ await traceLoops(argv);
198
+ break;
199
+ default:
200
+ printTraceHelp();
201
+ break;
202
+ }
203
+ }
204
+
205
+ // src/cli.ts
10
206
  function printHelp() {
11
- console.log(`
207
+ console.log(
208
+ `
12
209
  AgentFlow CLI \u2014 execution tracing and live monitoring for AI agent systems.
13
210
 
14
211
  Usage:
@@ -18,6 +215,7 @@ Commands:
18
215
  run [options] -- <cmd> Wrap a command with automatic execution tracing
19
216
  live [dir...] [options] Real-time terminal monitor (auto-detects any JSON/JSONL)
20
217
  watch [dir...] [options] Headless alert system \u2014 detects failures, sends notifications
218
+ trace <command> [options] Inspect saved execution traces (list, show, timeline, stuck, loops)
21
219
 
22
220
  Run \`agentflow <command> --help\` for command-specific options.
23
221
 
@@ -27,7 +225,8 @@ Examples:
27
225
  agentflow live ./traces ./cron ./workers -R
28
226
  agentflow watch ./data --alert-on error --notify telegram
29
227
  agentflow watch ./data ./cron --alert-on stale:15m --notify webhook:https://...
30
- `.trim());
228
+ `.trim()
229
+ );
31
230
  }
32
231
  function parseRunArgs(argv) {
33
232
  const result = {
@@ -88,7 +287,8 @@ function parseRunArgs(argv) {
88
287
  return result;
89
288
  }
90
289
  function printRunUsage() {
91
- console.log(`
290
+ console.log(
291
+ `
92
292
  AgentFlow Run \u2014 wrap any command with automatic execution tracing.
93
293
 
94
294
  Usage:
@@ -106,7 +306,8 @@ Examples:
106
306
  agentflow run -- python -m myagent process
107
307
  agentflow run --watch-dir ./data -- python worker.py
108
308
  agentflow run --traces-dir ./my-traces --agent-id recon -- node agent.js
109
- `.trim());
309
+ `.trim()
310
+ );
110
311
  }
111
312
  async function runCommand(argv) {
112
313
  if (argv.includes("--help") || argv.includes("-h")) {
@@ -115,7 +316,9 @@ async function runCommand(argv) {
115
316
  }
116
317
  const parsed = parseRunArgs(argv);
117
318
  if (parsed.command.length === 0) {
118
- console.error("Error: No command specified. Use -- to separate agentflow flags from the command.");
319
+ console.error(
320
+ "Error: No command specified. Use -- to separate agentflow flags from the command."
321
+ );
119
322
  console.error("Example: agentflow run -- python -m myagent process");
120
323
  process.exit(1);
121
324
  }
@@ -139,7 +342,9 @@ async function runCommand(argv) {
139
342
  try {
140
343
  const result = await runTraced(config);
141
344
  console.log("");
142
- console.log(`\u2705 Command completed (exit code ${result.exitCode}, ${result.duration.toFixed(1)}s)`);
345
+ console.log(
346
+ `\u2705 Command completed (exit code ${result.exitCode}, ${result.duration.toFixed(1)}s)`
347
+ );
143
348
  if (result.tracePaths.length > 0) {
144
349
  console.log("\u{1F4DD} Traces saved:");
145
350
  const orchPath = result.tracePaths[0];
@@ -164,7 +369,7 @@ async function runCommand(argv) {
164
369
  }
165
370
  async function main() {
166
371
  const argv = process.argv.slice(2);
167
- const knownCommands = ["run", "live", "watch"];
372
+ const knownCommands = ["run", "live", "watch", "trace"];
168
373
  if (argv.length === 0 || !knownCommands.includes(argv[0]) && (argv.includes("--help") || argv.includes("-h"))) {
169
374
  printHelp();
170
375
  process.exit(0);
@@ -180,6 +385,9 @@ async function main() {
180
385
  case "watch":
181
386
  startWatch(argv);
182
387
  break;
388
+ case "trace":
389
+ await handleTrace(argv);
390
+ break;
183
391
  default:
184
392
  if (!subcommand?.startsWith("-")) {
185
393
  startLive(["live", ...argv]);