agent-inspect 0.1.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.
@@ -0,0 +1,888 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var fs = require('fs');
5
+ var path = require('path');
6
+ var url = require('url');
7
+ var commander = require('commander');
8
+ var promises = require('fs/promises');
9
+ var os = require('os');
10
+ var nanoid = require('nanoid');
11
+ var async_hooks = require('async_hooks');
12
+ var chalk = require('chalk');
13
+
14
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
15
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
+
17
+ var path__default = /*#__PURE__*/_interopDefault(path);
18
+ var os__default = /*#__PURE__*/_interopDefault(os);
19
+ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
20
+
21
+ var STEP_TYPES = [
22
+ "run",
23
+ "llm",
24
+ "tool",
25
+ "decision",
26
+ "logic",
27
+ "state",
28
+ "custom"
29
+ ];
30
+ function isStepType(value) {
31
+ return typeof value === "string" && STEP_TYPES.includes(value);
32
+ }
33
+ var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
34
+ var RUNS_DIR_NAME = "runs";
35
+ var FALLBACK_TRACE_DIR = path__default.default.join(
36
+ os__default.default.tmpdir(),
37
+ "agent-inspect",
38
+ RUNS_DIR_NAME
39
+ );
40
+ var MAX_NAME_LENGTH = 100;
41
+ function createStepId() {
42
+ return `step_${nanoid.nanoid(10)}`;
43
+ }
44
+ function formatDuration(ms) {
45
+ if (!Number.isFinite(ms) || ms < 0) {
46
+ return "0ms";
47
+ }
48
+ if (ms < 1e3) {
49
+ return `${Math.floor(ms)}ms`;
50
+ }
51
+ const seconds = ms / 1e3;
52
+ return `${(Math.round(seconds * 10) / 10).toFixed(1)}s`;
53
+ }
54
+ function formatTimestamp(timestamp) {
55
+ if (!Number.isFinite(timestamp)) {
56
+ return "Invalid date";
57
+ }
58
+ const d = new Date(timestamp);
59
+ if (Number.isNaN(d.getTime())) {
60
+ return "Invalid date";
61
+ }
62
+ const y = d.getFullYear();
63
+ const mo = String(d.getMonth() + 1).padStart(2, "0");
64
+ const day = String(d.getDate()).padStart(2, "0");
65
+ const h = String(d.getHours()).padStart(2, "0");
66
+ const min = String(d.getMinutes()).padStart(2, "0");
67
+ const s = String(d.getSeconds()).padStart(2, "0");
68
+ return `${y}-${mo}-${day} ${h}:${min}:${s}`;
69
+ }
70
+ function getDefaultTraceDir() {
71
+ try {
72
+ const home = os__default.default.homedir();
73
+ if (typeof home !== "string" || home.trim() === "") {
74
+ return FALLBACK_TRACE_DIR;
75
+ }
76
+ return path__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
77
+ } catch {
78
+ return FALLBACK_TRACE_DIR;
79
+ }
80
+ }
81
+ function getTraceFilePath(runId, traceDir) {
82
+ const baseDir = traceDir ?? getDefaultTraceDir();
83
+ let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
84
+ safeId = path__default.default.basename(safeId);
85
+ if (safeId === "" || safeId === "." || safeId === "..") {
86
+ safeId = "run_unknown";
87
+ }
88
+ return path__default.default.join(baseDir, `${safeId}.jsonl`);
89
+ }
90
+ async function ensureTraceDir(traceDir) {
91
+ const primary = path__default.default.resolve(traceDir);
92
+ try {
93
+ await promises.mkdir(primary, { recursive: true });
94
+ return primary;
95
+ } catch {
96
+ warn(`Failed to create trace directory: ${primary}`);
97
+ const fallback = path__default.default.resolve(FALLBACK_TRACE_DIR);
98
+ try {
99
+ await promises.mkdir(fallback, { recursive: true });
100
+ return fallback;
101
+ } catch {
102
+ warn(`Failed to create fallback trace directory: ${fallback}`);
103
+ return primary;
104
+ }
105
+ }
106
+ }
107
+ function formatError(error) {
108
+ if (error instanceof Error) {
109
+ const out = { message: error.message };
110
+ if (typeof error.stack === "string" && error.stack.length > 0) {
111
+ out.stack = error.stack;
112
+ }
113
+ return out;
114
+ }
115
+ if (typeof error === "string") {
116
+ return { message: error };
117
+ }
118
+ if (error === null) {
119
+ return { message: "Unknown error: null" };
120
+ }
121
+ if (error === void 0) {
122
+ return { message: "Unknown error: undefined" };
123
+ }
124
+ if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") {
125
+ return { message: String(error) };
126
+ }
127
+ if (typeof error === "object") {
128
+ try {
129
+ return { message: JSON.stringify(error) };
130
+ } catch {
131
+ return { message: "Unknown error" };
132
+ }
133
+ }
134
+ return { message: "Unknown error" };
135
+ }
136
+ function truncateName(name, maxLength = MAX_NAME_LENGTH) {
137
+ if (typeof name !== "string" || name.trim() === "") {
138
+ return "unnamed";
139
+ }
140
+ const trimmed = name.trim();
141
+ if (trimmed.length <= maxLength) {
142
+ return trimmed;
143
+ }
144
+ const ellipsis = "...";
145
+ const head = Math.max(0, maxLength - ellipsis.length);
146
+ return `${trimmed.slice(0, head)}${ellipsis}`;
147
+ }
148
+ function warn(message, error) {
149
+ const base = `[AgentInspect] ${message}`;
150
+ if (error === void 0) {
151
+ console.warn(base);
152
+ return;
153
+ }
154
+ console.warn(`${base}: ${formatError(error).message}`);
155
+ }
156
+ var storage = new async_hooks.AsyncLocalStorage();
157
+ function toPublicContext(ctx) {
158
+ return {
159
+ runId: ctx.runId,
160
+ runName: ctx.runName,
161
+ traceDir: ctx.traceDir,
162
+ silent: ctx.silent,
163
+ metadata: ctx.metadata
164
+ };
165
+ }
166
+ function invoke(fn) {
167
+ return new Promise((resolve, reject) => {
168
+ try {
169
+ Promise.resolve(fn()).then(resolve, reject);
170
+ } catch (e) {
171
+ reject(e);
172
+ }
173
+ });
174
+ }
175
+ function getCurrentContext() {
176
+ try {
177
+ const s = storage.getStore();
178
+ if (!s) return void 0;
179
+ return toPublicContext(s);
180
+ } catch {
181
+ return void 0;
182
+ }
183
+ }
184
+ function getCurrentStepId() {
185
+ try {
186
+ return storage.getStore()?.currentStepId;
187
+ } catch {
188
+ return void 0;
189
+ }
190
+ }
191
+ function getParentStepId() {
192
+ return getCurrentStepId();
193
+ }
194
+ function getCurrentDepth() {
195
+ try {
196
+ const d = storage.getStore()?.currentDepth;
197
+ return typeof d === "number" && Number.isFinite(d) ? d : 0;
198
+ } catch {
199
+ return 0;
200
+ }
201
+ }
202
+ function isSilentContext() {
203
+ try {
204
+ const s = storage.getStore();
205
+ return s ? s.silent : false;
206
+ } catch {
207
+ return false;
208
+ }
209
+ }
210
+ function runWithStepContext(stepId, fn) {
211
+ let parent;
212
+ try {
213
+ parent = storage.getStore();
214
+ } catch {
215
+ parent = void 0;
216
+ }
217
+ if (!parent) {
218
+ return invoke(fn);
219
+ }
220
+ const derived = {
221
+ runId: parent.runId,
222
+ runName: parent.runName,
223
+ traceDir: parent.traceDir,
224
+ silent: parent.silent,
225
+ metadata: parent.metadata,
226
+ currentStepId: stepId,
227
+ currentDepth: parent.currentDepth + 1
228
+ };
229
+ return new Promise((resolve, reject) => {
230
+ storage.run(derived, () => {
231
+ try {
232
+ Promise.resolve(fn()).then(resolve, reject);
233
+ } catch (e) {
234
+ reject(e);
235
+ }
236
+ });
237
+ });
238
+ }
239
+ function isRecord2(value) {
240
+ return typeof value === "object" && value !== null && !Array.isArray(value);
241
+ }
242
+ function nonEmptyString(value) {
243
+ return typeof value === "string" && value.trim() !== "";
244
+ }
245
+ function finiteNumber(value) {
246
+ return typeof value === "number" && Number.isFinite(value);
247
+ }
248
+ function optionalErrorInfo(value) {
249
+ if (value === void 0) return true;
250
+ if (!isRecord2(value)) return false;
251
+ if (typeof value.message !== "string") return false;
252
+ if ("stack" in value && value.stack !== void 0) {
253
+ if (typeof value.stack !== "string") return false;
254
+ }
255
+ return true;
256
+ }
257
+ function validateEvent(event) {
258
+ if (!isRecord2(event)) return false;
259
+ if (event.schemaVersion !== "0.1") return false;
260
+ if (!finiteNumber(event.timestamp)) return false;
261
+ if (typeof event.event !== "string") return false;
262
+ switch (event.event) {
263
+ case "run_started": {
264
+ if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
265
+ return false;
266
+ }
267
+ if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
268
+ return false;
269
+ }
270
+ return true;
271
+ }
272
+ case "run_completed": {
273
+ return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
274
+ }
275
+ case "step_started": {
276
+ if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
277
+ return false;
278
+ }
279
+ if (event.parentId !== void 0 && typeof event.parentId !== "string") {
280
+ return false;
281
+ }
282
+ if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
283
+ return false;
284
+ }
285
+ return true;
286
+ }
287
+ case "step_completed": {
288
+ return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
289
+ }
290
+ default:
291
+ return false;
292
+ }
293
+ }
294
+ function serializeEvent(event) {
295
+ try {
296
+ return JSON.stringify(event);
297
+ } catch {
298
+ return "";
299
+ }
300
+ }
301
+ async function writeTraceEvent(event, traceDir) {
302
+ if (!validateEvent(event)) {
303
+ warn("Skipped invalid trace event (validation failed)");
304
+ return;
305
+ }
306
+ const line = serializeEvent(event);
307
+ if (line === "") {
308
+ warn("Skipped trace event (serialization failed)");
309
+ return;
310
+ }
311
+ const payload = `${line}
312
+ `;
313
+ const tryAppend = async (dir) => {
314
+ try {
315
+ const usable = await ensureTraceDir(dir);
316
+ const filePath = getTraceFilePath(event.runId, usable);
317
+ await promises.appendFile(filePath, payload, "utf-8");
318
+ return true;
319
+ } catch {
320
+ return false;
321
+ }
322
+ };
323
+ if (await tryAppend(traceDir)) {
324
+ return;
325
+ }
326
+ warn(`Failed to append trace event for run ${event.runId}`);
327
+ if (await tryAppend(FALLBACK_TRACE_DIR)) {
328
+ return;
329
+ }
330
+ warn("Failed to append trace event to fallback directory");
331
+ }
332
+ async function readTraceFile(runId, traceDir) {
333
+ try {
334
+ const filePath = getTraceFilePath(runId, traceDir);
335
+ return await promises.readFile(filePath, "utf-8");
336
+ } catch (e) {
337
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
338
+ return void 0;
339
+ }
340
+ warn("Unexpected error reading trace file", e);
341
+ return void 0;
342
+ }
343
+ }
344
+ async function readTraceEvents(runId, traceDir) {
345
+ const out = [];
346
+ try {
347
+ const raw = await readTraceFile(runId, traceDir);
348
+ if (raw === void 0) {
349
+ return out;
350
+ }
351
+ const lines = raw.split("\n");
352
+ for (const line of lines) {
353
+ const trimmed = line.trim();
354
+ if (trimmed === "") continue;
355
+ let parsed;
356
+ try {
357
+ parsed = JSON.parse(trimmed);
358
+ } catch {
359
+ warn("Skipped invalid JSON line in trace file");
360
+ continue;
361
+ }
362
+ if (validateEvent(parsed)) {
363
+ out.push(parsed);
364
+ } else {
365
+ warn("Skipped invalid trace event line in trace file");
366
+ }
367
+ }
368
+ } catch (e) {
369
+ warn("Failed to read trace events", e);
370
+ }
371
+ return out;
372
+ }
373
+ async function listTraceFiles(traceDir) {
374
+ try {
375
+ const usable = path__default.default.resolve(traceDir);
376
+ const names = await promises.readdir(usable);
377
+ const jsonl = names.filter((n) => n.endsWith(".jsonl"));
378
+ const withStat = await Promise.all(
379
+ jsonl.map(async (name) => {
380
+ try {
381
+ const st = await promises.stat(path__default.default.join(usable, name));
382
+ return { name, mtime: st.mtimeMs };
383
+ } catch {
384
+ return { name, mtime: 0 };
385
+ }
386
+ })
387
+ );
388
+ withStat.sort((a, b) => {
389
+ if (b.mtime !== a.mtime) return b.mtime - a.mtime;
390
+ return a.name.localeCompare(b.name);
391
+ });
392
+ return withStat.map((x) => x.name);
393
+ } catch {
394
+ return [];
395
+ }
396
+ }
397
+ function getRunIdFromTraceFileName(fileName) {
398
+ try {
399
+ const base = path__default.default.basename(fileName);
400
+ if (!base.endsWith(".jsonl")) return void 0;
401
+ const id = base.slice(0, -".jsonl".length);
402
+ return id === "" ? void 0 : id;
403
+ } catch {
404
+ return void 0;
405
+ }
406
+ }
407
+ var TERMINAL_INDENT = " ";
408
+ var MAX_TERMINAL_NAME_LENGTH = 80;
409
+ var MAX_TERMINAL_DEPTH = 10;
410
+ function normalizeDepth(depth) {
411
+ if (!Number.isFinite(depth) || depth < 0) {
412
+ return 0;
413
+ }
414
+ return Math.min(Math.floor(depth), MAX_TERMINAL_DEPTH);
415
+ }
416
+ function safePrint(line = "") {
417
+ try {
418
+ console.log(line);
419
+ } catch {
420
+ }
421
+ }
422
+ function getIndent(depth) {
423
+ return TERMINAL_INDENT.repeat(normalizeDepth(depth));
424
+ }
425
+ function formatTerminalName(name) {
426
+ if (typeof name !== "string" || name.trim() === "") {
427
+ return "unnamed";
428
+ }
429
+ return truncateName(name, MAX_TERMINAL_NAME_LENGTH);
430
+ }
431
+ function getStatusIcon(status) {
432
+ if (status === "success") return chalk__default.default.green("\u2714");
433
+ if (status === "error") return chalk__default.default.red("\u2716");
434
+ return chalk__default.default.yellow("\u23F3");
435
+ }
436
+ function renderStepLine(name, durationMs, status, depth) {
437
+ try {
438
+ const nm = formatTerminalName(name);
439
+ const ind = getIndent(depth ?? 0);
440
+ if (status === "running" && durationMs === void 0) {
441
+ return `${ind}${chalk__default.default.yellow("\u23F3")} ${nm}`;
442
+ }
443
+ const hasDur = durationMs !== void 0 && Number.isFinite(durationMs);
444
+ const dur = hasDur ? formatDuration(durationMs) : void 0;
445
+ if (status === "running") {
446
+ return dur !== void 0 ? `${ind}${chalk__default.default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${chalk__default.default.yellow("\u23F3")} ${nm}`;
447
+ }
448
+ if (!hasDur || dur === void 0) {
449
+ return `${ind}${chalk__default.default.yellow("\u23F3")} ${nm}`;
450
+ }
451
+ if (status === "success") {
452
+ return `${ind}${getStatusIcon("success")} ${nm} (${dur})`;
453
+ }
454
+ return `${ind}${getStatusIcon("error")} ${nm} (${dur})`;
455
+ } catch {
456
+ return "";
457
+ }
458
+ }
459
+ function renderErrorLine(error, depth) {
460
+ try {
461
+ const msg = typeof error.message === "string" ? error.message : "";
462
+ const ind = getIndent((depth ?? 0) + 1);
463
+ return `${ind}Error: ${msg}`;
464
+ } catch {
465
+ return "";
466
+ }
467
+ }
468
+ function printStepStart(name, depth = 0) {
469
+ if (isSilentContext()) return;
470
+ try {
471
+ safePrint(renderStepLine(name, void 0, "running", depth));
472
+ } catch {
473
+ }
474
+ }
475
+ function printStepComplete(name, durationMs, status, depth = 0) {
476
+ if (isSilentContext()) return;
477
+ try {
478
+ safePrint(renderStepLine(name, durationMs, status, depth));
479
+ } catch {
480
+ }
481
+ }
482
+ function printError(error, depth = 0) {
483
+ if (isSilentContext()) return;
484
+ try {
485
+ safePrint(renderErrorLine(error, depth));
486
+ } catch {
487
+ }
488
+ }
489
+ function printFailedAt(stepName) {
490
+ if (isSilentContext()) return;
491
+ try {
492
+ safePrint(`Failed at: ${formatTerminalName(stepName)}`);
493
+ } catch {
494
+ }
495
+ }
496
+ function normalizeStepName(name) {
497
+ if (typeof name !== "string" || name.trim() === "") {
498
+ return "unnamed-step";
499
+ }
500
+ return truncateName(name.trim(), 100);
501
+ }
502
+ async function safeInstrumentation2(label, op) {
503
+ try {
504
+ await Promise.resolve(op());
505
+ } catch (e) {
506
+ warn(`step: ${label}`, e);
507
+ }
508
+ }
509
+ async function stepImpl(name, fn, options) {
510
+ if (typeof fn !== "function") {
511
+ throw new TypeError("step requires `fn` to be a function");
512
+ }
513
+ const stepName = normalizeStepName(name);
514
+ const context = getCurrentContext();
515
+ if (!context) {
516
+ warn("step() called outside inspectRun(); executing without instrumentation");
517
+ return Promise.resolve(fn());
518
+ }
519
+ const stepId = createStepId();
520
+ const renderDepth = getCurrentDepth();
521
+ const parentId = getParentStepId();
522
+ const stepType = options?.type ?? "logic";
523
+ const metadata = options?.metadata;
524
+ const startTime = Date.now();
525
+ await safeInstrumentation2("writeTraceEvent(step_started)", async () => {
526
+ const started = {
527
+ schemaVersion: "0.1",
528
+ event: "step_started",
529
+ timestamp: startTime,
530
+ runId: context.runId,
531
+ stepId,
532
+ ...typeof parentId === "string" && parentId.trim() !== "" ? { parentId } : {},
533
+ name: stepName,
534
+ type: stepType,
535
+ startTime,
536
+ ...metadata !== void 0 ? { metadata } : {}
537
+ };
538
+ await writeTraceEvent(started, context.traceDir);
539
+ });
540
+ await safeInstrumentation2("printStepStart", () => {
541
+ printStepStart(stepName, renderDepth);
542
+ });
543
+ let result;
544
+ try {
545
+ result = await runWithStepContext(stepId, async () => {
546
+ return await Promise.resolve(fn());
547
+ });
548
+ } catch (userError) {
549
+ const endTime2 = Date.now();
550
+ const durationMs2 = endTime2 - startTime;
551
+ const formatted = formatError(userError);
552
+ await safeInstrumentation2("writeTraceEvent(step_completed error)", async () => {
553
+ const completed = {
554
+ schemaVersion: "0.1",
555
+ event: "step_completed",
556
+ timestamp: endTime2,
557
+ runId: context.runId,
558
+ stepId,
559
+ status: "error",
560
+ endTime: endTime2,
561
+ durationMs: durationMs2,
562
+ error: formatted
563
+ };
564
+ await writeTraceEvent(completed, context.traceDir);
565
+ });
566
+ await safeInstrumentation2("printStepComplete(error)", () => {
567
+ printStepComplete(stepName, durationMs2, "error", renderDepth);
568
+ });
569
+ await safeInstrumentation2("printError", () => {
570
+ printError(formatted, renderDepth);
571
+ });
572
+ await safeInstrumentation2("printFailedAt", () => {
573
+ printFailedAt(stepName);
574
+ });
575
+ throw userError;
576
+ }
577
+ const endTime = Date.now();
578
+ const durationMs = endTime - startTime;
579
+ await safeInstrumentation2("writeTraceEvent(step_completed success)", async () => {
580
+ const completed = {
581
+ schemaVersion: "0.1",
582
+ event: "step_completed",
583
+ timestamp: endTime,
584
+ runId: context.runId,
585
+ stepId,
586
+ status: "success",
587
+ endTime,
588
+ durationMs
589
+ };
590
+ await writeTraceEvent(completed, context.traceDir);
591
+ });
592
+ await safeInstrumentation2("printStepComplete(success)", () => {
593
+ printStepComplete(stepName, durationMs, "success", renderDepth);
594
+ });
595
+ return result;
596
+ }
597
+ async function stepLlm(model, fn) {
598
+ const modelName = typeof model === "string" && model.trim() !== "" ? model.trim() : "unknown-model";
599
+ return stepImpl(`llm:${modelName}`, fn, {
600
+ type: "llm",
601
+ metadata: { model: modelName }
602
+ });
603
+ }
604
+ async function stepTool(toolName, fn) {
605
+ const normalized = typeof toolName === "string" && toolName.trim() !== "" ? toolName.trim() : "unknown-tool";
606
+ return stepImpl(`tool:${normalized}`, fn, {
607
+ type: "tool",
608
+ metadata: { toolName: normalized }
609
+ });
610
+ }
611
+ Object.assign(stepImpl, {
612
+ llm: stepLlm,
613
+ tool: stepTool
614
+ });
615
+
616
+ // packages/cli/src/list.ts
617
+ function parseLimit(raw) {
618
+ const fallback = 20;
619
+ if (raw === void 0 || raw.trim() === "") return fallback;
620
+ const n = Number.parseInt(raw, 10);
621
+ if (!Number.isFinite(n) || n <= 0) return fallback;
622
+ return Math.min(n, 100);
623
+ }
624
+ function isStatusFilter(value) {
625
+ return value === "running" || value === "success" || value === "error";
626
+ }
627
+ function buildRunSummary(runId, events) {
628
+ const started = events.find(
629
+ (e) => e.event === "run_started"
630
+ );
631
+ if (!started) return void 0;
632
+ const completed = events.filter(
633
+ (e) => e.event === "run_completed"
634
+ );
635
+ const last = completed[completed.length - 1];
636
+ const status = last ? last.status : "running";
637
+ const startTime = Number.isFinite(started.startTime) ? started.startTime : Number.isFinite(started.timestamp) ? started.timestamp : 0;
638
+ const name = typeof started.name === "string" && started.name.trim() !== "" ? started.name.trim() : "unknown-run";
639
+ return {
640
+ runId,
641
+ name,
642
+ status,
643
+ durationMs: last !== void 0 ? last.durationMs : void 0,
644
+ startTime
645
+ };
646
+ }
647
+ function statusIcon(status) {
648
+ if (status === "success") return "\u2713";
649
+ if (status === "error") return "\u2717";
650
+ return "\u23F3";
651
+ }
652
+ function durationCell(status, durationMs) {
653
+ if (status === "running") return "-";
654
+ if (durationMs !== void 0 && Number.isFinite(durationMs)) {
655
+ return formatDuration(durationMs);
656
+ }
657
+ return "-";
658
+ }
659
+ function timestampCell(startTime) {
660
+ if (!Number.isFinite(startTime) || startTime <= 0) return "Invalid date";
661
+ const s = formatTimestamp(startTime);
662
+ return s === "Invalid date" ? "Invalid date" : s;
663
+ }
664
+ async function list(options = {}) {
665
+ try {
666
+ const traceDir = typeof options.dir === "string" && options.dir.trim() !== "" ? options.dir.trim() : getDefaultTraceDir();
667
+ const files = await listTraceFiles(traceDir);
668
+ if (files.length === 0) {
669
+ console.log("No AgentInspect runs found");
670
+ console.log(`Trace directory: ${traceDir}`);
671
+ return;
672
+ }
673
+ const summaries = [];
674
+ for (const fileName of files) {
675
+ try {
676
+ const runId = getRunIdFromTraceFileName(fileName);
677
+ if (runId === void 0) continue;
678
+ const events = await readTraceEvents(runId, traceDir);
679
+ const row = buildRunSummary(runId, events);
680
+ if (row !== void 0) summaries.push(row);
681
+ } catch {
682
+ }
683
+ }
684
+ if (summaries.length === 0) {
685
+ console.log("No AgentInspect runs found");
686
+ console.log(`Trace directory: ${traceDir}`);
687
+ return;
688
+ }
689
+ summaries.sort((a, b) => b.startTime - a.startTime);
690
+ const statusFilter = isStatusFilter(options.status) ? options.status : void 0;
691
+ const filtered = statusFilter === void 0 ? summaries : summaries.filter((s) => s.status === statusFilter);
692
+ const limit = parseLimit(options.limit);
693
+ const shown = filtered.slice(0, limit);
694
+ console.log("Recent AgentInspect Runs");
695
+ for (const s of shown) {
696
+ const icon = statusIcon(s.status);
697
+ const dur = durationCell(s.status, s.durationMs);
698
+ const ts = timestampCell(s.startTime);
699
+ const nm = truncateName(s.name, 80);
700
+ console.log(`${icon} ${s.runId} | ${nm} | ${dur} | ${ts}`);
701
+ }
702
+ console.log("");
703
+ console.log(`Showing ${shown.length} of ${filtered.length} runs`);
704
+ console.log(`Trace directory: ${traceDir}`);
705
+ } catch (e) {
706
+ const msg = e instanceof Error ? e.message : String(e);
707
+ console.error(`[AgentInspect] list failed: ${msg}`);
708
+ process.exitCode = 1;
709
+ }
710
+ }
711
+
712
+ // packages/cli/src/view.ts
713
+ function buildStepTree(events) {
714
+ const nodes = /* @__PURE__ */ new Map();
715
+ for (const e of events) {
716
+ if (e.event === "step_started") {
717
+ const s = e;
718
+ nodes.set(s.stepId, {
719
+ id: s.stepId,
720
+ parentId: s.parentId,
721
+ name: s.name,
722
+ type: s.type,
723
+ status: "running",
724
+ startedAt: s.startTime,
725
+ metadata: s.metadata,
726
+ children: []
727
+ });
728
+ }
729
+ }
730
+ for (const e of events) {
731
+ if (e.event !== "step_completed") continue;
732
+ const c = e;
733
+ const node = nodes.get(c.stepId);
734
+ if (!node) continue;
735
+ node.status = c.status;
736
+ node.durationMs = c.durationMs;
737
+ node.error = c.error;
738
+ }
739
+ const roots = [];
740
+ for (const n of nodes.values()) {
741
+ if (n.parentId !== void 0 && nodes.has(n.parentId)) {
742
+ nodes.get(n.parentId).children.push(n);
743
+ } else {
744
+ roots.push(n);
745
+ }
746
+ }
747
+ const sortByStarted = (a, b) => a.startedAt - b.startedAt;
748
+ roots.sort(sortByStarted);
749
+ for (const n of nodes.values()) {
750
+ n.children.sort(sortByStarted);
751
+ }
752
+ return roots;
753
+ }
754
+ function printStepTree(nodes, depth, verbose) {
755
+ for (const node of nodes) {
756
+ console.log(
757
+ renderStepLine(node.name, node.durationMs, node.status, depth)
758
+ );
759
+ if (node.error !== void 0) {
760
+ if (verbose) {
761
+ console.log(renderErrorLine(node.error, depth + 1));
762
+ if (typeof node.error.stack === "string" && node.error.stack.trim() !== "") {
763
+ console.log(node.error.stack);
764
+ }
765
+ } else {
766
+ console.log(
767
+ renderErrorLine({ message: node.error.message }, depth + 1)
768
+ );
769
+ }
770
+ }
771
+ if (verbose) {
772
+ console.log(`${getIndent(depth + 1)}type: ${node.type}`);
773
+ if (node.metadata !== void 0 && Object.keys(node.metadata).length > 0) {
774
+ try {
775
+ console.log(
776
+ `${getIndent(depth + 1)}metadata: ${JSON.stringify(node.metadata)}`
777
+ );
778
+ } catch {
779
+ }
780
+ }
781
+ }
782
+ printStepTree(node.children, depth + 1, verbose);
783
+ }
784
+ }
785
+ async function view(runId, options = {}) {
786
+ try {
787
+ const id = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "";
788
+ if (id === "") {
789
+ console.error("Run id is required");
790
+ process.exitCode = 1;
791
+ return;
792
+ }
793
+ const traceDir = typeof options.dir === "string" && options.dir.trim() !== "" ? options.dir.trim() : getDefaultTraceDir();
794
+ const events = await readTraceEvents(id, traceDir);
795
+ if (events.length === 0) {
796
+ console.log(`Run not found: ${id}`);
797
+ console.log(`Trace directory: ${traceDir}`);
798
+ process.exitCode = 1;
799
+ return;
800
+ }
801
+ if (options.json) {
802
+ console.log(JSON.stringify(events, null, 2));
803
+ return;
804
+ }
805
+ const started = events.find(
806
+ (e) => e.event === "run_started"
807
+ );
808
+ if (!started) {
809
+ console.error("Invalid trace: missing run_started");
810
+ process.exitCode = 1;
811
+ return;
812
+ }
813
+ const completed = events.filter(
814
+ (e) => e.event === "run_completed"
815
+ );
816
+ const last = completed[completed.length - 1];
817
+ const status = last ? last.status : "running";
818
+ const durationLine = last !== void 0 && Number.isFinite(last.durationMs) ? formatDuration(last.durationMs) : "-";
819
+ const startedTs = Number.isFinite(started.startTime) ? started.startTime : started.timestamp;
820
+ const startedLabel = formatTimestamp(startedTs);
821
+ console.log(`AgentInspect Run: ${started.name}`);
822
+ console.log(`ID: ${id}`);
823
+ console.log(`Status: ${status}`);
824
+ console.log(`Duration: ${durationLine}`);
825
+ console.log(`Started: ${startedLabel}`);
826
+ console.log("");
827
+ const tree = buildStepTree(events);
828
+ console.log("Execution Tree:");
829
+ if (tree.length === 0) {
830
+ console.log("No steps recorded");
831
+ } else {
832
+ printStepTree(tree, 0, options.verbose === true);
833
+ }
834
+ console.log("");
835
+ console.log(`Trace file: ${getTraceFilePath(id, traceDir)}`);
836
+ } catch (e) {
837
+ const msg = e instanceof Error ? e.message : String(e);
838
+ console.error(`[AgentInspect] view failed: ${msg}`);
839
+ process.exitCode = 1;
840
+ }
841
+ }
842
+
843
+ // packages/cli/src/index.ts
844
+ function runCommand(action) {
845
+ void action().catch((error) => {
846
+ const msg = error instanceof Error ? error.message : String(error);
847
+ console.error(`[AgentInspect] ${msg}`);
848
+ process.exitCode = 1;
849
+ });
850
+ }
851
+ function createCliProgram() {
852
+ const program = new commander.Command("agent-inspect").description("Local-first execution-tree debugger for AI agents").version("0.1.0");
853
+ program.command("list").description("List recent AgentInspect runs").option("--dir <path>", "trace directory").option("--limit <number>", "max runs to show (default 20, max 100)").addOption(
854
+ new commander.Option("--status <status>", "filter by run status").choices([
855
+ "running",
856
+ "success",
857
+ "error"
858
+ ])
859
+ ).action(
860
+ (opts) => {
861
+ runCommand(() => list(opts));
862
+ }
863
+ );
864
+ program.command("view").description("View a single run trace").argument("<run-id>", "run id (e.g. from list output)").option("--dir <path>", "trace directory").option("--verbose", "show extra detail (types, metadata, error stacks)").option("--json", "print raw trace events as JSON").action(
865
+ (runId, opts) => {
866
+ runCommand(() => view(runId, opts));
867
+ }
868
+ );
869
+ return program;
870
+ }
871
+ function isPrimaryModule() {
872
+ const entry = process.argv[1];
873
+ if (!entry) return false;
874
+ const selfPath = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
875
+ try {
876
+ return fs.realpathSync(path__default.default.resolve(entry)) === fs.realpathSync(path__default.default.resolve(selfPath));
877
+ } catch {
878
+ return path__default.default.resolve(entry) === path__default.default.resolve(selfPath);
879
+ }
880
+ }
881
+ if (isPrimaryModule()) {
882
+ createCliProgram().parse(process.argv);
883
+ }
884
+
885
+ exports.createCliProgram = createCliProgram;
886
+ exports.runCommand = runCommand;
887
+ //# sourceMappingURL=index.cjs.map
888
+ //# sourceMappingURL=index.cjs.map