agent-inspect 3.0.0 → 3.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.
@@ -5,15 +5,16 @@ import { fileURLToPath, pathToFileURL } from 'url';
5
5
  import { Command, Option } from 'commander';
6
6
  import { AsyncLocalStorage } from 'async_hooks';
7
7
  import crypto, { webcrypto, createHash } from 'crypto';
8
- import { unlink, stat, mkdir, writeFile, appendFile, readdir, readFile, access, open } from 'fs/promises';
8
+ import { unlink, stat, mkdir, writeFile, appendFile, readdir, readFile, access, open, constants } from 'fs/promises';
9
9
  import os from 'os';
10
- import process2, { stdin, stdout } from 'process';
10
+ import process3, { stdin, stdout } from 'process';
11
11
  import tty from 'tty';
12
12
  import { createInterface } from 'readline';
13
13
  import { createServer } from 'http';
14
+ import { createRequire } from 'module';
14
15
 
15
16
  // package.json
16
- var version = "3.0.0";
17
+ var version = "3.2.0";
17
18
 
18
19
  // packages/core/src/correlation-metadata.ts
19
20
  var TRACE_CORRELATION_KEYS = [
@@ -1177,13 +1178,13 @@ function assembleStyles() {
1177
1178
  }
1178
1179
  var ansiStyles = assembleStyles();
1179
1180
  var ansi_styles_default = ansiStyles;
1180
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
1181
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process3.argv) {
1181
1182
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
1182
1183
  const position = argv.indexOf(prefix + flag);
1183
1184
  const terminatorPosition = argv.indexOf("--");
1184
1185
  return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
1185
1186
  }
1186
- var { env } = process2;
1187
+ var { env } = process3;
1187
1188
  var flagForceColor;
1188
1189
  if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
1189
1190
  flagForceColor = 0;
@@ -1239,7 +1240,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
1239
1240
  if (env.TERM === "dumb") {
1240
1241
  return min;
1241
1242
  }
1242
- if (process2.platform === "win32") {
1243
+ if (process3.platform === "win32") {
1243
1244
  const osRelease = os.release().split(".");
1244
1245
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
1245
1246
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
@@ -3059,12 +3060,12 @@ function buildCriticalPath(runs, handoffs) {
3059
3060
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
3060
3061
  );
3061
3062
  const ordered = [...runs].sort(compareRuns);
3062
- const path16 = [];
3063
+ const path18 = [];
3063
3064
  const visited = /* @__PURE__ */ new Set();
3064
3065
  const pushRun = (run, confidence, source) => {
3065
3066
  if (visited.has(run.runId)) return;
3066
3067
  visited.add(run.runId);
3067
- path16.push({
3068
+ path18.push({
3068
3069
  runId: run.runId,
3069
3070
  name: run.name,
3070
3071
  startedAt: run.startedAt,
@@ -3089,7 +3090,7 @@ function buildCriticalPath(runs, handoffs) {
3089
3090
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
3090
3091
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
3091
3092
  }
3092
- return path16;
3093
+ return path18;
3093
3094
  }
3094
3095
  function metaRunIdMatches(run, token, runById) {
3095
3096
  const meta = extractSessionWorkflowMetadata(run.metadata);
@@ -8332,13 +8333,13 @@ function pairSteps(left, right) {
8332
8333
  return pairs;
8333
8334
  }
8334
8335
  function compareLeafSteps(L, R, segments, opts, out) {
8335
- const path16 = buildPath(segments);
8336
+ const path18 = buildPath(segments);
8336
8337
  if (L.name !== R.name) {
8337
8338
  out.push({
8338
8339
  kind: "structure",
8339
8340
  severity: "warning",
8340
8341
  message: "Step name differs",
8341
- path: path16,
8342
+ path: path18,
8342
8343
  left: L.name,
8343
8344
  right: R.name
8344
8345
  });
@@ -8348,7 +8349,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
8348
8349
  kind: "step-type",
8349
8350
  severity: "warning",
8350
8351
  message: "Step type differs",
8351
- path: path16,
8352
+ path: path18,
8352
8353
  left: L.type,
8353
8354
  right: R.type
8354
8355
  });
@@ -8358,7 +8359,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
8358
8359
  kind: "step-status",
8359
8360
  severity: "warning",
8360
8361
  message: "Step status differs",
8361
- path: path16,
8362
+ path: path18,
8362
8363
  left: L.status,
8363
8364
  right: R.status
8364
8365
  });
@@ -8370,7 +8371,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
8370
8371
  kind: "error",
8371
8372
  severity: "error",
8372
8373
  message: "Step error message differs",
8373
- path: path16,
8374
+ path: path18,
8374
8375
  left: le || void 0,
8375
8376
  right: re || void 0
8376
8377
  });
@@ -8388,7 +8389,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
8388
8389
  kind: "duration",
8389
8390
  severity: "info",
8390
8391
  message: "Step duration differs",
8391
- path: path16,
8392
+ path: path18,
8392
8393
  left: ld,
8393
8394
  right: rd
8394
8395
  });
@@ -8401,7 +8402,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
8401
8402
  kind: "metadata",
8402
8403
  severity: "info",
8403
8404
  message: "Step metadata differs",
8404
- path: path16,
8405
+ path: path18,
8405
8406
  left: L.metadata,
8406
8407
  right: R.metadata
8407
8408
  });
@@ -8413,7 +8414,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
8413
8414
  kind: "output",
8414
8415
  severity: "info",
8415
8416
  message: "Output preview differs",
8416
- path: path16,
8417
+ path: path18,
8417
8418
  left: L.outputPreview,
8418
8419
  right: R.outputPreview
8419
8420
  });
@@ -8573,11 +8574,11 @@ function diffRuns(left, right, options) {
8573
8574
  }
8574
8575
 
8575
8576
  // packages/core/src/diff/renderer.ts
8576
- function formatPath(path16) {
8577
- if (path16 === void 0 || path16.path.length === 0) {
8577
+ function formatPath(path18) {
8578
+ if (path18 === void 0 || path18.path.length === 0) {
8578
8579
  return "(run)";
8579
8580
  }
8580
- return path16.path.map((s) => s.name).join(" > ");
8581
+ return path18.path.map((s) => s.name).join(" > ");
8581
8582
  }
8582
8583
  function formatValue(v, verbose) {
8583
8584
  if (v === void 0) return "(undefined)";
@@ -9455,17 +9456,17 @@ function applyRule(rule, value, replacement) {
9455
9456
  }
9456
9457
  return value;
9457
9458
  }
9458
- function childPath(path16, key) {
9459
+ function childPath(path18, key) {
9459
9460
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
9460
- return path16 ? `${path16}.${key}` : key;
9461
+ return path18 ? `${path18}.${key}` : key;
9461
9462
  }
9462
- return `${path16 || "$"}[${JSON.stringify(key)}]`;
9463
+ return `${path18 || "$"}[${JSON.stringify(key)}]`;
9463
9464
  }
9464
- function indexPath(path16, index) {
9465
- return `${path16 || "$"}[${index}]`;
9465
+ function indexPath(path18, index) {
9466
+ return `${path18 || "$"}[${index}]`;
9466
9467
  }
9467
- function makeFinding(path16, detector, action, matchKind, severity = "warning", preview) {
9468
- return preview === void 0 ? { path: path16, detector, action, severity, matchKind } : { path: path16, detector, action, severity, matchKind, preview };
9468
+ function makeFinding(path18, detector, action, matchKind, severity = "warning", preview) {
9469
+ return preview === void 0 ? { path: path18, detector, action, severity, matchKind } : { path: path18, detector, action, severity, matchKind, preview };
9469
9470
  }
9470
9471
  function createRedactionProfile(profile = "local") {
9471
9472
  switch (profile) {
@@ -9534,11 +9535,11 @@ var Redactor2 = class {
9534
9535
  #recordFinding(state, finding) {
9535
9536
  if (this.#collectFindings) state.findings.push(finding);
9536
9537
  }
9537
- #redactValue(value, key, path16, depth, state) {
9538
+ #redactValue(value, key, path18, depth, state) {
9538
9539
  if (depth > this.#maxDepth) {
9539
9540
  this.#recordFinding(
9540
9541
  state,
9541
- makeFinding(path16, "structure.maxDepth", "truncate", "value", "warning")
9542
+ makeFinding(path18, "structure.maxDepth", "truncate", "value", "warning")
9542
9543
  );
9543
9544
  return "[Truncated]";
9544
9545
  }
@@ -9547,19 +9548,19 @@ var Redactor2 = class {
9547
9548
  if (rule) {
9548
9549
  this.#recordFinding(
9549
9550
  state,
9550
- makeFinding(path16, `key.${rule.key}`, actionForRule(rule), "key", "warning")
9551
+ makeFinding(path18, `key.${rule.key}`, actionForRule(rule), "key", "warning")
9551
9552
  );
9552
9553
  return applyRule(rule, value, this.#replacement);
9553
9554
  }
9554
9555
  }
9555
9556
  for (const detector of this.#detectors) {
9556
- const detections = detector.detect({ path: path16, key, value });
9557
+ const detections = detector.detect({ path: path18, key, value });
9557
9558
  for (const detection of detections) {
9558
9559
  const action = detection.action ?? "replace";
9559
9560
  this.#recordFinding(
9560
9561
  state,
9561
9562
  makeFinding(
9562
- path16,
9563
+ path18,
9563
9564
  detector.id,
9564
9565
  action,
9565
9566
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -9577,7 +9578,7 @@ var Redactor2 = class {
9577
9578
  const out = [];
9578
9579
  state.seen.set(value, out);
9579
9580
  value.forEach((item, index) => {
9580
- out[index] = this.#redactValue(item, void 0, indexPath(path16, index), depth + 1, state);
9581
+ out[index] = this.#redactValue(item, void 0, indexPath(path18, index), depth + 1, state);
9581
9582
  });
9582
9583
  return out;
9583
9584
  }
@@ -9589,7 +9590,7 @@ var Redactor2 = class {
9589
9590
  out[entryKey] = this.#redactValue(
9590
9591
  entryValue,
9591
9592
  entryKey,
9592
- childPath(path16 === "$" ? "" : path16, entryKey),
9593
+ childPath(path18 === "$" ? "" : path18, entryKey),
9593
9594
  depth + 1,
9594
9595
  state
9595
9596
  );
@@ -10461,7 +10462,7 @@ function stripPrefix(name, prefixes) {
10461
10462
  }
10462
10463
  return name;
10463
10464
  }
10464
- function eventEvidence(event, path16) {
10465
+ function eventEvidence(event, path18) {
10465
10466
  return {
10466
10467
  runId: event.runId,
10467
10468
  eventId: event.eventId,
@@ -10471,7 +10472,7 @@ function eventEvidence(event, path16) {
10471
10472
  kind: event.kind,
10472
10473
  name: event.name,
10473
10474
  status: event.status,
10474
- ...path16 ? { path: path16 } : {}
10475
+ ...path18 ? { path: path18 } : {}
10475
10476
  };
10476
10477
  }
10477
10478
  function runEvidence(run) {
@@ -10534,9 +10535,9 @@ function eventEndMs(event) {
10534
10535
  function normalizedKey(value) {
10535
10536
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
10536
10537
  }
10537
- function lastPathSegment(path16) {
10538
- const parts = path16.split(".");
10539
- return parts[parts.length - 1] ?? path16;
10538
+ function lastPathSegment(path18) {
10539
+ const parts = path18.split(".");
10540
+ return parts[parts.length - 1] ?? path18;
10540
10541
  }
10541
10542
  function valueType(value) {
10542
10543
  if (Array.isArray(value)) return "array";
@@ -10550,12 +10551,12 @@ function serializedByteLength(value) {
10550
10551
  return void 0;
10551
10552
  }
10552
10553
  }
10553
- function pushValueEntries(entries, event, value, path16, key, depth = 0) {
10554
- entries.push({ event, path: path16, key, value });
10554
+ function pushValueEntries(entries, event, value, path18, key, depth = 0) {
10555
+ entries.push({ event, path: path18, key, value });
10555
10556
  if (depth >= 8) return;
10556
10557
  if (Array.isArray(value)) {
10557
10558
  for (const [index, item] of value.entries()) {
10558
- pushValueEntries(entries, event, item, `${path16}.${index}`, String(index), depth + 1);
10559
+ pushValueEntries(entries, event, item, `${path18}.${index}`, String(index), depth + 1);
10559
10560
  }
10560
10561
  return;
10561
10562
  }
@@ -10565,7 +10566,7 @@ function pushValueEntries(entries, event, value, path16, key, depth = 0) {
10565
10566
  entries,
10566
10567
  event,
10567
10568
  value[nestedKey],
10568
- `${path16}.${nestedKey}`,
10569
+ `${path18}.${nestedKey}`,
10569
10570
  nestedKey,
10570
10571
  depth + 1
10571
10572
  );
@@ -10646,9 +10647,9 @@ function eventDurationMs(event) {
10646
10647
  }
10647
10648
  function treeShape(nodes) {
10648
10649
  const lines = [];
10649
- const visit = (node, path16) => {
10650
- lines.push(`${path16}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
10651
- node.children.forEach((child, index) => visit(child, `${path16}.${index}`));
10650
+ const visit = (node, path18) => {
10651
+ lines.push(`${path18}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
10652
+ node.children.forEach((child, index) => visit(child, `${path18}.${index}`));
10652
10653
  };
10653
10654
  nodes.forEach((node, index) => visit(node, String(index)));
10654
10655
  return lines;
@@ -10697,9 +10698,9 @@ function retrievalShape(context) {
10697
10698
  function guardrailShape(context) {
10698
10699
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
10699
10700
  }
10700
- function firstEvidenceForKind(context, kind, path16) {
10701
+ function firstEvidenceForKind(context, kind, path18) {
10701
10702
  const event = context.events.find((candidate) => candidate.kind === kind);
10702
- return event ? [eventEvidence(event, path16)] : runEvidence(context.selectedRun);
10703
+ return event ? [eventEvidence(event, path18)] : runEvidence(context.selectedRun);
10703
10704
  }
10704
10705
  function baselineDiffFinding(message, evidence, expected, actual) {
10705
10706
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -10947,13 +10948,13 @@ function createStructureCycleRule() {
10947
10948
  const seenCycles = /* @__PURE__ */ new Set();
10948
10949
  const findings = [];
10949
10950
  for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
10950
- const path16 = [];
10951
+ const path18 = [];
10951
10952
  const seenAt = /* @__PURE__ */ new Map();
10952
10953
  let current = event;
10953
10954
  while (current) {
10954
10955
  const existing = seenAt.get(current.eventId);
10955
10956
  if (existing !== void 0) {
10956
- const cycle = path16.slice(existing);
10957
+ const cycle = path18.slice(existing);
10957
10958
  const key = cycle.map((item) => item.eventId).sort().join("\0");
10958
10959
  if (!seenCycles.has(key)) {
10959
10960
  seenCycles.add(key);
@@ -10969,8 +10970,8 @@ function createStructureCycleRule() {
10969
10970
  }
10970
10971
  break;
10971
10972
  }
10972
- seenAt.set(current.eventId, path16.length);
10973
- path16.push(current);
10973
+ seenAt.set(current.eventId, path18.length);
10974
+ path18.push(current);
10974
10975
  current = current.parentId ? byId.get(current.parentId) : void 0;
10975
10976
  }
10976
10977
  }
@@ -11767,23 +11768,23 @@ function evaluatePromptInjection(text, options = {}) {
11767
11768
  }
11768
11769
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
11769
11770
  }
11770
- function validateSchemaField(value, field, path16, evidence) {
11771
+ function validateSchemaField(value, field, path18, evidence) {
11771
11772
  const ruleId = "guardrail.structured-output";
11772
11773
  if (field.type) {
11773
11774
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
11774
11775
  if (actual !== field.type) {
11775
- evidence.push({ ruleId, path: path16, preview: `expected ${field.type}, got ${actual}` });
11776
+ evidence.push({ ruleId, path: path18, preview: `expected ${field.type}, got ${actual}` });
11776
11777
  return;
11777
11778
  }
11778
11779
  }
11779
11780
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
11780
- evidence.push({ ruleId, path: path16, preview: "value not in enum" });
11781
+ evidence.push({ ruleId, path: path18, preview: "value not in enum" });
11781
11782
  }
11782
11783
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
11783
11784
  const record = value;
11784
11785
  for (const key of field.required) {
11785
11786
  if (!(key in record)) {
11786
- evidence.push({ ruleId, path: `${path16}.${key}`, preview: "missing required key" });
11787
+ evidence.push({ ruleId, path: `${path18}.${key}`, preview: "missing required key" });
11787
11788
  }
11788
11789
  }
11789
11790
  }
@@ -12248,10 +12249,10 @@ function printHuman(result) {
12248
12249
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
12249
12250
  }
12250
12251
  for (const finding of result.findings) {
12251
- const path16 = finding.evidence[0]?.path;
12252
+ const path18 = finding.evidence[0]?.path;
12252
12253
  const run = finding.evidence[0]?.runId;
12253
12254
  const runPrefix = run ? `[${run}] ` : "";
12254
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
12255
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
12255
12256
  }
12256
12257
  }
12257
12258
  function readErrorResult(error) {
@@ -12789,10 +12790,10 @@ async function evalRun(input3, options = {}) {
12789
12790
  diagnostics: []
12790
12791
  };
12791
12792
  }
12792
- function evidenceForRun(run, path16) {
12793
- return [{ runId: run.runId, ...path16 !== void 0 ? { path: path16 } : {} }];
12793
+ function evidenceForRun(run, path18) {
12794
+ return [{ runId: run.runId, ...path18 !== void 0 ? { path: path18 } : {} }];
12794
12795
  }
12795
- function evidenceForEvent(event, path16) {
12796
+ function evidenceForEvent(event, path18) {
12796
12797
  return [
12797
12798
  {
12798
12799
  runId: event.runId,
@@ -12800,7 +12801,7 @@ function evidenceForEvent(event, path16) {
12800
12801
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
12801
12802
  kind: event.kind,
12802
12803
  name: event.name,
12803
- ...path16 !== void 0 ? { path: path16 } : {}
12804
+ ...path18 !== void 0 ? { path: path18 } : {}
12804
12805
  }
12805
12806
  ];
12806
12807
  }
@@ -12958,9 +12959,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
12958
12959
  function tokenize(text) {
12959
12960
  return [...text.toLowerCase().matchAll(/[a-z0-9][a-z0-9'-]{2,}/g)].map((match) => match[0].replace(/^['-]+|['-]+$/g, "")).filter((token) => token.length > 2 && !STOP_WORDS.has(token));
12960
12961
  }
12961
- function firstEvidence(fields, run, path16) {
12962
+ function firstEvidence(fields, run, path18) {
12962
12963
  const first = fields[0];
12963
- return first === void 0 ? evidenceForRun(run, path16) : evidenceForEvent(first.node.event, first.path);
12964
+ return first === void 0 ? evidenceForRun(run, path18) : evidenceForEvent(first.node.event, first.path);
12964
12965
  }
12965
12966
  function collectSourceIds(nodes, keys) {
12966
12967
  const wanted = keySet(keys);
@@ -13337,8 +13338,8 @@ function renderEvalMarkdown(result) {
13337
13338
  if (result.findings.length > 0) {
13338
13339
  lines.push("", "## Findings");
13339
13340
  for (const finding of result.findings) {
13340
- const path16 = finding.evidence[0]?.path;
13341
- lines.push(`- ${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
13341
+ const path18 = finding.evidence[0]?.path;
13342
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
13342
13343
  }
13343
13344
  }
13344
13345
  return `${lines.join("\n")}
@@ -13531,8 +13532,8 @@ function printHuman2(result) {
13531
13532
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
13532
13533
  }
13533
13534
  for (const finding of result.findings) {
13534
- const path16 = finding.evidence[0]?.path;
13535
- console.log(`- ${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
13535
+ const path18 = finding.evidence[0]?.path;
13536
+ console.log(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
13536
13537
  }
13537
13538
  }
13538
13539
  function readErrorResult2(error) {
@@ -13770,8 +13771,8 @@ function printHuman3(result) {
13770
13771
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
13771
13772
  }
13772
13773
  for (const finding of result.findings) {
13773
- const path16 = finding.evidence[0]?.path;
13774
- console.log(`- ${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
13774
+ const path18 = finding.evidence[0]?.path;
13775
+ console.log(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
13775
13776
  }
13776
13777
  console.log(`Note: ${result.note}`);
13777
13778
  }
@@ -13890,8 +13891,8 @@ function renderCheckSection(result) {
13890
13891
  `Diagnostics: ${result.diagnostics.length}`
13891
13892
  ];
13892
13893
  for (const finding of result.findings.slice(0, 10)) {
13893
- const path16 = finding.evidence[0]?.path ?? "(run)";
13894
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path16})`);
13894
+ const path18 = finding.evidence[0]?.path ?? "(run)";
13895
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path18})`);
13895
13896
  }
13896
13897
  for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
13897
13898
  lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
@@ -14451,6 +14452,447 @@ ${markdown}`, "utf-8");
14451
14452
  console.log(markdown.trimEnd());
14452
14453
  }
14453
14454
  }
14455
+ var CONFIG_FILE = "agent-inspect.config.ts";
14456
+ var TRACE_DIR = ".agent-inspect";
14457
+ var GITKEEP = ".agent-inspect/.gitkeep";
14458
+ function normalizeFramework(value) {
14459
+ const raw = (value ?? "custom").trim();
14460
+ if (raw === "ai-sdk" || raw === "openai-agents" || raw === "langchain" || raw === "custom") {
14461
+ return raw;
14462
+ }
14463
+ throw new Error(
14464
+ "Unsupported --framework value. Use ai-sdk, openai-agents, langchain, or custom."
14465
+ );
14466
+ }
14467
+ function configTemplate(framework) {
14468
+ const base = `/**
14469
+ * AgentInspect local config (metadata-only capture by default).
14470
+ * See https://github.com/rajudandigam/agent-inspect/blob/main/docs/SAFE-TRACE-SHARING.md
14471
+ */
14472
+ export const agentInspectConfig = {
14473
+ traceDir: ".agent-inspect",
14474
+ enabled: process.env.AGENT_INSPECT !== "0",
14475
+ redactionProfile: "local" as const,
14476
+ };
14477
+ `;
14478
+ if (framework === "custom") return base;
14479
+ return `${base}
14480
+ export const framework = "${framework}" as const;
14481
+ `;
14482
+ }
14483
+ function demoTemplate(framework) {
14484
+ switch (framework) {
14485
+ case "ai-sdk":
14486
+ return `/**
14487
+ * AI SDK starter \u2014 metadata-only telemetry (no real model calls in this demo).
14488
+ * Install: npm install agent-inspect @agent-inspect/ai-sdk ai
14489
+ */
14490
+ import { inspectRun, step } from "agent-inspect";
14491
+
14492
+ async function main() {
14493
+ await inspectRun("ai-sdk-demo", async () => {
14494
+ await step.tool("mock-generate", async () => ({ text: "ok" }));
14495
+ }, { traceDir: ".agent-inspect", silent: true });
14496
+ console.log("Trace written to .agent-inspect/");
14497
+ }
14498
+
14499
+ main().catch((error) => {
14500
+ console.error(error);
14501
+ process.exitCode = 1;
14502
+ });
14503
+ `;
14504
+ case "openai-agents":
14505
+ return `/**
14506
+ * OpenAI Agents starter \u2014 use @agent-inspect/openai-agents for local-only processors.
14507
+ * This demo uses manual steps (no API keys).
14508
+ */
14509
+ import { inspectRun, step } from "agent-inspect";
14510
+
14511
+ async function main() {
14512
+ await inspectRun("openai-agents-demo", async () => {
14513
+ await step.tool("mock-agent-run", async () => "ok");
14514
+ }, { traceDir: ".agent-inspect", silent: true });
14515
+ console.log("Trace written to .agent-inspect/");
14516
+ }
14517
+
14518
+ main().catch((error) => {
14519
+ console.error(error);
14520
+ process.exitCode = 1;
14521
+ });
14522
+ `;
14523
+ case "langchain":
14524
+ return `/**
14525
+ * LangChain starter \u2014 wire @agent-inspect/langchain callbacks in your app.
14526
+ * This demo uses manual steps (no API keys).
14527
+ */
14528
+ import { inspectRun, step } from "agent-inspect";
14529
+
14530
+ async function main() {
14531
+ await inspectRun("langchain-demo", async () => {
14532
+ await step.tool("mock-chain", async () => "ok");
14533
+ }, { traceDir: ".agent-inspect", silent: true });
14534
+ console.log("Trace written to .agent-inspect/");
14535
+ }
14536
+
14537
+ main().catch((error) => {
14538
+ console.error(error);
14539
+ process.exitCode = 1;
14540
+ });
14541
+ `;
14542
+ default:
14543
+ return `import { observe } from "agent-inspect";
14544
+
14545
+ class DemoAgent {
14546
+ async run(input: { question: string }) {
14547
+ return { answer: \`Echo: \${input.question}\` };
14548
+ }
14549
+ }
14550
+
14551
+ const agent = observe(new DemoAgent(), {
14552
+ traceDir: ".agent-inspect",
14553
+ silent: true,
14554
+ });
14555
+
14556
+ await agent.run({ question: "hello" });
14557
+ console.log("Trace written to .agent-inspect/");
14558
+ `;
14559
+ }
14560
+ }
14561
+ function githubWorkflowTemplate() {
14562
+ return `name: AgentInspect artifacts
14563
+
14564
+ on:
14565
+ workflow_dispatch:
14566
+ push:
14567
+ branches: [main]
14568
+
14569
+ jobs:
14570
+ trace-artifacts:
14571
+ runs-on: ubuntu-latest
14572
+ steps:
14573
+ - uses: actions/checkout@v4
14574
+ - uses: actions/setup-node@v4
14575
+ with:
14576
+ node-version: "22"
14577
+ - run: npm ci
14578
+ - run: npm test
14579
+ - name: Upload AgentInspect traces
14580
+ if: always()
14581
+ uses: actions/upload-artifact@v4
14582
+ with:
14583
+ name: agent-inspect-traces
14584
+ path: .agent-inspect/**/*.jsonl
14585
+ if-no-files-found: ignore
14586
+ `;
14587
+ }
14588
+ async function planInit(options = {}) {
14589
+ const framework = normalizeFramework(options.framework);
14590
+ const cwd = path14.resolve(options.cwd ?? process.cwd());
14591
+ const demoPath = framework === "custom" ? path14.join("examples", "agent-inspect-demo.mjs") : path14.join("examples", `agent-inspect-${framework}-demo.mjs`);
14592
+ const candidates = [
14593
+ { rel: CONFIG_FILE, content: configTemplate(framework) },
14594
+ { rel: GITKEEP, content: "" },
14595
+ { rel: demoPath, content: demoTemplate(framework) }
14596
+ ];
14597
+ if (options.ci === "github") {
14598
+ candidates.push({
14599
+ rel: ".github/workflows/agent-inspect-artifacts.yml",
14600
+ content: githubWorkflowTemplate()
14601
+ });
14602
+ }
14603
+ const files = [];
14604
+ for (const candidate of candidates) {
14605
+ const abs = path14.join(cwd, candidate.rel);
14606
+ try {
14607
+ await access(abs);
14608
+ files.push({
14609
+ path: candidate.rel,
14610
+ action: "skip",
14611
+ reason: "file already exists"
14612
+ });
14613
+ } catch (error) {
14614
+ if (error.code !== "ENOENT") throw error;
14615
+ files.push({ path: candidate.rel, action: "create" });
14616
+ }
14617
+ }
14618
+ return { framework, ...options.ci ? { ci: options.ci } : {}, files };
14619
+ }
14620
+ async function writePlannedFiles(plan, cwd, options) {
14621
+ const written = [];
14622
+ for (const entry of plan.files) {
14623
+ if (entry.action === "skip") {
14624
+ continue;
14625
+ }
14626
+ const abs = path14.join(cwd, entry.path);
14627
+ if (options.dryRun) {
14628
+ written.push(entry.path);
14629
+ continue;
14630
+ }
14631
+ await mkdir(path14.dirname(abs), { recursive: true });
14632
+ const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
14633
+ await writeFile(abs, content, "utf-8");
14634
+ written.push(entry.path);
14635
+ }
14636
+ return written;
14637
+ }
14638
+ async function initCommand(options = {}) {
14639
+ const cwd = path14.resolve(options.cwd ?? process.cwd());
14640
+ try {
14641
+ const plan = await planInit({ ...options, cwd });
14642
+ const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
14643
+ const skipped = plan.files.filter((file) => file.action === "skip");
14644
+ if (options.json) {
14645
+ const payload = {
14646
+ ok: true,
14647
+ version,
14648
+ framework: plan.framework,
14649
+ ci: plan.ci ?? null,
14650
+ dryRun: options.dryRun === true,
14651
+ planned: plan.files,
14652
+ wouldWrite: options.dryRun ? toWrite : void 0
14653
+ };
14654
+ console.log(JSON.stringify(payload, null, 2));
14655
+ if (options.dryRun) return;
14656
+ }
14657
+ const written = await writePlannedFiles(plan, cwd, options);
14658
+ if (!options.json) {
14659
+ console.log("AgentInspect init");
14660
+ console.log(`Framework: ${plan.framework}`);
14661
+ console.log(`Trace directory: ${TRACE_DIR}/`);
14662
+ if (options.dryRun) {
14663
+ console.log("Dry run \u2014 would create:");
14664
+ for (const file of toWrite) console.log(`- ${file}`);
14665
+ for (const file of skipped) {
14666
+ console.log(`- ${file.path} (skip: ${file.reason ?? "exists"})`);
14667
+ }
14668
+ return;
14669
+ }
14670
+ console.log("Created:");
14671
+ for (const file of written) console.log(`- ${file}`);
14672
+ for (const file of skipped) {
14673
+ console.log(`- ${file.path} (skipped: ${file.reason ?? "exists"})`);
14674
+ }
14675
+ console.log("\nNext: run your demo, then `npx agent-inspect list --dir .agent-inspect`");
14676
+ console.log("No dependencies were installed. Add packages manually when ready.");
14677
+ }
14678
+ } catch (error) {
14679
+ const msg = error instanceof Error ? error.message : String(error);
14680
+ if (options.json) {
14681
+ console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
14682
+ } else {
14683
+ console.error(`[AgentInspect] init failed: ${msg}`);
14684
+ }
14685
+ process.exitCode = 1;
14686
+ }
14687
+ }
14688
+ var OPTIONAL_PACKAGES = {
14689
+ custom: [],
14690
+ "ai-sdk": ["@agent-inspect/ai-sdk"],
14691
+ "openai-agents": ["@agent-inspect/openai-agents"],
14692
+ langchain: ["@agent-inspect/langchain"]
14693
+ };
14694
+ function nodeVersionCheck() {
14695
+ const major = Number(process3.versions.node.split(".")[0]);
14696
+ if (Number.isNaN(major) || major < 20) {
14697
+ return {
14698
+ id: "node-version",
14699
+ status: "fail",
14700
+ message: `Node ${process3.versions.node} is below the supported minimum (20).`,
14701
+ remediation: "Upgrade to Node 20 LTS or newer.",
14702
+ evidence: process3.versions.node
14703
+ };
14704
+ }
14705
+ return {
14706
+ id: "node-version",
14707
+ status: "pass",
14708
+ message: `Node ${process3.versions.node} meets the minimum (>=20).`,
14709
+ evidence: process3.versions.node
14710
+ };
14711
+ }
14712
+ function envCheck(name, optional = true) {
14713
+ const value = process3.env[name];
14714
+ if (value === void 0 || value.trim() === "") {
14715
+ return {
14716
+ id: `env-${name.toLowerCase()}`,
14717
+ status: optional ? "skipped" : "warn",
14718
+ message: `${name} is not set.`,
14719
+ remediation: optional ? void 0 : `Set ${name}=1 to enable tracing.`
14720
+ };
14721
+ }
14722
+ return {
14723
+ id: `env-${name.toLowerCase()}`,
14724
+ status: "pass",
14725
+ message: `${name} is set.`,
14726
+ evidence: value
14727
+ };
14728
+ }
14729
+ async function traceDirWritable(traceDir) {
14730
+ const resolved = path14.resolve(traceDir);
14731
+ try {
14732
+ await mkdir(resolved, { recursive: true });
14733
+ await access(resolved, constants.W_OK);
14734
+ return {
14735
+ id: "trace-dir-writable",
14736
+ status: "pass",
14737
+ message: `Trace directory is writable: ${resolved}`,
14738
+ evidence: resolved
14739
+ };
14740
+ } catch (error) {
14741
+ return {
14742
+ id: "trace-dir-writable",
14743
+ status: "fail",
14744
+ message: `Trace directory is not writable: ${resolved}`,
14745
+ remediation: "Create the directory or set AGENT_INSPECT_TRACE_DIR to a writable path.",
14746
+ evidence: error instanceof Error ? error.message : String(error)
14747
+ };
14748
+ }
14749
+ }
14750
+ function resolvePackage(cwd, name) {
14751
+ const require2 = createRequire(path14.join(cwd, "package.json"));
14752
+ try {
14753
+ const pkgPath = require2.resolve(`${name}/package.json`);
14754
+ const pkg = require2(pkgPath);
14755
+ return { ok: true, version: pkg.version };
14756
+ } catch {
14757
+ return { ok: false };
14758
+ }
14759
+ }
14760
+ function importSmoke(cwd) {
14761
+ const results = [];
14762
+ const require2 = createRequire(path14.join(cwd, "package.json"));
14763
+ try {
14764
+ require2.resolve("agent-inspect");
14765
+ results.push({
14766
+ id: "import-agent-inspect",
14767
+ status: "pass",
14768
+ message: "agent-inspect resolves from the current project."
14769
+ });
14770
+ } catch {
14771
+ results.push({
14772
+ id: "import-agent-inspect",
14773
+ status: "warn",
14774
+ message: "agent-inspect is not installed in the current project.",
14775
+ remediation: "Run npm install agent-inspect (or pnpm add agent-inspect)."
14776
+ });
14777
+ }
14778
+ try {
14779
+ require2.resolve("agent-inspect/package.json");
14780
+ results.push({
14781
+ id: "import-agent-inspect-cjs",
14782
+ status: "pass",
14783
+ message: "CJS resolution for agent-inspect succeeded."
14784
+ });
14785
+ } catch {
14786
+ results.push({
14787
+ id: "import-agent-inspect-cjs",
14788
+ status: "skipped",
14789
+ message: "CJS resolution check skipped (package not installed locally)."
14790
+ });
14791
+ }
14792
+ return results;
14793
+ }
14794
+ function optionalPackageChecks(cwd, framework) {
14795
+ const packages = framework !== void 0 ? OPTIONAL_PACKAGES[framework] : [
14796
+ "@agent-inspect/ai-sdk",
14797
+ "@agent-inspect/openai-agents",
14798
+ "@agent-inspect/langchain",
14799
+ "@agent-inspect/redact",
14800
+ "@agent-inspect/eval"
14801
+ ];
14802
+ return packages.map((name) => {
14803
+ const resolved = resolvePackage(cwd, name);
14804
+ if (!resolved.ok) {
14805
+ return {
14806
+ id: `optional-package-${name}`,
14807
+ status: framework !== void 0 ? "warn" : "skipped",
14808
+ message: `${name} is not installed.`,
14809
+ remediation: framework !== void 0 ? `npm install ${name}` : void 0
14810
+ };
14811
+ }
14812
+ return {
14813
+ id: `optional-package-${name}`,
14814
+ status: "pass",
14815
+ message: `${name} is available.`,
14816
+ evidence: resolved.version
14817
+ };
14818
+ });
14819
+ }
14820
+ function versionMismatchCheck(cwd) {
14821
+ const root = resolvePackage(cwd, "agent-inspect");
14822
+ if (!root.ok || root.version === void 0) {
14823
+ return {
14824
+ id: "version-alignment",
14825
+ status: "skipped",
14826
+ message: "Skipped version alignment \u2014 agent-inspect not installed locally."
14827
+ };
14828
+ }
14829
+ if (root.version !== version) {
14830
+ return {
14831
+ id: "version-alignment",
14832
+ status: "warn",
14833
+ message: `CLI version ${version} differs from local agent-inspect@${root.version}.`,
14834
+ remediation: "Align versions with npm install agent-inspect@latest",
14835
+ evidence: `cli=${version};local=${root.version}`
14836
+ };
14837
+ }
14838
+ return {
14839
+ id: "version-alignment",
14840
+ status: "pass",
14841
+ message: `CLI and local agent-inspect are aligned at ${version}.`
14842
+ };
14843
+ }
14844
+ async function runDoctorChecks(options = {}) {
14845
+ const cwd = path14.resolve(options.cwd ?? process3.cwd());
14846
+ const traceDir = options.traceDir?.trim() || process3.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
14847
+ const checks2 = [
14848
+ nodeVersionCheck(),
14849
+ {
14850
+ id: "cli-version",
14851
+ status: "pass",
14852
+ message: `agent-inspect CLI ${version}`,
14853
+ evidence: version
14854
+ },
14855
+ await traceDirWritable(traceDir),
14856
+ envCheck("AGENT_INSPECT"),
14857
+ envCheck("AGENT_INSPECT_TRACE_DIR"),
14858
+ versionMismatchCheck(cwd)
14859
+ ];
14860
+ if (options.checkImports !== false) {
14861
+ checks2.push(...importSmoke(cwd));
14862
+ }
14863
+ checks2.push(...optionalPackageChecks(cwd, options.framework));
14864
+ return checks2.sort((a, b) => a.id.localeCompare(b.id));
14865
+ }
14866
+ async function doctorCommand(options = {}) {
14867
+ const checks2 = await runDoctorChecks(options);
14868
+ const failed = checks2.filter((check) => check.status === "fail").length;
14869
+ const warned = checks2.filter((check) => check.status === "warn").length;
14870
+ if (options.json) {
14871
+ console.log(
14872
+ JSON.stringify(
14873
+ {
14874
+ ok: failed === 0,
14875
+ version,
14876
+ summary: { pass: checks2.filter((c) => c.status === "pass").length, warn: warned, fail: failed },
14877
+ checks: checks2
14878
+ },
14879
+ null,
14880
+ 2
14881
+ )
14882
+ );
14883
+ if (failed > 0) process3.exitCode = 1;
14884
+ return;
14885
+ }
14886
+ console.log("AgentInspect doctor");
14887
+ for (const check of checks2) {
14888
+ const tag = check.status.toUpperCase();
14889
+ console.log(`[${tag}] ${check.id}: ${check.message}`);
14890
+ if (check.remediation) console.log(` \u2192 ${check.remediation}`);
14891
+ }
14892
+ console.log(`
14893
+ Summary: ${failed} failed, ${warned} warnings`);
14894
+ if (failed > 0) process3.exitCode = 1;
14895
+ }
14454
14896
 
14455
14897
  // packages/cli/src/index.ts
14456
14898
  function runCommand(action) {
@@ -14750,6 +15192,26 @@ function createCliProgram() {
14750
15192
  ).action((target, opts) => {
14751
15193
  runCommand(() => explainCommand(target, opts));
14752
15194
  });
15195
+ program.command("init").description("Initialize a minimal local AgentInspect setup (no dependency install)").addOption(
15196
+ new Option("--framework <framework>", "starter framework path").choices([
15197
+ "ai-sdk",
15198
+ "openai-agents",
15199
+ "langchain",
15200
+ "custom"
15201
+ ])
15202
+ ).addOption(new Option("--ci <provider>", "optional CI snippet").choices(["github"])).option("--dry-run", "print planned files without writing").option("--yes", "non-interactive; skip existing files").option("--json", "print deterministic JSON plan/result").action((opts) => {
15203
+ runCommand(() => initCommand(opts));
15204
+ });
15205
+ program.command("doctor").description("Diagnose local AgentInspect setup (no network, no installs)").option("--json", "print deterministic JSON results").option("--trace-dir <path>", "trace directory to validate (default .agent-inspect)").option("--check-imports", "check local package resolution", true).option("--no-check-imports", "skip import resolution checks").addOption(
15206
+ new Option("--framework <framework>", "check optional adapter packages").choices([
15207
+ "ai-sdk",
15208
+ "openai-agents",
15209
+ "langchain",
15210
+ "custom"
15211
+ ])
15212
+ ).action((opts) => {
15213
+ runCommand(() => doctorCommand(opts));
15214
+ });
14753
15215
  return program;
14754
15216
  }
14755
15217
  function isPrimaryModule() {