agent-inspect 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +31 -0
- package/SECURITY.md +18 -1
- package/docs/ADAPTERS.md +41 -0
- package/docs/CLI.md +18 -1
- package/package.json +2 -2
- package/packages/cli/dist/index.cjs +376 -116
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +375 -115
- package/packages/cli/dist/index.mjs.map +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var fs = require('fs');
|
|
5
|
-
var
|
|
5
|
+
var path14 = require('path');
|
|
6
6
|
var url = require('url');
|
|
7
7
|
var commander = require('commander');
|
|
8
8
|
var async_hooks = require('async_hooks');
|
|
@@ -12,18 +12,19 @@ var os = require('os');
|
|
|
12
12
|
var process2 = require('process');
|
|
13
13
|
var tty = require('tty');
|
|
14
14
|
var readline = require('readline');
|
|
15
|
+
var http = require('http');
|
|
15
16
|
|
|
16
17
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
17
18
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
19
|
|
|
19
|
-
var
|
|
20
|
+
var path14__default = /*#__PURE__*/_interopDefault(path14);
|
|
20
21
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
21
22
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
22
23
|
var process2__default = /*#__PURE__*/_interopDefault(process2);
|
|
23
24
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
24
25
|
|
|
25
26
|
// package.json
|
|
26
|
-
var version = "2.
|
|
27
|
+
var version = "2.6.0";
|
|
27
28
|
|
|
28
29
|
// packages/core/src/correlation-metadata.ts
|
|
29
30
|
var TRACE_CORRELATION_KEYS = [
|
|
@@ -755,7 +756,7 @@ function formatDuration(ms) {
|
|
|
755
756
|
// packages/core/src/utils.ts
|
|
756
757
|
var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
757
758
|
var RUNS_DIR_NAME = "runs";
|
|
758
|
-
var FALLBACK_TRACE_DIR =
|
|
759
|
+
var FALLBACK_TRACE_DIR = path14__default.default.join(
|
|
759
760
|
os__default.default.tmpdir(),
|
|
760
761
|
"agent-inspect",
|
|
761
762
|
RUNS_DIR_NAME
|
|
@@ -790,7 +791,7 @@ function getDefaultTraceDir() {
|
|
|
790
791
|
if (typeof home !== "string" || home.trim() === "") {
|
|
791
792
|
return FALLBACK_TRACE_DIR;
|
|
792
793
|
}
|
|
793
|
-
return
|
|
794
|
+
return path14__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
794
795
|
} catch {
|
|
795
796
|
return FALLBACK_TRACE_DIR;
|
|
796
797
|
}
|
|
@@ -798,11 +799,11 @@ function getDefaultTraceDir() {
|
|
|
798
799
|
function getTraceFilePath(runId, traceDir) {
|
|
799
800
|
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
800
801
|
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
801
|
-
safeId =
|
|
802
|
+
safeId = path14__default.default.basename(safeId);
|
|
802
803
|
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
803
804
|
safeId = "run_unknown";
|
|
804
805
|
}
|
|
805
|
-
return
|
|
806
|
+
return path14__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
806
807
|
}
|
|
807
808
|
function formatError(error) {
|
|
808
809
|
if (error instanceof Error) {
|
|
@@ -1564,7 +1565,7 @@ var TraceDirectory = class {
|
|
|
1564
1565
|
this.#dir = resolveTraceDir(options);
|
|
1565
1566
|
}
|
|
1566
1567
|
getPath(filename) {
|
|
1567
|
-
return filename ?
|
|
1568
|
+
return filename ? path14__default.default.join(this.#dir, filename) : this.#dir;
|
|
1568
1569
|
}
|
|
1569
1570
|
async list() {
|
|
1570
1571
|
try {
|
|
@@ -1591,7 +1592,7 @@ function parseIsoToMs2(value) {
|
|
|
1591
1592
|
}
|
|
1592
1593
|
async function extractMetadata(filePath, _quickScan) {
|
|
1593
1594
|
const stats = await promises.stat(filePath);
|
|
1594
|
-
let runIdFromFile =
|
|
1595
|
+
let runIdFromFile = path14__default.default.basename(filePath);
|
|
1595
1596
|
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1596
1597
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1597
1598
|
}
|
|
@@ -3069,12 +3070,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3069
3070
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3070
3071
|
);
|
|
3071
3072
|
const ordered = [...runs].sort(compareRuns);
|
|
3072
|
-
const
|
|
3073
|
+
const path16 = [];
|
|
3073
3074
|
const visited = /* @__PURE__ */ new Set();
|
|
3074
3075
|
const pushRun = (run, confidence, source) => {
|
|
3075
3076
|
if (visited.has(run.runId)) return;
|
|
3076
3077
|
visited.add(run.runId);
|
|
3077
|
-
|
|
3078
|
+
path16.push({
|
|
3078
3079
|
runId: run.runId,
|
|
3079
3080
|
name: run.name,
|
|
3080
3081
|
startedAt: run.startedAt,
|
|
@@ -3099,7 +3100,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3099
3100
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3100
3101
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3101
3102
|
}
|
|
3102
|
-
return
|
|
3103
|
+
return path16;
|
|
3103
3104
|
}
|
|
3104
3105
|
function metaRunIdMatches(run, token, runById) {
|
|
3105
3106
|
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -4037,7 +4038,7 @@ function findReaderByFormat(format, readers) {
|
|
|
4037
4038
|
}
|
|
4038
4039
|
async function jsonlFilesInDirectory(dirPath) {
|
|
4039
4040
|
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
4040
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
4041
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path14__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
4041
4042
|
}
|
|
4042
4043
|
async function resolveInput(input3) {
|
|
4043
4044
|
const cached = resolvedInputCache.get(input3);
|
|
@@ -8163,9 +8164,9 @@ Trace directory: ${traceDir}`);
|
|
|
8163
8164
|
if (validation !== void 0 && !validation.ok) {
|
|
8164
8165
|
process.exitCode = 1;
|
|
8165
8166
|
}
|
|
8166
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
8167
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path14__default.default.resolve(options.output.trim()) : void 0;
|
|
8167
8168
|
if (outPath !== void 0) {
|
|
8168
|
-
await promises.mkdir(
|
|
8169
|
+
await promises.mkdir(path14__default.default.dirname(outPath), { recursive: true });
|
|
8169
8170
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
8170
8171
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
8171
8172
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -8342,13 +8343,13 @@ function pairSteps(left, right) {
|
|
|
8342
8343
|
return pairs;
|
|
8343
8344
|
}
|
|
8344
8345
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
8345
|
-
const
|
|
8346
|
+
const path16 = buildPath(segments);
|
|
8346
8347
|
if (L.name !== R.name) {
|
|
8347
8348
|
out.push({
|
|
8348
8349
|
kind: "structure",
|
|
8349
8350
|
severity: "warning",
|
|
8350
8351
|
message: "Step name differs",
|
|
8351
|
-
path:
|
|
8352
|
+
path: path16,
|
|
8352
8353
|
left: L.name,
|
|
8353
8354
|
right: R.name
|
|
8354
8355
|
});
|
|
@@ -8358,7 +8359,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8358
8359
|
kind: "step-type",
|
|
8359
8360
|
severity: "warning",
|
|
8360
8361
|
message: "Step type differs",
|
|
8361
|
-
path:
|
|
8362
|
+
path: path16,
|
|
8362
8363
|
left: L.type,
|
|
8363
8364
|
right: R.type
|
|
8364
8365
|
});
|
|
@@ -8368,7 +8369,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8368
8369
|
kind: "step-status",
|
|
8369
8370
|
severity: "warning",
|
|
8370
8371
|
message: "Step status differs",
|
|
8371
|
-
path:
|
|
8372
|
+
path: path16,
|
|
8372
8373
|
left: L.status,
|
|
8373
8374
|
right: R.status
|
|
8374
8375
|
});
|
|
@@ -8380,7 +8381,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8380
8381
|
kind: "error",
|
|
8381
8382
|
severity: "error",
|
|
8382
8383
|
message: "Step error message differs",
|
|
8383
|
-
path:
|
|
8384
|
+
path: path16,
|
|
8384
8385
|
left: le || void 0,
|
|
8385
8386
|
right: re || void 0
|
|
8386
8387
|
});
|
|
@@ -8398,7 +8399,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8398
8399
|
kind: "duration",
|
|
8399
8400
|
severity: "info",
|
|
8400
8401
|
message: "Step duration differs",
|
|
8401
|
-
path:
|
|
8402
|
+
path: path16,
|
|
8402
8403
|
left: ld,
|
|
8403
8404
|
right: rd
|
|
8404
8405
|
});
|
|
@@ -8411,7 +8412,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8411
8412
|
kind: "metadata",
|
|
8412
8413
|
severity: "info",
|
|
8413
8414
|
message: "Step metadata differs",
|
|
8414
|
-
path:
|
|
8415
|
+
path: path16,
|
|
8415
8416
|
left: L.metadata,
|
|
8416
8417
|
right: R.metadata
|
|
8417
8418
|
});
|
|
@@ -8423,7 +8424,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8423
8424
|
kind: "output",
|
|
8424
8425
|
severity: "info",
|
|
8425
8426
|
message: "Output preview differs",
|
|
8426
|
-
path:
|
|
8427
|
+
path: path16,
|
|
8427
8428
|
left: L.outputPreview,
|
|
8428
8429
|
right: R.outputPreview
|
|
8429
8430
|
});
|
|
@@ -8583,11 +8584,11 @@ function diffRuns(left, right, options) {
|
|
|
8583
8584
|
}
|
|
8584
8585
|
|
|
8585
8586
|
// packages/core/src/diff/renderer.ts
|
|
8586
|
-
function formatPath(
|
|
8587
|
-
if (
|
|
8587
|
+
function formatPath(path16) {
|
|
8588
|
+
if (path16 === void 0 || path16.path.length === 0) {
|
|
8588
8589
|
return "(run)";
|
|
8589
8590
|
}
|
|
8590
|
-
return
|
|
8591
|
+
return path16.path.map((s) => s.name).join(" > ");
|
|
8591
8592
|
}
|
|
8592
8593
|
function formatValue(v, verbose) {
|
|
8593
8594
|
if (v === void 0) return "(undefined)";
|
|
@@ -9216,9 +9217,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
9216
9217
|
redactionProfile,
|
|
9217
9218
|
correlation: !options.noCorrelation
|
|
9218
9219
|
});
|
|
9219
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
9220
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path14__default.default.resolve(options.output.trim()) : void 0;
|
|
9220
9221
|
if (outPath !== void 0) {
|
|
9221
|
-
await promises.mkdir(
|
|
9222
|
+
await promises.mkdir(path14__default.default.dirname(outPath), { recursive: true });
|
|
9222
9223
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
9223
9224
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
9224
9225
|
}
|
|
@@ -9465,17 +9466,17 @@ function applyRule(rule, value, replacement) {
|
|
|
9465
9466
|
}
|
|
9466
9467
|
return value;
|
|
9467
9468
|
}
|
|
9468
|
-
function childPath(
|
|
9469
|
+
function childPath(path16, key) {
|
|
9469
9470
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
9470
|
-
return
|
|
9471
|
+
return path16 ? `${path16}.${key}` : key;
|
|
9471
9472
|
}
|
|
9472
|
-
return `${
|
|
9473
|
+
return `${path16 || "$"}[${JSON.stringify(key)}]`;
|
|
9473
9474
|
}
|
|
9474
|
-
function indexPath(
|
|
9475
|
-
return `${
|
|
9475
|
+
function indexPath(path16, index) {
|
|
9476
|
+
return `${path16 || "$"}[${index}]`;
|
|
9476
9477
|
}
|
|
9477
|
-
function makeFinding(
|
|
9478
|
-
return preview === void 0 ? { path:
|
|
9478
|
+
function makeFinding(path16, detector, action, matchKind, severity = "warning", preview) {
|
|
9479
|
+
return preview === void 0 ? { path: path16, detector, action, severity, matchKind } : { path: path16, detector, action, severity, matchKind, preview };
|
|
9479
9480
|
}
|
|
9480
9481
|
function createRedactionProfile(profile = "local") {
|
|
9481
9482
|
switch (profile) {
|
|
@@ -9544,11 +9545,11 @@ var Redactor2 = class {
|
|
|
9544
9545
|
#recordFinding(state, finding) {
|
|
9545
9546
|
if (this.#collectFindings) state.findings.push(finding);
|
|
9546
9547
|
}
|
|
9547
|
-
#redactValue(value, key,
|
|
9548
|
+
#redactValue(value, key, path16, depth, state) {
|
|
9548
9549
|
if (depth > this.#maxDepth) {
|
|
9549
9550
|
this.#recordFinding(
|
|
9550
9551
|
state,
|
|
9551
|
-
makeFinding(
|
|
9552
|
+
makeFinding(path16, "structure.maxDepth", "truncate", "value", "warning")
|
|
9552
9553
|
);
|
|
9553
9554
|
return "[Truncated]";
|
|
9554
9555
|
}
|
|
@@ -9557,19 +9558,19 @@ var Redactor2 = class {
|
|
|
9557
9558
|
if (rule) {
|
|
9558
9559
|
this.#recordFinding(
|
|
9559
9560
|
state,
|
|
9560
|
-
makeFinding(
|
|
9561
|
+
makeFinding(path16, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
9561
9562
|
);
|
|
9562
9563
|
return applyRule(rule, value, this.#replacement);
|
|
9563
9564
|
}
|
|
9564
9565
|
}
|
|
9565
9566
|
for (const detector of this.#detectors) {
|
|
9566
|
-
const detections = detector.detect({ path:
|
|
9567
|
+
const detections = detector.detect({ path: path16, key, value });
|
|
9567
9568
|
for (const detection of detections) {
|
|
9568
9569
|
const action = detection.action ?? "replace";
|
|
9569
9570
|
this.#recordFinding(
|
|
9570
9571
|
state,
|
|
9571
9572
|
makeFinding(
|
|
9572
|
-
|
|
9573
|
+
path16,
|
|
9573
9574
|
detector.id,
|
|
9574
9575
|
action,
|
|
9575
9576
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -9587,7 +9588,7 @@ var Redactor2 = class {
|
|
|
9587
9588
|
const out = [];
|
|
9588
9589
|
state.seen.set(value, out);
|
|
9589
9590
|
value.forEach((item, index) => {
|
|
9590
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
9591
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path16, index), depth + 1, state);
|
|
9591
9592
|
});
|
|
9592
9593
|
return out;
|
|
9593
9594
|
}
|
|
@@ -9599,7 +9600,7 @@ var Redactor2 = class {
|
|
|
9599
9600
|
out[entryKey] = this.#redactValue(
|
|
9600
9601
|
entryValue,
|
|
9601
9602
|
entryKey,
|
|
9602
|
-
childPath(
|
|
9603
|
+
childPath(path16 === "$" ? "" : path16, entryKey),
|
|
9603
9604
|
depth + 1,
|
|
9604
9605
|
state
|
|
9605
9606
|
);
|
|
@@ -10046,14 +10047,14 @@ function uniqueSorted(values) {
|
|
|
10046
10047
|
return [...new Set(values)].sort();
|
|
10047
10048
|
}
|
|
10048
10049
|
function isWithinDirectory(child, parent) {
|
|
10049
|
-
const relative =
|
|
10050
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
10050
|
+
const relative = path14__default.default.relative(parent, child);
|
|
10051
|
+
return relative === "" || !relative.startsWith("..") && !path14__default.default.isAbsolute(relative);
|
|
10051
10052
|
}
|
|
10052
10053
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
10053
10054
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
10054
|
-
const inputAbs =
|
|
10055
|
-
const outputAbs =
|
|
10056
|
-
const inputDir =
|
|
10055
|
+
const inputAbs = path14__default.default.resolve(inputPath);
|
|
10056
|
+
const outputAbs = path14__default.default.resolve(output2.trim());
|
|
10057
|
+
const inputDir = path14__default.default.dirname(inputAbs);
|
|
10057
10058
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
10058
10059
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
10059
10060
|
}
|
|
@@ -10174,7 +10175,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
10174
10175
|
process.exitCode = 1;
|
|
10175
10176
|
return;
|
|
10176
10177
|
}
|
|
10177
|
-
const inputPath =
|
|
10178
|
+
const inputPath = path14__default.default.resolve(input3.trim());
|
|
10178
10179
|
const dryRun = options.dryRun === true;
|
|
10179
10180
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
10180
10181
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -10193,7 +10194,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
10193
10194
|
);
|
|
10194
10195
|
const result = await buildMigration(inputPath, outputPath);
|
|
10195
10196
|
if (!dryRun && outputPath !== void 0) {
|
|
10196
|
-
await promises.mkdir(
|
|
10197
|
+
await promises.mkdir(path14__default.default.dirname(outputPath), { recursive: true });
|
|
10197
10198
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
10198
10199
|
}
|
|
10199
10200
|
printSummary2(result, dryRun);
|
|
@@ -10471,7 +10472,7 @@ function stripPrefix(name, prefixes) {
|
|
|
10471
10472
|
}
|
|
10472
10473
|
return name;
|
|
10473
10474
|
}
|
|
10474
|
-
function eventEvidence(event,
|
|
10475
|
+
function eventEvidence(event, path16) {
|
|
10475
10476
|
return {
|
|
10476
10477
|
runId: event.runId,
|
|
10477
10478
|
eventId: event.eventId,
|
|
@@ -10481,7 +10482,7 @@ function eventEvidence(event, path15) {
|
|
|
10481
10482
|
kind: event.kind,
|
|
10482
10483
|
name: event.name,
|
|
10483
10484
|
status: event.status,
|
|
10484
|
-
...
|
|
10485
|
+
...path16 ? { path: path16 } : {}
|
|
10485
10486
|
};
|
|
10486
10487
|
}
|
|
10487
10488
|
function runEvidence(run) {
|
|
@@ -10544,9 +10545,9 @@ function eventEndMs(event) {
|
|
|
10544
10545
|
function normalizedKey(value) {
|
|
10545
10546
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
10546
10547
|
}
|
|
10547
|
-
function lastPathSegment(
|
|
10548
|
-
const parts =
|
|
10549
|
-
return parts[parts.length - 1] ??
|
|
10548
|
+
function lastPathSegment(path16) {
|
|
10549
|
+
const parts = path16.split(".");
|
|
10550
|
+
return parts[parts.length - 1] ?? path16;
|
|
10550
10551
|
}
|
|
10551
10552
|
function valueType(value) {
|
|
10552
10553
|
if (Array.isArray(value)) return "array";
|
|
@@ -10560,12 +10561,12 @@ function serializedByteLength(value) {
|
|
|
10560
10561
|
return void 0;
|
|
10561
10562
|
}
|
|
10562
10563
|
}
|
|
10563
|
-
function pushValueEntries(entries, event, value,
|
|
10564
|
-
entries.push({ event, path:
|
|
10564
|
+
function pushValueEntries(entries, event, value, path16, key, depth = 0) {
|
|
10565
|
+
entries.push({ event, path: path16, key, value });
|
|
10565
10566
|
if (depth >= 8) return;
|
|
10566
10567
|
if (Array.isArray(value)) {
|
|
10567
10568
|
for (const [index, item] of value.entries()) {
|
|
10568
|
-
pushValueEntries(entries, event, item, `${
|
|
10569
|
+
pushValueEntries(entries, event, item, `${path16}.${index}`, String(index), depth + 1);
|
|
10569
10570
|
}
|
|
10570
10571
|
return;
|
|
10571
10572
|
}
|
|
@@ -10575,7 +10576,7 @@ function pushValueEntries(entries, event, value, path15, key, depth = 0) {
|
|
|
10575
10576
|
entries,
|
|
10576
10577
|
event,
|
|
10577
10578
|
value[nestedKey],
|
|
10578
|
-
`${
|
|
10579
|
+
`${path16}.${nestedKey}`,
|
|
10579
10580
|
nestedKey,
|
|
10580
10581
|
depth + 1
|
|
10581
10582
|
);
|
|
@@ -10656,9 +10657,9 @@ function eventDurationMs(event) {
|
|
|
10656
10657
|
}
|
|
10657
10658
|
function treeShape(nodes) {
|
|
10658
10659
|
const lines = [];
|
|
10659
|
-
const visit = (node,
|
|
10660
|
-
lines.push(`${
|
|
10661
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
10660
|
+
const visit = (node, path16) => {
|
|
10661
|
+
lines.push(`${path16}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
10662
|
+
node.children.forEach((child, index) => visit(child, `${path16}.${index}`));
|
|
10662
10663
|
};
|
|
10663
10664
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
10664
10665
|
return lines;
|
|
@@ -10707,9 +10708,9 @@ function retrievalShape(context) {
|
|
|
10707
10708
|
function guardrailShape(context) {
|
|
10708
10709
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
10709
10710
|
}
|
|
10710
|
-
function firstEvidenceForKind(context, kind,
|
|
10711
|
+
function firstEvidenceForKind(context, kind, path16) {
|
|
10711
10712
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
10712
|
-
return event ? [eventEvidence(event,
|
|
10713
|
+
return event ? [eventEvidence(event, path16)] : runEvidence(context.selectedRun);
|
|
10713
10714
|
}
|
|
10714
10715
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
10715
10716
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -10957,13 +10958,13 @@ function createStructureCycleRule() {
|
|
|
10957
10958
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
10958
10959
|
const findings = [];
|
|
10959
10960
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
10960
|
-
const
|
|
10961
|
+
const path16 = [];
|
|
10961
10962
|
const seenAt = /* @__PURE__ */ new Map();
|
|
10962
10963
|
let current = event;
|
|
10963
10964
|
while (current) {
|
|
10964
10965
|
const existing = seenAt.get(current.eventId);
|
|
10965
10966
|
if (existing !== void 0) {
|
|
10966
|
-
const cycle =
|
|
10967
|
+
const cycle = path16.slice(existing);
|
|
10967
10968
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
10968
10969
|
if (!seenCycles.has(key)) {
|
|
10969
10970
|
seenCycles.add(key);
|
|
@@ -10979,8 +10980,8 @@ function createStructureCycleRule() {
|
|
|
10979
10980
|
}
|
|
10980
10981
|
break;
|
|
10981
10982
|
}
|
|
10982
|
-
seenAt.set(current.eventId,
|
|
10983
|
-
|
|
10983
|
+
seenAt.set(current.eventId, path16.length);
|
|
10984
|
+
path16.push(current);
|
|
10984
10985
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
10985
10986
|
}
|
|
10986
10987
|
}
|
|
@@ -11777,23 +11778,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
11777
11778
|
}
|
|
11778
11779
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
11779
11780
|
}
|
|
11780
|
-
function validateSchemaField(value, field,
|
|
11781
|
+
function validateSchemaField(value, field, path16, evidence) {
|
|
11781
11782
|
const ruleId = "guardrail.structured-output";
|
|
11782
11783
|
if (field.type) {
|
|
11783
11784
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
11784
11785
|
if (actual !== field.type) {
|
|
11785
|
-
evidence.push({ ruleId, path:
|
|
11786
|
+
evidence.push({ ruleId, path: path16, preview: `expected ${field.type}, got ${actual}` });
|
|
11786
11787
|
return;
|
|
11787
11788
|
}
|
|
11788
11789
|
}
|
|
11789
11790
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
11790
|
-
evidence.push({ ruleId, path:
|
|
11791
|
+
evidence.push({ ruleId, path: path16, preview: "value not in enum" });
|
|
11791
11792
|
}
|
|
11792
11793
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
11793
11794
|
const record = value;
|
|
11794
11795
|
for (const key of field.required) {
|
|
11795
11796
|
if (!(key in record)) {
|
|
11796
|
-
evidence.push({ ruleId, path: `${
|
|
11797
|
+
evidence.push({ ruleId, path: `${path16}.${key}`, preview: "missing required key" });
|
|
11797
11798
|
}
|
|
11798
11799
|
}
|
|
11799
11800
|
}
|
|
@@ -12120,7 +12121,7 @@ function asConfig(value) {
|
|
|
12120
12121
|
}
|
|
12121
12122
|
async function loadConfig(configPath) {
|
|
12122
12123
|
if (configPath === void 0) return {};
|
|
12123
|
-
const extension =
|
|
12124
|
+
const extension = path14__default.default.extname(configPath);
|
|
12124
12125
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
12125
12126
|
throw new Error(
|
|
12126
12127
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -12129,7 +12130,7 @@ async function loadConfig(configPath) {
|
|
|
12129
12130
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
12130
12131
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
12131
12132
|
}
|
|
12132
|
-
const absolute =
|
|
12133
|
+
const absolute = path14__default.default.resolve(configPath);
|
|
12133
12134
|
if (extension === ".json") {
|
|
12134
12135
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
12135
12136
|
return asConfig(JSON.parse(raw));
|
|
@@ -12258,10 +12259,10 @@ function printHuman(result) {
|
|
|
12258
12259
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
12259
12260
|
}
|
|
12260
12261
|
for (const finding of result.findings) {
|
|
12261
|
-
const
|
|
12262
|
+
const path16 = finding.evidence[0]?.path;
|
|
12262
12263
|
const run = finding.evidence[0]?.runId;
|
|
12263
12264
|
const runPrefix = run ? `[${run}] ` : "";
|
|
12264
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
12265
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
|
|
12265
12266
|
}
|
|
12266
12267
|
}
|
|
12267
12268
|
function readErrorResult(error) {
|
|
@@ -12375,6 +12376,262 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
12375
12376
|
else printHuman(result);
|
|
12376
12377
|
}
|
|
12377
12378
|
|
|
12379
|
+
// packages/viewer/src/html.ts
|
|
12380
|
+
var viewerIndexHtml = `<!DOCTYPE html>
|
|
12381
|
+
<html lang="en">
|
|
12382
|
+
<head>
|
|
12383
|
+
<meta charset="utf-8" />
|
|
12384
|
+
<title>AgentInspect Viewer</title>
|
|
12385
|
+
<style>
|
|
12386
|
+
body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }
|
|
12387
|
+
h1 { font-size: 1.25rem; }
|
|
12388
|
+
pre { background: #f4f4f5; padding: 1rem; overflow: auto; max-height: 70vh; }
|
|
12389
|
+
a { color: #0b57d0; }
|
|
12390
|
+
.muted { color: #666; }
|
|
12391
|
+
</style>
|
|
12392
|
+
</head>
|
|
12393
|
+
<body>
|
|
12394
|
+
<h1>AgentInspect local viewer</h1>
|
|
12395
|
+
<p class="muted">Read-only. JSONL on disk remains canonical.</p>
|
|
12396
|
+
<p><a href="/api/health">/api/health</a> \xB7 <a href="/api/traces">/api/traces</a> \xB7 <a href="/api/sessions">/api/sessions</a></p>
|
|
12397
|
+
<pre id="out">Loading traces\u2026</pre>
|
|
12398
|
+
<script>
|
|
12399
|
+
fetch("/api/traces").then((r) => r.json()).then((data) => {
|
|
12400
|
+
document.getElementById("out").textContent = JSON.stringify(data, null, 2);
|
|
12401
|
+
}).catch((err) => {
|
|
12402
|
+
document.getElementById("out").textContent = String(err);
|
|
12403
|
+
});
|
|
12404
|
+
</script>
|
|
12405
|
+
</body>
|
|
12406
|
+
</html>
|
|
12407
|
+
`;
|
|
12408
|
+
|
|
12409
|
+
// packages/viewer/src/server.ts
|
|
12410
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
12411
|
+
var DEFAULT_PORT = 7337;
|
|
12412
|
+
var DEFAULT_MAX_EVENTS = 500;
|
|
12413
|
+
function sendJson(res, status, body) {
|
|
12414
|
+
const payload = JSON.stringify(body);
|
|
12415
|
+
res.writeHead(status, {
|
|
12416
|
+
"content-type": "application/json; charset=utf-8",
|
|
12417
|
+
"cache-control": "no-store"
|
|
12418
|
+
});
|
|
12419
|
+
res.end(payload);
|
|
12420
|
+
}
|
|
12421
|
+
function notFound(res, message) {
|
|
12422
|
+
sendJson(res, 404, { error: message });
|
|
12423
|
+
}
|
|
12424
|
+
function badRequest(res, message) {
|
|
12425
|
+
sendJson(res, 400, { error: message });
|
|
12426
|
+
}
|
|
12427
|
+
function decodeId(segment) {
|
|
12428
|
+
if (!segment) return "";
|
|
12429
|
+
try {
|
|
12430
|
+
return decodeURIComponent(segment);
|
|
12431
|
+
} catch {
|
|
12432
|
+
return segment;
|
|
12433
|
+
}
|
|
12434
|
+
}
|
|
12435
|
+
function boundedEvents(events, maxEvents) {
|
|
12436
|
+
if (events.length <= maxEvents) return [...events];
|
|
12437
|
+
return events.slice(0, maxEvents);
|
|
12438
|
+
}
|
|
12439
|
+
function createViewerServer(options = {}) {
|
|
12440
|
+
const traceDir = resolveTraceDir({ dir: options.traceDir });
|
|
12441
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
12442
|
+
const port = options.port ?? DEFAULT_PORT;
|
|
12443
|
+
const maxEvents = options.maxEvents ?? DEFAULT_MAX_EVENTS;
|
|
12444
|
+
if (host === "0.0.0.0") {
|
|
12445
|
+
console.warn(
|
|
12446
|
+
"[AgentInspect viewer] Binding to 0.0.0.0 exposes traces on the network. Use 127.0.0.1 unless you accept that risk."
|
|
12447
|
+
);
|
|
12448
|
+
}
|
|
12449
|
+
const server = http.createServer(async (req, res) => {
|
|
12450
|
+
try {
|
|
12451
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
12452
|
+
return badRequest(res, "Only GET is supported.");
|
|
12453
|
+
}
|
|
12454
|
+
const url = new URL(req.url ?? "/", `http://${host}:${port}`);
|
|
12455
|
+
const pathname = url.pathname;
|
|
12456
|
+
if (pathname === "/" || pathname === "/index.html") {
|
|
12457
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
12458
|
+
res.end(viewerIndexHtml);
|
|
12459
|
+
return;
|
|
12460
|
+
}
|
|
12461
|
+
if (pathname === "/api/health") {
|
|
12462
|
+
return sendJson(res, 200, {
|
|
12463
|
+
ok: true,
|
|
12464
|
+
readOnly: true,
|
|
12465
|
+
traceDir: path14__default.default.resolve(traceDir)
|
|
12466
|
+
});
|
|
12467
|
+
}
|
|
12468
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
12469
|
+
if (pathname === "/api/traces") {
|
|
12470
|
+
const files = await td.list();
|
|
12471
|
+
const metas = await loadTraceMetadataList(
|
|
12472
|
+
traceDir,
|
|
12473
|
+
files,
|
|
12474
|
+
(fileName) => td.getPath(fileName)
|
|
12475
|
+
);
|
|
12476
|
+
return sendJson(
|
|
12477
|
+
res,
|
|
12478
|
+
200,
|
|
12479
|
+
metas.map((meta) => ({
|
|
12480
|
+
runId: meta.runId,
|
|
12481
|
+
name: meta.name,
|
|
12482
|
+
status: meta.status,
|
|
12483
|
+
file: path14__default.default.basename(meta.filePath),
|
|
12484
|
+
startedAt: meta.startedAt,
|
|
12485
|
+
durationMs: meta.durationMs
|
|
12486
|
+
}))
|
|
12487
|
+
);
|
|
12488
|
+
}
|
|
12489
|
+
if (pathname === "/api/sessions") {
|
|
12490
|
+
const files = await td.list();
|
|
12491
|
+
const metas = await loadTraceMetadataList(
|
|
12492
|
+
traceDir,
|
|
12493
|
+
files,
|
|
12494
|
+
(fileName) => td.getPath(fileName)
|
|
12495
|
+
);
|
|
12496
|
+
const runs = await loadSessionRunRecords(metas);
|
|
12497
|
+
const index = buildSessionIndex(runs, {
|
|
12498
|
+
correlateByGroupId: url.searchParams.get("correlateGroup") === "true"
|
|
12499
|
+
});
|
|
12500
|
+
return sendJson(res, 200, index);
|
|
12501
|
+
}
|
|
12502
|
+
const sessionMatch = pathname.match(/^\/api\/session\/([^/]+)$/);
|
|
12503
|
+
if (sessionMatch) {
|
|
12504
|
+
const sessionId = decodeId(sessionMatch[1]);
|
|
12505
|
+
const files = await td.list();
|
|
12506
|
+
const metas = await loadTraceMetadataList(
|
|
12507
|
+
traceDir,
|
|
12508
|
+
files,
|
|
12509
|
+
(fileName) => td.getPath(fileName)
|
|
12510
|
+
);
|
|
12511
|
+
const runs = await loadSessionRunRecords(metas);
|
|
12512
|
+
const index = buildSessionIndex(runs, {
|
|
12513
|
+
correlateByGroupId: url.searchParams.get("correlateGroup") === "true"
|
|
12514
|
+
});
|
|
12515
|
+
const session = index.sessions.find((item) => item.sessionId === sessionId);
|
|
12516
|
+
if (!session) return notFound(res, `Session not found: ${sessionId}`);
|
|
12517
|
+
return sendJson(res, 200, session);
|
|
12518
|
+
}
|
|
12519
|
+
const traceMatch = pathname.match(/^\/api\/trace\/([^/]+)$/);
|
|
12520
|
+
if (traceMatch) {
|
|
12521
|
+
const runId = decodeId(traceMatch[1]);
|
|
12522
|
+
const files = await td.list();
|
|
12523
|
+
const metas = await loadTraceMetadataList(
|
|
12524
|
+
traceDir,
|
|
12525
|
+
files,
|
|
12526
|
+
(fileName) => td.getPath(fileName)
|
|
12527
|
+
);
|
|
12528
|
+
const meta = metas.find((item) => item.runId === runId);
|
|
12529
|
+
if (!meta) return notFound(res, `Run not found: ${runId}`);
|
|
12530
|
+
const read = await openTrace({ type: "file", path: meta.filePath });
|
|
12531
|
+
const run = read.runs.find((item) => item.runId === runId) ?? read.runs[0];
|
|
12532
|
+
return sendJson(res, 200, {
|
|
12533
|
+
runId,
|
|
12534
|
+
format: read.format,
|
|
12535
|
+
run,
|
|
12536
|
+
events: boundedEvents(read.events, maxEvents),
|
|
12537
|
+
warnings: read.warnings,
|
|
12538
|
+
truncated: read.events.length > maxEvents
|
|
12539
|
+
});
|
|
12540
|
+
}
|
|
12541
|
+
const timelineMatch = pathname.match(/^\/api\/trace\/([^/]+)\/timeline$/);
|
|
12542
|
+
if (timelineMatch) {
|
|
12543
|
+
const runId = decodeId(timelineMatch[1]);
|
|
12544
|
+
const files = await td.list();
|
|
12545
|
+
const metas = await loadTraceMetadataList(
|
|
12546
|
+
traceDir,
|
|
12547
|
+
files,
|
|
12548
|
+
(fileName) => td.getPath(fileName)
|
|
12549
|
+
);
|
|
12550
|
+
const meta = metas.find((item) => item.runId === runId);
|
|
12551
|
+
if (!meta) return notFound(res, `Run not found: ${runId}`);
|
|
12552
|
+
const read = await openTrace({ type: "file", path: meta.filePath });
|
|
12553
|
+
const legacyEvents = persistedInspectEventsToTraceEvents(
|
|
12554
|
+
boundedEvents(read.events, maxEvents)
|
|
12555
|
+
);
|
|
12556
|
+
const timeline = buildRunTimeline(legacyEvents, { focus: "all" });
|
|
12557
|
+
return sendJson(res, 200, { runId, timeline });
|
|
12558
|
+
}
|
|
12559
|
+
const checkMatch = pathname.match(/^\/api\/trace\/([^/]+)\/check$/);
|
|
12560
|
+
if (checkMatch) {
|
|
12561
|
+
const runId = decodeId(checkMatch[1]);
|
|
12562
|
+
const files = await td.list();
|
|
12563
|
+
const metas = await loadTraceMetadataList(
|
|
12564
|
+
traceDir,
|
|
12565
|
+
files,
|
|
12566
|
+
(fileName) => td.getPath(fileName)
|
|
12567
|
+
);
|
|
12568
|
+
const meta = metas.find((item) => item.runId === runId);
|
|
12569
|
+
if (!meta) return notFound(res, `Run not found: ${runId}`);
|
|
12570
|
+
const read = await openTrace({ type: "file", path: meta.filePath });
|
|
12571
|
+
const result = runTraceChecks(
|
|
12572
|
+
{ read },
|
|
12573
|
+
{ rules: [createRunStatusRule()], select: ["run.status"], runId }
|
|
12574
|
+
);
|
|
12575
|
+
return sendJson(res, 200, result);
|
|
12576
|
+
}
|
|
12577
|
+
return notFound(res, `Unknown route: ${pathname}`);
|
|
12578
|
+
} catch (error) {
|
|
12579
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12580
|
+
sendJson(res, 500, { error: message });
|
|
12581
|
+
}
|
|
12582
|
+
});
|
|
12583
|
+
return server;
|
|
12584
|
+
}
|
|
12585
|
+
function startViewerServer(options = {}) {
|
|
12586
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
12587
|
+
const port = options.port ?? DEFAULT_PORT;
|
|
12588
|
+
const traceDir = resolveTraceDir({ dir: options.traceDir });
|
|
12589
|
+
const server = createViewerServer(options);
|
|
12590
|
+
return new Promise((resolve, reject) => {
|
|
12591
|
+
server.once("error", reject);
|
|
12592
|
+
server.listen(port, host, () => {
|
|
12593
|
+
const address = server.address();
|
|
12594
|
+
const resolvedPort = typeof address === "object" && address ? address.port : port;
|
|
12595
|
+
resolve({
|
|
12596
|
+
host,
|
|
12597
|
+
port: resolvedPort,
|
|
12598
|
+
traceDir: path14__default.default.resolve(traceDir),
|
|
12599
|
+
url: `http://${host}:${resolvedPort}`
|
|
12600
|
+
});
|
|
12601
|
+
});
|
|
12602
|
+
});
|
|
12603
|
+
}
|
|
12604
|
+
|
|
12605
|
+
// packages/cli/src/serve.ts
|
|
12606
|
+
function parsePort(value) {
|
|
12607
|
+
if (value === void 0) return void 0;
|
|
12608
|
+
const parsed = Number(value);
|
|
12609
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) {
|
|
12610
|
+
throw new Error("--port must be an integer between 1 and 65535.");
|
|
12611
|
+
}
|
|
12612
|
+
return parsed;
|
|
12613
|
+
}
|
|
12614
|
+
async function serveCommand(options = {}) {
|
|
12615
|
+
const port = parsePort(options.port);
|
|
12616
|
+
const host = options.host?.trim() || "127.0.0.1";
|
|
12617
|
+
const info = await startViewerServer({
|
|
12618
|
+
...options.dir !== void 0 ? { traceDir: options.dir } : {},
|
|
12619
|
+
host,
|
|
12620
|
+
...port !== void 0 ? { port } : {}
|
|
12621
|
+
});
|
|
12622
|
+
console.log(`AgentInspect viewer (read-only): ${info.url}`);
|
|
12623
|
+
console.log(`Trace directory: ${info.traceDir}`);
|
|
12624
|
+
if (options.open === true && host !== "127.0.0.1" && host !== "localhost") {
|
|
12625
|
+
console.warn("Skipping browser open for non-local host binding.");
|
|
12626
|
+
} else if (options.open === true) {
|
|
12627
|
+
const openMod = await import('child_process');
|
|
12628
|
+
openMod.exec(`open ${info.url}`, () => {
|
|
12629
|
+
});
|
|
12630
|
+
}
|
|
12631
|
+
await new Promise(() => {
|
|
12632
|
+
});
|
|
12633
|
+
}
|
|
12634
|
+
|
|
12378
12635
|
// packages/eval/src/index.ts
|
|
12379
12636
|
function isTraceReadResult(value) {
|
|
12380
12637
|
return value !== null && typeof value === "object" && "runs" in value && "events" in value && "format" in value;
|
|
@@ -12543,10 +12800,10 @@ async function evalRun(input3, options = {}) {
|
|
|
12543
12800
|
diagnostics: []
|
|
12544
12801
|
};
|
|
12545
12802
|
}
|
|
12546
|
-
function evidenceForRun(run,
|
|
12547
|
-
return [{ runId: run.runId, ...
|
|
12803
|
+
function evidenceForRun(run, path16) {
|
|
12804
|
+
return [{ runId: run.runId, ...path16 !== void 0 ? { path: path16 } : {} }];
|
|
12548
12805
|
}
|
|
12549
|
-
function evidenceForEvent(event,
|
|
12806
|
+
function evidenceForEvent(event, path16) {
|
|
12550
12807
|
return [
|
|
12551
12808
|
{
|
|
12552
12809
|
runId: event.runId,
|
|
@@ -12554,7 +12811,7 @@ function evidenceForEvent(event, path15) {
|
|
|
12554
12811
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
12555
12812
|
kind: event.kind,
|
|
12556
12813
|
name: event.name,
|
|
12557
|
-
...
|
|
12814
|
+
...path16 !== void 0 ? { path: path16 } : {}
|
|
12558
12815
|
}
|
|
12559
12816
|
];
|
|
12560
12817
|
}
|
|
@@ -12712,9 +12969,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
12712
12969
|
function tokenize(text) {
|
|
12713
12970
|
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));
|
|
12714
12971
|
}
|
|
12715
|
-
function firstEvidence(fields, run,
|
|
12972
|
+
function firstEvidence(fields, run, path16) {
|
|
12716
12973
|
const first = fields[0];
|
|
12717
|
-
return first === void 0 ? evidenceForRun(run,
|
|
12974
|
+
return first === void 0 ? evidenceForRun(run, path16) : evidenceForEvent(first.node.event, first.path);
|
|
12718
12975
|
}
|
|
12719
12976
|
function collectSourceIds(nodes, keys) {
|
|
12720
12977
|
const wanted = keySet(keys);
|
|
@@ -13091,8 +13348,8 @@ function renderEvalMarkdown(result) {
|
|
|
13091
13348
|
if (result.findings.length > 0) {
|
|
13092
13349
|
lines.push("", "## Findings");
|
|
13093
13350
|
for (const finding of result.findings) {
|
|
13094
|
-
const
|
|
13095
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
13351
|
+
const path16 = finding.evidence[0]?.path;
|
|
13352
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
|
|
13096
13353
|
}
|
|
13097
13354
|
}
|
|
13098
13355
|
return `${lines.join("\n")}
|
|
@@ -13139,7 +13396,7 @@ function asConfig2(value) {
|
|
|
13139
13396
|
}
|
|
13140
13397
|
async function loadConfig2(configPath) {
|
|
13141
13398
|
if (configPath === void 0) return {};
|
|
13142
|
-
const extension =
|
|
13399
|
+
const extension = path14__default.default.extname(configPath);
|
|
13143
13400
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
13144
13401
|
throw new Error(
|
|
13145
13402
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -13148,7 +13405,7 @@ async function loadConfig2(configPath) {
|
|
|
13148
13405
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
13149
13406
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
13150
13407
|
}
|
|
13151
|
-
const absolute =
|
|
13408
|
+
const absolute = path14__default.default.resolve(configPath);
|
|
13152
13409
|
if (extension === ".json") {
|
|
13153
13410
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
13154
13411
|
return asConfig2(JSON.parse(raw));
|
|
@@ -13285,8 +13542,8 @@ function printHuman2(result) {
|
|
|
13285
13542
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13286
13543
|
}
|
|
13287
13544
|
for (const finding of result.findings) {
|
|
13288
|
-
const
|
|
13289
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
13545
|
+
const path16 = finding.evidence[0]?.path;
|
|
13546
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
|
|
13290
13547
|
}
|
|
13291
13548
|
}
|
|
13292
13549
|
function readErrorResult2(error) {
|
|
@@ -13524,8 +13781,8 @@ function printHuman3(result) {
|
|
|
13524
13781
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13525
13782
|
}
|
|
13526
13783
|
for (const finding of result.findings) {
|
|
13527
|
-
const
|
|
13528
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
13784
|
+
const path16 = finding.evidence[0]?.path;
|
|
13785
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path16 ? ` (${path16})` : ""}`);
|
|
13529
13786
|
}
|
|
13530
13787
|
console.log(`Note: ${result.note}`);
|
|
13531
13788
|
}
|
|
@@ -13644,8 +13901,8 @@ function renderCheckSection(result) {
|
|
|
13644
13901
|
`Diagnostics: ${result.diagnostics.length}`
|
|
13645
13902
|
];
|
|
13646
13903
|
for (const finding of result.findings.slice(0, 10)) {
|
|
13647
|
-
const
|
|
13648
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
13904
|
+
const path16 = finding.evidence[0]?.path ?? "(run)";
|
|
13905
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path16})`);
|
|
13649
13906
|
}
|
|
13650
13907
|
for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
|
|
13651
13908
|
lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
@@ -13723,8 +13980,8 @@ function renderHtml(trace, check, diff) {
|
|
|
13723
13980
|
`;
|
|
13724
13981
|
}
|
|
13725
13982
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
13726
|
-
const outPath =
|
|
13727
|
-
await promises.mkdir(
|
|
13983
|
+
const outPath = path14__default.default.join(outputDir, relativePath);
|
|
13984
|
+
await promises.mkdir(path14__default.default.dirname(outPath), { recursive: true });
|
|
13728
13985
|
await promises.writeFile(outPath, content, "utf-8");
|
|
13729
13986
|
files.push(relativePath);
|
|
13730
13987
|
}
|
|
@@ -13740,7 +13997,7 @@ function manifestStatus(check, diff) {
|
|
|
13740
13997
|
return "ok";
|
|
13741
13998
|
}
|
|
13742
13999
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
13743
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
14000
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path14__default.default.resolve(options.outputDir.trim()) : "";
|
|
13744
14001
|
if (outputDir === "") {
|
|
13745
14002
|
console.error("--output-dir is required.");
|
|
13746
14003
|
process.exitCode = 1;
|
|
@@ -13806,8 +14063,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
13806
14063
|
await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
|
|
13807
14064
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
13808
14065
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
13809
|
-
await promises.mkdir(
|
|
13810
|
-
await promises.appendFile(
|
|
14066
|
+
await promises.mkdir(path14__default.default.dirname(path14__default.default.resolve(summaryTarget)), { recursive: true });
|
|
14067
|
+
await promises.appendFile(path14__default.default.resolve(summaryTarget), `
|
|
13811
14068
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
13812
14069
|
}
|
|
13813
14070
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -13826,10 +14083,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
13826
14083
|
findings: diff?.findings.length ?? 0,
|
|
13827
14084
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
13828
14085
|
},
|
|
13829
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
14086
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path14__default.default.resolve(summaryTarget) } : {},
|
|
13830
14087
|
note: NOTE
|
|
13831
14088
|
};
|
|
13832
|
-
await promises.writeFile(
|
|
14089
|
+
await promises.writeFile(path14__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
13833
14090
|
if (options.json === true) {
|
|
13834
14091
|
console.log(writeJson3(manifest).trimEnd());
|
|
13835
14092
|
} else {
|
|
@@ -13841,7 +14098,7 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
13841
14098
|
}
|
|
13842
14099
|
}
|
|
13843
14100
|
function validateReporterArtifactPath(options) {
|
|
13844
|
-
const outputDir =
|
|
14101
|
+
const outputDir = path14__default.default.resolve(options.outputDir);
|
|
13845
14102
|
const diagnostics = [];
|
|
13846
14103
|
const rawPath = options.relativePath;
|
|
13847
14104
|
if (rawPath.length === 0) {
|
|
@@ -13861,7 +14118,7 @@ function validateReporterArtifactPath(options) {
|
|
|
13861
14118
|
});
|
|
13862
14119
|
return { ok: false, outputDir, diagnostics };
|
|
13863
14120
|
}
|
|
13864
|
-
if (
|
|
14121
|
+
if (path14__default.default.isAbsolute(rawPath) || path14__default.default.win32.isAbsolute(rawPath)) {
|
|
13865
14122
|
diagnostics.push({
|
|
13866
14123
|
code: "artifact_path_absolute",
|
|
13867
14124
|
severity: "error",
|
|
@@ -13870,7 +14127,7 @@ function validateReporterArtifactPath(options) {
|
|
|
13870
14127
|
});
|
|
13871
14128
|
return { ok: false, outputDir, diagnostics };
|
|
13872
14129
|
}
|
|
13873
|
-
const normalized =
|
|
14130
|
+
const normalized = path14__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
13874
14131
|
const segments = normalized.split("/");
|
|
13875
14132
|
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
13876
14133
|
diagnostics.push({
|
|
@@ -13881,9 +14138,9 @@ function validateReporterArtifactPath(options) {
|
|
|
13881
14138
|
});
|
|
13882
14139
|
return { ok: false, outputDir, diagnostics };
|
|
13883
14140
|
}
|
|
13884
|
-
const absolutePath =
|
|
13885
|
-
const relFromOutput =
|
|
13886
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") ||
|
|
14141
|
+
const absolutePath = path14__default.default.resolve(outputDir, normalized);
|
|
14142
|
+
const relFromOutput = path14__default.default.relative(outputDir, absolutePath);
|
|
14143
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path14__default.default.isAbsolute(relFromOutput)) {
|
|
13887
14144
|
diagnostics.push({
|
|
13888
14145
|
code: "artifact_path_escape",
|
|
13889
14146
|
severity: "error",
|
|
@@ -14029,23 +14286,23 @@ function readManifestDocument(value) {
|
|
|
14029
14286
|
};
|
|
14030
14287
|
}
|
|
14031
14288
|
function cwdRelative(filePath) {
|
|
14032
|
-
const relative =
|
|
14033
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
14034
|
-
return
|
|
14289
|
+
const relative = path14__default.default.relative(process.cwd(), path14__default.default.resolve(filePath)).replace(/\\/g, "/");
|
|
14290
|
+
if (relative === "" || relative.startsWith("../") || path14__default.default.isAbsolute(relative)) {
|
|
14291
|
+
return path14__default.default.basename(filePath);
|
|
14035
14292
|
}
|
|
14036
14293
|
return relative;
|
|
14037
14294
|
}
|
|
14038
14295
|
async function readReporterManifest(filePath) {
|
|
14039
|
-
const absolute =
|
|
14296
|
+
const absolute = path14__default.default.resolve(filePath);
|
|
14040
14297
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
14041
14298
|
const document = readManifestDocument(JSON.parse(raw));
|
|
14042
14299
|
const manifest = document.manifest;
|
|
14043
14300
|
const results = manifest.results.map((result) => ({
|
|
14044
14301
|
testId: safeText(result.testId),
|
|
14045
14302
|
name: safeText(result.name),
|
|
14046
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
14303
|
+
...result.file === void 0 ? {} : { file: safeText(path14__default.default.basename(result.file)) },
|
|
14047
14304
|
status: result.status,
|
|
14048
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
14305
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path14__default.default.basename(result.tracePath)) },
|
|
14049
14306
|
artifacts: result.artifacts,
|
|
14050
14307
|
diagnostics: result.diagnostics
|
|
14051
14308
|
}));
|
|
@@ -14184,15 +14441,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
14184
14441
|
return;
|
|
14185
14442
|
}
|
|
14186
14443
|
const markdown = renderMarkdown2(result);
|
|
14187
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
14444
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path14__default.default.resolve(options.output.trim()) : void 0;
|
|
14188
14445
|
if (outputPath !== void 0) {
|
|
14189
|
-
await promises.mkdir(
|
|
14446
|
+
await promises.mkdir(path14__default.default.dirname(outputPath), { recursive: true });
|
|
14190
14447
|
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
14191
14448
|
}
|
|
14192
14449
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
14193
14450
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
14194
|
-
const summaryPath =
|
|
14195
|
-
await promises.mkdir(
|
|
14451
|
+
const summaryPath = path14__default.default.resolve(summaryTarget);
|
|
14452
|
+
await promises.mkdir(path14__default.default.dirname(summaryPath), { recursive: true });
|
|
14196
14453
|
await promises.appendFile(summaryPath, `
|
|
14197
14454
|
${markdown}`, "utf-8");
|
|
14198
14455
|
}
|
|
@@ -14344,6 +14601,9 @@ function createCliProgram() {
|
|
|
14344
14601
|
).action((target, opts) => {
|
|
14345
14602
|
runCommand(() => checkCommand(target, opts));
|
|
14346
14603
|
});
|
|
14604
|
+
program.command("serve").description("Start optional localhost read-only trace viewer").option("--dir <path>", "trace directory to serve").option("--host <host>", "bind host (default 127.0.0.1)", "127.0.0.1").option("--port <number>", "bind port (default 7337)", "7337").option("--open", "open browser locally when host is localhost").action((opts) => {
|
|
14605
|
+
runCommand(() => serveCommand(opts));
|
|
14606
|
+
});
|
|
14347
14607
|
program.command("eval").description("Run deterministic local evals against a trace").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
|
|
14348
14608
|
new commander.Option("--format <format>", "trace input format").choices([
|
|
14349
14609
|
"agent-inspect-jsonl",
|
|
@@ -14508,9 +14768,9 @@ function isPrimaryModule() {
|
|
|
14508
14768
|
if (!entry) return false;
|
|
14509
14769
|
const selfPath = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
14510
14770
|
try {
|
|
14511
|
-
return fs.realpathSync(
|
|
14771
|
+
return fs.realpathSync(path14__default.default.resolve(entry)) === fs.realpathSync(path14__default.default.resolve(selfPath));
|
|
14512
14772
|
} catch {
|
|
14513
|
-
return
|
|
14773
|
+
return path14__default.default.resolve(entry) === path14__default.default.resolve(selfPath);
|
|
14514
14774
|
}
|
|
14515
14775
|
}
|
|
14516
14776
|
if (isPrimaryModule()) {
|