agent-inspect 5.1.0 → 5.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 +6 -0
- package/docs/CLI.md +32 -0
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-TSIQUIPF.mjs → chunk-SJ5R2XBE.mjs} +416 -28
- package/packages/cli/dist/chunk-SJ5R2XBE.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +753 -194
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +184 -49
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-2SZWGKMM.mjs → src-PK22BBMH.mjs} +3 -3
- package/packages/cli/dist/{src-2SZWGKMM.mjs.map → src-PK22BBMH.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +413 -9
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +47 -1
- package/packages/core/dist/advanced.d.ts +47 -1
- package/packages/core/dist/advanced.mjs +404 -8
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/cli/dist/chunk-TSIQUIPF.mjs.map +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
var crypto = require('crypto');
|
|
5
5
|
var promises = require('fs/promises');
|
|
6
6
|
var os = require('os');
|
|
7
|
-
var
|
|
7
|
+
var path24 = require('path');
|
|
8
8
|
var async_hooks = require('async_hooks');
|
|
9
9
|
var process3 = require('process');
|
|
10
10
|
var tty = require('tty');
|
|
@@ -20,7 +20,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
20
20
|
|
|
21
21
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
22
22
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
23
|
-
var
|
|
23
|
+
var path24__default = /*#__PURE__*/_interopDefault(path24);
|
|
24
24
|
var process3__default = /*#__PURE__*/_interopDefault(process3);
|
|
25
25
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
26
26
|
|
|
@@ -893,7 +893,7 @@ function getDefaultTraceDir() {
|
|
|
893
893
|
if (typeof home !== "string" || home.trim() === "") {
|
|
894
894
|
return FALLBACK_TRACE_DIR;
|
|
895
895
|
}
|
|
896
|
-
return
|
|
896
|
+
return path24__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
897
897
|
} catch {
|
|
898
898
|
return FALLBACK_TRACE_DIR;
|
|
899
899
|
}
|
|
@@ -901,11 +901,11 @@ function getDefaultTraceDir() {
|
|
|
901
901
|
function getTraceFilePath(runId, traceDir) {
|
|
902
902
|
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
903
903
|
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
904
|
-
safeId =
|
|
904
|
+
safeId = path24__default.default.basename(safeId);
|
|
905
905
|
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
906
906
|
safeId = "run_unknown";
|
|
907
907
|
}
|
|
908
|
-
return
|
|
908
|
+
return path24__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
909
909
|
}
|
|
910
910
|
function formatError(error) {
|
|
911
911
|
if (error instanceof Error) {
|
|
@@ -962,7 +962,7 @@ var init_utils = __esm({
|
|
|
962
962
|
init_duration();
|
|
963
963
|
DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
964
964
|
RUNS_DIR_NAME = "runs";
|
|
965
|
-
FALLBACK_TRACE_DIR =
|
|
965
|
+
FALLBACK_TRACE_DIR = path24__default.default.join(
|
|
966
966
|
os__default.default.tmpdir(),
|
|
967
967
|
"agent-inspect",
|
|
968
968
|
RUNS_DIR_NAME
|
|
@@ -1928,7 +1928,7 @@ var init_trace_directory = __esm({
|
|
|
1928
1928
|
this.#dir = resolveTraceDir(options);
|
|
1929
1929
|
}
|
|
1930
1930
|
getPath(filename) {
|
|
1931
|
-
return filename ?
|
|
1931
|
+
return filename ? path24__default.default.join(this.#dir, filename) : this.#dir;
|
|
1932
1932
|
}
|
|
1933
1933
|
async list() {
|
|
1934
1934
|
try {
|
|
@@ -1957,7 +1957,7 @@ function parseIsoToMs2(value) {
|
|
|
1957
1957
|
}
|
|
1958
1958
|
async function extractMetadata(filePath, _quickScan) {
|
|
1959
1959
|
const stats = await promises.stat(filePath);
|
|
1960
|
-
let runIdFromFile =
|
|
1960
|
+
let runIdFromFile = path24__default.default.basename(filePath);
|
|
1961
1961
|
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1962
1962
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1963
1963
|
}
|
|
@@ -2942,9 +2942,9 @@ async function searchTraces(metas, options) {
|
|
|
2942
2942
|
}
|
|
2943
2943
|
const limit = options.limit ?? 50;
|
|
2944
2944
|
const sessionId = options.session?.trim();
|
|
2945
|
-
const
|
|
2945
|
+
const observationStatus2 = parseObservationFilter(options.observation);
|
|
2946
2946
|
const hasContentFilter = Boolean(
|
|
2947
|
-
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter ||
|
|
2947
|
+
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter || observationStatus2
|
|
2948
2948
|
);
|
|
2949
2949
|
const results = [];
|
|
2950
2950
|
const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
|
|
@@ -2989,9 +2989,9 @@ async function searchTraces(metas, options) {
|
|
|
2989
2989
|
statusFilter: options.status
|
|
2990
2990
|
});
|
|
2991
2991
|
results.push(...stepMatches);
|
|
2992
|
-
if (
|
|
2992
|
+
if (observationStatus2) {
|
|
2993
2993
|
const outcomes = extractOutcomesFromTraceEvents(events);
|
|
2994
|
-
const matched = outcomes.filter((outcome) => outcome.status ===
|
|
2994
|
+
const matched = outcomes.filter((outcome) => outcome.status === observationStatus2);
|
|
2995
2995
|
for (const outcome of matched) {
|
|
2996
2996
|
results.push({
|
|
2997
2997
|
runId: m.runId,
|
|
@@ -3786,12 +3786,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3786
3786
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3787
3787
|
);
|
|
3788
3788
|
const ordered = [...runs].sort(compareRuns);
|
|
3789
|
-
const
|
|
3789
|
+
const path33 = [];
|
|
3790
3790
|
const visited = /* @__PURE__ */ new Set();
|
|
3791
3791
|
const pushRun = (run, confidence, source) => {
|
|
3792
3792
|
if (visited.has(run.runId)) return;
|
|
3793
3793
|
visited.add(run.runId);
|
|
3794
|
-
|
|
3794
|
+
path33.push({
|
|
3795
3795
|
runId: run.runId,
|
|
3796
3796
|
name: run.name,
|
|
3797
3797
|
startedAt: run.startedAt,
|
|
@@ -3816,7 +3816,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3816
3816
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3817
3817
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3818
3818
|
}
|
|
3819
|
-
return
|
|
3819
|
+
return path33;
|
|
3820
3820
|
}
|
|
3821
3821
|
function metaRunIdMatches(run, token, runById) {
|
|
3822
3822
|
const meta2 = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -4147,7 +4147,7 @@ function normalizeBundleOutputPath(out) {
|
|
|
4147
4147
|
if (trimmed === "") {
|
|
4148
4148
|
throw new Error("--out requires a non-empty path.");
|
|
4149
4149
|
}
|
|
4150
|
-
const resolved =
|
|
4150
|
+
const resolved = path24__default.default.resolve(trimmed);
|
|
4151
4151
|
if (resolved.toLowerCase().endsWith(".zip")) {
|
|
4152
4152
|
return resolved.slice(0, -4);
|
|
4153
4153
|
}
|
|
@@ -4156,7 +4156,7 @@ function normalizeBundleOutputPath(out) {
|
|
|
4156
4156
|
function defaultBundleOutputPath(runIds) {
|
|
4157
4157
|
const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
|
|
4158
4158
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4159
|
-
return
|
|
4159
|
+
return path24__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
4160
4160
|
}
|
|
4161
4161
|
var init_paths = __esm({
|
|
4162
4162
|
"packages/core/src/bundle/paths.ts"() {
|
|
@@ -4330,7 +4330,7 @@ function normalizeSuiteConfig(value) {
|
|
|
4330
4330
|
}
|
|
4331
4331
|
async function validateSuiteConfig(config, options) {
|
|
4332
4332
|
const diagnostics = [];
|
|
4333
|
-
const tracesDir =
|
|
4333
|
+
const tracesDir = path24__default.default.resolve(options.configDir, config.traces);
|
|
4334
4334
|
try {
|
|
4335
4335
|
await promises.access(tracesDir);
|
|
4336
4336
|
} catch {
|
|
@@ -4340,7 +4340,7 @@ async function validateSuiteConfig(config, options) {
|
|
|
4340
4340
|
}
|
|
4341
4341
|
for (const suiteCase of config.cases) {
|
|
4342
4342
|
if (suiteCase.input !== void 0) {
|
|
4343
|
-
const inputPath =
|
|
4343
|
+
const inputPath = path24__default.default.resolve(options.configDir, suiteCase.input);
|
|
4344
4344
|
try {
|
|
4345
4345
|
await promises.access(inputPath);
|
|
4346
4346
|
} catch {
|
|
@@ -4373,12 +4373,12 @@ async function fileExists(filePath) {
|
|
|
4373
4373
|
}
|
|
4374
4374
|
}
|
|
4375
4375
|
async function resolveSuiteConfigPath(options = {}) {
|
|
4376
|
-
const cwd =
|
|
4376
|
+
const cwd = path24__default.default.resolve(options.cwd ?? process.cwd());
|
|
4377
4377
|
if (options.configPath !== void 0 && options.configPath.trim() !== "") {
|
|
4378
|
-
return
|
|
4378
|
+
return path24__default.default.resolve(cwd, options.configPath.trim());
|
|
4379
4379
|
}
|
|
4380
4380
|
for (const name of DEFAULT_SUITE_CONFIG_NAMES) {
|
|
4381
|
-
const candidate =
|
|
4381
|
+
const candidate = path24__default.default.join(cwd, name);
|
|
4382
4382
|
if (await fileExists(candidate)) return candidate;
|
|
4383
4383
|
}
|
|
4384
4384
|
throw new Error(
|
|
@@ -4395,7 +4395,7 @@ async function loadSuiteConfig(options = {}) {
|
|
|
4395
4395
|
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
4396
4396
|
});
|
|
4397
4397
|
}
|
|
4398
|
-
const extension =
|
|
4398
|
+
const extension = path24__default.default.extname(configPath);
|
|
4399
4399
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
4400
4400
|
const message = "TypeScript suite configs require an explicit precompiled JavaScript config or future --config-loader support.";
|
|
4401
4401
|
throw Object.assign(new Error(message), {
|
|
@@ -4420,7 +4420,7 @@ async function loadSuiteConfig(options = {}) {
|
|
|
4420
4420
|
return {
|
|
4421
4421
|
config,
|
|
4422
4422
|
configPath,
|
|
4423
|
-
configDir:
|
|
4423
|
+
configDir: path24__default.default.dirname(configPath)
|
|
4424
4424
|
};
|
|
4425
4425
|
} catch (error) {
|
|
4426
4426
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -4470,7 +4470,7 @@ async function exists(filePath) {
|
|
|
4470
4470
|
}
|
|
4471
4471
|
async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
4472
4472
|
if (suiteCase.trace !== void 0) {
|
|
4473
|
-
const tracePath =
|
|
4473
|
+
const tracePath = path24__default.default.resolve(options.configDir, suiteCase.trace);
|
|
4474
4474
|
if (await exists(tracePath)) {
|
|
4475
4475
|
return { caseId: suiteCase.id, tracePath, missing: false };
|
|
4476
4476
|
}
|
|
@@ -4486,7 +4486,7 @@ async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
|
4486
4486
|
if (await exists(directPath)) {
|
|
4487
4487
|
return { caseId: suiteCase.id, tracePath: directPath, runId: runKey, missing: false };
|
|
4488
4488
|
}
|
|
4489
|
-
const nestedPath =
|
|
4489
|
+
const nestedPath = path24__default.default.join(options.tracesDir, `${path24__default.default.basename(runKey)}.jsonl`);
|
|
4490
4490
|
if (await exists(nestedPath)) {
|
|
4491
4491
|
return { caseId: suiteCase.id, tracePath: nestedPath, runId: runKey, missing: false };
|
|
4492
4492
|
}
|
|
@@ -4716,7 +4716,7 @@ function stripPrefix(name, prefixes) {
|
|
|
4716
4716
|
}
|
|
4717
4717
|
return name;
|
|
4718
4718
|
}
|
|
4719
|
-
function eventEvidence(event,
|
|
4719
|
+
function eventEvidence(event, path33) {
|
|
4720
4720
|
return {
|
|
4721
4721
|
runId: event.runId,
|
|
4722
4722
|
eventId: event.eventId,
|
|
@@ -4726,7 +4726,7 @@ function eventEvidence(event, path31) {
|
|
|
4726
4726
|
kind: event.kind,
|
|
4727
4727
|
name: event.name,
|
|
4728
4728
|
status: event.status,
|
|
4729
|
-
...
|
|
4729
|
+
...path33 ? { path: path33 } : {}
|
|
4730
4730
|
};
|
|
4731
4731
|
}
|
|
4732
4732
|
function runEvidence(run) {
|
|
@@ -4789,9 +4789,9 @@ function eventEndMs(event) {
|
|
|
4789
4789
|
function normalizedKey(value) {
|
|
4790
4790
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
4791
4791
|
}
|
|
4792
|
-
function lastPathSegment(
|
|
4793
|
-
const parts =
|
|
4794
|
-
return parts[parts.length - 1] ??
|
|
4792
|
+
function lastPathSegment(path33) {
|
|
4793
|
+
const parts = path33.split(".");
|
|
4794
|
+
return parts[parts.length - 1] ?? path33;
|
|
4795
4795
|
}
|
|
4796
4796
|
function valueType(value) {
|
|
4797
4797
|
if (Array.isArray(value)) return "array";
|
|
@@ -4805,12 +4805,12 @@ function serializedByteLength(value) {
|
|
|
4805
4805
|
return void 0;
|
|
4806
4806
|
}
|
|
4807
4807
|
}
|
|
4808
|
-
function pushValueEntries(entries, event, value,
|
|
4809
|
-
entries.push({ event, path:
|
|
4808
|
+
function pushValueEntries(entries, event, value, path33, key, depth = 0) {
|
|
4809
|
+
entries.push({ event, path: path33, key, value });
|
|
4810
4810
|
if (depth >= 8) return;
|
|
4811
4811
|
if (Array.isArray(value)) {
|
|
4812
4812
|
for (const [index, item] of value.entries()) {
|
|
4813
|
-
pushValueEntries(entries, event, item, `${
|
|
4813
|
+
pushValueEntries(entries, event, item, `${path33}.${index}`, String(index), depth + 1);
|
|
4814
4814
|
}
|
|
4815
4815
|
return;
|
|
4816
4816
|
}
|
|
@@ -4820,7 +4820,7 @@ function pushValueEntries(entries, event, value, path31, key, depth = 0) {
|
|
|
4820
4820
|
entries,
|
|
4821
4821
|
event,
|
|
4822
4822
|
value[nestedKey],
|
|
4823
|
-
`${
|
|
4823
|
+
`${path33}.${nestedKey}`,
|
|
4824
4824
|
nestedKey,
|
|
4825
4825
|
depth + 1
|
|
4826
4826
|
);
|
|
@@ -4901,9 +4901,9 @@ function eventDurationMs(event) {
|
|
|
4901
4901
|
}
|
|
4902
4902
|
function treeShape(nodes) {
|
|
4903
4903
|
const lines = [];
|
|
4904
|
-
const visit = (node,
|
|
4905
|
-
lines.push(`${
|
|
4906
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
4904
|
+
const visit = (node, path33) => {
|
|
4905
|
+
lines.push(`${path33}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
4906
|
+
node.children.forEach((child, index) => visit(child, `${path33}.${index}`));
|
|
4907
4907
|
};
|
|
4908
4908
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
4909
4909
|
return lines;
|
|
@@ -4952,9 +4952,9 @@ function retrievalShape(context) {
|
|
|
4952
4952
|
function guardrailShape(context) {
|
|
4953
4953
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
4954
4954
|
}
|
|
4955
|
-
function firstEvidenceForKind(context, kind,
|
|
4955
|
+
function firstEvidenceForKind(context, kind, path33) {
|
|
4956
4956
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
4957
|
-
return event ? [eventEvidence(event,
|
|
4957
|
+
return event ? [eventEvidence(event, path33)] : runEvidence(context.selectedRun);
|
|
4958
4958
|
}
|
|
4959
4959
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
4960
4960
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -5304,13 +5304,13 @@ function createStructureCycleRule() {
|
|
|
5304
5304
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
5305
5305
|
const findings = [];
|
|
5306
5306
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
5307
|
-
const
|
|
5307
|
+
const path33 = [];
|
|
5308
5308
|
const seenAt = /* @__PURE__ */ new Map();
|
|
5309
5309
|
let current = event;
|
|
5310
5310
|
while (current) {
|
|
5311
5311
|
const existing = seenAt.get(current.eventId);
|
|
5312
5312
|
if (existing !== void 0) {
|
|
5313
|
-
const cycle =
|
|
5313
|
+
const cycle = path33.slice(existing);
|
|
5314
5314
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
5315
5315
|
if (!seenCycles.has(key)) {
|
|
5316
5316
|
seenCycles.add(key);
|
|
@@ -5326,8 +5326,8 @@ function createStructureCycleRule() {
|
|
|
5326
5326
|
}
|
|
5327
5327
|
break;
|
|
5328
5328
|
}
|
|
5329
|
-
seenAt.set(current.eventId,
|
|
5330
|
-
|
|
5329
|
+
seenAt.set(current.eventId, path33.length);
|
|
5330
|
+
path33.push(current);
|
|
5331
5331
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
5332
5332
|
}
|
|
5333
5333
|
}
|
|
@@ -6468,7 +6468,7 @@ function findReaderByFormat(format, readers) {
|
|
|
6468
6468
|
}
|
|
6469
6469
|
async function jsonlFilesInDirectory(dirPath) {
|
|
6470
6470
|
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
6471
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
6471
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path24__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
6472
6472
|
}
|
|
6473
6473
|
async function resolveInput(input3) {
|
|
6474
6474
|
const cached = resolvedInputCache.get(input3);
|
|
@@ -8167,7 +8167,7 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
8167
8167
|
async function runSuite(options = {}) {
|
|
8168
8168
|
const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
|
|
8169
8169
|
const { config, configPath, configDir } = await loadSuiteConfig(options);
|
|
8170
|
-
const tracesDir =
|
|
8170
|
+
const tracesDir = path24__default.default.resolve(configDir, config.traces);
|
|
8171
8171
|
const cases = [];
|
|
8172
8172
|
const diagnostics = [];
|
|
8173
8173
|
for (const suiteCase of config.cases) {
|
|
@@ -8951,6 +8951,426 @@ var init_cohort2 = __esm({
|
|
|
8951
8951
|
}
|
|
8952
8952
|
});
|
|
8953
8953
|
|
|
8954
|
+
// packages/core/src/gate/parse.ts
|
|
8955
|
+
function parseGateList(value) {
|
|
8956
|
+
if (value === void 0 || value.trim() === "") return [];
|
|
8957
|
+
return value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
8958
|
+
}
|
|
8959
|
+
var init_parse = __esm({
|
|
8960
|
+
"packages/core/src/gate/parse.ts"() {
|
|
8961
|
+
}
|
|
8962
|
+
});
|
|
8963
|
+
|
|
8964
|
+
// packages/core/src/gate/evaluate.ts
|
|
8965
|
+
function percentile3(values, p) {
|
|
8966
|
+
if (values.length === 0) return void 0;
|
|
8967
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
8968
|
+
const idx = Math.min(
|
|
8969
|
+
sorted.length - 1,
|
|
8970
|
+
Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
|
|
8971
|
+
);
|
|
8972
|
+
return sorted[idx];
|
|
8973
|
+
}
|
|
8974
|
+
function hasThresholds(options) {
|
|
8975
|
+
return options.maxErrorRate !== void 0 || options.maxP95DurationMs !== void 0 || (options.forbidTools?.length ?? 0) > 0 || (options.requireObservations?.length ?? 0) > 0;
|
|
8976
|
+
}
|
|
8977
|
+
function gateHasThresholds(options) {
|
|
8978
|
+
return hasThresholds(options);
|
|
8979
|
+
}
|
|
8980
|
+
async function loadRunMetrics(runs) {
|
|
8981
|
+
const metrics = [];
|
|
8982
|
+
for (const run of runs) {
|
|
8983
|
+
if (run.filePath === void 0) continue;
|
|
8984
|
+
metrics.push(
|
|
8985
|
+
await computeCohortRunMetrics({
|
|
8986
|
+
runId: run.runId,
|
|
8987
|
+
filePath: run.filePath,
|
|
8988
|
+
metadata: run.metadata,
|
|
8989
|
+
status: run.status,
|
|
8990
|
+
durationMs: run.durationMs,
|
|
8991
|
+
groupKey: "all"
|
|
8992
|
+
})
|
|
8993
|
+
);
|
|
8994
|
+
}
|
|
8995
|
+
return metrics;
|
|
8996
|
+
}
|
|
8997
|
+
async function observationStatus(filePath, name) {
|
|
8998
|
+
const events = await readTraceEventsFromFile(filePath);
|
|
8999
|
+
const outcomes = extractOutcomesFromTraceEvents(events);
|
|
9000
|
+
const match = outcomes.find((item) => item.name === name);
|
|
9001
|
+
if (!match) return "missing";
|
|
9002
|
+
return match.status === "passed" ? "passed" : "failed";
|
|
9003
|
+
}
|
|
9004
|
+
async function evaluateGateThresholds(runs, options) {
|
|
9005
|
+
const checks2 = [];
|
|
9006
|
+
const readErrors = [];
|
|
9007
|
+
if (!hasThresholds(options)) {
|
|
9008
|
+
return { checks: checks2, readErrors };
|
|
9009
|
+
}
|
|
9010
|
+
if (runs.length === 0) {
|
|
9011
|
+
readErrors.push("No trace runs found in the gate directory.");
|
|
9012
|
+
return { checks: checks2, readErrors };
|
|
9013
|
+
}
|
|
9014
|
+
let runMetrics;
|
|
9015
|
+
try {
|
|
9016
|
+
runMetrics = await loadRunMetrics(runs);
|
|
9017
|
+
} catch (error) {
|
|
9018
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9019
|
+
readErrors.push(message);
|
|
9020
|
+
return { checks: checks2, readErrors };
|
|
9021
|
+
}
|
|
9022
|
+
if (options.maxErrorRate !== void 0) {
|
|
9023
|
+
const errors = runMetrics.filter((run) => run.error).length;
|
|
9024
|
+
const actual = runMetrics.length > 0 ? errors / runMetrics.length * 100 : 0;
|
|
9025
|
+
const ok = actual <= options.maxErrorRate;
|
|
9026
|
+
checks2.push({
|
|
9027
|
+
id: "maxErrorRate",
|
|
9028
|
+
name: "Max error rate",
|
|
9029
|
+
ok,
|
|
9030
|
+
expected: options.maxErrorRate,
|
|
9031
|
+
actual: Math.round(actual * 10) / 10,
|
|
9032
|
+
message: ok ? `Error rate ${actual.toFixed(1)}% within limit ${options.maxErrorRate}%` : `Error rate ${actual.toFixed(1)}% exceeds limit ${options.maxErrorRate}%`
|
|
9033
|
+
});
|
|
9034
|
+
}
|
|
9035
|
+
if (options.maxP95DurationMs !== void 0) {
|
|
9036
|
+
const durations = runMetrics.map((run) => run.durationMs).filter((value) => typeof value === "number");
|
|
9037
|
+
const actual = percentile3(durations, 95);
|
|
9038
|
+
const ok = actual !== void 0 && actual <= options.maxP95DurationMs;
|
|
9039
|
+
checks2.push({
|
|
9040
|
+
id: "maxP95Duration",
|
|
9041
|
+
name: "Max p95 duration (ms)",
|
|
9042
|
+
ok,
|
|
9043
|
+
expected: options.maxP95DurationMs,
|
|
9044
|
+
actual: actual ?? "n/a",
|
|
9045
|
+
message: actual === void 0 ? "No duration samples available for p95 check." : ok ? `P95 duration ${Math.round(actual)} ms within limit ${options.maxP95DurationMs} ms` : `P95 duration ${Math.round(actual)} ms exceeds limit ${options.maxP95DurationMs} ms`
|
|
9046
|
+
});
|
|
9047
|
+
}
|
|
9048
|
+
for (const tool of options.forbidTools ?? []) {
|
|
9049
|
+
let violated = false;
|
|
9050
|
+
for (const run of runMetrics) {
|
|
9051
|
+
const used = run.toolChoices.includes(tool) || run.toolOrdering.includes(tool);
|
|
9052
|
+
if (used) {
|
|
9053
|
+
violated = true;
|
|
9054
|
+
checks2.push({
|
|
9055
|
+
id: "forbidTool",
|
|
9056
|
+
name: `Forbid tool: ${tool}`,
|
|
9057
|
+
ok: false,
|
|
9058
|
+
expected: `not used`,
|
|
9059
|
+
actual: "used",
|
|
9060
|
+
runId: run.runId,
|
|
9061
|
+
message: `Forbidden tool "${tool}" used in run ${run.runId}`
|
|
9062
|
+
});
|
|
9063
|
+
}
|
|
9064
|
+
}
|
|
9065
|
+
if (!violated) {
|
|
9066
|
+
checks2.push({
|
|
9067
|
+
id: "forbidTool",
|
|
9068
|
+
name: `Forbid tool: ${tool}`,
|
|
9069
|
+
ok: true,
|
|
9070
|
+
message: `Forbidden tool "${tool}" not used`
|
|
9071
|
+
});
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
9074
|
+
for (const observation of options.requireObservations ?? []) {
|
|
9075
|
+
for (const run of runs) {
|
|
9076
|
+
if (run.filePath === void 0) continue;
|
|
9077
|
+
try {
|
|
9078
|
+
const status = await observationStatus(run.filePath, observation);
|
|
9079
|
+
const ok = status === "passed";
|
|
9080
|
+
checks2.push({
|
|
9081
|
+
id: "requireObservation",
|
|
9082
|
+
name: `Require observation: ${observation}`,
|
|
9083
|
+
ok,
|
|
9084
|
+
expected: "passed",
|
|
9085
|
+
actual: status,
|
|
9086
|
+
runId: run.runId,
|
|
9087
|
+
message: ok ? `Observation "${observation}" passed in run ${run.runId}` : status === "missing" ? `Observation "${observation}" missing in run ${run.runId}` : `Observation "${observation}" failed in run ${run.runId}`
|
|
9088
|
+
});
|
|
9089
|
+
} catch (error) {
|
|
9090
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9091
|
+
readErrors.push(`Run ${run.runId}: ${message}`);
|
|
9092
|
+
}
|
|
9093
|
+
}
|
|
9094
|
+
}
|
|
9095
|
+
return { checks: checks2, readErrors };
|
|
9096
|
+
}
|
|
9097
|
+
function checksFromSuiteResult(suiteResult) {
|
|
9098
|
+
const checks2 = [
|
|
9099
|
+
{
|
|
9100
|
+
id: "suite",
|
|
9101
|
+
name: `Suite: ${suiteResult.suiteName}`,
|
|
9102
|
+
ok: suiteResult.ok,
|
|
9103
|
+
message: suiteResult.ok ? `Suite passed (${suiteResult.summary.passed} cases)` : `Suite failed (${suiteResult.summary.failed} failed, ${suiteResult.summary.errors} errors)`
|
|
9104
|
+
}
|
|
9105
|
+
];
|
|
9106
|
+
for (const suiteCase of suiteResult.cases) {
|
|
9107
|
+
if (suiteCase.status === "pass") continue;
|
|
9108
|
+
checks2.push({
|
|
9109
|
+
id: "suite",
|
|
9110
|
+
name: `Case: ${suiteCase.id}`,
|
|
9111
|
+
ok: false,
|
|
9112
|
+
message: suiteCase.message ?? `Case status: ${suiteCase.status}`
|
|
9113
|
+
});
|
|
9114
|
+
}
|
|
9115
|
+
return checks2;
|
|
9116
|
+
}
|
|
9117
|
+
var init_evaluate = __esm({
|
|
9118
|
+
"packages/core/src/gate/evaluate.ts"() {
|
|
9119
|
+
init_extract();
|
|
9120
|
+
init_storage();
|
|
9121
|
+
init_metrics();
|
|
9122
|
+
}
|
|
9123
|
+
});
|
|
9124
|
+
function resolveExitCode(input3) {
|
|
9125
|
+
if (input3.configError) return 2;
|
|
9126
|
+
if (input3.readError) return 3;
|
|
9127
|
+
if (!input3.ok) return 1;
|
|
9128
|
+
return 0;
|
|
9129
|
+
}
|
|
9130
|
+
function validateOptions(options) {
|
|
9131
|
+
const errors = [];
|
|
9132
|
+
const hasSuite = options.suitePath !== void 0 && options.suitePath.trim() !== "";
|
|
9133
|
+
const hasThresholds2 = gateHasThresholds(options);
|
|
9134
|
+
if (!hasSuite && !hasThresholds2) {
|
|
9135
|
+
errors.push(
|
|
9136
|
+
"No gate rules specified. Pass --suite or at least one threshold flag."
|
|
9137
|
+
);
|
|
9138
|
+
}
|
|
9139
|
+
if (hasThresholds2 && (options.traceDir === void 0 || options.traceDir.trim() === "")) {
|
|
9140
|
+
if (!hasSuite) {
|
|
9141
|
+
errors.push("Threshold flags require --dir <trace-directory>.");
|
|
9142
|
+
}
|
|
9143
|
+
}
|
|
9144
|
+
if (options.maxErrorRate !== void 0 && options.maxErrorRate < 0) {
|
|
9145
|
+
errors.push("--max-error-rate must be a non-negative percentage.");
|
|
9146
|
+
}
|
|
9147
|
+
if (options.maxP95DurationMs !== void 0 && options.maxP95DurationMs < 0) {
|
|
9148
|
+
errors.push("--max-p95-duration must be a non-negative millisecond value.");
|
|
9149
|
+
}
|
|
9150
|
+
return errors;
|
|
9151
|
+
}
|
|
9152
|
+
function isConfigLoadError(error) {
|
|
9153
|
+
if (!(error instanceof Error)) return false;
|
|
9154
|
+
const ext = path24__default.default.extname(error.message);
|
|
9155
|
+
if (error.message.includes("Unsupported suite config extension")) return true;
|
|
9156
|
+
if (error.message.includes("TypeScript suite configs require")) return true;
|
|
9157
|
+
if (error.message.includes("No suite config found")) return true;
|
|
9158
|
+
if (error.message.includes("AI_SUITE_CONFIG")) return true;
|
|
9159
|
+
if (ext === ".ts" || ext === ".mts" || ext === ".cts") return true;
|
|
9160
|
+
return "diagnostics" in error;
|
|
9161
|
+
}
|
|
9162
|
+
async function runGate(runs, options) {
|
|
9163
|
+
const diagnostics = [];
|
|
9164
|
+
const checks2 = [];
|
|
9165
|
+
const validationErrors = validateOptions(options);
|
|
9166
|
+
if (validationErrors.length > 0) {
|
|
9167
|
+
return {
|
|
9168
|
+
ok: false,
|
|
9169
|
+
exitCode: 2,
|
|
9170
|
+
runCount: 0,
|
|
9171
|
+
checks: checks2,
|
|
9172
|
+
diagnostics: validationErrors
|
|
9173
|
+
};
|
|
9174
|
+
}
|
|
9175
|
+
let traceDir = options.traceDir?.trim();
|
|
9176
|
+
let suiteResult;
|
|
9177
|
+
if (options.suitePath !== void 0 && options.suitePath.trim() !== "") {
|
|
9178
|
+
try {
|
|
9179
|
+
suiteResult = await runSuite({
|
|
9180
|
+
configPath: options.suitePath,
|
|
9181
|
+
cwd: options.cwd
|
|
9182
|
+
});
|
|
9183
|
+
traceDir = traceDir ?? suiteResult.tracesDir;
|
|
9184
|
+
checks2.push(...checksFromSuiteResult(suiteResult));
|
|
9185
|
+
} catch (error) {
|
|
9186
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9187
|
+
diagnostics.push(message);
|
|
9188
|
+
return {
|
|
9189
|
+
ok: false,
|
|
9190
|
+
exitCode: isConfigLoadError(error) ? 2 : 3,
|
|
9191
|
+
traceDir,
|
|
9192
|
+
suitePath: options.suitePath,
|
|
9193
|
+
runCount: 0,
|
|
9194
|
+
checks: checks2,
|
|
9195
|
+
diagnostics
|
|
9196
|
+
};
|
|
9197
|
+
}
|
|
9198
|
+
}
|
|
9199
|
+
if (gateHasThresholds(options)) {
|
|
9200
|
+
const thresholdDir = traceDir;
|
|
9201
|
+
if (thresholdDir === void 0 || thresholdDir.trim() === "") {
|
|
9202
|
+
return {
|
|
9203
|
+
ok: false,
|
|
9204
|
+
exitCode: 2,
|
|
9205
|
+
traceDir,
|
|
9206
|
+
suitePath: options.suitePath,
|
|
9207
|
+
runCount: runs.length,
|
|
9208
|
+
checks: checks2,
|
|
9209
|
+
diagnostics: ["Threshold evaluation requires a trace directory."],
|
|
9210
|
+
...suiteResult !== void 0 ? { suiteResult } : {}
|
|
9211
|
+
};
|
|
9212
|
+
}
|
|
9213
|
+
const thresholdRuns = runs.length > 0 ? runs : [];
|
|
9214
|
+
const { checks: thresholdChecks, readErrors } = await evaluateGateThresholds(
|
|
9215
|
+
thresholdRuns,
|
|
9216
|
+
options
|
|
9217
|
+
);
|
|
9218
|
+
checks2.push(...thresholdChecks);
|
|
9219
|
+
diagnostics.push(...readErrors);
|
|
9220
|
+
if (readErrors.length > 0) {
|
|
9221
|
+
const ok2 = checks2.length > 0 && checks2.every((item) => item.ok);
|
|
9222
|
+
return {
|
|
9223
|
+
ok: ok2,
|
|
9224
|
+
exitCode: resolveExitCode({
|
|
9225
|
+
ok: ok2,
|
|
9226
|
+
configError: false,
|
|
9227
|
+
readError: true
|
|
9228
|
+
}),
|
|
9229
|
+
traceDir: thresholdDir,
|
|
9230
|
+
suitePath: options.suitePath,
|
|
9231
|
+
runCount: thresholdRuns.length,
|
|
9232
|
+
checks: checks2,
|
|
9233
|
+
diagnostics,
|
|
9234
|
+
...suiteResult !== void 0 ? { suiteResult } : {}
|
|
9235
|
+
};
|
|
9236
|
+
}
|
|
9237
|
+
}
|
|
9238
|
+
const ok = checks2.length > 0 && checks2.every((item) => item.ok);
|
|
9239
|
+
return {
|
|
9240
|
+
ok,
|
|
9241
|
+
exitCode: resolveExitCode({ ok, configError: false, readError: false }),
|
|
9242
|
+
traceDir,
|
|
9243
|
+
suitePath: options.suitePath,
|
|
9244
|
+
runCount: runs.length,
|
|
9245
|
+
checks: checks2,
|
|
9246
|
+
diagnostics,
|
|
9247
|
+
...suiteResult !== void 0 ? { suiteResult } : {}
|
|
9248
|
+
};
|
|
9249
|
+
}
|
|
9250
|
+
var init_run2 = __esm({
|
|
9251
|
+
"packages/core/src/gate/run.ts"() {
|
|
9252
|
+
init_run();
|
|
9253
|
+
init_evaluate();
|
|
9254
|
+
}
|
|
9255
|
+
});
|
|
9256
|
+
|
|
9257
|
+
// packages/core/src/gate/render.ts
|
|
9258
|
+
function escapeXml(value) {
|
|
9259
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
9260
|
+
}
|
|
9261
|
+
function renderGateSummaryMarkdown(result) {
|
|
9262
|
+
const lines = [];
|
|
9263
|
+
lines.push("# AgentInspect gate");
|
|
9264
|
+
lines.push("");
|
|
9265
|
+
lines.push(`Status: **${result.ok ? "PASS" : "FAIL"}** (exit ${result.exitCode})`);
|
|
9266
|
+
if (result.traceDir !== void 0) {
|
|
9267
|
+
lines.push(`Trace directory: \`${result.traceDir}\``);
|
|
9268
|
+
}
|
|
9269
|
+
if (result.suitePath !== void 0) {
|
|
9270
|
+
lines.push(`Suite config: \`${result.suitePath}\``);
|
|
9271
|
+
}
|
|
9272
|
+
lines.push(`Runs evaluated: ${result.runCount}`);
|
|
9273
|
+
lines.push("");
|
|
9274
|
+
if (result.diagnostics.length > 0) {
|
|
9275
|
+
lines.push("## Diagnostics");
|
|
9276
|
+
for (const item of result.diagnostics) lines.push(`- ${item}`);
|
|
9277
|
+
lines.push("");
|
|
9278
|
+
}
|
|
9279
|
+
lines.push("## Checks");
|
|
9280
|
+
for (const check of result.checks) {
|
|
9281
|
+
const flag = check.ok ? "PASS" : "FAIL";
|
|
9282
|
+
lines.push(`- [${flag}] ${check.name}: ${check.message}`);
|
|
9283
|
+
}
|
|
9284
|
+
lines.push("");
|
|
9285
|
+
return lines.join("\n").trimEnd();
|
|
9286
|
+
}
|
|
9287
|
+
function renderGateGithubStepSummary(result) {
|
|
9288
|
+
const lines = [];
|
|
9289
|
+
lines.push(`## AgentInspect gate: ${result.ok ? "PASS" : "FAIL"}`);
|
|
9290
|
+
lines.push("");
|
|
9291
|
+
lines.push("| Check | Status | Details |");
|
|
9292
|
+
lines.push("| --- | --- | --- |");
|
|
9293
|
+
for (const check of result.checks) {
|
|
9294
|
+
lines.push(
|
|
9295
|
+
`| ${check.name} | ${check.ok ? "pass" : "fail"} | ${check.message.replace(/\|/g, "/")} |`
|
|
9296
|
+
);
|
|
9297
|
+
}
|
|
9298
|
+
if (result.diagnostics.length > 0) {
|
|
9299
|
+
lines.push("");
|
|
9300
|
+
lines.push("**Diagnostics**");
|
|
9301
|
+
for (const item of result.diagnostics) lines.push(`- ${item}`);
|
|
9302
|
+
}
|
|
9303
|
+
return lines.join("\n").trimEnd();
|
|
9304
|
+
}
|
|
9305
|
+
function renderGateReportHtml(result) {
|
|
9306
|
+
const rows = result.checks.map(
|
|
9307
|
+
(check) => `<tr><td>${escapeHtml(check.name)}</td><td>${check.ok ? "PASS" : "FAIL"}</td><td>${escapeHtml(check.message)}</td></tr>`
|
|
9308
|
+
).join("");
|
|
9309
|
+
return `<!DOCTYPE html>
|
|
9310
|
+
<html lang="en">
|
|
9311
|
+
<head>
|
|
9312
|
+
<meta charset="utf-8" />
|
|
9313
|
+
<title>Gate report</title>
|
|
9314
|
+
<style>
|
|
9315
|
+
body { font-family: system-ui, sans-serif; margin: 2rem; }
|
|
9316
|
+
table { border-collapse: collapse; width: 100%; }
|
|
9317
|
+
th, td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; }
|
|
9318
|
+
th { background: #f6f6f6; }
|
|
9319
|
+
</style>
|
|
9320
|
+
</head>
|
|
9321
|
+
<body>
|
|
9322
|
+
<h1>AgentInspect gate</h1>
|
|
9323
|
+
<p>Status: <strong>${result.ok ? "PASS" : "FAIL"}</strong> (exit ${result.exitCode})</p>
|
|
9324
|
+
<h2>Checks</h2>
|
|
9325
|
+
<table>
|
|
9326
|
+
<thead><tr><th>Check</th><th>Status</th><th>Details</th></tr></thead>
|
|
9327
|
+
<tbody>${rows}</tbody>
|
|
9328
|
+
</table>
|
|
9329
|
+
</body>
|
|
9330
|
+
</html>`;
|
|
9331
|
+
}
|
|
9332
|
+
function renderGateJUnit(result) {
|
|
9333
|
+
const failures = result.checks.filter((check) => !check.ok).length;
|
|
9334
|
+
const tests = result.checks.length;
|
|
9335
|
+
const cases = result.checks.map((check) => {
|
|
9336
|
+
if (check.ok) {
|
|
9337
|
+
return ` <testcase name="${escapeXml(check.name)}" classname="gate" />`;
|
|
9338
|
+
}
|
|
9339
|
+
return ` <testcase name="${escapeXml(check.name)}" classname="gate">
|
|
9340
|
+
<failure message="${escapeXml(check.message)}">${escapeXml(check.message)}</failure>
|
|
9341
|
+
</testcase>`;
|
|
9342
|
+
}).join("\n");
|
|
9343
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
9344
|
+
<testsuites tests="${tests}" failures="${failures}" errors="0" time="0">
|
|
9345
|
+
<testsuite name="agent-inspect-gate" tests="${tests}" failures="${failures}" errors="0" time="0">
|
|
9346
|
+
${cases}
|
|
9347
|
+
</testsuite>
|
|
9348
|
+
</testsuites>`;
|
|
9349
|
+
}
|
|
9350
|
+
function renderGateReport(result, options = {}) {
|
|
9351
|
+
const format = options.format ?? "markdown";
|
|
9352
|
+
if (format === "json") return JSON.stringify(result, null, 2);
|
|
9353
|
+
if (format === "html") return renderGateReportHtml(result);
|
|
9354
|
+
if (format === "junit") return renderGateJUnit(result);
|
|
9355
|
+
if (format === "github") return renderGateGithubStepSummary(result);
|
|
9356
|
+
return renderGateSummaryMarkdown(result);
|
|
9357
|
+
}
|
|
9358
|
+
var init_render3 = __esm({
|
|
9359
|
+
"packages/core/src/gate/render.ts"() {
|
|
9360
|
+
init_helpers();
|
|
9361
|
+
}
|
|
9362
|
+
});
|
|
9363
|
+
|
|
9364
|
+
// packages/core/src/gate/index.ts
|
|
9365
|
+
var init_gate = __esm({
|
|
9366
|
+
"packages/core/src/gate/index.ts"() {
|
|
9367
|
+
init_parse();
|
|
9368
|
+
init_evaluate();
|
|
9369
|
+
init_run2();
|
|
9370
|
+
init_render3();
|
|
9371
|
+
}
|
|
9372
|
+
});
|
|
9373
|
+
|
|
8954
9374
|
// packages/core/src/inspect-run.ts
|
|
8955
9375
|
var init_inspect_run = __esm({
|
|
8956
9376
|
"packages/core/src/inspect-run.ts"() {
|
|
@@ -8997,6 +9417,7 @@ var init_advanced = __esm({
|
|
|
8997
9417
|
init_bundle();
|
|
8998
9418
|
init_suite();
|
|
8999
9419
|
init_cohort2();
|
|
9420
|
+
init_gate();
|
|
9000
9421
|
init_maybe_inspect_run();
|
|
9001
9422
|
}
|
|
9002
9423
|
});
|
|
@@ -9061,19 +9482,19 @@ var require_file_uri_to_path = __commonJS({
|
|
|
9061
9482
|
var rest = decodeURI(uri.substring(7));
|
|
9062
9483
|
var firstSlash = rest.indexOf("/");
|
|
9063
9484
|
var host = rest.substring(0, firstSlash);
|
|
9064
|
-
var
|
|
9485
|
+
var path33 = rest.substring(firstSlash + 1);
|
|
9065
9486
|
if ("localhost" == host) host = "";
|
|
9066
9487
|
if (host) {
|
|
9067
9488
|
host = sep + sep + host;
|
|
9068
9489
|
}
|
|
9069
|
-
|
|
9490
|
+
path33 = path33.replace(/^(.+)\|/, "$1:");
|
|
9070
9491
|
if (sep == "\\") {
|
|
9071
|
-
|
|
9492
|
+
path33 = path33.replace(/\//g, "\\");
|
|
9072
9493
|
}
|
|
9073
|
-
if (/^.+\:/.test(
|
|
9074
|
-
|
|
9494
|
+
if (/^.+\:/.test(path33)) ; else {
|
|
9495
|
+
path33 = sep + path33;
|
|
9075
9496
|
}
|
|
9076
|
-
return host +
|
|
9497
|
+
return host + path33;
|
|
9077
9498
|
}
|
|
9078
9499
|
}
|
|
9079
9500
|
});
|
|
@@ -9082,18 +9503,18 @@ var require_file_uri_to_path = __commonJS({
|
|
|
9082
9503
|
var require_bindings = __commonJS({
|
|
9083
9504
|
"node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js"(exports$1, module) {
|
|
9084
9505
|
var fs = __require("fs");
|
|
9085
|
-
var
|
|
9506
|
+
var path33 = __require("path");
|
|
9086
9507
|
var fileURLToPath2 = require_file_uri_to_path();
|
|
9087
|
-
var join =
|
|
9088
|
-
var dirname =
|
|
9089
|
-
var exists2 = fs.accessSync && function(
|
|
9508
|
+
var join = path33.join;
|
|
9509
|
+
var dirname = path33.dirname;
|
|
9510
|
+
var exists2 = fs.accessSync && function(path34) {
|
|
9090
9511
|
try {
|
|
9091
|
-
fs.accessSync(
|
|
9512
|
+
fs.accessSync(path34);
|
|
9092
9513
|
} catch (e) {
|
|
9093
9514
|
return false;
|
|
9094
9515
|
}
|
|
9095
9516
|
return true;
|
|
9096
|
-
} || fs.existsSync ||
|
|
9517
|
+
} || fs.existsSync || path33.existsSync;
|
|
9097
9518
|
var defaults = {
|
|
9098
9519
|
arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
|
|
9099
9520
|
compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
|
|
@@ -9138,7 +9559,7 @@ var require_bindings = __commonJS({
|
|
|
9138
9559
|
if (!opts.module_root) {
|
|
9139
9560
|
opts.module_root = exports$1.getRoot(exports$1.getFileName());
|
|
9140
9561
|
}
|
|
9141
|
-
if (
|
|
9562
|
+
if (path33.extname(opts.bindings) != ".node") {
|
|
9142
9563
|
opts.bindings += ".node";
|
|
9143
9564
|
}
|
|
9144
9565
|
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
@@ -9373,7 +9794,7 @@ var require_pragma = __commonJS({
|
|
|
9373
9794
|
var require_backup = __commonJS({
|
|
9374
9795
|
"node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/backup.js"(exports$1, module) {
|
|
9375
9796
|
var fs = __require("fs");
|
|
9376
|
-
var
|
|
9797
|
+
var path33 = __require("path");
|
|
9377
9798
|
var { promisify } = __require("util");
|
|
9378
9799
|
var { cppdb } = require_util();
|
|
9379
9800
|
var fsAccess = promisify(fs.access);
|
|
@@ -9389,7 +9810,7 @@ var require_backup = __commonJS({
|
|
|
9389
9810
|
if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
|
|
9390
9811
|
if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
|
|
9391
9812
|
if (handler != null && typeof handler !== "function") throw new TypeError('Expected the "progress" option to be a function');
|
|
9392
|
-
await fsAccess(
|
|
9813
|
+
await fsAccess(path33.dirname(filename)).catch(() => {
|
|
9393
9814
|
throw new TypeError("Cannot save backup because the directory does not exist");
|
|
9394
9815
|
});
|
|
9395
9816
|
const isNewFile = await fsAccess(filename).then(() => false, () => true);
|
|
@@ -9689,7 +10110,7 @@ var require_inspect = __commonJS({
|
|
|
9689
10110
|
var require_database = __commonJS({
|
|
9690
10111
|
"node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/database.js"(exports$1, module) {
|
|
9691
10112
|
var fs = __require("fs");
|
|
9692
|
-
var
|
|
10113
|
+
var path33 = __require("path");
|
|
9693
10114
|
var util = require_util();
|
|
9694
10115
|
var SqliteError = require_sqlite_error();
|
|
9695
10116
|
var DEFAULT_ADDON;
|
|
@@ -9725,7 +10146,7 @@ var require_database = __commonJS({
|
|
|
9725
10146
|
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
|
|
9726
10147
|
} else if (typeof nativeBinding === "string") {
|
|
9727
10148
|
const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
9728
|
-
addon = requireFunc(
|
|
10149
|
+
addon = requireFunc(path33.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
|
|
9729
10150
|
} else {
|
|
9730
10151
|
addon = nativeBinding;
|
|
9731
10152
|
}
|
|
@@ -9733,7 +10154,7 @@ var require_database = __commonJS({
|
|
|
9733
10154
|
addon.setErrorConstructor(SqliteError);
|
|
9734
10155
|
addon.isInitialized = true;
|
|
9735
10156
|
}
|
|
9736
|
-
if (!anonymous && !fs.existsSync(
|
|
10157
|
+
if (!anonymous && !fs.existsSync(path33.dirname(filename))) {
|
|
9737
10158
|
throw new TypeError("Cannot open database because the directory does not exist");
|
|
9738
10159
|
}
|
|
9739
10160
|
Object.defineProperties(this, {
|
|
@@ -9860,8 +10281,8 @@ GROUP BY session_id;
|
|
|
9860
10281
|
}
|
|
9861
10282
|
});
|
|
9862
10283
|
function resolveIndexDbPath(traceDir, dbPath) {
|
|
9863
|
-
if (dbPath && dbPath.trim() !== "") return
|
|
9864
|
-
return
|
|
10284
|
+
if (dbPath && dbPath.trim() !== "") return path24__default.default.resolve(dbPath);
|
|
10285
|
+
return path24__default.default.join(path24__default.default.resolve(traceDir), INDEX_DB_FILENAME);
|
|
9865
10286
|
}
|
|
9866
10287
|
function str(value) {
|
|
9867
10288
|
return typeof value === "string" && value !== "" ? value : null;
|
|
@@ -9953,7 +10374,7 @@ async function buildIndex(options = {}) {
|
|
|
9953
10374
|
warnings.push(`index.unreadable: ${file}`);
|
|
9954
10375
|
}
|
|
9955
10376
|
}
|
|
9956
|
-
await promises.mkdir(
|
|
10377
|
+
await promises.mkdir(path24__default.default.dirname(dbPath), { recursive: true });
|
|
9957
10378
|
await promises.rm(dbPath, { force: true });
|
|
9958
10379
|
const db = new import_better_sqlite3.default(dbPath);
|
|
9959
10380
|
let runCount = 0;
|
|
@@ -10191,7 +10612,7 @@ var init_src = __esm({
|
|
|
10191
10612
|
});
|
|
10192
10613
|
|
|
10193
10614
|
// package.json
|
|
10194
|
-
var version = "5.
|
|
10615
|
+
var version = "5.2.0";
|
|
10195
10616
|
|
|
10196
10617
|
// packages/cli/src/list.ts
|
|
10197
10618
|
init_advanced();
|
|
@@ -13192,9 +13613,9 @@ Trace directory: ${traceDir}`);
|
|
|
13192
13613
|
if (validation !== void 0 && !validation.ok) {
|
|
13193
13614
|
process.exitCode = 1;
|
|
13194
13615
|
}
|
|
13195
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
13616
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path24__default.default.resolve(options.output.trim()) : void 0;
|
|
13196
13617
|
if (outPath !== void 0) {
|
|
13197
|
-
await promises.mkdir(
|
|
13618
|
+
await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
|
|
13198
13619
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
13199
13620
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
13200
13621
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -13375,13 +13796,13 @@ function pairSteps(left, right) {
|
|
|
13375
13796
|
return pairs;
|
|
13376
13797
|
}
|
|
13377
13798
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
13378
|
-
const
|
|
13799
|
+
const path33 = buildPath(segments);
|
|
13379
13800
|
if (L.name !== R.name) {
|
|
13380
13801
|
out.push({
|
|
13381
13802
|
kind: "structure",
|
|
13382
13803
|
severity: "warning",
|
|
13383
13804
|
message: "Step name differs",
|
|
13384
|
-
path:
|
|
13805
|
+
path: path33,
|
|
13385
13806
|
left: L.name,
|
|
13386
13807
|
right: R.name
|
|
13387
13808
|
});
|
|
@@ -13391,7 +13812,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
13391
13812
|
kind: "step-type",
|
|
13392
13813
|
severity: "warning",
|
|
13393
13814
|
message: "Step type differs",
|
|
13394
|
-
path:
|
|
13815
|
+
path: path33,
|
|
13395
13816
|
left: L.type,
|
|
13396
13817
|
right: R.type
|
|
13397
13818
|
});
|
|
@@ -13401,7 +13822,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
13401
13822
|
kind: "step-status",
|
|
13402
13823
|
severity: "warning",
|
|
13403
13824
|
message: "Step status differs",
|
|
13404
|
-
path:
|
|
13825
|
+
path: path33,
|
|
13405
13826
|
left: L.status,
|
|
13406
13827
|
right: R.status
|
|
13407
13828
|
});
|
|
@@ -13413,7 +13834,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
13413
13834
|
kind: "error",
|
|
13414
13835
|
severity: "error",
|
|
13415
13836
|
message: "Step error message differs",
|
|
13416
|
-
path:
|
|
13837
|
+
path: path33,
|
|
13417
13838
|
left: le || void 0,
|
|
13418
13839
|
right: re || void 0
|
|
13419
13840
|
});
|
|
@@ -13431,7 +13852,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
13431
13852
|
kind: "duration",
|
|
13432
13853
|
severity: "info",
|
|
13433
13854
|
message: "Step duration differs",
|
|
13434
|
-
path:
|
|
13855
|
+
path: path33,
|
|
13435
13856
|
left: ld,
|
|
13436
13857
|
right: rd
|
|
13437
13858
|
});
|
|
@@ -13444,7 +13865,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
13444
13865
|
kind: "metadata",
|
|
13445
13866
|
severity: "info",
|
|
13446
13867
|
message: "Step metadata differs",
|
|
13447
|
-
path:
|
|
13868
|
+
path: path33,
|
|
13448
13869
|
left: L.metadata,
|
|
13449
13870
|
right: R.metadata
|
|
13450
13871
|
});
|
|
@@ -13456,7 +13877,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
13456
13877
|
kind: "output",
|
|
13457
13878
|
severity: "info",
|
|
13458
13879
|
message: "Output preview differs",
|
|
13459
|
-
path:
|
|
13880
|
+
path: path33,
|
|
13460
13881
|
left: L.outputPreview,
|
|
13461
13882
|
right: R.outputPreview
|
|
13462
13883
|
});
|
|
@@ -13617,11 +14038,11 @@ function diffRuns(left, right, options) {
|
|
|
13617
14038
|
|
|
13618
14039
|
// packages/core/src/diff/renderer.ts
|
|
13619
14040
|
init_source();
|
|
13620
|
-
function formatPath(
|
|
13621
|
-
if (
|
|
14041
|
+
function formatPath(path33) {
|
|
14042
|
+
if (path33 === void 0 || path33.path.length === 0) {
|
|
13622
14043
|
return "(run)";
|
|
13623
14044
|
}
|
|
13624
|
-
return
|
|
14045
|
+
return path33.path.map((s) => s.name).join(" > ");
|
|
13625
14046
|
}
|
|
13626
14047
|
function formatValue(v, verbose) {
|
|
13627
14048
|
if (v === void 0) return "(undefined)";
|
|
@@ -14009,7 +14430,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
14009
14430
|
endedAt: row.endedAt ?? void 0,
|
|
14010
14431
|
durationMs: row.durationMs ?? void 0,
|
|
14011
14432
|
eventCount: 0,
|
|
14012
|
-
filePath:
|
|
14433
|
+
filePath: path24__default.default.join(traceDir, row.file),
|
|
14013
14434
|
fileSize: 0,
|
|
14014
14435
|
createdAt: new Date(row.mtimeMs)
|
|
14015
14436
|
};
|
|
@@ -14490,9 +14911,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
14490
14911
|
correlation: !options.noCorrelation,
|
|
14491
14912
|
...options.section ? { section: options.section } : {}
|
|
14492
14913
|
});
|
|
14493
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
14914
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path24__default.default.resolve(options.output.trim()) : void 0;
|
|
14494
14915
|
if (outPath !== void 0) {
|
|
14495
|
-
await promises.mkdir(
|
|
14916
|
+
await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
|
|
14496
14917
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
14497
14918
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
14498
14919
|
}
|
|
@@ -14742,17 +15163,17 @@ function applyRule(rule, value, replacement) {
|
|
|
14742
15163
|
}
|
|
14743
15164
|
return value;
|
|
14744
15165
|
}
|
|
14745
|
-
function childPath(
|
|
15166
|
+
function childPath(path33, key) {
|
|
14746
15167
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
14747
|
-
return
|
|
15168
|
+
return path33 ? `${path33}.${key}` : key;
|
|
14748
15169
|
}
|
|
14749
|
-
return `${
|
|
15170
|
+
return `${path33 || "$"}[${JSON.stringify(key)}]`;
|
|
14750
15171
|
}
|
|
14751
|
-
function indexPath(
|
|
14752
|
-
return `${
|
|
15172
|
+
function indexPath(path33, index) {
|
|
15173
|
+
return `${path33 || "$"}[${index}]`;
|
|
14753
15174
|
}
|
|
14754
|
-
function makeFinding(
|
|
14755
|
-
return preview === void 0 ? { path:
|
|
15175
|
+
function makeFinding(path33, detector, action, matchKind, severity = "warning", preview) {
|
|
15176
|
+
return preview === void 0 ? { path: path33, detector, action, severity, matchKind } : { path: path33, detector, action, severity, matchKind, preview };
|
|
14756
15177
|
}
|
|
14757
15178
|
function createRedactionProfile(profile = "local") {
|
|
14758
15179
|
switch (profile) {
|
|
@@ -14821,11 +15242,11 @@ var Redactor2 = class {
|
|
|
14821
15242
|
#recordFinding(state, finding) {
|
|
14822
15243
|
if (this.#collectFindings) state.findings.push(finding);
|
|
14823
15244
|
}
|
|
14824
|
-
#redactValue(value, key,
|
|
15245
|
+
#redactValue(value, key, path33, depth, state) {
|
|
14825
15246
|
if (depth > this.#maxDepth) {
|
|
14826
15247
|
this.#recordFinding(
|
|
14827
15248
|
state,
|
|
14828
|
-
makeFinding(
|
|
15249
|
+
makeFinding(path33, "structure.maxDepth", "truncate", "value", "warning")
|
|
14829
15250
|
);
|
|
14830
15251
|
return "[Truncated]";
|
|
14831
15252
|
}
|
|
@@ -14834,19 +15255,19 @@ var Redactor2 = class {
|
|
|
14834
15255
|
if (rule) {
|
|
14835
15256
|
this.#recordFinding(
|
|
14836
15257
|
state,
|
|
14837
|
-
makeFinding(
|
|
15258
|
+
makeFinding(path33, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
14838
15259
|
);
|
|
14839
15260
|
return applyRule(rule, value, this.#replacement);
|
|
14840
15261
|
}
|
|
14841
15262
|
}
|
|
14842
15263
|
for (const detector of this.#detectors) {
|
|
14843
|
-
const detections = detector.detect({ path:
|
|
15264
|
+
const detections = detector.detect({ path: path33, key, value });
|
|
14844
15265
|
for (const detection of detections) {
|
|
14845
15266
|
const action = detection.action ?? "replace";
|
|
14846
15267
|
this.#recordFinding(
|
|
14847
15268
|
state,
|
|
14848
15269
|
makeFinding(
|
|
14849
|
-
|
|
15270
|
+
path33,
|
|
14850
15271
|
detector.id,
|
|
14851
15272
|
action,
|
|
14852
15273
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -14864,7 +15285,7 @@ var Redactor2 = class {
|
|
|
14864
15285
|
const out = [];
|
|
14865
15286
|
state.seen.set(value, out);
|
|
14866
15287
|
value.forEach((item, index) => {
|
|
14867
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
15288
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path33, index), depth + 1, state);
|
|
14868
15289
|
});
|
|
14869
15290
|
return out;
|
|
14870
15291
|
}
|
|
@@ -14876,7 +15297,7 @@ var Redactor2 = class {
|
|
|
14876
15297
|
out[entryKey] = this.#redactValue(
|
|
14877
15298
|
entryValue,
|
|
14878
15299
|
entryKey,
|
|
14879
|
-
childPath(
|
|
15300
|
+
childPath(path33 === "$" ? "" : path33, entryKey),
|
|
14880
15301
|
depth + 1,
|
|
14881
15302
|
state
|
|
14882
15303
|
);
|
|
@@ -15336,14 +15757,14 @@ function uniqueSorted(values) {
|
|
|
15336
15757
|
return [...new Set(values)].sort();
|
|
15337
15758
|
}
|
|
15338
15759
|
function isWithinDirectory(child, parent) {
|
|
15339
|
-
const relative =
|
|
15340
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
15760
|
+
const relative = path24__default.default.relative(parent, child);
|
|
15761
|
+
return relative === "" || !relative.startsWith("..") && !path24__default.default.isAbsolute(relative);
|
|
15341
15762
|
}
|
|
15342
15763
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
15343
15764
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
15344
|
-
const inputAbs =
|
|
15345
|
-
const outputAbs =
|
|
15346
|
-
const inputDir =
|
|
15765
|
+
const inputAbs = path24__default.default.resolve(inputPath);
|
|
15766
|
+
const outputAbs = path24__default.default.resolve(output2.trim());
|
|
15767
|
+
const inputDir = path24__default.default.dirname(inputAbs);
|
|
15347
15768
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
15348
15769
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
15349
15770
|
}
|
|
@@ -15464,7 +15885,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
15464
15885
|
process.exitCode = 1;
|
|
15465
15886
|
return;
|
|
15466
15887
|
}
|
|
15467
|
-
const inputPath =
|
|
15888
|
+
const inputPath = path24__default.default.resolve(input3.trim());
|
|
15468
15889
|
const dryRun = options.dryRun === true;
|
|
15469
15890
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
15470
15891
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -15483,7 +15904,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
15483
15904
|
);
|
|
15484
15905
|
const result = await buildMigration(inputPath, outputPath);
|
|
15485
15906
|
if (!dryRun && outputPath !== void 0) {
|
|
15486
|
-
await promises.mkdir(
|
|
15907
|
+
await promises.mkdir(path24__default.default.dirname(outputPath), { recursive: true });
|
|
15487
15908
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
15488
15909
|
}
|
|
15489
15910
|
printSummary2(result, dryRun);
|
|
@@ -15817,23 +16238,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
15817
16238
|
}
|
|
15818
16239
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
15819
16240
|
}
|
|
15820
|
-
function validateSchemaField(value, field,
|
|
16241
|
+
function validateSchemaField(value, field, path33, evidence) {
|
|
15821
16242
|
const ruleId = "guardrail.structured-output";
|
|
15822
16243
|
if (field.type) {
|
|
15823
16244
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
15824
16245
|
if (actual !== field.type) {
|
|
15825
|
-
evidence.push({ ruleId, path:
|
|
16246
|
+
evidence.push({ ruleId, path: path33, preview: `expected ${field.type}, got ${actual}` });
|
|
15826
16247
|
return;
|
|
15827
16248
|
}
|
|
15828
16249
|
}
|
|
15829
16250
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
15830
|
-
evidence.push({ ruleId, path:
|
|
16251
|
+
evidence.push({ ruleId, path: path33, preview: "value not in enum" });
|
|
15831
16252
|
}
|
|
15832
16253
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
15833
16254
|
const record = value;
|
|
15834
16255
|
for (const key of field.required) {
|
|
15835
16256
|
if (!(key in record)) {
|
|
15836
|
-
evidence.push({ ruleId, path: `${
|
|
16257
|
+
evidence.push({ ruleId, path: `${path33}.${key}`, preview: "missing required key" });
|
|
15837
16258
|
}
|
|
15838
16259
|
}
|
|
15839
16260
|
}
|
|
@@ -16160,7 +16581,7 @@ function asConfig(value) {
|
|
|
16160
16581
|
}
|
|
16161
16582
|
async function loadConfig(configPath) {
|
|
16162
16583
|
if (configPath === void 0) return {};
|
|
16163
|
-
const extension =
|
|
16584
|
+
const extension = path24__default.default.extname(configPath);
|
|
16164
16585
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
16165
16586
|
throw new Error(
|
|
16166
16587
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -16169,7 +16590,7 @@ async function loadConfig(configPath) {
|
|
|
16169
16590
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
16170
16591
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
16171
16592
|
}
|
|
16172
|
-
const absolute =
|
|
16593
|
+
const absolute = path24__default.default.resolve(configPath);
|
|
16173
16594
|
if (extension === ".json") {
|
|
16174
16595
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
16175
16596
|
return asConfig(JSON.parse(raw));
|
|
@@ -16334,10 +16755,10 @@ function printHuman(result) {
|
|
|
16334
16755
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
16335
16756
|
}
|
|
16336
16757
|
for (const finding of result.findings) {
|
|
16337
|
-
const
|
|
16758
|
+
const path33 = finding.evidence[0]?.path;
|
|
16338
16759
|
const run = finding.evidence[0]?.runId;
|
|
16339
16760
|
const runPrefix = run ? `[${run}] ` : "";
|
|
16340
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
16761
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
|
|
16341
16762
|
}
|
|
16342
16763
|
}
|
|
16343
16764
|
function readErrorResult(error) {
|
|
@@ -16540,7 +16961,7 @@ function createViewerServer(options = {}) {
|
|
|
16540
16961
|
return sendJson(res, 200, {
|
|
16541
16962
|
ok: true,
|
|
16542
16963
|
readOnly: true,
|
|
16543
|
-
traceDir:
|
|
16964
|
+
traceDir: path24__default.default.resolve(traceDir)
|
|
16544
16965
|
});
|
|
16545
16966
|
}
|
|
16546
16967
|
const td = new TraceDirectory({ dir: traceDir });
|
|
@@ -16558,7 +16979,7 @@ function createViewerServer(options = {}) {
|
|
|
16558
16979
|
runId: meta2.runId,
|
|
16559
16980
|
name: meta2.name,
|
|
16560
16981
|
status: meta2.status,
|
|
16561
|
-
file:
|
|
16982
|
+
file: path24__default.default.basename(meta2.filePath),
|
|
16562
16983
|
startedAt: meta2.startedAt,
|
|
16563
16984
|
durationMs: meta2.durationMs
|
|
16564
16985
|
}))
|
|
@@ -16673,7 +17094,7 @@ function startViewerServer(options = {}) {
|
|
|
16673
17094
|
resolve({
|
|
16674
17095
|
host,
|
|
16675
17096
|
port: resolvedPort,
|
|
16676
|
-
traceDir:
|
|
17097
|
+
traceDir: path24__default.default.resolve(traceDir),
|
|
16677
17098
|
url: `http://${host}:${resolvedPort}`
|
|
16678
17099
|
});
|
|
16679
17100
|
});
|
|
@@ -16878,10 +17299,10 @@ async function evalRun(input3, options = {}) {
|
|
|
16878
17299
|
diagnostics: []
|
|
16879
17300
|
};
|
|
16880
17301
|
}
|
|
16881
|
-
function evidenceForRun(run,
|
|
16882
|
-
return [{ runId: run.runId, ...
|
|
17302
|
+
function evidenceForRun(run, path33) {
|
|
17303
|
+
return [{ runId: run.runId, ...path33 !== void 0 ? { path: path33 } : {} }];
|
|
16883
17304
|
}
|
|
16884
|
-
function evidenceForEvent(event,
|
|
17305
|
+
function evidenceForEvent(event, path33) {
|
|
16885
17306
|
return [
|
|
16886
17307
|
{
|
|
16887
17308
|
runId: event.runId,
|
|
@@ -16889,7 +17310,7 @@ function evidenceForEvent(event, path31) {
|
|
|
16889
17310
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
16890
17311
|
kind: event.kind,
|
|
16891
17312
|
name: event.name,
|
|
16892
|
-
...
|
|
17313
|
+
...path33 !== void 0 ? { path: path33 } : {}
|
|
16893
17314
|
}
|
|
16894
17315
|
];
|
|
16895
17316
|
}
|
|
@@ -17047,9 +17468,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
17047
17468
|
function tokenize(text) {
|
|
17048
17469
|
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));
|
|
17049
17470
|
}
|
|
17050
|
-
function firstEvidence(fields, run,
|
|
17471
|
+
function firstEvidence(fields, run, path33) {
|
|
17051
17472
|
const first = fields[0];
|
|
17052
|
-
return first === void 0 ? evidenceForRun(run,
|
|
17473
|
+
return first === void 0 ? evidenceForRun(run, path33) : evidenceForEvent(first.node.event, first.path);
|
|
17053
17474
|
}
|
|
17054
17475
|
function collectSourceIds(nodes, keys) {
|
|
17055
17476
|
const wanted = keySet(keys);
|
|
@@ -17426,8 +17847,8 @@ function renderEvalMarkdown(result) {
|
|
|
17426
17847
|
if (result.findings.length > 0) {
|
|
17427
17848
|
lines.push("", "## Findings");
|
|
17428
17849
|
for (const finding of result.findings) {
|
|
17429
|
-
const
|
|
17430
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
17850
|
+
const path33 = finding.evidence[0]?.path;
|
|
17851
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
|
|
17431
17852
|
}
|
|
17432
17853
|
}
|
|
17433
17854
|
return `${lines.join("\n")}
|
|
@@ -17474,7 +17895,7 @@ function asConfig2(value) {
|
|
|
17474
17895
|
}
|
|
17475
17896
|
async function loadConfig2(configPath) {
|
|
17476
17897
|
if (configPath === void 0) return {};
|
|
17477
|
-
const extension =
|
|
17898
|
+
const extension = path24__default.default.extname(configPath);
|
|
17478
17899
|
if (TS_CONFIG_EXTENSIONS3.has(extension)) {
|
|
17479
17900
|
throw new Error(
|
|
17480
17901
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -17483,7 +17904,7 @@ async function loadConfig2(configPath) {
|
|
|
17483
17904
|
if (!CONFIG_EXTENSIONS3.has(extension)) {
|
|
17484
17905
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
17485
17906
|
}
|
|
17486
|
-
const absolute =
|
|
17907
|
+
const absolute = path24__default.default.resolve(configPath);
|
|
17487
17908
|
if (extension === ".json") {
|
|
17488
17909
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
17489
17910
|
return asConfig2(JSON.parse(raw));
|
|
@@ -17620,8 +18041,8 @@ function printHuman2(result) {
|
|
|
17620
18041
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
17621
18042
|
}
|
|
17622
18043
|
for (const finding of result.findings) {
|
|
17623
|
-
const
|
|
17624
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
18044
|
+
const path33 = finding.evidence[0]?.path;
|
|
18045
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
|
|
17625
18046
|
}
|
|
17626
18047
|
}
|
|
17627
18048
|
function readErrorResult2(error) {
|
|
@@ -17859,8 +18280,8 @@ function printHuman3(result) {
|
|
|
17859
18280
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
17860
18281
|
}
|
|
17861
18282
|
for (const finding of result.findings) {
|
|
17862
|
-
const
|
|
17863
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
18283
|
+
const path33 = finding.evidence[0]?.path;
|
|
18284
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
|
|
17864
18285
|
}
|
|
17865
18286
|
console.log(`Note: ${result.note}`);
|
|
17866
18287
|
}
|
|
@@ -18011,8 +18432,8 @@ function renderCheckSection(result) {
|
|
|
18011
18432
|
`Diagnostics: ${result.diagnostics.length}`
|
|
18012
18433
|
];
|
|
18013
18434
|
for (const finding of result.findings.slice(0, 10)) {
|
|
18014
|
-
const
|
|
18015
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
18435
|
+
const path33 = finding.evidence[0]?.path ?? "(run)";
|
|
18436
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path33})`);
|
|
18016
18437
|
}
|
|
18017
18438
|
for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
|
|
18018
18439
|
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
@@ -18090,8 +18511,8 @@ function renderHtml(trace, check, diff) {
|
|
|
18090
18511
|
`;
|
|
18091
18512
|
}
|
|
18092
18513
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
18093
|
-
const outPath =
|
|
18094
|
-
await promises.mkdir(
|
|
18514
|
+
const outPath = path24__default.default.join(outputDir, relativePath);
|
|
18515
|
+
await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
|
|
18095
18516
|
await promises.writeFile(outPath, content, "utf-8");
|
|
18096
18517
|
files.push(relativePath);
|
|
18097
18518
|
}
|
|
@@ -18107,7 +18528,7 @@ function manifestStatus(check, diff) {
|
|
|
18107
18528
|
return "ok";
|
|
18108
18529
|
}
|
|
18109
18530
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
18110
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
18531
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path24__default.default.resolve(options.outputDir.trim()) : "";
|
|
18111
18532
|
if (outputDir === "") {
|
|
18112
18533
|
console.error("--output-dir is required.");
|
|
18113
18534
|
process.exitCode = 1;
|
|
@@ -18173,8 +18594,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18173
18594
|
await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
|
|
18174
18595
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
18175
18596
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
18176
|
-
await promises.mkdir(
|
|
18177
|
-
await promises.appendFile(
|
|
18597
|
+
await promises.mkdir(path24__default.default.dirname(path24__default.default.resolve(summaryTarget)), { recursive: true });
|
|
18598
|
+
await promises.appendFile(path24__default.default.resolve(summaryTarget), `
|
|
18178
18599
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
18179
18600
|
}
|
|
18180
18601
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -18193,10 +18614,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
18193
18614
|
findings: diff?.findings.length ?? 0,
|
|
18194
18615
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
18195
18616
|
},
|
|
18196
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
18617
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path24__default.default.resolve(summaryTarget) } : {},
|
|
18197
18618
|
note: NOTE
|
|
18198
18619
|
};
|
|
18199
|
-
await promises.writeFile(
|
|
18620
|
+
await promises.writeFile(path24__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
18200
18621
|
if (options.json === true) {
|
|
18201
18622
|
console.log(writeJson3(manifest).trimEnd());
|
|
18202
18623
|
} else {
|
|
@@ -18390,19 +18811,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
18390
18811
|
}
|
|
18391
18812
|
var INDEX_DIR_NAME = "index";
|
|
18392
18813
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
18393
|
-
const projectRoot =
|
|
18394
|
-
const workspaceDir =
|
|
18814
|
+
const projectRoot = path24__default.default.resolve(cwd);
|
|
18815
|
+
const workspaceDir = path24__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
18395
18816
|
return {
|
|
18396
18817
|
projectRoot,
|
|
18397
18818
|
workspaceDir,
|
|
18398
|
-
manifestPath:
|
|
18819
|
+
manifestPath: path24__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
18399
18820
|
};
|
|
18400
18821
|
}
|
|
18401
18822
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
18402
|
-
const base =
|
|
18403
|
-
const resolved =
|
|
18404
|
-
const rel =
|
|
18405
|
-
if (rel === "" || rel === "." || !rel.startsWith("..") && !
|
|
18823
|
+
const base = path24__default.default.resolve(workspaceDir);
|
|
18824
|
+
const resolved = path24__default.default.resolve(base, relative);
|
|
18825
|
+
const rel = path24__default.default.relative(base, resolved);
|
|
18826
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path24__default.default.isAbsolute(rel)) {
|
|
18406
18827
|
return resolved;
|
|
18407
18828
|
}
|
|
18408
18829
|
throw new Error(
|
|
@@ -18471,7 +18892,7 @@ async function createWorkspace(options = {}) {
|
|
|
18471
18892
|
created = false;
|
|
18472
18893
|
adopted = true;
|
|
18473
18894
|
} else {
|
|
18474
|
-
const project = options.project?.trim() ||
|
|
18895
|
+
const project = options.project?.trim() || path24__default.default.basename(location.projectRoot) || "workspace";
|
|
18475
18896
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
18476
18897
|
manifest = createDefaultWorkspaceManifest({
|
|
18477
18898
|
project,
|
|
@@ -18610,7 +19031,7 @@ async function doctorWorkspace(location) {
|
|
|
18610
19031
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
18611
19032
|
for (const file of await listJsonl(abs)) {
|
|
18612
19033
|
try {
|
|
18613
|
-
const s = await promises.stat(
|
|
19034
|
+
const s = await promises.stat(path24__default.default.join(abs, file));
|
|
18614
19035
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
18615
19036
|
} catch {
|
|
18616
19037
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -18658,7 +19079,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
18658
19079
|
const relPath = `${rel}/${entry}`;
|
|
18659
19080
|
removed.push(relPath);
|
|
18660
19081
|
if (!dryRun) {
|
|
18661
|
-
await promises.rm(
|
|
19082
|
+
await promises.rm(path24__default.default.join(abs, entry), { recursive: true, force: true });
|
|
18662
19083
|
}
|
|
18663
19084
|
}
|
|
18664
19085
|
}
|
|
@@ -18704,8 +19125,8 @@ async function resolveOutputDir(options, runIds, cwd) {
|
|
|
18704
19125
|
const location = resolveWorkspaceLocation(cwd);
|
|
18705
19126
|
const manifest = await readWorkspaceManifestFile(location);
|
|
18706
19127
|
if (manifest.ok && manifest.manifest) {
|
|
18707
|
-
const rel =
|
|
18708
|
-
if (!rel.startsWith("..") && !
|
|
19128
|
+
const rel = path24__default.default.relative(location.workspaceDir, normalized);
|
|
19129
|
+
if (!rel.startsWith("..") && !path24__default.default.isAbsolute(rel)) {
|
|
18709
19130
|
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
18710
19131
|
}
|
|
18711
19132
|
}
|
|
@@ -18721,7 +19142,7 @@ async function resolveOutputDir(options, runIds, cwd) {
|
|
|
18721
19142
|
const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
|
|
18722
19143
|
return resolveInsideWorkspace(
|
|
18723
19144
|
location.workspaceDir,
|
|
18724
|
-
|
|
19145
|
+
path24__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
18725
19146
|
);
|
|
18726
19147
|
}
|
|
18727
19148
|
} catch {
|
|
@@ -18729,8 +19150,8 @@ async function resolveOutputDir(options, runIds, cwd) {
|
|
|
18729
19150
|
return defaultBundleOutputPath(runIds);
|
|
18730
19151
|
}
|
|
18731
19152
|
async function writeBundleFile(outputDir, relativePath, content, files) {
|
|
18732
|
-
const outPath =
|
|
18733
|
-
await promises.mkdir(
|
|
19153
|
+
const outPath = path24__default.default.join(outputDir, relativePath);
|
|
19154
|
+
await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
|
|
18734
19155
|
await promises.writeFile(outPath, content, "utf-8");
|
|
18735
19156
|
files.push(relativePath);
|
|
18736
19157
|
}
|
|
@@ -18956,7 +19377,7 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
18956
19377
|
files
|
|
18957
19378
|
);
|
|
18958
19379
|
metadata.files = [...files].sort((a, b) => a.localeCompare(b));
|
|
18959
|
-
await promises.writeFile(
|
|
19380
|
+
await promises.writeFile(path24__default.default.join(outputDir, "metadata.json"), writeJson4(metadata), "utf-8");
|
|
18960
19381
|
if (options.json) {
|
|
18961
19382
|
console.log(
|
|
18962
19383
|
writeJson4({
|
|
@@ -18990,7 +19411,7 @@ ${body}
|
|
|
18990
19411
|
`;
|
|
18991
19412
|
}
|
|
18992
19413
|
function validateReporterArtifactPath(options) {
|
|
18993
|
-
const outputDir =
|
|
19414
|
+
const outputDir = path24__default.default.resolve(options.outputDir);
|
|
18994
19415
|
const diagnostics = [];
|
|
18995
19416
|
const rawPath = options.relativePath;
|
|
18996
19417
|
if (rawPath.length === 0) {
|
|
@@ -19010,7 +19431,7 @@ function validateReporterArtifactPath(options) {
|
|
|
19010
19431
|
});
|
|
19011
19432
|
return { ok: false, outputDir, diagnostics };
|
|
19012
19433
|
}
|
|
19013
|
-
if (
|
|
19434
|
+
if (path24__default.default.isAbsolute(rawPath) || path24__default.default.win32.isAbsolute(rawPath)) {
|
|
19014
19435
|
diagnostics.push({
|
|
19015
19436
|
code: "artifact_path_absolute",
|
|
19016
19437
|
severity: "error",
|
|
@@ -19019,7 +19440,7 @@ function validateReporterArtifactPath(options) {
|
|
|
19019
19440
|
});
|
|
19020
19441
|
return { ok: false, outputDir, diagnostics };
|
|
19021
19442
|
}
|
|
19022
|
-
const normalized =
|
|
19443
|
+
const normalized = path24__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
19023
19444
|
const segments = normalized.split("/");
|
|
19024
19445
|
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
19025
19446
|
diagnostics.push({
|
|
@@ -19030,9 +19451,9 @@ function validateReporterArtifactPath(options) {
|
|
|
19030
19451
|
});
|
|
19031
19452
|
return { ok: false, outputDir, diagnostics };
|
|
19032
19453
|
}
|
|
19033
|
-
const absolutePath =
|
|
19034
|
-
const relFromOutput =
|
|
19035
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") ||
|
|
19454
|
+
const absolutePath = path24__default.default.resolve(outputDir, normalized);
|
|
19455
|
+
const relFromOutput = path24__default.default.relative(outputDir, absolutePath);
|
|
19456
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path24__default.default.isAbsolute(relFromOutput)) {
|
|
19036
19457
|
diagnostics.push({
|
|
19037
19458
|
code: "artifact_path_escape",
|
|
19038
19459
|
severity: "error",
|
|
@@ -19178,23 +19599,23 @@ function readManifestDocument(value) {
|
|
|
19178
19599
|
};
|
|
19179
19600
|
}
|
|
19180
19601
|
function cwdRelative(filePath) {
|
|
19181
|
-
const relative =
|
|
19182
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
19183
|
-
return
|
|
19602
|
+
const relative = path24__default.default.relative(process.cwd(), path24__default.default.resolve(filePath)).replace(/\\/g, "/");
|
|
19603
|
+
if (relative === "" || relative.startsWith("../") || path24__default.default.isAbsolute(relative)) {
|
|
19604
|
+
return path24__default.default.basename(filePath);
|
|
19184
19605
|
}
|
|
19185
19606
|
return relative;
|
|
19186
19607
|
}
|
|
19187
19608
|
async function readReporterManifest(filePath) {
|
|
19188
|
-
const absolute =
|
|
19609
|
+
const absolute = path24__default.default.resolve(filePath);
|
|
19189
19610
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
19190
19611
|
const document = readManifestDocument(JSON.parse(raw));
|
|
19191
19612
|
const manifest = document.manifest;
|
|
19192
19613
|
const results = manifest.results.map((result) => ({
|
|
19193
19614
|
testId: safeText(result.testId),
|
|
19194
19615
|
name: safeText(result.name),
|
|
19195
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
19616
|
+
...result.file === void 0 ? {} : { file: safeText(path24__default.default.basename(result.file)) },
|
|
19196
19617
|
status: result.status,
|
|
19197
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
19618
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path24__default.default.basename(result.tracePath)) },
|
|
19198
19619
|
artifacts: result.artifacts,
|
|
19199
19620
|
diagnostics: result.diagnostics
|
|
19200
19621
|
}));
|
|
@@ -19333,15 +19754,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
19333
19754
|
return;
|
|
19334
19755
|
}
|
|
19335
19756
|
const markdown = renderMarkdown2(result);
|
|
19336
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
19757
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path24__default.default.resolve(options.output.trim()) : void 0;
|
|
19337
19758
|
if (outputPath !== void 0) {
|
|
19338
|
-
await promises.mkdir(
|
|
19759
|
+
await promises.mkdir(path24__default.default.dirname(outputPath), { recursive: true });
|
|
19339
19760
|
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
19340
19761
|
}
|
|
19341
19762
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
19342
19763
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
19343
|
-
const summaryPath =
|
|
19344
|
-
await promises.mkdir(
|
|
19764
|
+
const summaryPath = path24__default.default.resolve(summaryTarget);
|
|
19765
|
+
await promises.mkdir(path24__default.default.dirname(summaryPath), { recursive: true });
|
|
19345
19766
|
await promises.appendFile(summaryPath, `
|
|
19346
19767
|
${markdown}`, "utf-8");
|
|
19347
19768
|
}
|
|
@@ -19489,8 +19910,8 @@ jobs:
|
|
|
19489
19910
|
}
|
|
19490
19911
|
async function planInit(options = {}) {
|
|
19491
19912
|
const framework = normalizeFramework(options.framework);
|
|
19492
|
-
const cwd =
|
|
19493
|
-
const demoPath = framework === "custom" ?
|
|
19913
|
+
const cwd = path24__default.default.resolve(options.cwd ?? process.cwd());
|
|
19914
|
+
const demoPath = framework === "custom" ? path24__default.default.join("examples", "agent-inspect-demo.mjs") : path24__default.default.join("examples", `agent-inspect-${framework}-demo.mjs`);
|
|
19494
19915
|
const candidates = [
|
|
19495
19916
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
19496
19917
|
{ rel: GITKEEP, content: "" },
|
|
@@ -19504,7 +19925,7 @@ async function planInit(options = {}) {
|
|
|
19504
19925
|
}
|
|
19505
19926
|
const files = [];
|
|
19506
19927
|
for (const candidate of candidates) {
|
|
19507
|
-
const abs =
|
|
19928
|
+
const abs = path24__default.default.join(cwd, candidate.rel);
|
|
19508
19929
|
try {
|
|
19509
19930
|
await promises.access(abs);
|
|
19510
19931
|
files.push({
|
|
@@ -19525,12 +19946,12 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
19525
19946
|
if (entry.action === "skip") {
|
|
19526
19947
|
continue;
|
|
19527
19948
|
}
|
|
19528
|
-
const abs =
|
|
19949
|
+
const abs = path24__default.default.join(cwd, entry.path);
|
|
19529
19950
|
if (options.dryRun) {
|
|
19530
19951
|
written.push(entry.path);
|
|
19531
19952
|
continue;
|
|
19532
19953
|
}
|
|
19533
|
-
await promises.mkdir(
|
|
19954
|
+
await promises.mkdir(path24__default.default.dirname(abs), { recursive: true });
|
|
19534
19955
|
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
|
|
19535
19956
|
await promises.writeFile(abs, content, "utf-8");
|
|
19536
19957
|
written.push(entry.path);
|
|
@@ -19538,7 +19959,7 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
19538
19959
|
return written;
|
|
19539
19960
|
}
|
|
19540
19961
|
async function initCommand(options = {}) {
|
|
19541
|
-
const cwd =
|
|
19962
|
+
const cwd = path24__default.default.resolve(options.cwd ?? process.cwd());
|
|
19542
19963
|
try {
|
|
19543
19964
|
const plan = await planInit({ ...options, cwd });
|
|
19544
19965
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -19629,7 +20050,7 @@ function envCheck(name, optional = true) {
|
|
|
19629
20050
|
};
|
|
19630
20051
|
}
|
|
19631
20052
|
async function traceDirWritable(traceDir) {
|
|
19632
|
-
const resolved =
|
|
20053
|
+
const resolved = path24__default.default.resolve(traceDir);
|
|
19633
20054
|
try {
|
|
19634
20055
|
await promises.mkdir(resolved, { recursive: true });
|
|
19635
20056
|
await promises.access(resolved, promises.constants.W_OK);
|
|
@@ -19650,7 +20071,7 @@ async function traceDirWritable(traceDir) {
|
|
|
19650
20071
|
}
|
|
19651
20072
|
}
|
|
19652
20073
|
function resolvePackage(cwd, name) {
|
|
19653
|
-
const require2 = module$1.createRequire(
|
|
20074
|
+
const require2 = module$1.createRequire(path24__default.default.join(cwd, "package.json"));
|
|
19654
20075
|
try {
|
|
19655
20076
|
const pkgPath = require2.resolve(`${name}/package.json`);
|
|
19656
20077
|
const pkg = require2(pkgPath);
|
|
@@ -19661,7 +20082,7 @@ function resolvePackage(cwd, name) {
|
|
|
19661
20082
|
}
|
|
19662
20083
|
function importSmoke(cwd) {
|
|
19663
20084
|
const results = [];
|
|
19664
|
-
const require2 = module$1.createRequire(
|
|
20085
|
+
const require2 = module$1.createRequire(path24__default.default.join(cwd, "package.json"));
|
|
19665
20086
|
try {
|
|
19666
20087
|
require2.resolve("agent-inspect");
|
|
19667
20088
|
results.push({
|
|
@@ -19744,7 +20165,7 @@ function versionMismatchCheck(cwd) {
|
|
|
19744
20165
|
};
|
|
19745
20166
|
}
|
|
19746
20167
|
async function runDoctorChecks(options = {}) {
|
|
19747
|
-
const cwd =
|
|
20168
|
+
const cwd = path24__default.default.resolve(options.cwd ?? process3__default.default.cwd());
|
|
19748
20169
|
const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
19749
20170
|
const checks2 = [
|
|
19750
20171
|
nodeVersionCheck(),
|
|
@@ -19858,7 +20279,7 @@ function createTraceDirectoryIndexer() {
|
|
|
19858
20279
|
init_advanced();
|
|
19859
20280
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
19860
20281
|
function traceIndexPath(traceDir) {
|
|
19861
|
-
return
|
|
20282
|
+
return path24__default.default.join(traceDir, INDEX_FILENAME);
|
|
19862
20283
|
}
|
|
19863
20284
|
function parseMaxEntries(raw) {
|
|
19864
20285
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -20004,7 +20425,7 @@ async function newestTraceMtimeMs2(traceDir) {
|
|
|
20004
20425
|
for (const file of files) {
|
|
20005
20426
|
if (!file.endsWith(".jsonl")) continue;
|
|
20006
20427
|
try {
|
|
20007
|
-
const s = await promises.stat(
|
|
20428
|
+
const s = await promises.stat(path24__default.default.join(traceDir, file));
|
|
20008
20429
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
20009
20430
|
} catch {
|
|
20010
20431
|
}
|
|
@@ -20259,11 +20680,11 @@ function printJson5(value) {
|
|
|
20259
20680
|
console.log(JSON.stringify(value, null, 2));
|
|
20260
20681
|
}
|
|
20261
20682
|
function resolveCwd(options) {
|
|
20262
|
-
return
|
|
20683
|
+
return path24__default.default.resolve(options.cwd ?? process.cwd());
|
|
20263
20684
|
}
|
|
20264
20685
|
async function suiteInitCommand(options = {}) {
|
|
20265
20686
|
const cwd = resolveCwd(options);
|
|
20266
|
-
const configPath =
|
|
20687
|
+
const configPath = path24__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
20267
20688
|
const template = defaultSuiteConfigTemplate();
|
|
20268
20689
|
if (options.dryRun) {
|
|
20269
20690
|
if (options.json) {
|
|
@@ -20373,13 +20794,13 @@ async function suiteListCommand(options = {}) {
|
|
|
20373
20794
|
}
|
|
20374
20795
|
async function writeSuiteArtifact(result, configOutputDir, options) {
|
|
20375
20796
|
const cwd = resolveCwd(options);
|
|
20376
|
-
const outputDir =
|
|
20797
|
+
const outputDir = path24__default.default.resolve(
|
|
20377
20798
|
cwd,
|
|
20378
20799
|
options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
|
|
20379
20800
|
);
|
|
20380
20801
|
await promises.mkdir(outputDir, { recursive: true });
|
|
20381
20802
|
const stamp = result.startedAt.replace(/[:.]/g, "-");
|
|
20382
|
-
const filePath =
|
|
20803
|
+
const filePath = path24__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
|
|
20383
20804
|
await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
|
|
20384
20805
|
`, "utf-8");
|
|
20385
20806
|
return filePath;
|
|
@@ -20437,7 +20858,7 @@ async function loadSuiteResultFromInput(options) {
|
|
|
20437
20858
|
if (options.input === void 0 || options.input.trim() === "") {
|
|
20438
20859
|
throw new Error("Pass --input <suite-run.json> from a prior suite run.");
|
|
20439
20860
|
}
|
|
20440
|
-
const inputPath =
|
|
20861
|
+
const inputPath = path24__default.default.resolve(cwd, options.input.trim());
|
|
20441
20862
|
const raw = await promises.readFile(inputPath, "utf-8");
|
|
20442
20863
|
return JSON.parse(raw);
|
|
20443
20864
|
}
|
|
@@ -20474,9 +20895,9 @@ function normalizeMetrics2(raw) {
|
|
|
20474
20895
|
}
|
|
20475
20896
|
async function writeArtifacts(result, outputDir) {
|
|
20476
20897
|
await promises.mkdir(outputDir, { recursive: true });
|
|
20477
|
-
const jsonPath =
|
|
20478
|
-
const markdownPath =
|
|
20479
|
-
const htmlPath =
|
|
20898
|
+
const jsonPath = path24__default.default.join(outputDir, "cohort-results.json");
|
|
20899
|
+
const markdownPath = path24__default.default.join(outputDir, "cohort-summary.md");
|
|
20900
|
+
const htmlPath = path24__default.default.join(outputDir, "cohort-report.html");
|
|
20480
20901
|
await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
20481
20902
|
`, "utf-8");
|
|
20482
20903
|
await promises.writeFile(
|
|
@@ -20504,7 +20925,7 @@ async function cohortCommand(options = {}) {
|
|
|
20504
20925
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
20505
20926
|
let artifacts;
|
|
20506
20927
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
20507
|
-
artifacts = await writeArtifacts(result,
|
|
20928
|
+
artifacts = await writeArtifacts(result, path24__default.default.resolve(options.output.trim()));
|
|
20508
20929
|
}
|
|
20509
20930
|
if (options.json || format === "json") {
|
|
20510
20931
|
console.log(
|
|
@@ -20544,6 +20965,135 @@ async function cohortCommand(options = {}) {
|
|
|
20544
20965
|
}
|
|
20545
20966
|
}
|
|
20546
20967
|
|
|
20968
|
+
// packages/cli/src/gate.ts
|
|
20969
|
+
init_advanced();
|
|
20970
|
+
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set(["markdown", "json", "html", "junit", "github"]);
|
|
20971
|
+
function collectList(value) {
|
|
20972
|
+
if (value === void 0) return [];
|
|
20973
|
+
const items = Array.isArray(value) ? value : [value];
|
|
20974
|
+
return items.flatMap((item) => parseGateList(item));
|
|
20975
|
+
}
|
|
20976
|
+
function parseRate(value) {
|
|
20977
|
+
if (value === void 0 || value.trim() === "") return void 0;
|
|
20978
|
+
const parsed = Number(value);
|
|
20979
|
+
if (!Number.isFinite(parsed)) {
|
|
20980
|
+
throw new Error(`Invalid --max-error-rate: ${value}`);
|
|
20981
|
+
}
|
|
20982
|
+
return parsed;
|
|
20983
|
+
}
|
|
20984
|
+
function parseDuration2(value) {
|
|
20985
|
+
if (value === void 0 || value.trim() === "") return void 0;
|
|
20986
|
+
const parsed = Number(value);
|
|
20987
|
+
if (!Number.isFinite(parsed)) {
|
|
20988
|
+
throw new Error(`Invalid --max-p95-duration: ${value}`);
|
|
20989
|
+
}
|
|
20990
|
+
return parsed;
|
|
20991
|
+
}
|
|
20992
|
+
async function writeArtifacts2(result, outputDir) {
|
|
20993
|
+
await promises.mkdir(outputDir, { recursive: true });
|
|
20994
|
+
const paths = {
|
|
20995
|
+
jsonPath: path24__default.default.join(outputDir, "gate-results.json"),
|
|
20996
|
+
markdownPath: path24__default.default.join(outputDir, "gate-summary.md"),
|
|
20997
|
+
htmlPath: path24__default.default.join(outputDir, "gate-report.html"),
|
|
20998
|
+
junitPath: path24__default.default.join(outputDir, "junit.xml"),
|
|
20999
|
+
githubPath: path24__default.default.join(outputDir, "github-step-summary.md")
|
|
21000
|
+
};
|
|
21001
|
+
await promises.writeFile(
|
|
21002
|
+
paths.jsonPath,
|
|
21003
|
+
`${renderGateReport(result, { format: "json" })}
|
|
21004
|
+
`,
|
|
21005
|
+
"utf-8"
|
|
21006
|
+
);
|
|
21007
|
+
await promises.writeFile(
|
|
21008
|
+
paths.markdownPath,
|
|
21009
|
+
`${renderGateReport(result, { format: "markdown" })}
|
|
21010
|
+
`,
|
|
21011
|
+
"utf-8"
|
|
21012
|
+
);
|
|
21013
|
+
await promises.writeFile(
|
|
21014
|
+
paths.htmlPath,
|
|
21015
|
+
`${renderGateReport(result, { format: "html" })}
|
|
21016
|
+
`,
|
|
21017
|
+
"utf-8"
|
|
21018
|
+
);
|
|
21019
|
+
await promises.writeFile(
|
|
21020
|
+
paths.junitPath,
|
|
21021
|
+
`${renderGateReport(result, { format: "junit" })}
|
|
21022
|
+
`,
|
|
21023
|
+
"utf-8"
|
|
21024
|
+
);
|
|
21025
|
+
await promises.writeFile(
|
|
21026
|
+
paths.githubPath,
|
|
21027
|
+
`${renderGateReport(result, { format: "github" })}
|
|
21028
|
+
`,
|
|
21029
|
+
"utf-8"
|
|
21030
|
+
);
|
|
21031
|
+
return paths;
|
|
21032
|
+
}
|
|
21033
|
+
async function gateCommand(options = {}) {
|
|
21034
|
+
try {
|
|
21035
|
+
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
21036
|
+
if (!SUPPORTED_FORMATS.has(format)) {
|
|
21037
|
+
if (options.json) {
|
|
21038
|
+
console.log(
|
|
21039
|
+
JSON.stringify({ ok: false, exitCode: 4, error: `Unsupported format: ${format}` }, null, 2)
|
|
21040
|
+
);
|
|
21041
|
+
} else {
|
|
21042
|
+
console.error(`[AgentInspect] Unsupported format: ${format}`);
|
|
21043
|
+
}
|
|
21044
|
+
process.exitCode = 4;
|
|
21045
|
+
return;
|
|
21046
|
+
}
|
|
21047
|
+
const gateOptions = {
|
|
21048
|
+
...options.dir !== void 0 ? { traceDir: resolveTraceDir({ dir: options.dir }) } : {},
|
|
21049
|
+
...options.suite !== void 0 ? { suitePath: options.suite } : {},
|
|
21050
|
+
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
21051
|
+
...parseRate(options.maxErrorRate) !== void 0 ? { maxErrorRate: parseRate(options.maxErrorRate) } : {},
|
|
21052
|
+
...parseDuration2(options.maxP95Duration) !== void 0 ? { maxP95DurationMs: parseDuration2(options.maxP95Duration) } : {},
|
|
21053
|
+
forbidTools: collectList(options.forbidTool),
|
|
21054
|
+
requireObservations: collectList(options.requireObservation)
|
|
21055
|
+
};
|
|
21056
|
+
let runs = [];
|
|
21057
|
+
const needsRuns = gateHasThresholds(gateOptions) || gateOptions.traceDir !== void 0 && gateOptions.suitePath === void 0;
|
|
21058
|
+
if (needsRuns) {
|
|
21059
|
+
const traceDir = gateOptions.traceDir ?? resolveTraceDir({ dir: options.dir });
|
|
21060
|
+
const loaded = await loadSessionRuns(traceDir);
|
|
21061
|
+
runs = loaded.runs;
|
|
21062
|
+
gateOptions.traceDir = traceDir;
|
|
21063
|
+
}
|
|
21064
|
+
const result = await runGate(runs, gateOptions);
|
|
21065
|
+
let artifacts;
|
|
21066
|
+
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
21067
|
+
artifacts = await writeArtifacts2(result, path24__default.default.resolve(options.output.trim()));
|
|
21068
|
+
}
|
|
21069
|
+
if (options.json || format === "json") {
|
|
21070
|
+
console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
|
|
21071
|
+
} else if (format === "html") {
|
|
21072
|
+
console.log(renderGateReport(result, { format: "html" }));
|
|
21073
|
+
} else if (format === "junit") {
|
|
21074
|
+
console.log(renderGateReport(result, { format: "junit" }));
|
|
21075
|
+
} else if (format === "github") {
|
|
21076
|
+
console.log(renderGateReport(result, { format: "github" }));
|
|
21077
|
+
} else {
|
|
21078
|
+
console.log(renderGateReport(result, { format: "markdown" }));
|
|
21079
|
+
if (artifacts !== void 0) {
|
|
21080
|
+
console.log("");
|
|
21081
|
+
console.log("Artifacts:");
|
|
21082
|
+
for (const value of Object.values(artifacts)) console.log(`- ${value}`);
|
|
21083
|
+
}
|
|
21084
|
+
}
|
|
21085
|
+
process.exitCode = result.exitCode;
|
|
21086
|
+
} catch (error) {
|
|
21087
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21088
|
+
if (options.json) {
|
|
21089
|
+
console.log(JSON.stringify({ ok: false, exitCode: 2, error: message }, null, 2));
|
|
21090
|
+
} else {
|
|
21091
|
+
console.error(`[AgentInspect] gate failed: ${message}`);
|
|
21092
|
+
}
|
|
21093
|
+
process.exitCode = 2;
|
|
21094
|
+
}
|
|
21095
|
+
}
|
|
21096
|
+
|
|
20547
21097
|
// packages/cli/src/index.ts
|
|
20548
21098
|
function runCommand(action) {
|
|
20549
21099
|
void action().catch((error) => {
|
|
@@ -20983,6 +21533,15 @@ function createCliProgram() {
|
|
|
20983
21533
|
).option("--format <format>", "markdown, json, or html", "markdown").option("-o, --output <dir>", "write cohort-results.json, cohort-summary.md, cohort-report.html").option("--json", "print deterministic JSON result").action((opts) => {
|
|
20984
21534
|
runCommand(() => cohortCommand(opts));
|
|
20985
21535
|
});
|
|
21536
|
+
program.command("gate").description("Run deterministic CI quality gates over traces or suites (v5.2+)").option("--dir <path>", "trace directory for threshold checks").option("--suite <path>", "suite config path").option("--max-error-rate <percent>", "maximum allowed error rate percentage").option("--max-p95-duration <ms>", "maximum allowed p95 run duration in ms").option("--forbid-tool <name>", "forbidden tool name (repeatable or comma-separated)").option(
|
|
21537
|
+
"--require-observation <name>",
|
|
21538
|
+
"required passed observation (repeatable or comma-separated)"
|
|
21539
|
+
).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
|
|
21540
|
+
"-o, --output <dir>",
|
|
21541
|
+
"write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
|
|
21542
|
+
).option("--json", "print deterministic JSON result").action((opts) => {
|
|
21543
|
+
runCommand(() => gateCommand(opts));
|
|
21544
|
+
});
|
|
20986
21545
|
return program;
|
|
20987
21546
|
}
|
|
20988
21547
|
function isPrimaryModule() {
|
|
@@ -20990,9 +21549,9 @@ function isPrimaryModule() {
|
|
|
20990
21549
|
if (!entry) return false;
|
|
20991
21550
|
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)));
|
|
20992
21551
|
try {
|
|
20993
|
-
return fs.realpathSync(
|
|
21552
|
+
return fs.realpathSync(path24__default.default.resolve(entry)) === fs.realpathSync(path24__default.default.resolve(selfPath));
|
|
20994
21553
|
} catch {
|
|
20995
|
-
return
|
|
21554
|
+
return path24__default.default.resolve(entry) === path24__default.default.resolve(selfPath);
|
|
20996
21555
|
}
|
|
20997
21556
|
}
|
|
20998
21557
|
if (isPrimaryModule()) {
|