agent-inspect 4.1.0 → 4.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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { resolveTraceDir, TraceDirectory, parseDuration, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, loadTraceMetadataList, loadSessionRunRecords, filterMetasBySessionScope, aggregateSessionCheckResults, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, validateEvent, isPersistedInspectEvent, buildSessionIndex, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, extractCorrelationMetadata, truncateStringForProfile, parseTraceJsonl } from './chunk-MT5G7JFO.mjs';
2
+ import { resolveTraceDir, parseDuration, buildSessionIndex, enrichSessionRunRecord, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, validateEvent, isPersistedInspectEvent, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, extractCorrelationMetadata, truncateStringForProfile, parseTraceJsonl } from './chunk-5VSPJEZ7.mjs';
3
3
  import { realpathSync, constants as constants$1 } from 'fs';
4
- import path10 from 'path';
4
+ import path11 from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
6
6
  import { Command, Option } from 'commander';
7
7
  import { unlink, stat, mkdir, writeFile, appendFile, rm, access, readFile, open, readdir, constants } from 'fs/promises';
@@ -11,7 +11,7 @@ import { createServer } from 'http';
11
11
  import { createRequire } from 'module';
12
12
 
13
13
  // package.json
14
- var version = "4.1.0";
14
+ var version = "4.2.0";
15
15
 
16
16
  // packages/cli/src/trace-dir-scale.ts
17
17
  var TRACE_COUNT_WARN = 1e3;
@@ -895,7 +895,7 @@ function findReaderByFormat(format, readers) {
895
895
  }
896
896
  async function jsonlFilesInDirectory(dirPath) {
897
897
  const entries = await readdir(dirPath, { withFileTypes: true });
898
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path10.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
898
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path11.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
899
899
  }
900
900
  async function resolveInput(input3) {
901
901
  const cached = resolvedInputCache.get(input3);
@@ -5024,9 +5024,9 @@ Trace directory: ${traceDir}`);
5024
5024
  if (validation !== void 0 && !validation.ok) {
5025
5025
  process.exitCode = 1;
5026
5026
  }
5027
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path10.resolve(options.output.trim()) : void 0;
5027
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path11.resolve(options.output.trim()) : void 0;
5028
5028
  if (outPath !== void 0) {
5029
- await mkdir(path10.dirname(outPath), { recursive: true });
5029
+ await mkdir(path11.dirname(outPath), { recursive: true });
5030
5030
  await writeFile(outPath, result.content, "utf-8");
5031
5031
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
5032
5032
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -5203,13 +5203,13 @@ function pairSteps(left, right) {
5203
5203
  return pairs;
5204
5204
  }
5205
5205
  function compareLeafSteps(L, R, segments, opts, out) {
5206
- const path17 = buildPath(segments);
5206
+ const path18 = buildPath(segments);
5207
5207
  if (L.name !== R.name) {
5208
5208
  out.push({
5209
5209
  kind: "structure",
5210
5210
  severity: "warning",
5211
5211
  message: "Step name differs",
5212
- path: path17,
5212
+ path: path18,
5213
5213
  left: L.name,
5214
5214
  right: R.name
5215
5215
  });
@@ -5219,7 +5219,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5219
5219
  kind: "step-type",
5220
5220
  severity: "warning",
5221
5221
  message: "Step type differs",
5222
- path: path17,
5222
+ path: path18,
5223
5223
  left: L.type,
5224
5224
  right: R.type
5225
5225
  });
@@ -5229,7 +5229,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5229
5229
  kind: "step-status",
5230
5230
  severity: "warning",
5231
5231
  message: "Step status differs",
5232
- path: path17,
5232
+ path: path18,
5233
5233
  left: L.status,
5234
5234
  right: R.status
5235
5235
  });
@@ -5241,7 +5241,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5241
5241
  kind: "error",
5242
5242
  severity: "error",
5243
5243
  message: "Step error message differs",
5244
- path: path17,
5244
+ path: path18,
5245
5245
  left: le || void 0,
5246
5246
  right: re || void 0
5247
5247
  });
@@ -5259,7 +5259,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5259
5259
  kind: "duration",
5260
5260
  severity: "info",
5261
5261
  message: "Step duration differs",
5262
- path: path17,
5262
+ path: path18,
5263
5263
  left: ld,
5264
5264
  right: rd
5265
5265
  });
@@ -5272,7 +5272,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5272
5272
  kind: "metadata",
5273
5273
  severity: "info",
5274
5274
  message: "Step metadata differs",
5275
- path: path17,
5275
+ path: path18,
5276
5276
  left: L.metadata,
5277
5277
  right: R.metadata
5278
5278
  });
@@ -5284,7 +5284,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5284
5284
  kind: "output",
5285
5285
  severity: "info",
5286
5286
  message: "Output preview differs",
5287
- path: path17,
5287
+ path: path18,
5288
5288
  left: L.outputPreview,
5289
5289
  right: R.outputPreview
5290
5290
  });
@@ -5444,11 +5444,11 @@ function diffRuns(left, right, options) {
5444
5444
  }
5445
5445
 
5446
5446
  // packages/core/src/diff/renderer.ts
5447
- function formatPath(path17) {
5448
- if (path17 === void 0 || path17.path.length === 0) {
5447
+ function formatPath(path18) {
5448
+ if (path18 === void 0 || path18.path.length === 0) {
5449
5449
  return "(run)";
5450
5450
  }
5451
- return path17.path.map((s) => s.name).join(" > ");
5451
+ return path18.path.map((s) => s.name).join(" > ");
5452
5452
  }
5453
5453
  function formatValue(v, verbose) {
5454
5454
  if (v === void 0) return "(undefined)";
@@ -5810,9 +5810,28 @@ async function searchCommand(options = {}) {
5810
5810
  process.exitCode = 1;
5811
5811
  }
5812
5812
  }
5813
-
5814
- // packages/cli/src/sessions.ts
5815
- async function loadSessionIndex(traceDir, correlateGroup) {
5813
+ function isModuleNotFound2(e) {
5814
+ return e !== null && typeof e === "object" && "code" in e && (e.code === "ERR_MODULE_NOT_FOUND" || e.code === "MODULE_NOT_FOUND");
5815
+ }
5816
+ function toStatus(raw) {
5817
+ if (raw === "success" || raw === "error" || raw === "running") return raw;
5818
+ return "unknown";
5819
+ }
5820
+ function indexedToMetadata(row, traceDir) {
5821
+ return {
5822
+ runId: row.runId,
5823
+ name: row.name ?? void 0,
5824
+ status: toStatus(row.status),
5825
+ startedAt: row.startedAt ?? void 0,
5826
+ endedAt: row.endedAt ?? void 0,
5827
+ durationMs: row.durationMs ?? void 0,
5828
+ eventCount: 0,
5829
+ filePath: path11.join(traceDir, row.file),
5830
+ fileSize: 0,
5831
+ createdAt: new Date(row.mtimeMs)
5832
+ };
5833
+ }
5834
+ async function loadFromScan(traceDir) {
5816
5835
  const td = new TraceDirectory({ dir: traceDir });
5817
5836
  const files = await td.list();
5818
5837
  const metas = await loadTraceMetadataList(
@@ -5820,12 +5839,77 @@ async function loadSessionIndex(traceDir, correlateGroup) {
5820
5839
  files,
5821
5840
  (fileName) => td.getPath(fileName)
5822
5841
  );
5823
- const runs = await loadSessionRunRecords(metas);
5824
- return buildSessionIndex(runs, { correlateByGroupId: correlateGroup === true });
5842
+ return loadSessionRunRecords(metas);
5843
+ }
5844
+ async function newestTraceMtimeMs(traceDir) {
5845
+ const td = new TraceDirectory({ dir: traceDir });
5846
+ let newest = 0;
5847
+ for (const file of await td.list()) {
5848
+ try {
5849
+ const stats = await td.getFileStats(file);
5850
+ if (stats.mtimeMs > newest) newest = stats.mtimeMs;
5851
+ } catch {
5852
+ }
5853
+ }
5854
+ return newest;
5855
+ }
5856
+ async function loadSessionRuns(traceDir) {
5857
+ try {
5858
+ const mod = await import('./src-VQT7QLGV.mjs');
5859
+ const dbPath = mod.resolveIndexDbPath(traceDir);
5860
+ const status = mod.indexStatus(dbPath);
5861
+ if (!status.healthy) {
5862
+ return { runs: await loadFromScan(traceDir), source: "scan" };
5863
+ }
5864
+ const newest = await newestTraceMtimeMs(traceDir);
5865
+ if (mod.isIndexStale(dbPath, newest)) {
5866
+ return { runs: await loadFromScan(traceDir), source: "scan" };
5867
+ }
5868
+ const indexed = mod.queryRuns(dbPath, { limit: 1e4 });
5869
+ if (indexed.length === 0) {
5870
+ return { runs: await loadFromScan(traceDir), source: "scan" };
5871
+ }
5872
+ const runs = [];
5873
+ for (const row of indexed) {
5874
+ runs.push(await enrichSessionRunRecord(indexedToMetadata(row, traceDir)));
5875
+ }
5876
+ runs.sort((a, b) => (a.startedAt ?? 0) - (b.startedAt ?? 0));
5877
+ return { runs, source: "index" };
5878
+ } catch (e) {
5879
+ if (!isModuleNotFound2(e)) ;
5880
+ return { runs: await loadFromScan(traceDir), source: "scan" };
5881
+ }
5882
+ }
5883
+
5884
+ // packages/cli/src/sessions.ts
5885
+ async function loadSessionIndex(traceDir, options = {}) {
5886
+ const { runs } = await loadSessionRuns(traceDir);
5887
+ const staleThresholdMs = options.staleAfter && options.staleAfter.trim() !== "" ? parseDuration(options.staleAfter.trim()) : void 0;
5888
+ return buildSessionIndex(runs, {
5889
+ correlateByGroupId: options.correlateGroup === true,
5890
+ staleThresholdMs
5891
+ });
5825
5892
  }
5826
5893
  function findSession(index, sessionId) {
5827
5894
  return index.sessions.find((session) => session.sessionId === sessionId);
5828
5895
  }
5896
+ function latestSession(index) {
5897
+ if (index.sessions.length === 0) return void 0;
5898
+ return [...index.sessions].sort(
5899
+ (a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity)
5900
+ )[0];
5901
+ }
5902
+ function parseSinceCutoff(since) {
5903
+ if (!since || since.trim() === "") return void 0;
5904
+ return Date.now() - parseDuration(since.trim());
5905
+ }
5906
+ function sessionsInSinceWindow(index, since) {
5907
+ const cutoff = parseSinceCutoff(since);
5908
+ if (cutoff === void 0) return index.sessions;
5909
+ return index.sessions.filter(
5910
+ (session) => Date.parse(session.lastActivity) >= cutoff
5911
+ );
5912
+ }
5829
5913
  function renderSessionsHuman(index, traceDir) {
5830
5914
  if (index.sessions.length === 0) {
5831
5915
  console.log("No sessions found");
@@ -5839,13 +5923,9 @@ function renderSessionsHuman(index, traceDir) {
5839
5923
  }
5840
5924
  console.log("Sessions:");
5841
5925
  for (const session of index.sessions) {
5842
- const firstRun = index.runs.find(
5843
- (run) => session.runIds.includes(run.runId)
5844
- );
5845
- const workflowName = firstRun?.metadata && typeof firstRun.metadata.workflowName === "string" ? firstRun.metadata.workflowName : void 0;
5846
- const suffix = workflowName ? ` workflow=${workflowName}` : "";
5926
+ const suffix = session.workflowId ? ` workflow=${session.workflowId}` : "";
5847
5927
  console.log(
5848
- ` ${session.sessionId} (${session.runIds.length} run${session.runIds.length === 1 ? "" : "s"})${suffix}`
5928
+ ` ${session.sessionId} [${session.status}] (${session.runIds.length} run${session.runIds.length === 1 ? "" : "s"})${suffix}`
5849
5929
  );
5850
5930
  }
5851
5931
  if (index.unscopedRunIds.length > 0) {
@@ -5857,7 +5937,14 @@ function renderSessionsHuman(index, traceDir) {
5857
5937
  }
5858
5938
  function renderSessionHuman(session, index, options) {
5859
5939
  console.log(`Session: ${session.sessionId}`);
5940
+ console.log(`Status: ${session.status}`);
5860
5941
  console.log(`Runs: ${session.runIds.join(", ")}`);
5942
+ if (session.lastActivity) console.log(`Last activity: ${session.lastActivity}`);
5943
+ if (session.lastError) {
5944
+ console.log(
5945
+ `Last error: ${session.lastError.message} (run ${session.lastError.runId})`
5946
+ );
5947
+ }
5861
5948
  if (session.handoffs.length > 0) {
5862
5949
  console.log("");
5863
5950
  console.log("Handoffs:");
@@ -5902,10 +5989,29 @@ function renderSessionHuman(session, index, options) {
5902
5989
  }
5903
5990
  }
5904
5991
  }
5992
+ function collectHandoffs(index, sessionId) {
5993
+ const sessions = sessionId ? index.sessions.filter((s) => s.sessionId === sessionId) : index.sessions;
5994
+ const out = [];
5995
+ for (const session of sessions) {
5996
+ for (const edge of session.handoffs) {
5997
+ out.push({ ...edge, sessionId: session.sessionId });
5998
+ }
5999
+ }
6000
+ return out.sort((a, b) => {
6001
+ const session = a.sessionId.localeCompare(b.sessionId);
6002
+ if (session !== 0) return session;
6003
+ const from = a.from.localeCompare(b.from);
6004
+ if (from !== 0) return from;
6005
+ return a.to.localeCompare(b.to);
6006
+ });
6007
+ }
5905
6008
  async function sessionsCommand(options = {}) {
5906
6009
  try {
5907
6010
  const traceDir = resolveTraceDir({ dir: options.dir });
5908
- const index = await loadSessionIndex(traceDir, options.correlateGroup);
6011
+ const index = await loadSessionIndex(traceDir, {
6012
+ correlateGroup: options.correlateGroup,
6013
+ staleAfter: options.staleAfter
6014
+ });
5909
6015
  if (options.json) {
5910
6016
  console.log(
5911
6017
  JSON.stringify(
@@ -5928,6 +6034,121 @@ async function sessionsCommand(options = {}) {
5928
6034
  process.exitCode = 1;
5929
6035
  }
5930
6036
  }
6037
+ async function sessionsLatestCommand(options = {}) {
6038
+ try {
6039
+ const traceDir = resolveTraceDir({ dir: options.dir });
6040
+ const index = await loadSessionIndex(traceDir, {
6041
+ correlateGroup: options.correlateGroup,
6042
+ staleAfter: options.staleAfter
6043
+ });
6044
+ const latest = latestSession(index);
6045
+ if (!latest) {
6046
+ if (options.json) {
6047
+ console.log(JSON.stringify({ ok: false, traceDir, reason: "no-sessions" }, null, 2));
6048
+ } else {
6049
+ console.log("No sessions found");
6050
+ console.log(`Trace directory: ${traceDir}`);
6051
+ }
6052
+ process.exitCode = 1;
6053
+ return;
6054
+ }
6055
+ if (options.json) {
6056
+ console.log(JSON.stringify({ ok: true, traceDir, session: latest }, null, 2));
6057
+ return;
6058
+ }
6059
+ console.log(`Latest session: ${latest.sessionId}`);
6060
+ console.log(`Status: ${latest.status}`);
6061
+ console.log(`Last activity: ${latest.lastActivity}`);
6062
+ console.log(`Runs: ${latest.runIds.join(", ")}`);
6063
+ } catch (e) {
6064
+ const msg = e instanceof Error ? e.message : String(e);
6065
+ console.error(`[AgentInspect] sessions latest failed: ${msg}`);
6066
+ process.exitCode = 1;
6067
+ }
6068
+ }
6069
+ async function sessionsActivityCommand(options = {}) {
6070
+ try {
6071
+ const traceDir = resolveTraceDir({ dir: options.dir });
6072
+ const index = await loadSessionIndex(traceDir, {
6073
+ correlateGroup: options.correlateGroup,
6074
+ staleAfter: options.staleAfter
6075
+ });
6076
+ const summary = buildActivitySummary(index, { since: options.since });
6077
+ if (options.json) {
6078
+ console.log(JSON.stringify({ ok: true, traceDir, ...summary }, null, 2));
6079
+ return;
6080
+ }
6081
+ console.log(renderActivitySummaryHuman(summary));
6082
+ } catch (e) {
6083
+ const msg = e instanceof Error ? e.message : String(e);
6084
+ console.error(`[AgentInspect] sessions activity failed: ${msg}`);
6085
+ process.exitCode = 1;
6086
+ }
6087
+ }
6088
+ async function sessionsHandoffsCommand(options = {}) {
6089
+ try {
6090
+ const traceDir = resolveTraceDir({ dir: options.dir });
6091
+ const index = await loadSessionIndex(traceDir, {
6092
+ correlateGroup: options.correlateGroup
6093
+ });
6094
+ const handoffs = collectHandoffs(index, options.session);
6095
+ if (options.json) {
6096
+ console.log(
6097
+ JSON.stringify({ ok: true, traceDir, count: handoffs.length, handoffs }, null, 2)
6098
+ );
6099
+ return;
6100
+ }
6101
+ if (handoffs.length === 0) {
6102
+ console.log("No handoffs found");
6103
+ return;
6104
+ }
6105
+ for (const edge of handoffs) {
6106
+ console.log(
6107
+ `${edge.sessionId}: ${edge.from} -> ${edge.to} (${edge.confidence})`
6108
+ );
6109
+ }
6110
+ } catch (e) {
6111
+ const msg = e instanceof Error ? e.message : String(e);
6112
+ console.error(`[AgentInspect] sessions handoffs failed: ${msg}`);
6113
+ process.exitCode = 1;
6114
+ }
6115
+ }
6116
+ async function sessionsErrorsCommand(options = {}) {
6117
+ try {
6118
+ const traceDir = resolveTraceDir({ dir: options.dir });
6119
+ const index = await loadSessionIndex(traceDir, {
6120
+ correlateGroup: options.correlateGroup,
6121
+ staleAfter: options.staleAfter
6122
+ });
6123
+ const scoped = sessionsInSinceWindow(index, options.since);
6124
+ const errors = scoped.filter((session) => session.status === "error");
6125
+ if (options.json) {
6126
+ console.log(
6127
+ JSON.stringify(
6128
+ { ok: true, traceDir, count: errors.length, sessions: errors },
6129
+ null,
6130
+ 2
6131
+ )
6132
+ );
6133
+ return;
6134
+ }
6135
+ if (errors.length === 0) {
6136
+ console.log("No error sessions found");
6137
+ return;
6138
+ }
6139
+ for (const session of errors) {
6140
+ const detail = session.lastError?.message ?? "error";
6141
+ console.log(`${session.sessionId} ${detail} (${session.runIds.length} runs)`);
6142
+ }
6143
+ } catch (e) {
6144
+ const msg = e instanceof Error ? e.message : String(e);
6145
+ console.error(`[AgentInspect] sessions errors failed: ${msg}`);
6146
+ process.exitCode = 1;
6147
+ }
6148
+ }
6149
+ async function sessionsShowCommand(sessionId, options = {}) {
6150
+ await sessionCommand(sessionId, options);
6151
+ }
5931
6152
  async function sessionCommand(sessionId, options = {}) {
5932
6153
  const id = typeof sessionId === "string" && sessionId.trim() !== "" ? sessionId.trim() : "";
5933
6154
  if (id === "") {
@@ -6081,9 +6302,9 @@ async function reportCommand(runId, options = {}) {
6081
6302
  redactionProfile,
6082
6303
  correlation: !options.noCorrelation
6083
6304
  });
6084
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path10.resolve(options.output.trim()) : void 0;
6305
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path11.resolve(options.output.trim()) : void 0;
6085
6306
  if (outPath !== void 0) {
6086
- await mkdir(path10.dirname(outPath), { recursive: true });
6307
+ await mkdir(path11.dirname(outPath), { recursive: true });
6087
6308
  await writeFile(outPath, result.content, "utf-8");
6088
6309
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
6089
6310
  }
@@ -6330,17 +6551,17 @@ function applyRule(rule, value, replacement) {
6330
6551
  }
6331
6552
  return value;
6332
6553
  }
6333
- function childPath(path17, key) {
6554
+ function childPath(path18, key) {
6334
6555
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
6335
- return path17 ? `${path17}.${key}` : key;
6556
+ return path18 ? `${path18}.${key}` : key;
6336
6557
  }
6337
- return `${path17 || "$"}[${JSON.stringify(key)}]`;
6558
+ return `${path18 || "$"}[${JSON.stringify(key)}]`;
6338
6559
  }
6339
- function indexPath(path17, index) {
6340
- return `${path17 || "$"}[${index}]`;
6560
+ function indexPath(path18, index) {
6561
+ return `${path18 || "$"}[${index}]`;
6341
6562
  }
6342
- function makeFinding(path17, detector, action, matchKind, severity = "warning", preview) {
6343
- return preview === void 0 ? { path: path17, detector, action, severity, matchKind } : { path: path17, detector, action, severity, matchKind, preview };
6563
+ function makeFinding(path18, detector, action, matchKind, severity = "warning", preview) {
6564
+ return preview === void 0 ? { path: path18, detector, action, severity, matchKind } : { path: path18, detector, action, severity, matchKind, preview };
6344
6565
  }
6345
6566
  function createRedactionProfile(profile = "local") {
6346
6567
  switch (profile) {
@@ -6409,11 +6630,11 @@ var Redactor2 = class {
6409
6630
  #recordFinding(state, finding) {
6410
6631
  if (this.#collectFindings) state.findings.push(finding);
6411
6632
  }
6412
- #redactValue(value, key, path17, depth, state) {
6633
+ #redactValue(value, key, path18, depth, state) {
6413
6634
  if (depth > this.#maxDepth) {
6414
6635
  this.#recordFinding(
6415
6636
  state,
6416
- makeFinding(path17, "structure.maxDepth", "truncate", "value", "warning")
6637
+ makeFinding(path18, "structure.maxDepth", "truncate", "value", "warning")
6417
6638
  );
6418
6639
  return "[Truncated]";
6419
6640
  }
@@ -6422,19 +6643,19 @@ var Redactor2 = class {
6422
6643
  if (rule) {
6423
6644
  this.#recordFinding(
6424
6645
  state,
6425
- makeFinding(path17, `key.${rule.key}`, actionForRule(rule), "key", "warning")
6646
+ makeFinding(path18, `key.${rule.key}`, actionForRule(rule), "key", "warning")
6426
6647
  );
6427
6648
  return applyRule(rule, value, this.#replacement);
6428
6649
  }
6429
6650
  }
6430
6651
  for (const detector of this.#detectors) {
6431
- const detections = detector.detect({ path: path17, key, value });
6652
+ const detections = detector.detect({ path: path18, key, value });
6432
6653
  for (const detection of detections) {
6433
6654
  const action = detection.action ?? "replace";
6434
6655
  this.#recordFinding(
6435
6656
  state,
6436
6657
  makeFinding(
6437
- path17,
6658
+ path18,
6438
6659
  detector.id,
6439
6660
  action,
6440
6661
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -6452,7 +6673,7 @@ var Redactor2 = class {
6452
6673
  const out = [];
6453
6674
  state.seen.set(value, out);
6454
6675
  value.forEach((item, index) => {
6455
- out[index] = this.#redactValue(item, void 0, indexPath(path17, index), depth + 1, state);
6676
+ out[index] = this.#redactValue(item, void 0, indexPath(path18, index), depth + 1, state);
6456
6677
  });
6457
6678
  return out;
6458
6679
  }
@@ -6464,7 +6685,7 @@ var Redactor2 = class {
6464
6685
  out[entryKey] = this.#redactValue(
6465
6686
  entryValue,
6466
6687
  entryKey,
6467
- childPath(path17 === "$" ? "" : path17, entryKey),
6688
+ childPath(path18 === "$" ? "" : path18, entryKey),
6468
6689
  depth + 1,
6469
6690
  state
6470
6691
  );
@@ -6911,14 +7132,14 @@ function uniqueSorted(values) {
6911
7132
  return [...new Set(values)].sort();
6912
7133
  }
6913
7134
  function isWithinDirectory(child, parent) {
6914
- const relative = path10.relative(parent, child);
6915
- return relative === "" || !relative.startsWith("..") && !path10.isAbsolute(relative);
7135
+ const relative = path11.relative(parent, child);
7136
+ return relative === "" || !relative.startsWith("..") && !path11.isAbsolute(relative);
6916
7137
  }
6917
7138
  async function resolveOutputPath(inputPath, output2, force) {
6918
7139
  if (output2 === void 0 || output2.trim() === "") return void 0;
6919
- const inputAbs = path10.resolve(inputPath);
6920
- const outputAbs = path10.resolve(output2.trim());
6921
- const inputDir = path10.dirname(inputAbs);
7140
+ const inputAbs = path11.resolve(inputPath);
7141
+ const outputAbs = path11.resolve(output2.trim());
7142
+ const inputDir = path11.dirname(inputAbs);
6922
7143
  if (!isWithinDirectory(outputAbs, inputDir)) {
6923
7144
  throw new Error("Refusing to write migrated output outside the input directory.");
6924
7145
  }
@@ -7039,7 +7260,7 @@ async function migrateCommand(input3, options = {}) {
7039
7260
  process.exitCode = 1;
7040
7261
  return;
7041
7262
  }
7042
- const inputPath = path10.resolve(input3.trim());
7263
+ const inputPath = path11.resolve(input3.trim());
7043
7264
  const dryRun = options.dryRun === true;
7044
7265
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
7045
7266
  console.error("migrate requires --dry-run or --output <path>.");
@@ -7058,7 +7279,7 @@ async function migrateCommand(input3, options = {}) {
7058
7279
  );
7059
7280
  const result = await buildMigration(inputPath, outputPath);
7060
7281
  if (!dryRun && outputPath !== void 0) {
7061
- await mkdir(path10.dirname(outputPath), { recursive: true });
7282
+ await mkdir(path11.dirname(outputPath), { recursive: true });
7062
7283
  await writeFile(outputPath, result.content, "utf-8");
7063
7284
  }
7064
7285
  printSummary2(result, dryRun);
@@ -7336,7 +7557,7 @@ function stripPrefix(name, prefixes) {
7336
7557
  }
7337
7558
  return name;
7338
7559
  }
7339
- function eventEvidence(event, path17) {
7560
+ function eventEvidence(event, path18) {
7340
7561
  return {
7341
7562
  runId: event.runId,
7342
7563
  eventId: event.eventId,
@@ -7346,7 +7567,7 @@ function eventEvidence(event, path17) {
7346
7567
  kind: event.kind,
7347
7568
  name: event.name,
7348
7569
  status: event.status,
7349
- ...path17 ? { path: path17 } : {}
7570
+ ...path18 ? { path: path18 } : {}
7350
7571
  };
7351
7572
  }
7352
7573
  function runEvidence(run) {
@@ -7409,9 +7630,9 @@ function eventEndMs(event) {
7409
7630
  function normalizedKey(value) {
7410
7631
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
7411
7632
  }
7412
- function lastPathSegment(path17) {
7413
- const parts = path17.split(".");
7414
- return parts[parts.length - 1] ?? path17;
7633
+ function lastPathSegment(path18) {
7634
+ const parts = path18.split(".");
7635
+ return parts[parts.length - 1] ?? path18;
7415
7636
  }
7416
7637
  function valueType(value) {
7417
7638
  if (Array.isArray(value)) return "array";
@@ -7425,12 +7646,12 @@ function serializedByteLength(value) {
7425
7646
  return void 0;
7426
7647
  }
7427
7648
  }
7428
- function pushValueEntries(entries, event, value, path17, key, depth = 0) {
7429
- entries.push({ event, path: path17, key, value });
7649
+ function pushValueEntries(entries, event, value, path18, key, depth = 0) {
7650
+ entries.push({ event, path: path18, key, value });
7430
7651
  if (depth >= 8) return;
7431
7652
  if (Array.isArray(value)) {
7432
7653
  for (const [index, item] of value.entries()) {
7433
- pushValueEntries(entries, event, item, `${path17}.${index}`, String(index), depth + 1);
7654
+ pushValueEntries(entries, event, item, `${path18}.${index}`, String(index), depth + 1);
7434
7655
  }
7435
7656
  return;
7436
7657
  }
@@ -7440,7 +7661,7 @@ function pushValueEntries(entries, event, value, path17, key, depth = 0) {
7440
7661
  entries,
7441
7662
  event,
7442
7663
  value[nestedKey],
7443
- `${path17}.${nestedKey}`,
7664
+ `${path18}.${nestedKey}`,
7444
7665
  nestedKey,
7445
7666
  depth + 1
7446
7667
  );
@@ -7521,9 +7742,9 @@ function eventDurationMs(event) {
7521
7742
  }
7522
7743
  function treeShape(nodes) {
7523
7744
  const lines = [];
7524
- const visit = (node, path17) => {
7525
- lines.push(`${path17}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
7526
- node.children.forEach((child, index) => visit(child, `${path17}.${index}`));
7745
+ const visit = (node, path18) => {
7746
+ lines.push(`${path18}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
7747
+ node.children.forEach((child, index) => visit(child, `${path18}.${index}`));
7527
7748
  };
7528
7749
  nodes.forEach((node, index) => visit(node, String(index)));
7529
7750
  return lines;
@@ -7572,9 +7793,9 @@ function retrievalShape(context) {
7572
7793
  function guardrailShape(context) {
7573
7794
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
7574
7795
  }
7575
- function firstEvidenceForKind(context, kind, path17) {
7796
+ function firstEvidenceForKind(context, kind, path18) {
7576
7797
  const event = context.events.find((candidate) => candidate.kind === kind);
7577
- return event ? [eventEvidence(event, path17)] : runEvidence(context.selectedRun);
7798
+ return event ? [eventEvidence(event, path18)] : runEvidence(context.selectedRun);
7578
7799
  }
7579
7800
  function baselineDiffFinding(message, evidence, expected, actual) {
7580
7801
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -7924,13 +8145,13 @@ function createStructureCycleRule() {
7924
8145
  const seenCycles = /* @__PURE__ */ new Set();
7925
8146
  const findings = [];
7926
8147
  for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
7927
- const path17 = [];
8148
+ const path18 = [];
7928
8149
  const seenAt = /* @__PURE__ */ new Map();
7929
8150
  let current = event;
7930
8151
  while (current) {
7931
8152
  const existing = seenAt.get(current.eventId);
7932
8153
  if (existing !== void 0) {
7933
- const cycle = path17.slice(existing);
8154
+ const cycle = path18.slice(existing);
7934
8155
  const key = cycle.map((item) => item.eventId).sort().join("\0");
7935
8156
  if (!seenCycles.has(key)) {
7936
8157
  seenCycles.add(key);
@@ -7946,8 +8167,8 @@ function createStructureCycleRule() {
7946
8167
  }
7947
8168
  break;
7948
8169
  }
7949
- seenAt.set(current.eventId, path17.length);
7950
- path17.push(current);
8170
+ seenAt.set(current.eventId, path18.length);
8171
+ path18.push(current);
7951
8172
  current = current.parentId ? byId.get(current.parentId) : void 0;
7952
8173
  }
7953
8174
  }
@@ -8744,23 +8965,23 @@ function evaluatePromptInjection(text, options = {}) {
8744
8965
  }
8745
8966
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
8746
8967
  }
8747
- function validateSchemaField(value, field, path17, evidence) {
8968
+ function validateSchemaField(value, field, path18, evidence) {
8748
8969
  const ruleId = "guardrail.structured-output";
8749
8970
  if (field.type) {
8750
8971
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
8751
8972
  if (actual !== field.type) {
8752
- evidence.push({ ruleId, path: path17, preview: `expected ${field.type}, got ${actual}` });
8973
+ evidence.push({ ruleId, path: path18, preview: `expected ${field.type}, got ${actual}` });
8753
8974
  return;
8754
8975
  }
8755
8976
  }
8756
8977
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
8757
- evidence.push({ ruleId, path: path17, preview: "value not in enum" });
8978
+ evidence.push({ ruleId, path: path18, preview: "value not in enum" });
8758
8979
  }
8759
8980
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
8760
8981
  const record = value;
8761
8982
  for (const key of field.required) {
8762
8983
  if (!(key in record)) {
8763
- evidence.push({ ruleId, path: `${path17}.${key}`, preview: "missing required key" });
8984
+ evidence.push({ ruleId, path: `${path18}.${key}`, preview: "missing required key" });
8764
8985
  }
8765
8986
  }
8766
8987
  }
@@ -9087,7 +9308,7 @@ function asConfig(value) {
9087
9308
  }
9088
9309
  async function loadConfig(configPath) {
9089
9310
  if (configPath === void 0) return {};
9090
- const extension = path10.extname(configPath);
9311
+ const extension = path11.extname(configPath);
9091
9312
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
9092
9313
  throw new Error(
9093
9314
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -9096,7 +9317,7 @@ async function loadConfig(configPath) {
9096
9317
  if (!CONFIG_EXTENSIONS.has(extension)) {
9097
9318
  throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
9098
9319
  }
9099
- const absolute = path10.resolve(configPath);
9320
+ const absolute = path11.resolve(configPath);
9100
9321
  if (extension === ".json") {
9101
9322
  const raw = await readFile(absolute, "utf-8");
9102
9323
  return asConfig(JSON.parse(raw));
@@ -9245,10 +9466,10 @@ function printHuman(result) {
9245
9466
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
9246
9467
  }
9247
9468
  for (const finding of result.findings) {
9248
- const path17 = finding.evidence[0]?.path;
9469
+ const path18 = finding.evidence[0]?.path;
9249
9470
  const run = finding.evidence[0]?.runId;
9250
9471
  const runPrefix = run ? `[${run}] ` : "";
9251
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
9472
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
9252
9473
  }
9253
9474
  }
9254
9475
  function readErrorResult(error) {
@@ -9448,7 +9669,7 @@ function createViewerServer(options = {}) {
9448
9669
  return sendJson(res, 200, {
9449
9670
  ok: true,
9450
9671
  readOnly: true,
9451
- traceDir: path10.resolve(traceDir)
9672
+ traceDir: path11.resolve(traceDir)
9452
9673
  });
9453
9674
  }
9454
9675
  const td = new TraceDirectory({ dir: traceDir });
@@ -9466,7 +9687,7 @@ function createViewerServer(options = {}) {
9466
9687
  runId: meta.runId,
9467
9688
  name: meta.name,
9468
9689
  status: meta.status,
9469
- file: path10.basename(meta.filePath),
9690
+ file: path11.basename(meta.filePath),
9470
9691
  startedAt: meta.startedAt,
9471
9692
  durationMs: meta.durationMs
9472
9693
  }))
@@ -9581,7 +9802,7 @@ function startViewerServer(options = {}) {
9581
9802
  resolve({
9582
9803
  host,
9583
9804
  port: resolvedPort,
9584
- traceDir: path10.resolve(traceDir),
9805
+ traceDir: path11.resolve(traceDir),
9585
9806
  url: `http://${host}:${resolvedPort}`
9586
9807
  });
9587
9808
  });
@@ -9786,10 +10007,10 @@ async function evalRun(input3, options = {}) {
9786
10007
  diagnostics: []
9787
10008
  };
9788
10009
  }
9789
- function evidenceForRun(run, path17) {
9790
- return [{ runId: run.runId, ...path17 !== void 0 ? { path: path17 } : {} }];
10010
+ function evidenceForRun(run, path18) {
10011
+ return [{ runId: run.runId, ...path18 !== void 0 ? { path: path18 } : {} }];
9791
10012
  }
9792
- function evidenceForEvent(event, path17) {
10013
+ function evidenceForEvent(event, path18) {
9793
10014
  return [
9794
10015
  {
9795
10016
  runId: event.runId,
@@ -9797,7 +10018,7 @@ function evidenceForEvent(event, path17) {
9797
10018
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
9798
10019
  kind: event.kind,
9799
10020
  name: event.name,
9800
- ...path17 !== void 0 ? { path: path17 } : {}
10021
+ ...path18 !== void 0 ? { path: path18 } : {}
9801
10022
  }
9802
10023
  ];
9803
10024
  }
@@ -9955,9 +10176,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
9955
10176
  function tokenize(text) {
9956
10177
  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));
9957
10178
  }
9958
- function firstEvidence(fields, run, path17) {
10179
+ function firstEvidence(fields, run, path18) {
9959
10180
  const first = fields[0];
9960
- return first === void 0 ? evidenceForRun(run, path17) : evidenceForEvent(first.node.event, first.path);
10181
+ return first === void 0 ? evidenceForRun(run, path18) : evidenceForEvent(first.node.event, first.path);
9961
10182
  }
9962
10183
  function collectSourceIds(nodes, keys) {
9963
10184
  const wanted = keySet(keys);
@@ -10334,8 +10555,8 @@ function renderEvalMarkdown(result) {
10334
10555
  if (result.findings.length > 0) {
10335
10556
  lines.push("", "## Findings");
10336
10557
  for (const finding of result.findings) {
10337
- const path17 = finding.evidence[0]?.path;
10338
- lines.push(`- ${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
10558
+ const path18 = finding.evidence[0]?.path;
10559
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
10339
10560
  }
10340
10561
  }
10341
10562
  return `${lines.join("\n")}
@@ -10382,7 +10603,7 @@ function asConfig2(value) {
10382
10603
  }
10383
10604
  async function loadConfig2(configPath) {
10384
10605
  if (configPath === void 0) return {};
10385
- const extension = path10.extname(configPath);
10606
+ const extension = path11.extname(configPath);
10386
10607
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
10387
10608
  throw new Error(
10388
10609
  "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -10391,7 +10612,7 @@ async function loadConfig2(configPath) {
10391
10612
  if (!CONFIG_EXTENSIONS2.has(extension)) {
10392
10613
  throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
10393
10614
  }
10394
- const absolute = path10.resolve(configPath);
10615
+ const absolute = path11.resolve(configPath);
10395
10616
  if (extension === ".json") {
10396
10617
  const raw = await readFile(absolute, "utf-8");
10397
10618
  return asConfig2(JSON.parse(raw));
@@ -10528,8 +10749,8 @@ function printHuman2(result) {
10528
10749
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
10529
10750
  }
10530
10751
  for (const finding of result.findings) {
10531
- const path17 = finding.evidence[0]?.path;
10532
- console.log(`- ${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
10752
+ const path18 = finding.evidence[0]?.path;
10753
+ console.log(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
10533
10754
  }
10534
10755
  }
10535
10756
  function readErrorResult2(error) {
@@ -10767,8 +10988,8 @@ function printHuman3(result) {
10767
10988
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
10768
10989
  }
10769
10990
  for (const finding of result.findings) {
10770
- const path17 = finding.evidence[0]?.path;
10771
- console.log(`- ${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
10991
+ const path18 = finding.evidence[0]?.path;
10992
+ console.log(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
10772
10993
  }
10773
10994
  console.log(`Note: ${result.note}`);
10774
10995
  }
@@ -10887,8 +11108,8 @@ function renderCheckSection(result) {
10887
11108
  `Diagnostics: ${result.diagnostics.length}`
10888
11109
  ];
10889
11110
  for (const finding of result.findings.slice(0, 10)) {
10890
- const path17 = finding.evidence[0]?.path ?? "(run)";
10891
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path17})`);
11111
+ const path18 = finding.evidence[0]?.path ?? "(run)";
11112
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path18})`);
10892
11113
  }
10893
11114
  for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
10894
11115
  lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
@@ -10966,8 +11187,8 @@ function renderHtml(trace, check, diff) {
10966
11187
  `;
10967
11188
  }
10968
11189
  async function writeArtifact(outputDir, relativePath, content, files) {
10969
- const outPath = path10.join(outputDir, relativePath);
10970
- await mkdir(path10.dirname(outPath), { recursive: true });
11190
+ const outPath = path11.join(outputDir, relativePath);
11191
+ await mkdir(path11.dirname(outPath), { recursive: true });
10971
11192
  await writeFile(outPath, content, "utf-8");
10972
11193
  files.push(relativePath);
10973
11194
  }
@@ -10983,7 +11204,7 @@ function manifestStatus(check, diff) {
10983
11204
  return "ok";
10984
11205
  }
10985
11206
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
10986
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path10.resolve(options.outputDir.trim()) : "";
11207
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path11.resolve(options.outputDir.trim()) : "";
10987
11208
  if (outputDir === "") {
10988
11209
  console.error("--output-dir is required.");
10989
11210
  process.exitCode = 1;
@@ -11049,8 +11270,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
11049
11270
  await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
11050
11271
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
11051
11272
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
11052
- await mkdir(path10.dirname(path10.resolve(summaryTarget)), { recursive: true });
11053
- await appendFile(path10.resolve(summaryTarget), `
11273
+ await mkdir(path11.dirname(path11.resolve(summaryTarget)), { recursive: true });
11274
+ await appendFile(path11.resolve(summaryTarget), `
11054
11275
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
11055
11276
  }
11056
11277
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -11069,10 +11290,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
11069
11290
  findings: diff?.findings.length ?? 0,
11070
11291
  diagnostics: diff?.diagnostics.length ?? 0
11071
11292
  },
11072
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path10.resolve(summaryTarget) } : {},
11293
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path11.resolve(summaryTarget) } : {},
11073
11294
  note: NOTE
11074
11295
  };
11075
- await writeFile(path10.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
11296
+ await writeFile(path11.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
11076
11297
  if (options.json === true) {
11077
11298
  console.log(writeJson3(manifest).trimEnd());
11078
11299
  } else {
@@ -11084,7 +11305,7 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
11084
11305
  }
11085
11306
  }
11086
11307
  function validateReporterArtifactPath(options) {
11087
- const outputDir = path10.resolve(options.outputDir);
11308
+ const outputDir = path11.resolve(options.outputDir);
11088
11309
  const diagnostics = [];
11089
11310
  const rawPath = options.relativePath;
11090
11311
  if (rawPath.length === 0) {
@@ -11104,7 +11325,7 @@ function validateReporterArtifactPath(options) {
11104
11325
  });
11105
11326
  return { ok: false, outputDir, diagnostics };
11106
11327
  }
11107
- if (path10.isAbsolute(rawPath) || path10.win32.isAbsolute(rawPath)) {
11328
+ if (path11.isAbsolute(rawPath) || path11.win32.isAbsolute(rawPath)) {
11108
11329
  diagnostics.push({
11109
11330
  code: "artifact_path_absolute",
11110
11331
  severity: "error",
@@ -11113,7 +11334,7 @@ function validateReporterArtifactPath(options) {
11113
11334
  });
11114
11335
  return { ok: false, outputDir, diagnostics };
11115
11336
  }
11116
- const normalized = path10.posix.normalize(rawPath.replace(/\\/g, "/"));
11337
+ const normalized = path11.posix.normalize(rawPath.replace(/\\/g, "/"));
11117
11338
  const segments = normalized.split("/");
11118
11339
  if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
11119
11340
  diagnostics.push({
@@ -11124,9 +11345,9 @@ function validateReporterArtifactPath(options) {
11124
11345
  });
11125
11346
  return { ok: false, outputDir, diagnostics };
11126
11347
  }
11127
- const absolutePath = path10.resolve(outputDir, normalized);
11128
- const relFromOutput = path10.relative(outputDir, absolutePath);
11129
- if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path10.isAbsolute(relFromOutput)) {
11348
+ const absolutePath = path11.resolve(outputDir, normalized);
11349
+ const relFromOutput = path11.relative(outputDir, absolutePath);
11350
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path11.isAbsolute(relFromOutput)) {
11130
11351
  diagnostics.push({
11131
11352
  code: "artifact_path_escape",
11132
11353
  severity: "error",
@@ -11272,23 +11493,23 @@ function readManifestDocument(value) {
11272
11493
  };
11273
11494
  }
11274
11495
  function cwdRelative(filePath) {
11275
- const relative = path10.relative(process.cwd(), path10.resolve(filePath)).replace(/\\/g, "/");
11276
- if (relative === "" || relative.startsWith("../") || path10.isAbsolute(relative)) {
11277
- return path10.basename(filePath);
11496
+ const relative = path11.relative(process.cwd(), path11.resolve(filePath)).replace(/\\/g, "/");
11497
+ if (relative === "" || relative.startsWith("../") || path11.isAbsolute(relative)) {
11498
+ return path11.basename(filePath);
11278
11499
  }
11279
11500
  return relative;
11280
11501
  }
11281
11502
  async function readReporterManifest(filePath) {
11282
- const absolute = path10.resolve(filePath);
11503
+ const absolute = path11.resolve(filePath);
11283
11504
  const raw = await readFile(absolute, "utf-8");
11284
11505
  const document = readManifestDocument(JSON.parse(raw));
11285
11506
  const manifest = document.manifest;
11286
11507
  const results = manifest.results.map((result) => ({
11287
11508
  testId: safeText(result.testId),
11288
11509
  name: safeText(result.name),
11289
- ...result.file === void 0 ? {} : { file: safeText(path10.basename(result.file)) },
11510
+ ...result.file === void 0 ? {} : { file: safeText(path11.basename(result.file)) },
11290
11511
  status: result.status,
11291
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path10.basename(result.tracePath)) },
11512
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path11.basename(result.tracePath)) },
11292
11513
  artifacts: result.artifacts,
11293
11514
  diagnostics: result.diagnostics
11294
11515
  }));
@@ -11427,15 +11648,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
11427
11648
  return;
11428
11649
  }
11429
11650
  const markdown = renderMarkdown2(result);
11430
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path10.resolve(options.output.trim()) : void 0;
11651
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path11.resolve(options.output.trim()) : void 0;
11431
11652
  if (outputPath !== void 0) {
11432
- await mkdir(path10.dirname(outputPath), { recursive: true });
11653
+ await mkdir(path11.dirname(outputPath), { recursive: true });
11433
11654
  await writeFile(outputPath, markdown, "utf-8");
11434
11655
  }
11435
11656
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
11436
11657
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
11437
- const summaryPath = path10.resolve(summaryTarget);
11438
- await mkdir(path10.dirname(summaryPath), { recursive: true });
11658
+ const summaryPath = path11.resolve(summaryTarget);
11659
+ await mkdir(path11.dirname(summaryPath), { recursive: true });
11439
11660
  await appendFile(summaryPath, `
11440
11661
  ${markdown}`, "utf-8");
11441
11662
  }
@@ -11583,8 +11804,8 @@ jobs:
11583
11804
  }
11584
11805
  async function planInit(options = {}) {
11585
11806
  const framework = normalizeFramework(options.framework);
11586
- const cwd = path10.resolve(options.cwd ?? process.cwd());
11587
- const demoPath = framework === "custom" ? path10.join("examples", "agent-inspect-demo.mjs") : path10.join("examples", `agent-inspect-${framework}-demo.mjs`);
11807
+ const cwd = path11.resolve(options.cwd ?? process.cwd());
11808
+ const demoPath = framework === "custom" ? path11.join("examples", "agent-inspect-demo.mjs") : path11.join("examples", `agent-inspect-${framework}-demo.mjs`);
11588
11809
  const candidates = [
11589
11810
  { rel: CONFIG_FILE, content: configTemplate(framework) },
11590
11811
  { rel: GITKEEP, content: "" },
@@ -11598,7 +11819,7 @@ async function planInit(options = {}) {
11598
11819
  }
11599
11820
  const files = [];
11600
11821
  for (const candidate of candidates) {
11601
- const abs = path10.join(cwd, candidate.rel);
11822
+ const abs = path11.join(cwd, candidate.rel);
11602
11823
  try {
11603
11824
  await access(abs);
11604
11825
  files.push({
@@ -11619,12 +11840,12 @@ async function writePlannedFiles(plan, cwd, options) {
11619
11840
  if (entry.action === "skip") {
11620
11841
  continue;
11621
11842
  }
11622
- const abs = path10.join(cwd, entry.path);
11843
+ const abs = path11.join(cwd, entry.path);
11623
11844
  if (options.dryRun) {
11624
11845
  written.push(entry.path);
11625
11846
  continue;
11626
11847
  }
11627
- await mkdir(path10.dirname(abs), { recursive: true });
11848
+ await mkdir(path11.dirname(abs), { recursive: true });
11628
11849
  const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
11629
11850
  await writeFile(abs, content, "utf-8");
11630
11851
  written.push(entry.path);
@@ -11632,7 +11853,7 @@ async function writePlannedFiles(plan, cwd, options) {
11632
11853
  return written;
11633
11854
  }
11634
11855
  async function initCommand(options = {}) {
11635
- const cwd = path10.resolve(options.cwd ?? process.cwd());
11856
+ const cwd = path11.resolve(options.cwd ?? process.cwd());
11636
11857
  try {
11637
11858
  const plan = await planInit({ ...options, cwd });
11638
11859
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -11723,7 +11944,7 @@ function envCheck(name, optional = true) {
11723
11944
  };
11724
11945
  }
11725
11946
  async function traceDirWritable(traceDir) {
11726
- const resolved = path10.resolve(traceDir);
11947
+ const resolved = path11.resolve(traceDir);
11727
11948
  try {
11728
11949
  await mkdir(resolved, { recursive: true });
11729
11950
  await access(resolved, constants.W_OK);
@@ -11744,7 +11965,7 @@ async function traceDirWritable(traceDir) {
11744
11965
  }
11745
11966
  }
11746
11967
  function resolvePackage(cwd, name) {
11747
- const require2 = createRequire(path10.join(cwd, "package.json"));
11968
+ const require2 = createRequire(path11.join(cwd, "package.json"));
11748
11969
  try {
11749
11970
  const pkgPath = require2.resolve(`${name}/package.json`);
11750
11971
  const pkg = require2(pkgPath);
@@ -11755,7 +11976,7 @@ function resolvePackage(cwd, name) {
11755
11976
  }
11756
11977
  function importSmoke(cwd) {
11757
11978
  const results = [];
11758
- const require2 = createRequire(path10.join(cwd, "package.json"));
11979
+ const require2 = createRequire(path11.join(cwd, "package.json"));
11759
11980
  try {
11760
11981
  require2.resolve("agent-inspect");
11761
11982
  results.push({
@@ -11838,7 +12059,7 @@ function versionMismatchCheck(cwd) {
11838
12059
  };
11839
12060
  }
11840
12061
  async function runDoctorChecks(options = {}) {
11841
- const cwd = path10.resolve(options.cwd ?? process2.cwd());
12062
+ const cwd = path11.resolve(options.cwd ?? process2.cwd());
11842
12063
  const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
11843
12064
  const checks2 = [
11844
12065
  nodeVersionCheck(),
@@ -11950,7 +12171,7 @@ function createTraceDirectoryIndexer() {
11950
12171
  // packages/cli/src/index-cmd.ts
11951
12172
  var INDEX_FILENAME = ".agent-inspect-index.json";
11952
12173
  function traceIndexPath(traceDir) {
11953
- return path10.join(traceDir, INDEX_FILENAME);
12174
+ return path11.join(traceDir, INDEX_FILENAME);
11954
12175
  }
11955
12176
  function parseMaxEntries(raw) {
11956
12177
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -12058,14 +12279,14 @@ async function indexCleanCommand(options = {}) {
12058
12279
  }
12059
12280
  }
12060
12281
  var PACKAGE = "@agent-inspect/index-sqlite";
12061
- function isModuleNotFound2(e) {
12282
+ function isModuleNotFound3(e) {
12062
12283
  return e !== null && typeof e === "object" && "code" in e && (e.code === "ERR_MODULE_NOT_FOUND" || e.code === "MODULE_NOT_FOUND");
12063
12284
  }
12064
12285
  async function loadIndexSqlite() {
12065
12286
  try {
12066
- return await import('./src-DUGEOAZ7.mjs');
12287
+ return await import('./src-VQT7QLGV.mjs');
12067
12288
  } catch (e) {
12068
- if (isModuleNotFound2(e)) {
12289
+ if (isModuleNotFound3(e)) {
12069
12290
  console.error(
12070
12291
  `The optional SQLite index is not installed. Run: npm install ${PACKAGE}`
12071
12292
  );
@@ -12086,14 +12307,14 @@ function parsePositiveInt(raw, flag) {
12086
12307
  }
12087
12308
  return parsed;
12088
12309
  }
12089
- async function newestTraceMtimeMs(traceDir) {
12310
+ async function newestTraceMtimeMs2(traceDir) {
12090
12311
  let newest = 0;
12091
12312
  try {
12092
12313
  const files = await readdir(traceDir);
12093
12314
  for (const file of files) {
12094
12315
  if (!file.endsWith(".jsonl")) continue;
12095
12316
  try {
12096
- const s = await stat(path10.join(traceDir, file));
12317
+ const s = await stat(path11.join(traceDir, file));
12097
12318
  if (s.mtimeMs > newest) newest = s.mtimeMs;
12098
12319
  } catch {
12099
12320
  }
@@ -12123,7 +12344,7 @@ async function indexSqliteStatusCommand(options = {}) {
12123
12344
  const traceDir = resolveTraceDir({ dir: options.dir });
12124
12345
  const dbPath = mod.resolveIndexDbPath(traceDir);
12125
12346
  const status = mod.indexStatus(dbPath);
12126
- const stale = mod.isIndexStale(dbPath, await newestTraceMtimeMs(traceDir));
12347
+ const stale = mod.isIndexStale(dbPath, await newestTraceMtimeMs2(traceDir));
12127
12348
  if (options.json) {
12128
12349
  console.log(JSON.stringify({ ok: true, traceDir, stale, ...status }, null, 2));
12129
12350
  return;
@@ -12372,19 +12593,19 @@ function serializeWorkspaceManifest(manifest) {
12372
12593
  }
12373
12594
  var INDEX_DIR_NAME = "index";
12374
12595
  function resolveWorkspaceLocation(cwd = process.cwd()) {
12375
- const projectRoot = path10.resolve(cwd);
12376
- const workspaceDir = path10.join(projectRoot, WORKSPACE_DIR_NAME);
12596
+ const projectRoot = path11.resolve(cwd);
12597
+ const workspaceDir = path11.join(projectRoot, WORKSPACE_DIR_NAME);
12377
12598
  return {
12378
12599
  projectRoot,
12379
12600
  workspaceDir,
12380
- manifestPath: path10.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
12601
+ manifestPath: path11.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
12381
12602
  };
12382
12603
  }
12383
12604
  function resolveInsideWorkspace(workspaceDir, relative) {
12384
- const base = path10.resolve(workspaceDir);
12385
- const resolved = path10.resolve(base, relative);
12386
- const rel = path10.relative(base, resolved);
12387
- if (rel === "" || rel === "." || !rel.startsWith("..") && !path10.isAbsolute(rel)) {
12605
+ const base = path11.resolve(workspaceDir);
12606
+ const resolved = path11.resolve(base, relative);
12607
+ const rel = path11.relative(base, resolved);
12608
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path11.isAbsolute(rel)) {
12388
12609
  return resolved;
12389
12610
  }
12390
12611
  throw new Error(
@@ -12453,7 +12674,7 @@ async function createWorkspace(options = {}) {
12453
12674
  created = false;
12454
12675
  adopted = true;
12455
12676
  } else {
12456
- const project = options.project?.trim() || path10.basename(location.projectRoot) || "workspace";
12677
+ const project = options.project?.trim() || path11.basename(location.projectRoot) || "workspace";
12457
12678
  const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
12458
12679
  manifest = createDefaultWorkspaceManifest({
12459
12680
  project,
@@ -12592,7 +12813,7 @@ async function doctorWorkspace(location) {
12592
12813
  const abs = resolveInsideWorkspace(location.workspaceDir, rel);
12593
12814
  for (const file of await listJsonl(abs)) {
12594
12815
  try {
12595
- const s = await stat(path10.join(abs, file));
12816
+ const s = await stat(path11.join(abs, file));
12596
12817
  newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
12597
12818
  } catch {
12598
12819
  checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
@@ -12640,7 +12861,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
12640
12861
  const relPath = `${rel}/${entry}`;
12641
12862
  removed.push(relPath);
12642
12863
  if (!dryRun) {
12643
- await rm(path10.join(abs, entry), { recursive: true, force: true });
12864
+ await rm(path11.join(abs, entry), { recursive: true, force: true });
12644
12865
  }
12645
12866
  }
12646
12867
  }
@@ -13046,12 +13267,32 @@ function createCliProgram() {
13046
13267
  ).option("--json", "print results as JSON").action((opts) => {
13047
13268
  runCommand(() => searchCommand(opts));
13048
13269
  });
13049
- program.command("sessions").description("List workflow sessions grouped from local trace metadata (read-only)").option("--dir <path>", "trace directory").option(
13270
+ const sessionsCmd = program.command("sessions").description(
13271
+ "Workflow sessions and activity from local trace metadata (read-only, v4.2+)"
13272
+ ).option("--dir <path>", "trace directory").option(
13050
13273
  "--correlate-group",
13051
13274
  "treat shared groupId as a synthetic session when sessionId is absent"
13052
- ).option("--json", "print sessions index as JSON").action((opts) => {
13275
+ ).option("--json", "print JSON output").option(
13276
+ "--stale-after <duration>",
13277
+ "mark sessions stale after inactivity (e.g. 24h, 7d)"
13278
+ ).action((opts) => {
13053
13279
  runCommand(() => sessionsCommand(opts));
13054
13280
  });
13281
+ sessionsCmd.command("latest").description("Show the most recently active session").option("--dir <path>", "trace directory").option("--correlate-group", "include synthetic group: sessions").option("--stale-after <duration>", "staleness threshold for status derivation").option("--json", "print JSON result").action((opts) => {
13282
+ runCommand(() => sessionsLatestCommand(opts));
13283
+ });
13284
+ sessionsCmd.command("activity").description("Summarize recent session activity").option("--dir <path>", "trace directory").option("--since <duration>", "activity window (default 7d)").option("--correlate-group", "include synthetic group: sessions").option("--stale-after <duration>", "staleness threshold for status derivation").option("--json", "print JSON result").action((opts) => {
13285
+ runCommand(() => sessionsActivityCommand(opts));
13286
+ });
13287
+ sessionsCmd.command("show").description("Show one session (alias for session <id>)").argument("<session-id>", "session id").option("--dir <path>", "trace directory").option("--timeline", "include per-run timelines").option("--critical-path", "include critical path section").option("--diagnostics", "include ambiguity warnings").option("--json", "print JSON result").action((sessionId, opts) => {
13288
+ runCommand(() => sessionsShowCommand(sessionId, opts));
13289
+ });
13290
+ sessionsCmd.command("handoffs").description("List handoff edges across sessions").option("--dir <path>", "trace directory").option("--session <id>", "limit to one session").option("--correlate-group", "include synthetic group: sessions").option("--json", "print JSON result").action((opts) => {
13291
+ runCommand(() => sessionsHandoffsCommand(opts));
13292
+ });
13293
+ sessionsCmd.command("errors").description("List sessions with errors in a time window").option("--dir <path>", "trace directory").option("--since <duration>", "filter by last activity (default: all)").option("--correlate-group", "include synthetic group: sessions").option("--stale-after <duration>", "staleness threshold for status derivation").option("--json", "print JSON result").action((opts) => {
13294
+ runCommand(() => sessionsErrorsCommand(opts));
13295
+ });
13055
13296
  program.command("session").description("Inspect one workflow session: runs, handoffs, retries (read-only)").argument("<session-id>", "session id (from sessions output)").option("--dir <path>", "trace directory").option("--timeline", "include per-run timelines").option("--critical-path", "include critical path section").option("--diagnostics", "include ambiguity warnings").option("--json", "print session view as JSON").action((sessionId, opts) => {
13056
13297
  runCommand(() => sessionCommand(sessionId, opts));
13057
13298
  });
@@ -13180,9 +13421,9 @@ function isPrimaryModule() {
13180
13421
  if (!entry) return false;
13181
13422
  const selfPath = fileURLToPath(import.meta.url);
13182
13423
  try {
13183
- return realpathSync(path10.resolve(entry)) === realpathSync(path10.resolve(selfPath));
13424
+ return realpathSync(path11.resolve(entry)) === realpathSync(path11.resolve(selfPath));
13184
13425
  } catch {
13185
- return path10.resolve(entry) === path10.resolve(selfPath);
13426
+ return path11.resolve(entry) === path11.resolve(selfPath);
13186
13427
  }
13187
13428
  }
13188
13429
  if (isPrimaryModule()) {