agent-inspect 2.1.0 → 2.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.
- package/CHANGELOG.md +16 -0
- package/README.md +13 -3
- package/docs/API.md +29 -4
- package/docs/CLI.md +34 -7
- package/package.json +11 -1
- package/packages/cli/dist/index.cjs +461 -93
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +460 -92
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/reporters.cjs +185 -0
- package/packages/core/dist/reporters.cjs.map +1 -0
- package/packages/core/dist/reporters.d.cts +91 -0
- package/packages/core/dist/reporters.d.ts +91 -0
- package/packages/core/dist/reporters.mjs +175 -0
- package/packages/core/dist/reporters.mjs.map +1 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var fs = require('fs');
|
|
5
|
-
var
|
|
5
|
+
var path13 = require('path');
|
|
6
6
|
var url = require('url');
|
|
7
7
|
var commander = require('commander');
|
|
8
8
|
var async_hooks = require('async_hooks');
|
|
@@ -16,14 +16,14 @@ var readline = require('readline');
|
|
|
16
16
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
17
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
18
|
|
|
19
|
-
var
|
|
19
|
+
var path13__default = /*#__PURE__*/_interopDefault(path13);
|
|
20
20
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
21
21
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
22
22
|
var process2__default = /*#__PURE__*/_interopDefault(process2);
|
|
23
23
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
24
24
|
|
|
25
25
|
// package.json
|
|
26
|
-
var version = "2.
|
|
26
|
+
var version = "2.2.0";
|
|
27
27
|
|
|
28
28
|
// packages/core/src/correlation-metadata.ts
|
|
29
29
|
var TRACE_CORRELATION_KEYS = [
|
|
@@ -755,7 +755,7 @@ function formatDuration(ms) {
|
|
|
755
755
|
// packages/core/src/utils.ts
|
|
756
756
|
var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
757
757
|
var RUNS_DIR_NAME = "runs";
|
|
758
|
-
var FALLBACK_TRACE_DIR =
|
|
758
|
+
var FALLBACK_TRACE_DIR = path13__default.default.join(
|
|
759
759
|
os__default.default.tmpdir(),
|
|
760
760
|
"agent-inspect",
|
|
761
761
|
RUNS_DIR_NAME
|
|
@@ -790,7 +790,7 @@ function getDefaultTraceDir() {
|
|
|
790
790
|
if (typeof home !== "string" || home.trim() === "") {
|
|
791
791
|
return FALLBACK_TRACE_DIR;
|
|
792
792
|
}
|
|
793
|
-
return
|
|
793
|
+
return path13__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
794
794
|
} catch {
|
|
795
795
|
return FALLBACK_TRACE_DIR;
|
|
796
796
|
}
|
|
@@ -798,11 +798,11 @@ function getDefaultTraceDir() {
|
|
|
798
798
|
function getTraceFilePath(runId, traceDir) {
|
|
799
799
|
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
800
800
|
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
801
|
-
safeId =
|
|
801
|
+
safeId = path13__default.default.basename(safeId);
|
|
802
802
|
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
803
803
|
safeId = "run_unknown";
|
|
804
804
|
}
|
|
805
|
-
return
|
|
805
|
+
return path13__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
806
806
|
}
|
|
807
807
|
function formatError(error) {
|
|
808
808
|
if (error instanceof Error) {
|
|
@@ -1564,7 +1564,7 @@ var TraceDirectory = class {
|
|
|
1564
1564
|
this.#dir = resolveTraceDir(options);
|
|
1565
1565
|
}
|
|
1566
1566
|
getPath(filename) {
|
|
1567
|
-
return filename ?
|
|
1567
|
+
return filename ? path13__default.default.join(this.#dir, filename) : this.#dir;
|
|
1568
1568
|
}
|
|
1569
1569
|
async list() {
|
|
1570
1570
|
try {
|
|
@@ -1591,7 +1591,7 @@ function parseIsoToMs2(value) {
|
|
|
1591
1591
|
}
|
|
1592
1592
|
async function extractMetadata(filePath, _quickScan) {
|
|
1593
1593
|
const stats = await promises.stat(filePath);
|
|
1594
|
-
let runIdFromFile =
|
|
1594
|
+
let runIdFromFile = path13__default.default.basename(filePath);
|
|
1595
1595
|
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1596
1596
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1597
1597
|
}
|
|
@@ -3562,7 +3562,7 @@ function findReaderByFormat(format, readers) {
|
|
|
3562
3562
|
}
|
|
3563
3563
|
async function jsonlFilesInDirectory(dirPath) {
|
|
3564
3564
|
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
3565
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
3565
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path13__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
3566
3566
|
}
|
|
3567
3567
|
async function resolveInput(input3) {
|
|
3568
3568
|
const cached = resolvedInputCache.get(input3);
|
|
@@ -7688,9 +7688,9 @@ Trace directory: ${traceDir}`);
|
|
|
7688
7688
|
if (validation !== void 0 && !validation.ok) {
|
|
7689
7689
|
process.exitCode = 1;
|
|
7690
7690
|
}
|
|
7691
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
7691
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path13__default.default.resolve(options.output.trim()) : void 0;
|
|
7692
7692
|
if (outPath !== void 0) {
|
|
7693
|
-
await promises.mkdir(
|
|
7693
|
+
await promises.mkdir(path13__default.default.dirname(outPath), { recursive: true });
|
|
7694
7694
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
7695
7695
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
7696
7696
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -7867,13 +7867,13 @@ function pairSteps(left, right) {
|
|
|
7867
7867
|
return pairs;
|
|
7868
7868
|
}
|
|
7869
7869
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
7870
|
-
const
|
|
7870
|
+
const path15 = buildPath(segments);
|
|
7871
7871
|
if (L.name !== R.name) {
|
|
7872
7872
|
out.push({
|
|
7873
7873
|
kind: "structure",
|
|
7874
7874
|
severity: "warning",
|
|
7875
7875
|
message: "Step name differs",
|
|
7876
|
-
path:
|
|
7876
|
+
path: path15,
|
|
7877
7877
|
left: L.name,
|
|
7878
7878
|
right: R.name
|
|
7879
7879
|
});
|
|
@@ -7883,7 +7883,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
7883
7883
|
kind: "step-type",
|
|
7884
7884
|
severity: "warning",
|
|
7885
7885
|
message: "Step type differs",
|
|
7886
|
-
path:
|
|
7886
|
+
path: path15,
|
|
7887
7887
|
left: L.type,
|
|
7888
7888
|
right: R.type
|
|
7889
7889
|
});
|
|
@@ -7893,7 +7893,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
7893
7893
|
kind: "step-status",
|
|
7894
7894
|
severity: "warning",
|
|
7895
7895
|
message: "Step status differs",
|
|
7896
|
-
path:
|
|
7896
|
+
path: path15,
|
|
7897
7897
|
left: L.status,
|
|
7898
7898
|
right: R.status
|
|
7899
7899
|
});
|
|
@@ -7905,7 +7905,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
7905
7905
|
kind: "error",
|
|
7906
7906
|
severity: "error",
|
|
7907
7907
|
message: "Step error message differs",
|
|
7908
|
-
path:
|
|
7908
|
+
path: path15,
|
|
7909
7909
|
left: le || void 0,
|
|
7910
7910
|
right: re || void 0
|
|
7911
7911
|
});
|
|
@@ -7923,7 +7923,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
7923
7923
|
kind: "duration",
|
|
7924
7924
|
severity: "info",
|
|
7925
7925
|
message: "Step duration differs",
|
|
7926
|
-
path:
|
|
7926
|
+
path: path15,
|
|
7927
7927
|
left: ld,
|
|
7928
7928
|
right: rd
|
|
7929
7929
|
});
|
|
@@ -7936,7 +7936,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
7936
7936
|
kind: "metadata",
|
|
7937
7937
|
severity: "info",
|
|
7938
7938
|
message: "Step metadata differs",
|
|
7939
|
-
path:
|
|
7939
|
+
path: path15,
|
|
7940
7940
|
left: L.metadata,
|
|
7941
7941
|
right: R.metadata
|
|
7942
7942
|
});
|
|
@@ -7948,7 +7948,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
7948
7948
|
kind: "output",
|
|
7949
7949
|
severity: "info",
|
|
7950
7950
|
message: "Output preview differs",
|
|
7951
|
-
path:
|
|
7951
|
+
path: path15,
|
|
7952
7952
|
left: L.outputPreview,
|
|
7953
7953
|
right: R.outputPreview
|
|
7954
7954
|
});
|
|
@@ -8108,11 +8108,11 @@ function diffRuns(left, right, options) {
|
|
|
8108
8108
|
}
|
|
8109
8109
|
|
|
8110
8110
|
// packages/core/src/diff/renderer.ts
|
|
8111
|
-
function formatPath(
|
|
8112
|
-
if (
|
|
8111
|
+
function formatPath(path15) {
|
|
8112
|
+
if (path15 === void 0 || path15.path.length === 0) {
|
|
8113
8113
|
return "(run)";
|
|
8114
8114
|
}
|
|
8115
|
-
return
|
|
8115
|
+
return path15.path.map((s) => s.name).join(" > ");
|
|
8116
8116
|
}
|
|
8117
8117
|
function formatValue(v, verbose) {
|
|
8118
8118
|
if (v === void 0) return "(undefined)";
|
|
@@ -8543,9 +8543,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
8543
8543
|
redactionProfile,
|
|
8544
8544
|
correlation: !options.noCorrelation
|
|
8545
8545
|
});
|
|
8546
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
8546
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path13__default.default.resolve(options.output.trim()) : void 0;
|
|
8547
8547
|
if (outPath !== void 0) {
|
|
8548
|
-
await promises.mkdir(
|
|
8548
|
+
await promises.mkdir(path13__default.default.dirname(outPath), { recursive: true });
|
|
8549
8549
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
8550
8550
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
8551
8551
|
}
|
|
@@ -8792,17 +8792,17 @@ function applyRule(rule, value, replacement) {
|
|
|
8792
8792
|
}
|
|
8793
8793
|
return value;
|
|
8794
8794
|
}
|
|
8795
|
-
function childPath(
|
|
8795
|
+
function childPath(path15, key) {
|
|
8796
8796
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
8797
|
-
return
|
|
8797
|
+
return path15 ? `${path15}.${key}` : key;
|
|
8798
8798
|
}
|
|
8799
|
-
return `${
|
|
8799
|
+
return `${path15 || "$"}[${JSON.stringify(key)}]`;
|
|
8800
8800
|
}
|
|
8801
|
-
function indexPath(
|
|
8802
|
-
return `${
|
|
8801
|
+
function indexPath(path15, index) {
|
|
8802
|
+
return `${path15 || "$"}[${index}]`;
|
|
8803
8803
|
}
|
|
8804
|
-
function makeFinding(
|
|
8805
|
-
return preview === void 0 ? { path:
|
|
8804
|
+
function makeFinding(path15, detector, action, matchKind, severity = "warning", preview) {
|
|
8805
|
+
return preview === void 0 ? { path: path15, detector, action, severity, matchKind } : { path: path15, detector, action, severity, matchKind, preview };
|
|
8806
8806
|
}
|
|
8807
8807
|
function createRedactionProfile(profile = "local") {
|
|
8808
8808
|
switch (profile) {
|
|
@@ -8871,11 +8871,11 @@ var Redactor2 = class {
|
|
|
8871
8871
|
#recordFinding(state, finding) {
|
|
8872
8872
|
if (this.#collectFindings) state.findings.push(finding);
|
|
8873
8873
|
}
|
|
8874
|
-
#redactValue(value, key,
|
|
8874
|
+
#redactValue(value, key, path15, depth, state) {
|
|
8875
8875
|
if (depth > this.#maxDepth) {
|
|
8876
8876
|
this.#recordFinding(
|
|
8877
8877
|
state,
|
|
8878
|
-
makeFinding(
|
|
8878
|
+
makeFinding(path15, "structure.maxDepth", "truncate", "value", "warning")
|
|
8879
8879
|
);
|
|
8880
8880
|
return "[Truncated]";
|
|
8881
8881
|
}
|
|
@@ -8884,19 +8884,19 @@ var Redactor2 = class {
|
|
|
8884
8884
|
if (rule) {
|
|
8885
8885
|
this.#recordFinding(
|
|
8886
8886
|
state,
|
|
8887
|
-
makeFinding(
|
|
8887
|
+
makeFinding(path15, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
8888
8888
|
);
|
|
8889
8889
|
return applyRule(rule, value, this.#replacement);
|
|
8890
8890
|
}
|
|
8891
8891
|
}
|
|
8892
8892
|
for (const detector of this.#detectors) {
|
|
8893
|
-
const detections = detector.detect({ path:
|
|
8893
|
+
const detections = detector.detect({ path: path15, key, value });
|
|
8894
8894
|
for (const detection of detections) {
|
|
8895
8895
|
const action = detection.action ?? "replace";
|
|
8896
8896
|
this.#recordFinding(
|
|
8897
8897
|
state,
|
|
8898
8898
|
makeFinding(
|
|
8899
|
-
|
|
8899
|
+
path15,
|
|
8900
8900
|
detector.id,
|
|
8901
8901
|
action,
|
|
8902
8902
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -8914,7 +8914,7 @@ var Redactor2 = class {
|
|
|
8914
8914
|
const out = [];
|
|
8915
8915
|
state.seen.set(value, out);
|
|
8916
8916
|
value.forEach((item, index) => {
|
|
8917
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
8917
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path15, index), depth + 1, state);
|
|
8918
8918
|
});
|
|
8919
8919
|
return out;
|
|
8920
8920
|
}
|
|
@@ -8926,7 +8926,7 @@ var Redactor2 = class {
|
|
|
8926
8926
|
out[entryKey] = this.#redactValue(
|
|
8927
8927
|
entryValue,
|
|
8928
8928
|
entryKey,
|
|
8929
|
-
childPath(
|
|
8929
|
+
childPath(path15 === "$" ? "" : path15, entryKey),
|
|
8930
8930
|
depth + 1,
|
|
8931
8931
|
state
|
|
8932
8932
|
);
|
|
@@ -9373,14 +9373,14 @@ function uniqueSorted(values) {
|
|
|
9373
9373
|
return [...new Set(values)].sort();
|
|
9374
9374
|
}
|
|
9375
9375
|
function isWithinDirectory(child, parent) {
|
|
9376
|
-
const relative =
|
|
9377
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
9376
|
+
const relative = path13__default.default.relative(parent, child);
|
|
9377
|
+
return relative === "" || !relative.startsWith("..") && !path13__default.default.isAbsolute(relative);
|
|
9378
9378
|
}
|
|
9379
9379
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
9380
9380
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
9381
|
-
const inputAbs =
|
|
9382
|
-
const outputAbs =
|
|
9383
|
-
const inputDir =
|
|
9381
|
+
const inputAbs = path13__default.default.resolve(inputPath);
|
|
9382
|
+
const outputAbs = path13__default.default.resolve(output2.trim());
|
|
9383
|
+
const inputDir = path13__default.default.dirname(inputAbs);
|
|
9384
9384
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
9385
9385
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
9386
9386
|
}
|
|
@@ -9501,7 +9501,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
9501
9501
|
process.exitCode = 1;
|
|
9502
9502
|
return;
|
|
9503
9503
|
}
|
|
9504
|
-
const inputPath =
|
|
9504
|
+
const inputPath = path13__default.default.resolve(input3.trim());
|
|
9505
9505
|
const dryRun = options.dryRun === true;
|
|
9506
9506
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
9507
9507
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -9520,7 +9520,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
9520
9520
|
);
|
|
9521
9521
|
const result = await buildMigration(inputPath, outputPath);
|
|
9522
9522
|
if (!dryRun && outputPath !== void 0) {
|
|
9523
|
-
await promises.mkdir(
|
|
9523
|
+
await promises.mkdir(path13__default.default.dirname(outputPath), { recursive: true });
|
|
9524
9524
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
9525
9525
|
}
|
|
9526
9526
|
printSummary2(result, dryRun);
|
|
@@ -9798,7 +9798,7 @@ function stripPrefix(name, prefixes) {
|
|
|
9798
9798
|
}
|
|
9799
9799
|
return name;
|
|
9800
9800
|
}
|
|
9801
|
-
function eventEvidence(event,
|
|
9801
|
+
function eventEvidence(event, path15) {
|
|
9802
9802
|
return {
|
|
9803
9803
|
runId: event.runId,
|
|
9804
9804
|
eventId: event.eventId,
|
|
@@ -9808,7 +9808,7 @@ function eventEvidence(event, path13) {
|
|
|
9808
9808
|
kind: event.kind,
|
|
9809
9809
|
name: event.name,
|
|
9810
9810
|
status: event.status,
|
|
9811
|
-
...
|
|
9811
|
+
...path15 ? { path: path15 } : {}
|
|
9812
9812
|
};
|
|
9813
9813
|
}
|
|
9814
9814
|
function runEvidence(run) {
|
|
@@ -9871,9 +9871,9 @@ function eventEndMs(event) {
|
|
|
9871
9871
|
function normalizedKey(value) {
|
|
9872
9872
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
9873
9873
|
}
|
|
9874
|
-
function lastPathSegment(
|
|
9875
|
-
const parts =
|
|
9876
|
-
return parts[parts.length - 1] ??
|
|
9874
|
+
function lastPathSegment(path15) {
|
|
9875
|
+
const parts = path15.split(".");
|
|
9876
|
+
return parts[parts.length - 1] ?? path15;
|
|
9877
9877
|
}
|
|
9878
9878
|
function valueType(value) {
|
|
9879
9879
|
if (Array.isArray(value)) return "array";
|
|
@@ -9887,12 +9887,12 @@ function serializedByteLength(value) {
|
|
|
9887
9887
|
return void 0;
|
|
9888
9888
|
}
|
|
9889
9889
|
}
|
|
9890
|
-
function pushValueEntries(entries, event, value,
|
|
9891
|
-
entries.push({ event, path:
|
|
9890
|
+
function pushValueEntries(entries, event, value, path15, key, depth = 0) {
|
|
9891
|
+
entries.push({ event, path: path15, key, value });
|
|
9892
9892
|
if (depth >= 8) return;
|
|
9893
9893
|
if (Array.isArray(value)) {
|
|
9894
9894
|
for (const [index, item] of value.entries()) {
|
|
9895
|
-
pushValueEntries(entries, event, item, `${
|
|
9895
|
+
pushValueEntries(entries, event, item, `${path15}.${index}`, String(index), depth + 1);
|
|
9896
9896
|
}
|
|
9897
9897
|
return;
|
|
9898
9898
|
}
|
|
@@ -9902,7 +9902,7 @@ function pushValueEntries(entries, event, value, path13, key, depth = 0) {
|
|
|
9902
9902
|
entries,
|
|
9903
9903
|
event,
|
|
9904
9904
|
value[nestedKey],
|
|
9905
|
-
`${
|
|
9905
|
+
`${path15}.${nestedKey}`,
|
|
9906
9906
|
nestedKey,
|
|
9907
9907
|
depth + 1
|
|
9908
9908
|
);
|
|
@@ -9983,9 +9983,9 @@ function eventDurationMs(event) {
|
|
|
9983
9983
|
}
|
|
9984
9984
|
function treeShape(nodes) {
|
|
9985
9985
|
const lines = [];
|
|
9986
|
-
const visit = (node,
|
|
9987
|
-
lines.push(`${
|
|
9988
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
9986
|
+
const visit = (node, path15) => {
|
|
9987
|
+
lines.push(`${path15}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
9988
|
+
node.children.forEach((child, index) => visit(child, `${path15}.${index}`));
|
|
9989
9989
|
};
|
|
9990
9990
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
9991
9991
|
return lines;
|
|
@@ -10034,9 +10034,9 @@ function retrievalShape(context) {
|
|
|
10034
10034
|
function guardrailShape(context) {
|
|
10035
10035
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
10036
10036
|
}
|
|
10037
|
-
function firstEvidenceForKind(context, kind,
|
|
10037
|
+
function firstEvidenceForKind(context, kind, path15) {
|
|
10038
10038
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
10039
|
-
return event ? [eventEvidence(event,
|
|
10039
|
+
return event ? [eventEvidence(event, path15)] : runEvidence(context.selectedRun);
|
|
10040
10040
|
}
|
|
10041
10041
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
10042
10042
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -10284,13 +10284,13 @@ function createStructureCycleRule() {
|
|
|
10284
10284
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
10285
10285
|
const findings = [];
|
|
10286
10286
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
10287
|
-
const
|
|
10287
|
+
const path15 = [];
|
|
10288
10288
|
const seenAt = /* @__PURE__ */ new Map();
|
|
10289
10289
|
let current = event;
|
|
10290
10290
|
while (current) {
|
|
10291
10291
|
const existing = seenAt.get(current.eventId);
|
|
10292
10292
|
if (existing !== void 0) {
|
|
10293
|
-
const cycle =
|
|
10293
|
+
const cycle = path15.slice(existing);
|
|
10294
10294
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
10295
10295
|
if (!seenCycles.has(key)) {
|
|
10296
10296
|
seenCycles.add(key);
|
|
@@ -10306,8 +10306,8 @@ function createStructureCycleRule() {
|
|
|
10306
10306
|
}
|
|
10307
10307
|
break;
|
|
10308
10308
|
}
|
|
10309
|
-
seenAt.set(current.eventId,
|
|
10310
|
-
|
|
10309
|
+
seenAt.set(current.eventId, path15.length);
|
|
10310
|
+
path15.push(current);
|
|
10311
10311
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
10312
10312
|
}
|
|
10313
10313
|
}
|
|
@@ -10832,7 +10832,7 @@ function asConfig(value) {
|
|
|
10832
10832
|
}
|
|
10833
10833
|
async function loadConfig(configPath) {
|
|
10834
10834
|
if (configPath === void 0) return {};
|
|
10835
|
-
const extension =
|
|
10835
|
+
const extension = path13__default.default.extname(configPath);
|
|
10836
10836
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
10837
10837
|
throw new Error(
|
|
10838
10838
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -10841,7 +10841,7 @@ async function loadConfig(configPath) {
|
|
|
10841
10841
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
10842
10842
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
10843
10843
|
}
|
|
10844
|
-
const absolute =
|
|
10844
|
+
const absolute = path13__default.default.resolve(configPath);
|
|
10845
10845
|
if (extension === ".json") {
|
|
10846
10846
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
10847
10847
|
return asConfig(JSON.parse(raw));
|
|
@@ -10963,8 +10963,8 @@ function printHuman(result) {
|
|
|
10963
10963
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
10964
10964
|
}
|
|
10965
10965
|
for (const finding of result.findings) {
|
|
10966
|
-
const
|
|
10967
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
10966
|
+
const path15 = finding.evidence[0]?.path;
|
|
10967
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
|
|
10968
10968
|
}
|
|
10969
10969
|
}
|
|
10970
10970
|
function readErrorResult(error) {
|
|
@@ -11186,10 +11186,10 @@ async function evalRun(input3, options = {}) {
|
|
|
11186
11186
|
diagnostics: []
|
|
11187
11187
|
};
|
|
11188
11188
|
}
|
|
11189
|
-
function evidenceForRun(run,
|
|
11190
|
-
return [{ runId: run.runId, ...
|
|
11189
|
+
function evidenceForRun(run, path15) {
|
|
11190
|
+
return [{ runId: run.runId, ...path15 !== void 0 ? { path: path15 } : {} }];
|
|
11191
11191
|
}
|
|
11192
|
-
function evidenceForEvent(event,
|
|
11192
|
+
function evidenceForEvent(event, path15) {
|
|
11193
11193
|
return [
|
|
11194
11194
|
{
|
|
11195
11195
|
runId: event.runId,
|
|
@@ -11197,7 +11197,7 @@ function evidenceForEvent(event, path13) {
|
|
|
11197
11197
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
11198
11198
|
kind: event.kind,
|
|
11199
11199
|
name: event.name,
|
|
11200
|
-
...
|
|
11200
|
+
...path15 !== void 0 ? { path: path15 } : {}
|
|
11201
11201
|
}
|
|
11202
11202
|
];
|
|
11203
11203
|
}
|
|
@@ -11355,9 +11355,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
11355
11355
|
function tokenize(text) {
|
|
11356
11356
|
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));
|
|
11357
11357
|
}
|
|
11358
|
-
function firstEvidence(fields, run,
|
|
11358
|
+
function firstEvidence(fields, run, path15) {
|
|
11359
11359
|
const first = fields[0];
|
|
11360
|
-
return first === void 0 ? evidenceForRun(run,
|
|
11360
|
+
return first === void 0 ? evidenceForRun(run, path15) : evidenceForEvent(first.node.event, first.path);
|
|
11361
11361
|
}
|
|
11362
11362
|
function collectSourceIds(nodes, keys) {
|
|
11363
11363
|
const wanted = keySet(keys);
|
|
@@ -11734,8 +11734,8 @@ function renderEvalMarkdown(result) {
|
|
|
11734
11734
|
if (result.findings.length > 0) {
|
|
11735
11735
|
lines.push("", "## Findings");
|
|
11736
11736
|
for (const finding of result.findings) {
|
|
11737
|
-
const
|
|
11738
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
11737
|
+
const path15 = finding.evidence[0]?.path;
|
|
11738
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
|
|
11739
11739
|
}
|
|
11740
11740
|
}
|
|
11741
11741
|
return `${lines.join("\n")}
|
|
@@ -11782,7 +11782,7 @@ function asConfig2(value) {
|
|
|
11782
11782
|
}
|
|
11783
11783
|
async function loadConfig2(configPath) {
|
|
11784
11784
|
if (configPath === void 0) return {};
|
|
11785
|
-
const extension =
|
|
11785
|
+
const extension = path13__default.default.extname(configPath);
|
|
11786
11786
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
11787
11787
|
throw new Error(
|
|
11788
11788
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -11791,7 +11791,7 @@ async function loadConfig2(configPath) {
|
|
|
11791
11791
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
11792
11792
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
11793
11793
|
}
|
|
11794
|
-
const absolute =
|
|
11794
|
+
const absolute = path13__default.default.resolve(configPath);
|
|
11795
11795
|
if (extension === ".json") {
|
|
11796
11796
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
11797
11797
|
return asConfig2(JSON.parse(raw));
|
|
@@ -11928,8 +11928,8 @@ function printHuman2(result) {
|
|
|
11928
11928
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
11929
11929
|
}
|
|
11930
11930
|
for (const finding of result.findings) {
|
|
11931
|
-
const
|
|
11932
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
11931
|
+
const path15 = finding.evidence[0]?.path;
|
|
11932
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
|
|
11933
11933
|
}
|
|
11934
11934
|
}
|
|
11935
11935
|
function readErrorResult2(error) {
|
|
@@ -12167,8 +12167,8 @@ function printHuman3(result) {
|
|
|
12167
12167
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
12168
12168
|
}
|
|
12169
12169
|
for (const finding of result.findings) {
|
|
12170
|
-
const
|
|
12171
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
12170
|
+
const path15 = finding.evidence[0]?.path;
|
|
12171
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
|
|
12172
12172
|
}
|
|
12173
12173
|
console.log(`Note: ${result.note}`);
|
|
12174
12174
|
}
|
|
@@ -12287,8 +12287,8 @@ function renderCheckSection(result) {
|
|
|
12287
12287
|
`Diagnostics: ${result.diagnostics.length}`
|
|
12288
12288
|
];
|
|
12289
12289
|
for (const finding of result.findings.slice(0, 10)) {
|
|
12290
|
-
const
|
|
12291
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
12290
|
+
const path15 = finding.evidence[0]?.path ?? "(run)";
|
|
12291
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path15})`);
|
|
12292
12292
|
}
|
|
12293
12293
|
for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
|
|
12294
12294
|
lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
@@ -12366,8 +12366,8 @@ function renderHtml(trace, check, diff) {
|
|
|
12366
12366
|
`;
|
|
12367
12367
|
}
|
|
12368
12368
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
12369
|
-
const outPath =
|
|
12370
|
-
await promises.mkdir(
|
|
12369
|
+
const outPath = path13__default.default.join(outputDir, relativePath);
|
|
12370
|
+
await promises.mkdir(path13__default.default.dirname(outPath), { recursive: true });
|
|
12371
12371
|
await promises.writeFile(outPath, content, "utf-8");
|
|
12372
12372
|
files.push(relativePath);
|
|
12373
12373
|
}
|
|
@@ -12383,7 +12383,7 @@ function manifestStatus(check, diff) {
|
|
|
12383
12383
|
return "ok";
|
|
12384
12384
|
}
|
|
12385
12385
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
12386
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
12386
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path13__default.default.resolve(options.outputDir.trim()) : "";
|
|
12387
12387
|
if (outputDir === "") {
|
|
12388
12388
|
console.error("--output-dir is required.");
|
|
12389
12389
|
process.exitCode = 1;
|
|
@@ -12449,8 +12449,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
12449
12449
|
await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
|
|
12450
12450
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
12451
12451
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
12452
|
-
await promises.mkdir(
|
|
12453
|
-
await promises.appendFile(
|
|
12452
|
+
await promises.mkdir(path13__default.default.dirname(path13__default.default.resolve(summaryTarget)), { recursive: true });
|
|
12453
|
+
await promises.appendFile(path13__default.default.resolve(summaryTarget), `
|
|
12454
12454
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
12455
12455
|
}
|
|
12456
12456
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -12469,10 +12469,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
12469
12469
|
findings: diff?.findings.length ?? 0,
|
|
12470
12470
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
12471
12471
|
},
|
|
12472
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
12472
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path13__default.default.resolve(summaryTarget) } : {},
|
|
12473
12473
|
note: NOTE
|
|
12474
12474
|
};
|
|
12475
|
-
await promises.writeFile(
|
|
12475
|
+
await promises.writeFile(path13__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
12476
12476
|
if (options.json === true) {
|
|
12477
12477
|
console.log(writeJson3(manifest).trimEnd());
|
|
12478
12478
|
} else {
|
|
@@ -12483,6 +12483,371 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
12483
12483
|
}
|
|
12484
12484
|
}
|
|
12485
12485
|
}
|
|
12486
|
+
function validateReporterArtifactPath(options) {
|
|
12487
|
+
const outputDir = path13__default.default.resolve(options.outputDir);
|
|
12488
|
+
const diagnostics = [];
|
|
12489
|
+
const rawPath = options.relativePath;
|
|
12490
|
+
if (rawPath.length === 0) {
|
|
12491
|
+
diagnostics.push({
|
|
12492
|
+
code: "artifact_path_empty",
|
|
12493
|
+
severity: "error",
|
|
12494
|
+
message: "Reporter artifact path must not be empty."
|
|
12495
|
+
});
|
|
12496
|
+
return { ok: false, outputDir, diagnostics };
|
|
12497
|
+
}
|
|
12498
|
+
if (rawPath.includes("\0")) {
|
|
12499
|
+
diagnostics.push({
|
|
12500
|
+
code: "invalid_artifact_path",
|
|
12501
|
+
severity: "error",
|
|
12502
|
+
message: "Reporter artifact path must not contain null bytes.",
|
|
12503
|
+
target: rawPath
|
|
12504
|
+
});
|
|
12505
|
+
return { ok: false, outputDir, diagnostics };
|
|
12506
|
+
}
|
|
12507
|
+
if (path13__default.default.isAbsolute(rawPath) || path13__default.default.win32.isAbsolute(rawPath)) {
|
|
12508
|
+
diagnostics.push({
|
|
12509
|
+
code: "artifact_path_absolute",
|
|
12510
|
+
severity: "error",
|
|
12511
|
+
message: "Reporter artifact path must be relative.",
|
|
12512
|
+
target: rawPath
|
|
12513
|
+
});
|
|
12514
|
+
return { ok: false, outputDir, diagnostics };
|
|
12515
|
+
}
|
|
12516
|
+
const normalized = path13__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
12517
|
+
const segments = normalized.split("/");
|
|
12518
|
+
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
12519
|
+
diagnostics.push({
|
|
12520
|
+
code: "artifact_path_escape",
|
|
12521
|
+
severity: "error",
|
|
12522
|
+
message: "Reporter artifact path must stay under the output directory.",
|
|
12523
|
+
target: rawPath
|
|
12524
|
+
});
|
|
12525
|
+
return { ok: false, outputDir, diagnostics };
|
|
12526
|
+
}
|
|
12527
|
+
const absolutePath = path13__default.default.resolve(outputDir, normalized);
|
|
12528
|
+
const relFromOutput = path13__default.default.relative(outputDir, absolutePath);
|
|
12529
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path13__default.default.isAbsolute(relFromOutput)) {
|
|
12530
|
+
diagnostics.push({
|
|
12531
|
+
code: "artifact_path_escape",
|
|
12532
|
+
severity: "error",
|
|
12533
|
+
message: "Reporter artifact path resolved outside the output directory.",
|
|
12534
|
+
target: rawPath
|
|
12535
|
+
});
|
|
12536
|
+
return { ok: false, outputDir, diagnostics };
|
|
12537
|
+
}
|
|
12538
|
+
return {
|
|
12539
|
+
ok: true,
|
|
12540
|
+
outputDir,
|
|
12541
|
+
relativePath: normalized,
|
|
12542
|
+
absolutePath,
|
|
12543
|
+
diagnostics
|
|
12544
|
+
};
|
|
12545
|
+
}
|
|
12546
|
+
|
|
12547
|
+
// packages/cli/src/ci-summary.ts
|
|
12548
|
+
var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
|
|
12549
|
+
var MAX_TEXT = 180;
|
|
12550
|
+
var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
|
|
12551
|
+
var STATUSES = /* @__PURE__ */ new Set(["passed", "failed", "skipped", "todo"]);
|
|
12552
|
+
var ARTIFACT_KINDS = /* @__PURE__ */ new Set(["trace", "report", "eval", "redaction", "summary"]);
|
|
12553
|
+
var ARTIFACT_FORMATS = /* @__PURE__ */ new Set(["json", "jsonl", "md", "html"]);
|
|
12554
|
+
var REDACTION_PROFILES = /* @__PURE__ */ new Set(["local", "share", "strict"]);
|
|
12555
|
+
function stable6(value) {
|
|
12556
|
+
if (Array.isArray(value)) return value.map(stable6);
|
|
12557
|
+
if (value === null || typeof value !== "object") return value;
|
|
12558
|
+
const record = value;
|
|
12559
|
+
return Object.fromEntries(
|
|
12560
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable6(record[key])])
|
|
12561
|
+
);
|
|
12562
|
+
}
|
|
12563
|
+
function writeJson4(value) {
|
|
12564
|
+
return `${JSON.stringify(stable6(value), null, 2)}
|
|
12565
|
+
`;
|
|
12566
|
+
}
|
|
12567
|
+
function isObject(value) {
|
|
12568
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12569
|
+
}
|
|
12570
|
+
function readString(value, label) {
|
|
12571
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
12572
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
12573
|
+
}
|
|
12574
|
+
return safeText(value);
|
|
12575
|
+
}
|
|
12576
|
+
function readOptionalString(value) {
|
|
12577
|
+
return typeof value === "string" && value.trim() !== "" ? safeText(value) : void 0;
|
|
12578
|
+
}
|
|
12579
|
+
function readFramework(value) {
|
|
12580
|
+
const framework = readString(value, "manifest.framework");
|
|
12581
|
+
if (!FRAMEWORKS.has(framework)) {
|
|
12582
|
+
throw new Error(`Unsupported reporter framework: ${framework}.`);
|
|
12583
|
+
}
|
|
12584
|
+
return framework;
|
|
12585
|
+
}
|
|
12586
|
+
function readStatus(value) {
|
|
12587
|
+
const status = readString(value, "result.status");
|
|
12588
|
+
if (!STATUSES.has(status)) {
|
|
12589
|
+
throw new Error(`Unsupported reporter test status: ${status}.`);
|
|
12590
|
+
}
|
|
12591
|
+
return status;
|
|
12592
|
+
}
|
|
12593
|
+
function readArtifact(value, index) {
|
|
12594
|
+
if (!isObject(value)) throw new Error(`manifest.artifacts[${index}] must be an object.`);
|
|
12595
|
+
const kind = readString(value.kind, `manifest.artifacts[${index}].kind`);
|
|
12596
|
+
const format = readString(value.format, `manifest.artifacts[${index}].format`);
|
|
12597
|
+
const redactionProfile = readString(
|
|
12598
|
+
value.redactionProfile,
|
|
12599
|
+
`manifest.artifacts[${index}].redactionProfile`
|
|
12600
|
+
);
|
|
12601
|
+
if (!ARTIFACT_KINDS.has(kind)) throw new Error(`Unsupported artifact kind: ${kind}.`);
|
|
12602
|
+
if (!ARTIFACT_FORMATS.has(format)) throw new Error(`Unsupported artifact format: ${format}.`);
|
|
12603
|
+
if (!REDACTION_PROFILES.has(redactionProfile)) {
|
|
12604
|
+
throw new Error(`Unsupported artifact redaction profile: ${redactionProfile}.`);
|
|
12605
|
+
}
|
|
12606
|
+
const artifactPath = readString(value.path, `manifest.artifacts[${index}].path`);
|
|
12607
|
+
const pathCheck = validateReporterArtifactPath({
|
|
12608
|
+
outputDir: process.cwd(),
|
|
12609
|
+
relativePath: artifactPath
|
|
12610
|
+
});
|
|
12611
|
+
if (!pathCheck.ok || pathCheck.relativePath === void 0) {
|
|
12612
|
+
throw new Error(`Unsafe reporter artifact path: ${artifactPath}.`);
|
|
12613
|
+
}
|
|
12614
|
+
return {
|
|
12615
|
+
kind,
|
|
12616
|
+
path: pathCheck.relativePath,
|
|
12617
|
+
format,
|
|
12618
|
+
redactionProfile
|
|
12619
|
+
};
|
|
12620
|
+
}
|
|
12621
|
+
function readArtifacts(value, label) {
|
|
12622
|
+
if (value === void 0) return [];
|
|
12623
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
12624
|
+
return value.map((item, index) => readArtifact(item, index));
|
|
12625
|
+
}
|
|
12626
|
+
function readDiagnosticsCount(value, label) {
|
|
12627
|
+
if (value === void 0) return 0;
|
|
12628
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
12629
|
+
return value.length;
|
|
12630
|
+
}
|
|
12631
|
+
function readResult(value, index) {
|
|
12632
|
+
if (!isObject(value)) throw new Error(`manifest.results[${index}] must be an object.`);
|
|
12633
|
+
const file = readOptionalString(value.file);
|
|
12634
|
+
const tracePath = readOptionalString(value.tracePath);
|
|
12635
|
+
return {
|
|
12636
|
+
testId: readString(value.testId, `manifest.results[${index}].testId`),
|
|
12637
|
+
name: readString(value.name, `manifest.results[${index}].name`),
|
|
12638
|
+
...file === void 0 ? {} : { file },
|
|
12639
|
+
status: readStatus(value.status),
|
|
12640
|
+
...tracePath === void 0 ? {} : { tracePath },
|
|
12641
|
+
artifacts: readArtifacts(value.artifacts, `manifest.results[${index}].artifacts`),
|
|
12642
|
+
diagnostics: readDiagnosticsCount(
|
|
12643
|
+
value.diagnostics,
|
|
12644
|
+
`manifest.results[${index}].diagnostics`
|
|
12645
|
+
)
|
|
12646
|
+
};
|
|
12647
|
+
}
|
|
12648
|
+
function readManifestDocument(value) {
|
|
12649
|
+
if (!isObject(value)) throw new Error("Reporter manifest file must contain a JSON object.");
|
|
12650
|
+
const candidate = isObject(value.manifest) ? value.manifest : value;
|
|
12651
|
+
if (!isObject(candidate)) throw new Error("Reporter manifest must be a JSON object.");
|
|
12652
|
+
const schemaVersion = readString(candidate.schemaVersion, "manifest.schemaVersion");
|
|
12653
|
+
if (schemaVersion !== "0.1") {
|
|
12654
|
+
throw new Error(`Unsupported reporter manifest schemaVersion: ${schemaVersion}.`);
|
|
12655
|
+
}
|
|
12656
|
+
if (!Array.isArray(candidate.results)) {
|
|
12657
|
+
throw new Error("manifest.results must be an array.");
|
|
12658
|
+
}
|
|
12659
|
+
const artifacts = readArtifacts(candidate.artifacts, "manifest.artifacts");
|
|
12660
|
+
const results = candidate.results.map((item, index) => readResult(item, index));
|
|
12661
|
+
const diagnostics = readDiagnosticsCount(candidate.diagnostics, "manifest.diagnostics");
|
|
12662
|
+
const manifest = {
|
|
12663
|
+
framework: readFramework(candidate.framework),
|
|
12664
|
+
generatedAt: readString(candidate.generatedAt, "manifest.generatedAt"),
|
|
12665
|
+
results,
|
|
12666
|
+
artifacts
|
|
12667
|
+
};
|
|
12668
|
+
return {
|
|
12669
|
+
packageName: readOptionalString(value.package),
|
|
12670
|
+
manifest,
|
|
12671
|
+
diagnostics
|
|
12672
|
+
};
|
|
12673
|
+
}
|
|
12674
|
+
function cwdRelative(filePath) {
|
|
12675
|
+
const relative = path13__default.default.relative(process.cwd(), path13__default.default.resolve(filePath)).replace(/\\/g, "/");
|
|
12676
|
+
if (relative === "" || relative.startsWith("../") || path13__default.default.isAbsolute(relative)) {
|
|
12677
|
+
return path13__default.default.basename(filePath);
|
|
12678
|
+
}
|
|
12679
|
+
return relative;
|
|
12680
|
+
}
|
|
12681
|
+
async function readReporterManifest(filePath) {
|
|
12682
|
+
const absolute = path13__default.default.resolve(filePath);
|
|
12683
|
+
const raw = await promises.readFile(absolute, "utf-8");
|
|
12684
|
+
const document = readManifestDocument(JSON.parse(raw));
|
|
12685
|
+
const manifest = document.manifest;
|
|
12686
|
+
const results = manifest.results.map((result) => ({
|
|
12687
|
+
testId: safeText(result.testId),
|
|
12688
|
+
name: safeText(result.name),
|
|
12689
|
+
...result.file === void 0 ? {} : { file: safeText(path13__default.default.basename(result.file)) },
|
|
12690
|
+
status: result.status,
|
|
12691
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path13__default.default.basename(result.tracePath)) },
|
|
12692
|
+
artifacts: result.artifacts,
|
|
12693
|
+
diagnostics: result.diagnostics
|
|
12694
|
+
}));
|
|
12695
|
+
return {
|
|
12696
|
+
...document.packageName === void 0 ? {} : { packageName: document.packageName },
|
|
12697
|
+
manifestFile: cwdRelative(absolute),
|
|
12698
|
+
framework: manifest.framework,
|
|
12699
|
+
generatedAt: manifest.generatedAt,
|
|
12700
|
+
results,
|
|
12701
|
+
artifacts: manifest.artifacts,
|
|
12702
|
+
diagnostics: document.diagnostics
|
|
12703
|
+
};
|
|
12704
|
+
}
|
|
12705
|
+
function summarize3(manifests) {
|
|
12706
|
+
const summary = {
|
|
12707
|
+
manifests: manifests.length,
|
|
12708
|
+
tests: 0,
|
|
12709
|
+
failed: 0,
|
|
12710
|
+
passed: 0,
|
|
12711
|
+
skipped: 0,
|
|
12712
|
+
todo: 0,
|
|
12713
|
+
artifacts: 0,
|
|
12714
|
+
diagnostics: 0
|
|
12715
|
+
};
|
|
12716
|
+
for (const manifest of manifests) {
|
|
12717
|
+
summary.artifacts += manifest.artifacts.length;
|
|
12718
|
+
summary.diagnostics += manifest.diagnostics;
|
|
12719
|
+
for (const result of manifest.results) {
|
|
12720
|
+
summary.tests += 1;
|
|
12721
|
+
if (result.status === "failed") summary.failed += 1;
|
|
12722
|
+
else if (result.status === "passed") summary.passed += 1;
|
|
12723
|
+
else if (result.status === "skipped") summary.skipped += 1;
|
|
12724
|
+
else summary.todo += 1;
|
|
12725
|
+
summary.artifacts += result.artifacts.length;
|
|
12726
|
+
summary.diagnostics += result.diagnostics;
|
|
12727
|
+
}
|
|
12728
|
+
}
|
|
12729
|
+
return {
|
|
12730
|
+
status: summary.failed > 0 ? "failed" : summary.diagnostics > 0 ? "warning" : "ok",
|
|
12731
|
+
manifests,
|
|
12732
|
+
summary,
|
|
12733
|
+
note: NOTE2
|
|
12734
|
+
};
|
|
12735
|
+
}
|
|
12736
|
+
function markdownCell(value) {
|
|
12737
|
+
return safeText(String(value ?? "unknown")).replaceAll("|", "\\|").replace(/\r?\n/g, " ");
|
|
12738
|
+
}
|
|
12739
|
+
function renderMarkdown2(result) {
|
|
12740
|
+
const lines = [
|
|
12741
|
+
"# AgentInspect CI Summary",
|
|
12742
|
+
"",
|
|
12743
|
+
NOTE2,
|
|
12744
|
+
"",
|
|
12745
|
+
"| Field | Value |",
|
|
12746
|
+
"| --- | --- |",
|
|
12747
|
+
`| Status | ${result.status} |`,
|
|
12748
|
+
`| Manifests | ${result.summary.manifests} |`,
|
|
12749
|
+
`| Tests | ${result.summary.tests} |`,
|
|
12750
|
+
`| Failed | ${result.summary.failed} |`,
|
|
12751
|
+
`| Passed | ${result.summary.passed} |`,
|
|
12752
|
+
`| Skipped | ${result.summary.skipped} |`,
|
|
12753
|
+
`| Todo | ${result.summary.todo} |`,
|
|
12754
|
+
`| Artifacts | ${result.summary.artifacts} |`,
|
|
12755
|
+
`| Diagnostics | ${result.summary.diagnostics} |`,
|
|
12756
|
+
"",
|
|
12757
|
+
"## Tests",
|
|
12758
|
+
"",
|
|
12759
|
+
"| Framework | Status | Test | File | Trace | Artifacts |",
|
|
12760
|
+
"| --- | --- | --- | --- | --- | --- |"
|
|
12761
|
+
];
|
|
12762
|
+
const rows = result.manifests.flatMap(
|
|
12763
|
+
(manifest) => manifest.results.map((test) => ({
|
|
12764
|
+
framework: manifest.framework,
|
|
12765
|
+
test
|
|
12766
|
+
}))
|
|
12767
|
+
);
|
|
12768
|
+
if (rows.length === 0) {
|
|
12769
|
+
lines.push("| unknown | unknown | No tests found | unknown | unknown | 0 |");
|
|
12770
|
+
} else {
|
|
12771
|
+
for (const row of rows) {
|
|
12772
|
+
lines.push(
|
|
12773
|
+
`| ${markdownCell(row.framework)} | ${markdownCell(row.test.status)} | ${markdownCell(row.test.name)} | ${markdownCell(row.test.file)} | ${markdownCell(row.test.tracePath)} | ${row.test.artifacts.length} |`
|
|
12774
|
+
);
|
|
12775
|
+
}
|
|
12776
|
+
}
|
|
12777
|
+
lines.push("", "## Manifests", "", "| Framework | File | Generated | Artifacts |", "| --- | --- | --- | --- |");
|
|
12778
|
+
for (const manifest of result.manifests) {
|
|
12779
|
+
lines.push(
|
|
12780
|
+
`| ${markdownCell(manifest.framework)} | ${markdownCell(manifest.manifestFile)} | ${markdownCell(manifest.generatedAt)} | ${manifest.artifacts.length} |`
|
|
12781
|
+
);
|
|
12782
|
+
}
|
|
12783
|
+
lines.push("", "## Artifacts", "", "| Framework | Kind | Path | Format | Profile |", "| --- | --- | --- | --- | --- |");
|
|
12784
|
+
const artifacts = result.manifests.flatMap(
|
|
12785
|
+
(manifest) => manifest.artifacts.map((artifact) => ({ framework: manifest.framework, artifact }))
|
|
12786
|
+
);
|
|
12787
|
+
if (artifacts.length === 0) {
|
|
12788
|
+
lines.push("| unknown | unknown | No artifacts found | unknown | unknown |");
|
|
12789
|
+
} else {
|
|
12790
|
+
for (const row of artifacts) {
|
|
12791
|
+
lines.push(
|
|
12792
|
+
`| ${markdownCell(row.framework)} | ${markdownCell(row.artifact.kind)} | ${markdownCell(row.artifact.path)} | ${markdownCell(row.artifact.format)} | ${markdownCell(row.artifact.redactionProfile)} |`
|
|
12793
|
+
);
|
|
12794
|
+
}
|
|
12795
|
+
}
|
|
12796
|
+
lines.push("");
|
|
12797
|
+
return `${lines.join("\n")}
|
|
12798
|
+
`;
|
|
12799
|
+
}
|
|
12800
|
+
function safeText(value) {
|
|
12801
|
+
const compact = value.replace(/\s+/g, " ").trim();
|
|
12802
|
+
const redacted = compact.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(
|
|
12803
|
+
/\b(?:api[_-]?key|authorization|token|secret|password)\s*[:=]\s*[^,\s]+/gi,
|
|
12804
|
+
"$1=[REDACTED]"
|
|
12805
|
+
);
|
|
12806
|
+
if (redacted.length <= MAX_TEXT) return redacted;
|
|
12807
|
+
return `${redacted.slice(0, MAX_TEXT - 12)}...[truncated]`;
|
|
12808
|
+
}
|
|
12809
|
+
async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
12810
|
+
if (manifestPaths.length === 0) {
|
|
12811
|
+
console.error("At least one reporter manifest path is required.");
|
|
12812
|
+
process.exitCode = 1;
|
|
12813
|
+
return;
|
|
12814
|
+
}
|
|
12815
|
+
let result;
|
|
12816
|
+
try {
|
|
12817
|
+
const manifests = [];
|
|
12818
|
+
for (const manifestPath of manifestPaths) {
|
|
12819
|
+
manifests.push(await readReporterManifest(manifestPath));
|
|
12820
|
+
}
|
|
12821
|
+
manifests.sort((a, b) => a.manifestFile.localeCompare(b.manifestFile));
|
|
12822
|
+
result = summarize3(manifests);
|
|
12823
|
+
} catch (error) {
|
|
12824
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12825
|
+
console.error(`[AgentInspect] ci-summary failed: ${message}`);
|
|
12826
|
+
process.exitCode = 1;
|
|
12827
|
+
return;
|
|
12828
|
+
}
|
|
12829
|
+
const markdown = renderMarkdown2(result);
|
|
12830
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path13__default.default.resolve(options.output.trim()) : void 0;
|
|
12831
|
+
if (outputPath !== void 0) {
|
|
12832
|
+
await promises.mkdir(path13__default.default.dirname(outputPath), { recursive: true });
|
|
12833
|
+
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
12834
|
+
}
|
|
12835
|
+
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
12836
|
+
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
12837
|
+
const summaryPath = path13__default.default.resolve(summaryTarget);
|
|
12838
|
+
await promises.mkdir(path13__default.default.dirname(summaryPath), { recursive: true });
|
|
12839
|
+
await promises.appendFile(summaryPath, `
|
|
12840
|
+
${markdown}`, "utf-8");
|
|
12841
|
+
}
|
|
12842
|
+
if (options.json === true) {
|
|
12843
|
+
console.log(writeJson4(result).trimEnd());
|
|
12844
|
+
} else if (outputPath !== void 0) {
|
|
12845
|
+
console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
|
|
12846
|
+
console.log(`Status: ${result.status}`);
|
|
12847
|
+
} else {
|
|
12848
|
+
console.log(markdown.trimEnd());
|
|
12849
|
+
}
|
|
12850
|
+
}
|
|
12486
12851
|
|
|
12487
12852
|
// packages/cli/src/index.ts
|
|
12488
12853
|
function runCommand(action) {
|
|
@@ -12668,6 +13033,9 @@ function createCliProgram() {
|
|
|
12668
13033
|
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--baseline <trace-path-or-run-id>", "optional baseline trace for diff artifacts").option("--baseline-run <run-id>", "select a run from the baseline trace").option("--github-summary <path>", "append a safe summary to this file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON manifest").action((target, opts) => {
|
|
12669
13034
|
runCommand(() => artifactsCommand(target, opts));
|
|
12670
13035
|
});
|
|
13036
|
+
program.command("ci-summary").description("Summarize local reporter artifact manifests for CI").argument("<manifest...>", "reporter artifact manifest JSON files").option("-o, --output <path>", "write Markdown summary to a local file").option("--github-summary <path>", "append Markdown summary to this local file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON summary").action((manifest, opts) => {
|
|
13037
|
+
runCommand(() => ciSummaryCommand(manifest, opts));
|
|
13038
|
+
});
|
|
12671
13039
|
program.command("diff").description("Compare two local AgentInspect JSONL traces (read-only)").argument("<left-run-id>", "first run id").argument("<right-run-id>", "second run id").option("--dir <path>", "trace directory").option("--json", "print diff result as JSON").option("--ignore-duration", "omit duration comparisons").option(
|
|
12672
13040
|
"--duration-threshold <duration>",
|
|
12673
13041
|
"ignore duration deltas at or below this (e.g. 500ms, 2s, 1m)"
|
|
@@ -12760,9 +13128,9 @@ function isPrimaryModule() {
|
|
|
12760
13128
|
if (!entry) return false;
|
|
12761
13129
|
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)));
|
|
12762
13130
|
try {
|
|
12763
|
-
return fs.realpathSync(
|
|
13131
|
+
return fs.realpathSync(path13__default.default.resolve(entry)) === fs.realpathSync(path13__default.default.resolve(selfPath));
|
|
12764
13132
|
} catch {
|
|
12765
|
-
return
|
|
13133
|
+
return path13__default.default.resolve(entry) === path13__default.default.resolve(selfPath);
|
|
12766
13134
|
}
|
|
12767
13135
|
}
|
|
12768
13136
|
if (isPrimaryModule()) {
|