agent-inspect 6.16.2 → 6.17.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/README.md +1 -1
- package/docs/CI-ARTIFACTS.md +31 -0
- package/docs/CLI.md +24 -2
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +910 -320
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +832 -248
- package/packages/cli/dist/index.mjs.map +1 -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 path32 = require('path');
|
|
8
8
|
var async_hooks = require('async_hooks');
|
|
9
9
|
var process3 = require('process');
|
|
10
10
|
var tty = require('tty');
|
|
@@ -14,13 +14,14 @@ var url = require('url');
|
|
|
14
14
|
var module$1 = require('module');
|
|
15
15
|
var commander = require('commander');
|
|
16
16
|
var http = require('http');
|
|
17
|
+
var child_process = require('child_process');
|
|
17
18
|
|
|
18
19
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
19
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
21
|
|
|
21
22
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
22
23
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
23
|
-
var
|
|
24
|
+
var path32__default = /*#__PURE__*/_interopDefault(path32);
|
|
24
25
|
var process3__default = /*#__PURE__*/_interopDefault(process3);
|
|
25
26
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
26
27
|
|
|
@@ -864,7 +865,7 @@ function getDefaultTraceDir() {
|
|
|
864
865
|
if (typeof home !== "string" || home.trim() === "") {
|
|
865
866
|
return FALLBACK_TRACE_DIR;
|
|
866
867
|
}
|
|
867
|
-
return
|
|
868
|
+
return path32__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
868
869
|
} catch {
|
|
869
870
|
return FALLBACK_TRACE_DIR;
|
|
870
871
|
}
|
|
@@ -872,11 +873,11 @@ function getDefaultTraceDir() {
|
|
|
872
873
|
function getTraceFilePath(runId, traceDir) {
|
|
873
874
|
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
874
875
|
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
875
|
-
safeId =
|
|
876
|
+
safeId = path32__default.default.basename(safeId);
|
|
876
877
|
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
877
878
|
safeId = "run_unknown";
|
|
878
879
|
}
|
|
879
|
-
return
|
|
880
|
+
return path32__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
880
881
|
}
|
|
881
882
|
function formatError(error) {
|
|
882
883
|
if (error instanceof Error) {
|
|
@@ -933,7 +934,7 @@ var init_utils = __esm({
|
|
|
933
934
|
init_duration();
|
|
934
935
|
DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
935
936
|
RUNS_DIR_NAME = "runs";
|
|
936
|
-
FALLBACK_TRACE_DIR =
|
|
937
|
+
FALLBACK_TRACE_DIR = path32__default.default.join(
|
|
937
938
|
os__default.default.tmpdir(),
|
|
938
939
|
"agent-inspect",
|
|
939
940
|
RUNS_DIR_NAME
|
|
@@ -1899,7 +1900,7 @@ var init_trace_directory = __esm({
|
|
|
1899
1900
|
this.#dir = resolveTraceDir(options);
|
|
1900
1901
|
}
|
|
1901
1902
|
getPath(filename) {
|
|
1902
|
-
return filename ?
|
|
1903
|
+
return filename ? path32__default.default.join(this.#dir, filename) : this.#dir;
|
|
1903
1904
|
}
|
|
1904
1905
|
async list() {
|
|
1905
1906
|
try {
|
|
@@ -1928,7 +1929,7 @@ function parseIsoToMs2(value) {
|
|
|
1928
1929
|
}
|
|
1929
1930
|
async function extractMetadata(filePath, _quickScan) {
|
|
1930
1931
|
const stats = await promises.stat(filePath);
|
|
1931
|
-
let runIdFromFile =
|
|
1932
|
+
let runIdFromFile = path32__default.default.basename(filePath);
|
|
1932
1933
|
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1933
1934
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1934
1935
|
}
|
|
@@ -3781,12 +3782,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3781
3782
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3782
3783
|
);
|
|
3783
3784
|
const ordered = [...runs].sort(compareRuns);
|
|
3784
|
-
const
|
|
3785
|
+
const path43 = [];
|
|
3785
3786
|
const visited = /* @__PURE__ */ new Set();
|
|
3786
3787
|
const pushRun = (run, confidence, source) => {
|
|
3787
3788
|
if (visited.has(run.runId)) return;
|
|
3788
3789
|
visited.add(run.runId);
|
|
3789
|
-
|
|
3790
|
+
path43.push({
|
|
3790
3791
|
runId: run.runId,
|
|
3791
3792
|
name: run.name,
|
|
3792
3793
|
startedAt: run.startedAt,
|
|
@@ -3811,7 +3812,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3811
3812
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3812
3813
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3813
3814
|
}
|
|
3814
|
-
return
|
|
3815
|
+
return path43;
|
|
3815
3816
|
}
|
|
3816
3817
|
function metaRunIdMatches(run, token, runById) {
|
|
3817
3818
|
const meta2 = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -4140,7 +4141,7 @@ var init_summary = __esm({
|
|
|
4140
4141
|
});
|
|
4141
4142
|
function sanitizeBundleRunId(runId) {
|
|
4142
4143
|
let safe = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
4143
|
-
safe =
|
|
4144
|
+
safe = path32__default.default.basename(safe);
|
|
4144
4145
|
safe = safe.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
4145
4146
|
if (safe === "" || safe === "." || safe === "..") {
|
|
4146
4147
|
safe = "run_unknown";
|
|
@@ -4150,12 +4151,12 @@ function sanitizeBundleRunId(runId) {
|
|
|
4150
4151
|
function bundleRunAssetRelativePath(runId, extension) {
|
|
4151
4152
|
const safe = sanitizeBundleRunId(runId);
|
|
4152
4153
|
const ext = extension.startsWith(".") ? extension : `.${extension}`;
|
|
4153
|
-
return
|
|
4154
|
+
return path32__default.default.posix.join("assets", "runs", `${safe}${ext}`);
|
|
4154
4155
|
}
|
|
4155
4156
|
function assertBundlePathContained(outputDir, relativePath) {
|
|
4156
|
-
const base =
|
|
4157
|
-
const resolved =
|
|
4158
|
-
if (resolved !== base && !resolved.startsWith(base +
|
|
4157
|
+
const base = path32__default.default.resolve(outputDir);
|
|
4158
|
+
const resolved = path32__default.default.resolve(base, relativePath);
|
|
4159
|
+
if (resolved !== base && !resolved.startsWith(base + path32__default.default.sep)) {
|
|
4159
4160
|
throw new Error(`Bundle path escapes output directory: ${relativePath}`);
|
|
4160
4161
|
}
|
|
4161
4162
|
return resolved;
|
|
@@ -4165,7 +4166,7 @@ function normalizeBundleOutputPath(out, options) {
|
|
|
4165
4166
|
if (trimmed === "") {
|
|
4166
4167
|
throw new Error("--out requires a non-empty path.");
|
|
4167
4168
|
}
|
|
4168
|
-
const resolved =
|
|
4169
|
+
const resolved = path32__default.default.resolve(trimmed);
|
|
4169
4170
|
if (options?.preserveZipExtension !== true && resolved.toLowerCase().endsWith(".zip")) {
|
|
4170
4171
|
return resolved.slice(0, -4);
|
|
4171
4172
|
}
|
|
@@ -4174,7 +4175,7 @@ function normalizeBundleOutputPath(out, options) {
|
|
|
4174
4175
|
function defaultBundleOutputPath(runIds) {
|
|
4175
4176
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
4176
4177
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4177
|
-
return
|
|
4178
|
+
return path32__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
4178
4179
|
}
|
|
4179
4180
|
var init_paths = __esm({
|
|
4180
4181
|
"packages/core/src/bundle/paths.ts"() {
|
|
@@ -4237,7 +4238,7 @@ function assertEvidenceRelativePath(relativePath) {
|
|
|
4237
4238
|
throw new Error("Evidence file path must be a non-empty relative path.");
|
|
4238
4239
|
}
|
|
4239
4240
|
const trimmed = relativePath.trim().replaceAll("\\", "/");
|
|
4240
|
-
if (
|
|
4241
|
+
if (path32__default.default.isAbsolute(trimmed) || trimmed.startsWith("/")) {
|
|
4241
4242
|
throw new Error(`Evidence file path must be relative: ${relativePath}`);
|
|
4242
4243
|
}
|
|
4243
4244
|
const parts = trimmed.split("/").filter((part) => part !== "");
|
|
@@ -5104,13 +5105,13 @@ function pairSteps(left, right) {
|
|
|
5104
5105
|
return pairs;
|
|
5105
5106
|
}
|
|
5106
5107
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
5107
|
-
const
|
|
5108
|
+
const path43 = buildPath(segments);
|
|
5108
5109
|
if (L.name !== R.name) {
|
|
5109
5110
|
out.push({
|
|
5110
5111
|
kind: "structure",
|
|
5111
5112
|
severity: "warning",
|
|
5112
5113
|
message: "Step name differs",
|
|
5113
|
-
path:
|
|
5114
|
+
path: path43,
|
|
5114
5115
|
left: L.name,
|
|
5115
5116
|
right: R.name
|
|
5116
5117
|
});
|
|
@@ -5120,7 +5121,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5120
5121
|
kind: "step-type",
|
|
5121
5122
|
severity: "warning",
|
|
5122
5123
|
message: "Step type differs",
|
|
5123
|
-
path:
|
|
5124
|
+
path: path43,
|
|
5124
5125
|
left: L.type,
|
|
5125
5126
|
right: R.type
|
|
5126
5127
|
});
|
|
@@ -5130,7 +5131,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5130
5131
|
kind: "step-status",
|
|
5131
5132
|
severity: "warning",
|
|
5132
5133
|
message: "Step status differs",
|
|
5133
|
-
path:
|
|
5134
|
+
path: path43,
|
|
5134
5135
|
left: L.status,
|
|
5135
5136
|
right: R.status
|
|
5136
5137
|
});
|
|
@@ -5142,7 +5143,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5142
5143
|
kind: "error",
|
|
5143
5144
|
severity: "error",
|
|
5144
5145
|
message: "Step error message differs",
|
|
5145
|
-
path:
|
|
5146
|
+
path: path43,
|
|
5146
5147
|
left: le || void 0,
|
|
5147
5148
|
right: re || void 0
|
|
5148
5149
|
});
|
|
@@ -5160,7 +5161,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5160
5161
|
kind: "duration",
|
|
5161
5162
|
severity: "info",
|
|
5162
5163
|
message: "Step duration differs",
|
|
5163
|
-
path:
|
|
5164
|
+
path: path43,
|
|
5164
5165
|
left: ld,
|
|
5165
5166
|
right: rd
|
|
5166
5167
|
});
|
|
@@ -5173,7 +5174,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5173
5174
|
kind: "metadata",
|
|
5174
5175
|
severity: "info",
|
|
5175
5176
|
message: "Step metadata differs",
|
|
5176
|
-
path:
|
|
5177
|
+
path: path43,
|
|
5177
5178
|
left: L.metadata,
|
|
5178
5179
|
right: R.metadata
|
|
5179
5180
|
});
|
|
@@ -5185,7 +5186,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5185
5186
|
kind: "output",
|
|
5186
5187
|
severity: "info",
|
|
5187
5188
|
message: "Output preview differs",
|
|
5188
|
-
path:
|
|
5189
|
+
path: path43,
|
|
5189
5190
|
left: L.outputPreview,
|
|
5190
5191
|
right: R.outputPreview
|
|
5191
5192
|
});
|
|
@@ -5352,11 +5353,11 @@ var init_engine = __esm({
|
|
|
5352
5353
|
});
|
|
5353
5354
|
|
|
5354
5355
|
// packages/core/src/diff/renderer.ts
|
|
5355
|
-
function formatPath(
|
|
5356
|
-
if (
|
|
5356
|
+
function formatPath(path43) {
|
|
5357
|
+
if (path43 === void 0 || path43.path.length === 0) {
|
|
5357
5358
|
return "(run)";
|
|
5358
5359
|
}
|
|
5359
|
-
return
|
|
5360
|
+
return path43.path.map((s) => s.name).join(" > ");
|
|
5360
5361
|
}
|
|
5361
5362
|
function formatValue(v, verbose) {
|
|
5362
5363
|
if (v === void 0) return "(undefined)";
|
|
@@ -5736,11 +5737,11 @@ async function listFilesRecursive(root) {
|
|
|
5736
5737
|
async function walk(dir) {
|
|
5737
5738
|
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
5738
5739
|
for (const entry of entries) {
|
|
5739
|
-
const abs =
|
|
5740
|
+
const abs = path32__default.default.join(dir, entry.name);
|
|
5740
5741
|
if (entry.isDirectory()) {
|
|
5741
5742
|
await walk(abs);
|
|
5742
5743
|
} else if (entry.isFile()) {
|
|
5743
|
-
const rel =
|
|
5744
|
+
const rel = path32__default.default.relative(root, abs).split(path32__default.default.sep).join("/");
|
|
5744
5745
|
out.push(rel);
|
|
5745
5746
|
}
|
|
5746
5747
|
}
|
|
@@ -5750,7 +5751,7 @@ async function listFilesRecursive(root) {
|
|
|
5750
5751
|
}
|
|
5751
5752
|
async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
5752
5753
|
const unexpectedMode = options.unexpectedFiles ?? "fail";
|
|
5753
|
-
const root =
|
|
5754
|
+
const root = path32__default.default.resolve(rootPath);
|
|
5754
5755
|
const issues = [];
|
|
5755
5756
|
let rootStat;
|
|
5756
5757
|
try {
|
|
@@ -5780,7 +5781,7 @@ async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
|
5780
5781
|
checkedFiles: 0
|
|
5781
5782
|
};
|
|
5782
5783
|
}
|
|
5783
|
-
const manifestPath =
|
|
5784
|
+
const manifestPath = path32__default.default.join(root, EVIDENCE_MANIFEST_FILENAME);
|
|
5784
5785
|
let manifestText;
|
|
5785
5786
|
try {
|
|
5786
5787
|
manifestText = await promises.readFile(manifestPath, "utf-8");
|
|
@@ -5866,7 +5867,7 @@ async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
|
5866
5867
|
continue;
|
|
5867
5868
|
}
|
|
5868
5869
|
listed.add(rel);
|
|
5869
|
-
const abs =
|
|
5870
|
+
const abs = path32__default.default.join(root, ...rel.split("/"));
|
|
5870
5871
|
let bytes;
|
|
5871
5872
|
try {
|
|
5872
5873
|
bytes = await promises.readFile(abs);
|
|
@@ -6181,7 +6182,7 @@ function normalizeSuiteConfig(value) {
|
|
|
6181
6182
|
}
|
|
6182
6183
|
async function validateSuiteConfig(config, options) {
|
|
6183
6184
|
const diagnostics = [];
|
|
6184
|
-
const tracesDir =
|
|
6185
|
+
const tracesDir = path32__default.default.resolve(options.configDir, config.traces);
|
|
6185
6186
|
try {
|
|
6186
6187
|
await promises.access(tracesDir);
|
|
6187
6188
|
} catch {
|
|
@@ -6191,7 +6192,7 @@ async function validateSuiteConfig(config, options) {
|
|
|
6191
6192
|
}
|
|
6192
6193
|
for (const suiteCase of config.cases) {
|
|
6193
6194
|
if (suiteCase.input !== void 0) {
|
|
6194
|
-
const inputPath =
|
|
6195
|
+
const inputPath = path32__default.default.resolve(options.configDir, suiteCase.input);
|
|
6195
6196
|
try {
|
|
6196
6197
|
await promises.access(inputPath);
|
|
6197
6198
|
} catch {
|
|
@@ -6224,12 +6225,12 @@ async function fileExists(filePath) {
|
|
|
6224
6225
|
}
|
|
6225
6226
|
}
|
|
6226
6227
|
async function resolveSuiteConfigPath(options = {}) {
|
|
6227
|
-
const cwd =
|
|
6228
|
+
const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
|
|
6228
6229
|
if (options.configPath !== void 0 && options.configPath.trim() !== "") {
|
|
6229
|
-
return
|
|
6230
|
+
return path32__default.default.resolve(cwd, options.configPath.trim());
|
|
6230
6231
|
}
|
|
6231
6232
|
for (const name of DEFAULT_SUITE_CONFIG_NAMES) {
|
|
6232
|
-
const candidate =
|
|
6233
|
+
const candidate = path32__default.default.join(cwd, name);
|
|
6233
6234
|
if (await fileExists(candidate)) return candidate;
|
|
6234
6235
|
}
|
|
6235
6236
|
throw new Error(
|
|
@@ -6246,7 +6247,7 @@ async function loadSuiteConfig(options = {}) {
|
|
|
6246
6247
|
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
6247
6248
|
});
|
|
6248
6249
|
}
|
|
6249
|
-
const extension =
|
|
6250
|
+
const extension = path32__default.default.extname(configPath);
|
|
6250
6251
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
6251
6252
|
const message = "TypeScript suite configs require an explicit precompiled JavaScript config or future --config-loader support.";
|
|
6252
6253
|
throw Object.assign(new Error(message), {
|
|
@@ -6271,7 +6272,7 @@ async function loadSuiteConfig(options = {}) {
|
|
|
6271
6272
|
return {
|
|
6272
6273
|
config,
|
|
6273
6274
|
configPath,
|
|
6274
|
-
configDir:
|
|
6275
|
+
configDir: path32__default.default.dirname(configPath)
|
|
6275
6276
|
};
|
|
6276
6277
|
} catch (error) {
|
|
6277
6278
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -6321,7 +6322,7 @@ async function exists(filePath) {
|
|
|
6321
6322
|
}
|
|
6322
6323
|
async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
6323
6324
|
if (suiteCase.trace !== void 0) {
|
|
6324
|
-
const tracePath =
|
|
6325
|
+
const tracePath = path32__default.default.resolve(options.configDir, suiteCase.trace);
|
|
6325
6326
|
if (await exists(tracePath)) {
|
|
6326
6327
|
return { caseId: suiteCase.id, tracePath, missing: false };
|
|
6327
6328
|
}
|
|
@@ -6337,7 +6338,7 @@ async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
|
6337
6338
|
if (await exists(directPath)) {
|
|
6338
6339
|
return { caseId: suiteCase.id, tracePath: directPath, runId: runKey, missing: false };
|
|
6339
6340
|
}
|
|
6340
|
-
const nestedPath =
|
|
6341
|
+
const nestedPath = path32__default.default.join(options.tracesDir, `${path32__default.default.basename(runKey)}.jsonl`);
|
|
6341
6342
|
if (await exists(nestedPath)) {
|
|
6342
6343
|
return { caseId: suiteCase.id, tracePath: nestedPath, runId: runKey, missing: false };
|
|
6343
6344
|
}
|
|
@@ -7055,7 +7056,7 @@ function stripPrefix(name, prefixes) {
|
|
|
7055
7056
|
}
|
|
7056
7057
|
return name;
|
|
7057
7058
|
}
|
|
7058
|
-
function eventEvidence(event,
|
|
7059
|
+
function eventEvidence(event, path43) {
|
|
7059
7060
|
return {
|
|
7060
7061
|
runId: event.runId,
|
|
7061
7062
|
eventId: event.eventId,
|
|
@@ -7065,7 +7066,7 @@ function eventEvidence(event, path41) {
|
|
|
7065
7066
|
kind: event.kind,
|
|
7066
7067
|
name: event.name,
|
|
7067
7068
|
status: event.status,
|
|
7068
|
-
...
|
|
7069
|
+
...path43 ? { path: path43 } : {}
|
|
7069
7070
|
};
|
|
7070
7071
|
}
|
|
7071
7072
|
function runEvidence(run) {
|
|
@@ -7135,9 +7136,9 @@ function eventEndMs(event) {
|
|
|
7135
7136
|
function normalizedKey(value) {
|
|
7136
7137
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
7137
7138
|
}
|
|
7138
|
-
function lastPathSegment(
|
|
7139
|
-
const parts =
|
|
7140
|
-
return parts[parts.length - 1] ??
|
|
7139
|
+
function lastPathSegment(path43) {
|
|
7140
|
+
const parts = path43.split(".");
|
|
7141
|
+
return parts[parts.length - 1] ?? path43;
|
|
7141
7142
|
}
|
|
7142
7143
|
function valueType(value) {
|
|
7143
7144
|
if (Array.isArray(value)) return "array";
|
|
@@ -7151,12 +7152,12 @@ function serializedByteLength(value) {
|
|
|
7151
7152
|
return void 0;
|
|
7152
7153
|
}
|
|
7153
7154
|
}
|
|
7154
|
-
function pushValueEntries(entries, event, value,
|
|
7155
|
-
entries.push({ event, path:
|
|
7155
|
+
function pushValueEntries(entries, event, value, path43, key, depth = 0) {
|
|
7156
|
+
entries.push({ event, path: path43, key, value });
|
|
7156
7157
|
if (depth >= 8) return;
|
|
7157
7158
|
if (Array.isArray(value)) {
|
|
7158
7159
|
for (const [index, item] of value.entries()) {
|
|
7159
|
-
pushValueEntries(entries, event, item, `${
|
|
7160
|
+
pushValueEntries(entries, event, item, `${path43}.${index}`, String(index), depth + 1);
|
|
7160
7161
|
}
|
|
7161
7162
|
return;
|
|
7162
7163
|
}
|
|
@@ -7166,7 +7167,7 @@ function pushValueEntries(entries, event, value, path41, key, depth = 0) {
|
|
|
7166
7167
|
entries,
|
|
7167
7168
|
event,
|
|
7168
7169
|
value[nestedKey],
|
|
7169
|
-
`${
|
|
7170
|
+
`${path43}.${nestedKey}`,
|
|
7170
7171
|
nestedKey,
|
|
7171
7172
|
depth + 1
|
|
7172
7173
|
);
|
|
@@ -7205,18 +7206,18 @@ function isRawContentKey(key, forbiddenKeys) {
|
|
|
7205
7206
|
const normalized = normalizedKey(key);
|
|
7206
7207
|
return forbiddenKeys.some((forbidden) => normalized === normalizedKey(forbidden));
|
|
7207
7208
|
}
|
|
7208
|
-
function isSafeRawContentMetricPath(
|
|
7209
|
-
const leaf = normalizedKey(key ?? lastPathSegment(
|
|
7209
|
+
function isSafeRawContentMetricPath(path43, key, safePathPrefixes) {
|
|
7210
|
+
const leaf = normalizedKey(key ?? lastPathSegment(path43));
|
|
7210
7211
|
if (!SAFE_USAGE_LEAF_KEYS.has(leaf)) return false;
|
|
7211
|
-
const parts =
|
|
7212
|
+
const parts = path43.split(".").filter(Boolean);
|
|
7212
7213
|
if (parts.length < 2) return false;
|
|
7213
7214
|
const parent = parts[parts.length - 2] ?? "";
|
|
7214
7215
|
const parentNorm = normalizedKey(parent);
|
|
7215
7216
|
return safePathPrefixes.some((prefix) => parentNorm === normalizedKey(prefix));
|
|
7216
7217
|
}
|
|
7217
|
-
function isRawContentPath(
|
|
7218
|
-
if (isSafeRawContentMetricPath(
|
|
7219
|
-
return isRawContentKey(key ?? lastPathSegment(
|
|
7218
|
+
function isRawContentPath(path43, key, forbiddenKeys, safePathPrefixes) {
|
|
7219
|
+
if (isSafeRawContentMetricPath(path43, key, safePathPrefixes)) return false;
|
|
7220
|
+
return isRawContentKey(key ?? lastPathSegment(path43), forbiddenKeys);
|
|
7220
7221
|
}
|
|
7221
7222
|
function parentMarkedUnresolved(event) {
|
|
7222
7223
|
if (booleanAttr(event, [
|
|
@@ -7255,9 +7256,9 @@ function eventDurationMs(event) {
|
|
|
7255
7256
|
}
|
|
7256
7257
|
function treeShape(nodes) {
|
|
7257
7258
|
const lines = [];
|
|
7258
|
-
const visit = (node,
|
|
7259
|
-
lines.push(`${
|
|
7260
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
7259
|
+
const visit = (node, path43) => {
|
|
7260
|
+
lines.push(`${path43}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
7261
|
+
node.children.forEach((child, index) => visit(child, `${path43}.${index}`));
|
|
7261
7262
|
};
|
|
7262
7263
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
7263
7264
|
return lines;
|
|
@@ -7306,9 +7307,9 @@ function retrievalShape(context) {
|
|
|
7306
7307
|
function guardrailShape(context) {
|
|
7307
7308
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
7308
7309
|
}
|
|
7309
|
-
function firstEvidenceForKind(context, kind,
|
|
7310
|
+
function firstEvidenceForKind(context, kind, path43) {
|
|
7310
7311
|
const event = semanticEvents(context).find((candidate) => candidate.kind === kind);
|
|
7311
|
-
return event ? [eventEvidence(event,
|
|
7312
|
+
return event ? [eventEvidence(event, path43)] : runEvidence(context.selectedRun);
|
|
7312
7313
|
}
|
|
7313
7314
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
7314
7315
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -7658,13 +7659,13 @@ function createStructureCycleRule() {
|
|
|
7658
7659
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
7659
7660
|
const findings = [];
|
|
7660
7661
|
for (const event of [...semanticEvents(context)].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
7661
|
-
const
|
|
7662
|
+
const path43 = [];
|
|
7662
7663
|
const seenAt = /* @__PURE__ */ new Map();
|
|
7663
7664
|
let current = event;
|
|
7664
7665
|
while (current) {
|
|
7665
7666
|
const existing = seenAt.get(current.eventId);
|
|
7666
7667
|
if (existing !== void 0) {
|
|
7667
|
-
const cycle =
|
|
7668
|
+
const cycle = path43.slice(existing);
|
|
7668
7669
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
7669
7670
|
if (!seenCycles.has(key)) {
|
|
7670
7671
|
seenCycles.add(key);
|
|
@@ -7680,8 +7681,8 @@ function createStructureCycleRule() {
|
|
|
7680
7681
|
}
|
|
7681
7682
|
break;
|
|
7682
7683
|
}
|
|
7683
|
-
seenAt.set(current.eventId,
|
|
7684
|
-
|
|
7684
|
+
seenAt.set(current.eventId, path43.length);
|
|
7685
|
+
path43.push(current);
|
|
7685
7686
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
7686
7687
|
}
|
|
7687
7688
|
}
|
|
@@ -9015,7 +9016,7 @@ function findReaderByFormat(format, readers) {
|
|
|
9015
9016
|
}
|
|
9016
9017
|
async function jsonlFilesInDirectory(dirPath) {
|
|
9017
9018
|
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
9018
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
9019
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path32__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
9019
9020
|
}
|
|
9020
9021
|
async function resolveInput(input3) {
|
|
9021
9022
|
const cached2 = resolvedInputCache.get(input3);
|
|
@@ -10723,7 +10724,7 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
10723
10724
|
async function runSuite(options = {}) {
|
|
10724
10725
|
const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
|
|
10725
10726
|
const { config, configPath, configDir } = await loadSuiteConfig(options);
|
|
10726
|
-
const tracesDir =
|
|
10727
|
+
const tracesDir = path32__default.default.resolve(configDir, config.traces);
|
|
10727
10728
|
const cases = [];
|
|
10728
10729
|
const diagnostics = [];
|
|
10729
10730
|
for (const suiteCase of config.cases) {
|
|
@@ -11750,7 +11751,7 @@ function validateOptions(options) {
|
|
|
11750
11751
|
}
|
|
11751
11752
|
function isConfigLoadError(error) {
|
|
11752
11753
|
if (!(error instanceof Error)) return false;
|
|
11753
|
-
const ext =
|
|
11754
|
+
const ext = path32__default.default.extname(error.message);
|
|
11754
11755
|
if (error.message.includes("Unsupported suite config extension")) return true;
|
|
11755
11756
|
if (error.message.includes("TypeScript suite configs require")) return true;
|
|
11756
11757
|
if (error.message.includes("No suite config found")) return true;
|
|
@@ -12144,8 +12145,8 @@ var init_load_sqlite = __esm({
|
|
|
12144
12145
|
}
|
|
12145
12146
|
});
|
|
12146
12147
|
function resolveIndexDbPath(traceDir, dbPath) {
|
|
12147
|
-
if (dbPath && dbPath.trim() !== "") return
|
|
12148
|
-
return
|
|
12148
|
+
if (dbPath && dbPath.trim() !== "") return path32__default.default.resolve(dbPath);
|
|
12149
|
+
return path32__default.default.join(path32__default.default.resolve(traceDir), INDEX_DB_FILENAME);
|
|
12149
12150
|
}
|
|
12150
12151
|
function str(value) {
|
|
12151
12152
|
return typeof value === "string" && value !== "" ? value : null;
|
|
@@ -12237,7 +12238,7 @@ async function buildIndex(options = {}) {
|
|
|
12237
12238
|
warnings.push(`index.unreadable: ${file}`);
|
|
12238
12239
|
}
|
|
12239
12240
|
}
|
|
12240
|
-
await promises.mkdir(
|
|
12241
|
+
await promises.mkdir(path32__default.default.dirname(dbPath), { recursive: true });
|
|
12241
12242
|
await promises.rm(dbPath, { force: true });
|
|
12242
12243
|
const Sqlite = loadBetterSqlite3();
|
|
12243
12244
|
const db = new Sqlite(dbPath);
|
|
@@ -12485,7 +12486,7 @@ var init_src = __esm({
|
|
|
12485
12486
|
});
|
|
12486
12487
|
|
|
12487
12488
|
// package.json
|
|
12488
|
-
var version = "6.
|
|
12489
|
+
var version = "6.17.0";
|
|
12489
12490
|
|
|
12490
12491
|
// packages/cli/src/list.ts
|
|
12491
12492
|
init_advanced();
|
|
@@ -15508,9 +15509,9 @@ Trace directory: ${traceDir}`);
|
|
|
15508
15509
|
process.exitCode = 1;
|
|
15509
15510
|
}
|
|
15510
15511
|
const resolvedOutput = resolveOutputOption(options);
|
|
15511
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
15512
|
+
const outPath = resolvedOutput !== void 0 ? path32__default.default.resolve(resolvedOutput) : void 0;
|
|
15512
15513
|
if (outPath !== void 0) {
|
|
15513
|
-
await promises.mkdir(
|
|
15514
|
+
await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
|
|
15514
15515
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
15515
15516
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
15516
15517
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -15869,7 +15870,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
15869
15870
|
endedAt: row.endedAt ?? void 0,
|
|
15870
15871
|
durationMs: row.durationMs ?? void 0,
|
|
15871
15872
|
eventCount: 0,
|
|
15872
|
-
filePath:
|
|
15873
|
+
filePath: path32__default.default.join(traceDir, row.file),
|
|
15873
15874
|
fileSize: 0,
|
|
15874
15875
|
createdAt: new Date(row.mtimeMs)
|
|
15875
15876
|
};
|
|
@@ -16351,9 +16352,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
16351
16352
|
...options.section ? { section: options.section } : {}
|
|
16352
16353
|
});
|
|
16353
16354
|
const resolvedOutput = resolveOutputOption(options);
|
|
16354
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
16355
|
+
const outPath = resolvedOutput !== void 0 ? path32__default.default.resolve(resolvedOutput) : void 0;
|
|
16355
16356
|
if (outPath !== void 0) {
|
|
16356
|
-
await promises.mkdir(
|
|
16357
|
+
await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
|
|
16357
16358
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
16358
16359
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
16359
16360
|
}
|
|
@@ -16535,8 +16536,8 @@ function passesLuhn(value) {
|
|
|
16535
16536
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
16536
16537
|
var EPOCH_MS_RE = /^1[0-9]{12}$/;
|
|
16537
16538
|
var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
16538
|
-
function pathSuggestsNonCard(
|
|
16539
|
-
const normalized =
|
|
16539
|
+
function pathSuggestsNonCard(path43) {
|
|
16540
|
+
const normalized = path43.toLowerCase().replace(/[^a-z0-9._]/g, "");
|
|
16540
16541
|
return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
|
|
16541
16542
|
normalized
|
|
16542
16543
|
) || /(^|\.)ts(\.|$)/.test(normalized);
|
|
@@ -16723,17 +16724,17 @@ function applyRule(rule, value, replacement) {
|
|
|
16723
16724
|
}
|
|
16724
16725
|
return value;
|
|
16725
16726
|
}
|
|
16726
|
-
function childPath(
|
|
16727
|
+
function childPath(path43, key) {
|
|
16727
16728
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
16728
|
-
return
|
|
16729
|
+
return path43 ? `${path43}.${key}` : key;
|
|
16729
16730
|
}
|
|
16730
|
-
return `${
|
|
16731
|
+
return `${path43 || "$"}[${JSON.stringify(key)}]`;
|
|
16731
16732
|
}
|
|
16732
|
-
function indexPath(
|
|
16733
|
-
return `${
|
|
16733
|
+
function indexPath(path43, index) {
|
|
16734
|
+
return `${path43 || "$"}[${index}]`;
|
|
16734
16735
|
}
|
|
16735
|
-
function makeFinding(
|
|
16736
|
-
return preview === void 0 ? { path:
|
|
16736
|
+
function makeFinding(path43, detector, action, matchKind, severity = "warning", preview) {
|
|
16737
|
+
return preview === void 0 ? { path: path43, detector, action, severity, matchKind } : { path: path43, detector, action, severity, matchKind, preview };
|
|
16737
16738
|
}
|
|
16738
16739
|
function createRedactionProfile(profile = "local") {
|
|
16739
16740
|
switch (profile) {
|
|
@@ -16802,11 +16803,11 @@ var Redactor2 = class {
|
|
|
16802
16803
|
#recordFinding(state, finding) {
|
|
16803
16804
|
if (this.#collectFindings) state.findings.push(finding);
|
|
16804
16805
|
}
|
|
16805
|
-
#redactValue(value, key,
|
|
16806
|
+
#redactValue(value, key, path43, depth, state) {
|
|
16806
16807
|
if (depth > this.#maxDepth) {
|
|
16807
16808
|
this.#recordFinding(
|
|
16808
16809
|
state,
|
|
16809
|
-
makeFinding(
|
|
16810
|
+
makeFinding(path43, "structure.maxDepth", "truncate", "value", "warning")
|
|
16810
16811
|
);
|
|
16811
16812
|
return "[Truncated]";
|
|
16812
16813
|
}
|
|
@@ -16815,19 +16816,19 @@ var Redactor2 = class {
|
|
|
16815
16816
|
if (rule) {
|
|
16816
16817
|
this.#recordFinding(
|
|
16817
16818
|
state,
|
|
16818
|
-
makeFinding(
|
|
16819
|
+
makeFinding(path43, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
16819
16820
|
);
|
|
16820
16821
|
return applyRule(rule, value, this.#replacement);
|
|
16821
16822
|
}
|
|
16822
16823
|
}
|
|
16823
16824
|
for (const detector of this.#detectors) {
|
|
16824
|
-
const detections = detector.detect({ path:
|
|
16825
|
+
const detections = detector.detect({ path: path43, key, value });
|
|
16825
16826
|
for (const detection of detections) {
|
|
16826
16827
|
const action = detection.action ?? "replace";
|
|
16827
16828
|
this.#recordFinding(
|
|
16828
16829
|
state,
|
|
16829
16830
|
makeFinding(
|
|
16830
|
-
|
|
16831
|
+
path43,
|
|
16831
16832
|
detector.id,
|
|
16832
16833
|
action,
|
|
16833
16834
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -16845,7 +16846,7 @@ var Redactor2 = class {
|
|
|
16845
16846
|
const out = [];
|
|
16846
16847
|
state.seen.set(value, out);
|
|
16847
16848
|
value.forEach((item, index) => {
|
|
16848
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
16849
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path43, index), depth + 1, state);
|
|
16849
16850
|
});
|
|
16850
16851
|
return out;
|
|
16851
16852
|
}
|
|
@@ -16857,7 +16858,7 @@ var Redactor2 = class {
|
|
|
16857
16858
|
out[entryKey] = this.#redactValue(
|
|
16858
16859
|
entryValue,
|
|
16859
16860
|
entryKey,
|
|
16860
|
-
childPath(
|
|
16861
|
+
childPath(path43 === "$" ? "" : path43, entryKey),
|
|
16861
16862
|
depth + 1,
|
|
16862
16863
|
state
|
|
16863
16864
|
);
|
|
@@ -17328,14 +17329,14 @@ function uniqueSorted(values) {
|
|
|
17328
17329
|
return [...new Set(values)].sort();
|
|
17329
17330
|
}
|
|
17330
17331
|
function isWithinDirectory(child, parent) {
|
|
17331
|
-
const relative =
|
|
17332
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
17332
|
+
const relative = path32__default.default.relative(parent, child);
|
|
17333
|
+
return relative === "" || !relative.startsWith("..") && !path32__default.default.isAbsolute(relative);
|
|
17333
17334
|
}
|
|
17334
17335
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
17335
17336
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
17336
|
-
const inputAbs =
|
|
17337
|
-
const outputAbs =
|
|
17338
|
-
const inputDir =
|
|
17337
|
+
const inputAbs = path32__default.default.resolve(inputPath);
|
|
17338
|
+
const outputAbs = path32__default.default.resolve(output2.trim());
|
|
17339
|
+
const inputDir = path32__default.default.dirname(inputAbs);
|
|
17339
17340
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
17340
17341
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
17341
17342
|
}
|
|
@@ -17456,7 +17457,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17456
17457
|
process.exitCode = 1;
|
|
17457
17458
|
return;
|
|
17458
17459
|
}
|
|
17459
|
-
const inputPath =
|
|
17460
|
+
const inputPath = path32__default.default.resolve(input3.trim());
|
|
17460
17461
|
const dryRun = options.dryRun === true;
|
|
17461
17462
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
17462
17463
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -17475,7 +17476,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17475
17476
|
);
|
|
17476
17477
|
const result = await buildMigration(inputPath, outputPath);
|
|
17477
17478
|
if (!dryRun && outputPath !== void 0) {
|
|
17478
|
-
await promises.mkdir(
|
|
17479
|
+
await promises.mkdir(path32__default.default.dirname(outputPath), { recursive: true });
|
|
17479
17480
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
17480
17481
|
}
|
|
17481
17482
|
printSummary2(result, dryRun);
|
|
@@ -17489,6 +17490,246 @@ init_advanced();
|
|
|
17489
17490
|
|
|
17490
17491
|
// packages/core/src/entries/checks.ts
|
|
17491
17492
|
init_checks2();
|
|
17493
|
+
|
|
17494
|
+
// packages/cli/src/evidence-on.ts
|
|
17495
|
+
init_advanced();
|
|
17496
|
+
function validateReporterArtifactPath(options) {
|
|
17497
|
+
const outputDir = path32__default.default.resolve(options.outputDir);
|
|
17498
|
+
const diagnostics = [];
|
|
17499
|
+
const rawPath = options.relativePath;
|
|
17500
|
+
if (rawPath.length === 0) {
|
|
17501
|
+
diagnostics.push({
|
|
17502
|
+
code: "artifact_path_empty",
|
|
17503
|
+
severity: "error",
|
|
17504
|
+
message: "Reporter artifact path must not be empty."
|
|
17505
|
+
});
|
|
17506
|
+
return { ok: false, outputDir, diagnostics };
|
|
17507
|
+
}
|
|
17508
|
+
if (rawPath.includes("\0")) {
|
|
17509
|
+
diagnostics.push({
|
|
17510
|
+
code: "invalid_artifact_path",
|
|
17511
|
+
severity: "error",
|
|
17512
|
+
message: "Reporter artifact path must not contain null bytes.",
|
|
17513
|
+
target: rawPath
|
|
17514
|
+
});
|
|
17515
|
+
return { ok: false, outputDir, diagnostics };
|
|
17516
|
+
}
|
|
17517
|
+
if (path32__default.default.isAbsolute(rawPath) || path32__default.default.win32.isAbsolute(rawPath)) {
|
|
17518
|
+
diagnostics.push({
|
|
17519
|
+
code: "artifact_path_absolute",
|
|
17520
|
+
severity: "error",
|
|
17521
|
+
message: "Reporter artifact path must be relative.",
|
|
17522
|
+
target: rawPath
|
|
17523
|
+
});
|
|
17524
|
+
return { ok: false, outputDir, diagnostics };
|
|
17525
|
+
}
|
|
17526
|
+
const normalized = path32__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
17527
|
+
const segments = normalized.split("/");
|
|
17528
|
+
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
17529
|
+
diagnostics.push({
|
|
17530
|
+
code: "artifact_path_escape",
|
|
17531
|
+
severity: "error",
|
|
17532
|
+
message: "Reporter artifact path must stay under the output directory.",
|
|
17533
|
+
target: rawPath
|
|
17534
|
+
});
|
|
17535
|
+
return { ok: false, outputDir, diagnostics };
|
|
17536
|
+
}
|
|
17537
|
+
const absolutePath = path32__default.default.resolve(outputDir, normalized);
|
|
17538
|
+
const relFromOutput = path32__default.default.relative(outputDir, absolutePath);
|
|
17539
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path32__default.default.isAbsolute(relFromOutput)) {
|
|
17540
|
+
diagnostics.push({
|
|
17541
|
+
code: "artifact_path_escape",
|
|
17542
|
+
severity: "error",
|
|
17543
|
+
message: "Reporter artifact path resolved outside the output directory.",
|
|
17544
|
+
target: rawPath
|
|
17545
|
+
});
|
|
17546
|
+
return { ok: false, outputDir, diagnostics };
|
|
17547
|
+
}
|
|
17548
|
+
return {
|
|
17549
|
+
ok: true,
|
|
17550
|
+
outputDir,
|
|
17551
|
+
relativePath: normalized,
|
|
17552
|
+
absolutePath,
|
|
17553
|
+
diagnostics
|
|
17554
|
+
};
|
|
17555
|
+
}
|
|
17556
|
+
var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
17557
|
+
"evidence.html",
|
|
17558
|
+
"evidence.json",
|
|
17559
|
+
"check-results.json",
|
|
17560
|
+
"trace.jsonl"
|
|
17561
|
+
];
|
|
17562
|
+
function createEvidenceCiArtifacts(options) {
|
|
17563
|
+
const profile = options.redactionProfile ?? "share";
|
|
17564
|
+
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
17565
|
+
const join = (name) => prefix === "" ? name : path32__default.default.posix.join(prefix, name);
|
|
17566
|
+
const formatFor = (name) => {
|
|
17567
|
+
if (name.endsWith(".html")) return "html";
|
|
17568
|
+
if (name.endsWith(".jsonl")) return "jsonl";
|
|
17569
|
+
return "json";
|
|
17570
|
+
};
|
|
17571
|
+
return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
|
|
17572
|
+
kind: "evidence",
|
|
17573
|
+
path: join(name),
|
|
17574
|
+
format: formatFor(name),
|
|
17575
|
+
redactionProfile: profile,
|
|
17576
|
+
title: `Evidence v2 ${name}`
|
|
17577
|
+
}));
|
|
17578
|
+
}
|
|
17579
|
+
|
|
17580
|
+
// packages/cli/src/evidence-on.ts
|
|
17581
|
+
function shouldEmitEvidence(mode, failed) {
|
|
17582
|
+
if (mode === void 0 || mode === "never") return false;
|
|
17583
|
+
if (mode === "always") return true;
|
|
17584
|
+
return failed;
|
|
17585
|
+
}
|
|
17586
|
+
function parseEvidenceProfile(value) {
|
|
17587
|
+
const profile = (value ?? "share").trim().toLowerCase();
|
|
17588
|
+
if (profile === "local" || profile === "share" || profile === "strict") {
|
|
17589
|
+
return profile;
|
|
17590
|
+
}
|
|
17591
|
+
throw new Error(
|
|
17592
|
+
`Unsupported --evidence-profile "${value}". Use local, share, or strict.`
|
|
17593
|
+
);
|
|
17594
|
+
}
|
|
17595
|
+
function parseEvidenceFormat(value) {
|
|
17596
|
+
const format = (value ?? "directory").trim().toLowerCase();
|
|
17597
|
+
if (format === "directory" || format === "html" || format === "zip") {
|
|
17598
|
+
return format;
|
|
17599
|
+
}
|
|
17600
|
+
throw new Error(
|
|
17601
|
+
`Unsupported --evidence-format "${value}". Use directory, html, or zip.`
|
|
17602
|
+
);
|
|
17603
|
+
}
|
|
17604
|
+
function toAssessmentStatus(failed) {
|
|
17605
|
+
return failed ? "UNSAFE" : "SAFE";
|
|
17606
|
+
}
|
|
17607
|
+
function stableJson2(value) {
|
|
17608
|
+
return `${JSON.stringify(value, null, 2)}
|
|
17609
|
+
`;
|
|
17610
|
+
}
|
|
17611
|
+
async function writeLocalEvidence(input3) {
|
|
17612
|
+
const profile = input3.redactionProfile ?? "share";
|
|
17613
|
+
const format = input3.format ?? "directory";
|
|
17614
|
+
const baseDir = path32__default.default.resolve(input3.outputDir);
|
|
17615
|
+
await promises.mkdir(
|
|
17616
|
+
format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path32__default.default.dirname(baseDir) : baseDir,
|
|
17617
|
+
{ recursive: true }
|
|
17618
|
+
);
|
|
17619
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
17620
|
+
if (input3.sourceContents instanceof Map) {
|
|
17621
|
+
for (const [runId, content] of input3.sourceContents) {
|
|
17622
|
+
sourceContents.set(runId, content);
|
|
17623
|
+
}
|
|
17624
|
+
} else if (input3.sourceContents !== void 0) {
|
|
17625
|
+
for (const [runId, content] of Object.entries(input3.sourceContents)) {
|
|
17626
|
+
sourceContents.set(runId, content);
|
|
17627
|
+
}
|
|
17628
|
+
}
|
|
17629
|
+
const traceDir = resolveTraceDir({ dir: input3.dir });
|
|
17630
|
+
let combined = "";
|
|
17631
|
+
for (const runId of input3.runIds) {
|
|
17632
|
+
let raw = sourceContents.get(runId) ?? "";
|
|
17633
|
+
if (raw === "") {
|
|
17634
|
+
try {
|
|
17635
|
+
raw = await promises.readFile(getTraceFilePath(runId, traceDir), "utf-8");
|
|
17636
|
+
} catch {
|
|
17637
|
+
raw = "";
|
|
17638
|
+
}
|
|
17639
|
+
sourceContents.set(runId, raw);
|
|
17640
|
+
}
|
|
17641
|
+
const redacted = redactTraceContent(raw, profile);
|
|
17642
|
+
combined += redacted.content.endsWith("\n") ? redacted.content : `${redacted.content}
|
|
17643
|
+
`;
|
|
17644
|
+
}
|
|
17645
|
+
const assessmentStatus = toAssessmentStatus(input3.failed);
|
|
17646
|
+
const evidencePackage = buildEvidenceCiPackage({
|
|
17647
|
+
generatorVersion: version,
|
|
17648
|
+
runIds: input3.runIds,
|
|
17649
|
+
sourceContents,
|
|
17650
|
+
redactedTraceJsonl: combined,
|
|
17651
|
+
redactionProfile: profile,
|
|
17652
|
+
assessmentStatus,
|
|
17653
|
+
checkResultsJson: input3.checkResultsJson,
|
|
17654
|
+
...input3.summaryText !== void 0 ? { summaryText: input3.summaryText } : {}
|
|
17655
|
+
});
|
|
17656
|
+
const files = [
|
|
17657
|
+
["evidence.html", evidencePackage["evidence.html"]],
|
|
17658
|
+
["evidence.json", evidencePackage["evidence.json"]],
|
|
17659
|
+
["check-results.json", evidencePackage["check-results.json"]],
|
|
17660
|
+
["trace.jsonl", evidencePackage["trace.jsonl"]]
|
|
17661
|
+
];
|
|
17662
|
+
const expected = createEvidenceCiArtifacts({
|
|
17663
|
+
redactionProfile: profile
|
|
17664
|
+
}).map((a) => a.path);
|
|
17665
|
+
for (const name of expected) {
|
|
17666
|
+
if (!files.some(([fileName]) => fileName === name)) {
|
|
17667
|
+
throw new Error(`Evidence CI package missing expected file: ${name}`);
|
|
17668
|
+
}
|
|
17669
|
+
}
|
|
17670
|
+
if (format === "zip") {
|
|
17671
|
+
const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
|
|
17672
|
+
await promises.mkdir(path32__default.default.dirname(zipPath), { recursive: true });
|
|
17673
|
+
const archive = buildZipArchive(
|
|
17674
|
+
files.map(([relativePath, content]) => ({
|
|
17675
|
+
path: relativePath,
|
|
17676
|
+
content
|
|
17677
|
+
}))
|
|
17678
|
+
);
|
|
17679
|
+
await promises.writeFile(zipPath, archive);
|
|
17680
|
+
return zipPath;
|
|
17681
|
+
}
|
|
17682
|
+
if (format === "html") {
|
|
17683
|
+
let htmlPath = baseDir;
|
|
17684
|
+
let sidecarDir = baseDir;
|
|
17685
|
+
if (baseDir.toLowerCase().endsWith(".html")) {
|
|
17686
|
+
htmlPath = baseDir;
|
|
17687
|
+
sidecarDir = path32__default.default.dirname(baseDir);
|
|
17688
|
+
} else {
|
|
17689
|
+
await promises.mkdir(baseDir, { recursive: true });
|
|
17690
|
+
htmlPath = path32__default.default.join(baseDir, "evidence.html");
|
|
17691
|
+
sidecarDir = baseDir;
|
|
17692
|
+
}
|
|
17693
|
+
await promises.mkdir(sidecarDir, { recursive: true });
|
|
17694
|
+
await promises.writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
|
|
17695
|
+
await promises.writeFile(
|
|
17696
|
+
path32__default.default.join(sidecarDir, "evidence.json"),
|
|
17697
|
+
evidencePackage["evidence.json"],
|
|
17698
|
+
"utf-8"
|
|
17699
|
+
);
|
|
17700
|
+
return htmlPath;
|
|
17701
|
+
}
|
|
17702
|
+
await promises.mkdir(baseDir, { recursive: true });
|
|
17703
|
+
for (const [name, content] of files) {
|
|
17704
|
+
await promises.writeFile(path32__default.default.join(baseDir, name), content, "utf-8");
|
|
17705
|
+
}
|
|
17706
|
+
return baseDir;
|
|
17707
|
+
}
|
|
17708
|
+
function checkResultToEvidenceJson(result, runIds) {
|
|
17709
|
+
const status = result.status === "pass" ? "SAFE" : result.status === "fail" ? "UNSAFE" : "UNKNOWN";
|
|
17710
|
+
return stableJson2({
|
|
17711
|
+
aggregateStatus: status,
|
|
17712
|
+
runs: runIds.map((runId) => ({
|
|
17713
|
+
runId,
|
|
17714
|
+
status,
|
|
17715
|
+
errors: result.summary.errors,
|
|
17716
|
+
warnings: result.summary.warnings,
|
|
17717
|
+
findings: result.findings.length
|
|
17718
|
+
})),
|
|
17719
|
+
findings: result.findings,
|
|
17720
|
+
diagnostics: result.diagnostics
|
|
17721
|
+
});
|
|
17722
|
+
}
|
|
17723
|
+
function defaultEvidenceDir(label) {
|
|
17724
|
+
const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
|
|
17725
|
+
return path32__default.default.join(".agent-inspect", "evidence", safe);
|
|
17726
|
+
}
|
|
17727
|
+
function resolveEvidenceOutputDir(evidenceDir, label) {
|
|
17728
|
+
if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
|
|
17729
|
+
return path32__default.default.resolve(evidenceDir.trim());
|
|
17730
|
+
}
|
|
17731
|
+
return defaultEvidenceDir(label);
|
|
17732
|
+
}
|
|
17492
17733
|
var ALL_RULES = [
|
|
17493
17734
|
"circuit.same-tool-repetition",
|
|
17494
17735
|
"circuit.same-args-repetition",
|
|
@@ -17809,23 +18050,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
17809
18050
|
}
|
|
17810
18051
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
17811
18052
|
}
|
|
17812
|
-
function validateSchemaField(value, field,
|
|
18053
|
+
function validateSchemaField(value, field, path43, evidence) {
|
|
17813
18054
|
const ruleId = "guardrail.structured-output";
|
|
17814
18055
|
if (field.type) {
|
|
17815
18056
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
17816
18057
|
if (actual !== field.type) {
|
|
17817
|
-
evidence.push({ ruleId, path:
|
|
18058
|
+
evidence.push({ ruleId, path: path43, preview: `expected ${field.type}, got ${actual}` });
|
|
17818
18059
|
return;
|
|
17819
18060
|
}
|
|
17820
18061
|
}
|
|
17821
18062
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
17822
|
-
evidence.push({ ruleId, path:
|
|
18063
|
+
evidence.push({ ruleId, path: path43, preview: "value not in enum" });
|
|
17823
18064
|
}
|
|
17824
18065
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
17825
18066
|
const record = value;
|
|
17826
18067
|
for (const key of field.required) {
|
|
17827
18068
|
if (!(key in record)) {
|
|
17828
|
-
evidence.push({ ruleId, path: `${
|
|
18069
|
+
evidence.push({ ruleId, path: `${path43}.${key}`, preview: "missing required key" });
|
|
17829
18070
|
}
|
|
17830
18071
|
}
|
|
17831
18072
|
}
|
|
@@ -18106,6 +18347,54 @@ function mergeSafetyExtensions(result, read, options) {
|
|
|
18106
18347
|
}
|
|
18107
18348
|
|
|
18108
18349
|
// packages/cli/src/check.ts
|
|
18350
|
+
function resolvePreset(preset, context = {}) {
|
|
18351
|
+
if (preset === void 0 || preset.trim() === "") return void 0;
|
|
18352
|
+
const name = preset.trim().toLowerCase();
|
|
18353
|
+
if (name !== "trajectory" && name !== "safety" && name !== "comprehensive") {
|
|
18354
|
+
throw new Error(
|
|
18355
|
+
`Unknown --preset "${preset}". Use trajectory, safety, or comprehensive.`
|
|
18356
|
+
);
|
|
18357
|
+
}
|
|
18358
|
+
const trajectorySelect = [
|
|
18359
|
+
"run.status",
|
|
18360
|
+
"run.requireCompleted",
|
|
18361
|
+
"structure.orphan",
|
|
18362
|
+
"structure.cycle",
|
|
18363
|
+
"structure.relationship"
|
|
18364
|
+
];
|
|
18365
|
+
if (context.hasToolRules === true) {
|
|
18366
|
+
trajectorySelect.push("tool.usage");
|
|
18367
|
+
}
|
|
18368
|
+
const safetySelect = [
|
|
18369
|
+
"run.status",
|
|
18370
|
+
"safety.rawPrompt",
|
|
18371
|
+
"safety.secretPattern",
|
|
18372
|
+
"safety.redaction"
|
|
18373
|
+
];
|
|
18374
|
+
if (name === "trajectory") {
|
|
18375
|
+
return {
|
|
18376
|
+
requireCompleted: true,
|
|
18377
|
+
enableSafetyRedaction: false,
|
|
18378
|
+
enableStructureRelationshipDefaults: true,
|
|
18379
|
+
select: trajectorySelect
|
|
18380
|
+
};
|
|
18381
|
+
}
|
|
18382
|
+
if (name === "safety") {
|
|
18383
|
+
return {
|
|
18384
|
+
requireCompleted: false,
|
|
18385
|
+
enableSafetyRedaction: true,
|
|
18386
|
+
enableStructureRelationshipDefaults: false,
|
|
18387
|
+
select: safetySelect
|
|
18388
|
+
};
|
|
18389
|
+
}
|
|
18390
|
+
const select = [.../* @__PURE__ */ new Set([...trajectorySelect, ...safetySelect])];
|
|
18391
|
+
return {
|
|
18392
|
+
requireCompleted: true,
|
|
18393
|
+
enableSafetyRedaction: true,
|
|
18394
|
+
enableStructureRelationshipDefaults: true,
|
|
18395
|
+
select
|
|
18396
|
+
};
|
|
18397
|
+
}
|
|
18109
18398
|
var DEFAULT_SELECT = ["run.status"];
|
|
18110
18399
|
var CONFIG_EXTENSIONS2 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
18111
18400
|
var TS_CONFIG_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
|
|
@@ -18152,7 +18441,7 @@ function asConfig(value) {
|
|
|
18152
18441
|
}
|
|
18153
18442
|
async function loadConfig(configPath) {
|
|
18154
18443
|
if (configPath === void 0) return {};
|
|
18155
|
-
const extension =
|
|
18444
|
+
const extension = path32__default.default.extname(configPath);
|
|
18156
18445
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
18157
18446
|
throw new Error(
|
|
18158
18447
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -18161,7 +18450,7 @@ async function loadConfig(configPath) {
|
|
|
18161
18450
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
18162
18451
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
18163
18452
|
}
|
|
18164
|
-
const absolute =
|
|
18453
|
+
const absolute = path32__default.default.resolve(configPath);
|
|
18165
18454
|
if (extension === ".json") {
|
|
18166
18455
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
18167
18456
|
return asConfig(JSON.parse(raw));
|
|
@@ -18176,6 +18465,33 @@ function normalizeConfig(config) {
|
|
|
18176
18465
|
}
|
|
18177
18466
|
return config.checks;
|
|
18178
18467
|
}
|
|
18468
|
+
function hasToolRulesConfigured(config, options) {
|
|
18469
|
+
const tool = normalizeConfig(config).tool ?? {};
|
|
18470
|
+
return Boolean(
|
|
18471
|
+
(tool.required?.length ?? 0) > 0 || (tool.forbidden?.length ?? 0) > 0 || (tool.allowed?.length ?? 0) > 0 || tool.minCount !== void 0 || tool.maxCount !== void 0 || (options.requiredTool?.length ?? 0) > 0 || (options.forbiddenTool?.length ?? 0) > 0
|
|
18472
|
+
);
|
|
18473
|
+
}
|
|
18474
|
+
function applyResolvedPreset(config, options, resolved) {
|
|
18475
|
+
const checks2 = { ...normalizeConfig(config) };
|
|
18476
|
+
if (resolved.enableSafetyRedaction) {
|
|
18477
|
+
checks2.safety = { ...checks2.safety, redaction: true };
|
|
18478
|
+
}
|
|
18479
|
+
if (resolved.enableStructureRelationshipDefaults) {
|
|
18480
|
+
const structure = checks2.structure ?? {};
|
|
18481
|
+
const needed = structure.minConfidence === void 0 && structure.requireParentBeforeChild === void 0 && structure.requireTraceParentSpan === void 0;
|
|
18482
|
+
if (needed) {
|
|
18483
|
+
checks2.structure = { ...structure, requireParentBeforeChild: true };
|
|
18484
|
+
}
|
|
18485
|
+
}
|
|
18486
|
+
return {
|
|
18487
|
+
config: { checks: checks2 },
|
|
18488
|
+
options: {
|
|
18489
|
+
...options,
|
|
18490
|
+
...resolved.requireCompleted ? { requireCompleted: true } : {},
|
|
18491
|
+
rule: [...resolved.select, ...options.rule ?? []]
|
|
18492
|
+
}
|
|
18493
|
+
};
|
|
18494
|
+
}
|
|
18179
18495
|
function buildRules(config, options) {
|
|
18180
18496
|
const diagnostics = [];
|
|
18181
18497
|
const checks2 = normalizeConfig(config);
|
|
@@ -18319,7 +18635,42 @@ function stable3(value) {
|
|
|
18319
18635
|
function printJson(result) {
|
|
18320
18636
|
console.log(JSON.stringify(stable3(result), null, 2));
|
|
18321
18637
|
}
|
|
18322
|
-
function
|
|
18638
|
+
function isSafetyFinding(ruleId) {
|
|
18639
|
+
return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
|
|
18640
|
+
}
|
|
18641
|
+
function printPresetClassSummary(result, preset) {
|
|
18642
|
+
const name = preset?.trim().toLowerCase();
|
|
18643
|
+
if (name !== "trajectory" && name !== "safety" && name !== "comprehensive") {
|
|
18644
|
+
return;
|
|
18645
|
+
}
|
|
18646
|
+
const hasSafetyFindings = result.findings.some(
|
|
18647
|
+
(finding) => isSafetyFinding(finding.ruleId)
|
|
18648
|
+
);
|
|
18649
|
+
const hasTrajectoryFindings = result.findings.some(
|
|
18650
|
+
(finding) => !isSafetyFinding(finding.ruleId)
|
|
18651
|
+
);
|
|
18652
|
+
if (name === "trajectory") {
|
|
18653
|
+
console.log(
|
|
18654
|
+
`Trajectory: ${result.status === "pass" && !hasTrajectoryFindings ? "PASS" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
18655
|
+
);
|
|
18656
|
+
console.log("Share safety: not evaluated");
|
|
18657
|
+
console.log("Run verify-safe before sharing.");
|
|
18658
|
+
return;
|
|
18659
|
+
}
|
|
18660
|
+
if (name === "safety") {
|
|
18661
|
+
console.log(
|
|
18662
|
+
`Share safety: ${result.status === "pass" && !hasSafetyFindings ? "PASS" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
18663
|
+
);
|
|
18664
|
+
return;
|
|
18665
|
+
}
|
|
18666
|
+
console.log(
|
|
18667
|
+
`Trajectory: ${hasTrajectoryFindings || result.status === "error" ? "FAIL" : "PASS"}`
|
|
18668
|
+
);
|
|
18669
|
+
console.log(
|
|
18670
|
+
`Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
18671
|
+
);
|
|
18672
|
+
}
|
|
18673
|
+
function printHuman(result, options = {}) {
|
|
18323
18674
|
const scoped = result;
|
|
18324
18675
|
if (scoped.scopeLabel) {
|
|
18325
18676
|
console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
|
|
@@ -18328,6 +18679,7 @@ function printHuman(result) {
|
|
|
18328
18679
|
}
|
|
18329
18680
|
}
|
|
18330
18681
|
console.log(`Check status: ${result.status}`);
|
|
18682
|
+
printPresetClassSummary(result, options.preset);
|
|
18331
18683
|
console.log(`Format: ${result.format}`);
|
|
18332
18684
|
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
18333
18685
|
console.log(
|
|
@@ -18337,10 +18689,10 @@ function printHuman(result) {
|
|
|
18337
18689
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
18338
18690
|
}
|
|
18339
18691
|
for (const finding of result.findings) {
|
|
18340
|
-
const
|
|
18692
|
+
const path43 = finding.evidence[0]?.path;
|
|
18341
18693
|
const run = finding.evidence[0]?.runId;
|
|
18342
18694
|
const runPrefix = run ? `[${run}] ` : "";
|
|
18343
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
18695
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
18344
18696
|
}
|
|
18345
18697
|
}
|
|
18346
18698
|
function readErrorResult(error) {
|
|
@@ -18356,12 +18708,24 @@ function readErrorResult(error) {
|
|
|
18356
18708
|
async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
18357
18709
|
let result;
|
|
18358
18710
|
let phase = "config";
|
|
18711
|
+
let evidenceRead;
|
|
18712
|
+
let evidenceRunIds = [];
|
|
18713
|
+
let evidenceSourceContents;
|
|
18359
18714
|
const sessionId = options.session?.trim();
|
|
18360
18715
|
const groupId = options.group?.trim();
|
|
18361
18716
|
const useSessionScope = Boolean(sessionId || groupId);
|
|
18362
18717
|
try {
|
|
18363
|
-
|
|
18364
|
-
|
|
18718
|
+
let config = await loadConfig(options.config);
|
|
18719
|
+
let effectiveOptions = options;
|
|
18720
|
+
const resolved = resolvePreset(options.preset, {
|
|
18721
|
+
hasToolRules: hasToolRulesConfigured(config, options)
|
|
18722
|
+
});
|
|
18723
|
+
if (resolved !== void 0) {
|
|
18724
|
+
const applied = applyResolvedPreset(config, options, resolved);
|
|
18725
|
+
config = applied.config;
|
|
18726
|
+
effectiveOptions = applied.options;
|
|
18727
|
+
}
|
|
18728
|
+
const built = buildRules(config, effectiveOptions);
|
|
18365
18729
|
if (built.diagnostics.some((item) => item.severity === "error")) {
|
|
18366
18730
|
result = errorResult2("AI_CHECK_INVALID_CONFIG", "Invalid check configuration.");
|
|
18367
18731
|
result.diagnostics = [...built.diagnostics];
|
|
@@ -18382,6 +18746,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18382
18746
|
correlateByGroupId: options.correlateGroup === true
|
|
18383
18747
|
});
|
|
18384
18748
|
const perRun = [];
|
|
18749
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
18385
18750
|
for (const meta2 of scoped.metas) {
|
|
18386
18751
|
const read = await openTrace(
|
|
18387
18752
|
{ type: "file", path: meta2.filePath },
|
|
@@ -18389,6 +18754,15 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18389
18754
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
18390
18755
|
}
|
|
18391
18756
|
);
|
|
18757
|
+
try {
|
|
18758
|
+
sourceContents.set(meta2.runId, await promises.readFile(meta2.filePath, "utf-8"));
|
|
18759
|
+
} catch {
|
|
18760
|
+
sourceContents.set(
|
|
18761
|
+
meta2.runId,
|
|
18762
|
+
`${read.events.map((event) => JSON.stringify(event)).join("\n")}
|
|
18763
|
+
`
|
|
18764
|
+
);
|
|
18765
|
+
}
|
|
18392
18766
|
perRun.push(
|
|
18393
18767
|
mergeSafetyExtensions(
|
|
18394
18768
|
runTraceChecks(
|
|
@@ -18407,6 +18781,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18407
18781
|
)
|
|
18408
18782
|
);
|
|
18409
18783
|
}
|
|
18784
|
+
evidenceRunIds = scoped.runIds;
|
|
18785
|
+
evidenceSourceContents = sourceContents;
|
|
18410
18786
|
result = aggregateSessionCheckResults(perRun, {
|
|
18411
18787
|
scopeKind: scoped.scopeKind,
|
|
18412
18788
|
scopeLabel: scoped.scopeLabel,
|
|
@@ -18421,6 +18797,26 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18421
18797
|
const read = await openTrace(input3, {
|
|
18422
18798
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
18423
18799
|
});
|
|
18800
|
+
evidenceRead = read;
|
|
18801
|
+
evidenceRunIds = options.run !== void 0 ? [options.run] : read.runs.length === 1 ? [read.runs[0].runId] : read.runs.map((run) => run.runId);
|
|
18802
|
+
if (input3.type === "file") {
|
|
18803
|
+
try {
|
|
18804
|
+
const raw = await promises.readFile(input3.path, "utf-8");
|
|
18805
|
+
evidenceSourceContents = new Map(
|
|
18806
|
+
evidenceRunIds.map((runId) => [runId, raw])
|
|
18807
|
+
);
|
|
18808
|
+
} catch {
|
|
18809
|
+
evidenceSourceContents = void 0;
|
|
18810
|
+
}
|
|
18811
|
+
} else {
|
|
18812
|
+
evidenceSourceContents = new Map(
|
|
18813
|
+
evidenceRunIds.map((runId) => [
|
|
18814
|
+
runId,
|
|
18815
|
+
`${read.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
|
|
18816
|
+
`
|
|
18817
|
+
])
|
|
18818
|
+
);
|
|
18819
|
+
}
|
|
18424
18820
|
result = mergeSafetyExtensions(
|
|
18425
18821
|
runTraceChecks(
|
|
18426
18822
|
{ read },
|
|
@@ -18440,7 +18836,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18440
18836
|
} catch (error) {
|
|
18441
18837
|
if (phase === "config") {
|
|
18442
18838
|
const message = error instanceof Error ? error.message : String(error);
|
|
18443
|
-
const code = message.startsWith("--") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
|
|
18839
|
+
const code = message.startsWith("--") || message.includes("Unknown --preset") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
|
|
18444
18840
|
result = errorResult2(
|
|
18445
18841
|
code,
|
|
18446
18842
|
message
|
|
@@ -18450,8 +18846,47 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18450
18846
|
}
|
|
18451
18847
|
}
|
|
18452
18848
|
process.exitCode = exitCodeFor(result);
|
|
18849
|
+
const failed = result.status !== "pass";
|
|
18850
|
+
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
18851
|
+
try {
|
|
18852
|
+
const runIds = evidenceRunIds.length > 0 ? evidenceRunIds : result.runId !== void 0 ? [result.runId] : ["check"];
|
|
18853
|
+
if (evidenceSourceContents === void 0 && evidenceRead !== void 0) {
|
|
18854
|
+
evidenceSourceContents = new Map(
|
|
18855
|
+
runIds.map((runId) => [
|
|
18856
|
+
runId,
|
|
18857
|
+
`${evidenceRead.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
|
|
18858
|
+
`
|
|
18859
|
+
])
|
|
18860
|
+
);
|
|
18861
|
+
}
|
|
18862
|
+
let redactionProfile = parseEvidenceProfile(options.evidenceProfile);
|
|
18863
|
+
let evidenceFormat = parseEvidenceFormat(options.evidenceFormat);
|
|
18864
|
+
const outputDir = resolveEvidenceOutputDir(
|
|
18865
|
+
options.evidenceDir,
|
|
18866
|
+
runIds[0] ?? "check"
|
|
18867
|
+
);
|
|
18868
|
+
const written = await writeLocalEvidence({
|
|
18869
|
+
outputDir,
|
|
18870
|
+
runIds,
|
|
18871
|
+
...evidenceSourceContents !== void 0 ? { sourceContents: evidenceSourceContents } : {},
|
|
18872
|
+
...options.dir !== void 0 ? { dir: options.dir } : {},
|
|
18873
|
+
failed,
|
|
18874
|
+
checkResultsJson: checkResultToEvidenceJson(result, runIds),
|
|
18875
|
+
summaryText: `Check status: ${result.status}`,
|
|
18876
|
+
redactionProfile,
|
|
18877
|
+
format: evidenceFormat
|
|
18878
|
+
});
|
|
18879
|
+
if (!options.json) {
|
|
18880
|
+
console.log(`Evidence: ${written}`);
|
|
18881
|
+
}
|
|
18882
|
+
} catch (error) {
|
|
18883
|
+
console.error(
|
|
18884
|
+
`[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
|
|
18885
|
+
);
|
|
18886
|
+
}
|
|
18887
|
+
}
|
|
18453
18888
|
if (options.json) printJson(result);
|
|
18454
|
-
else printHuman(result);
|
|
18889
|
+
else printHuman(result, options);
|
|
18455
18890
|
}
|
|
18456
18891
|
|
|
18457
18892
|
// packages/viewer/src/server.ts
|
|
@@ -18608,7 +19043,7 @@ async function loadSuiteViewerData(options) {
|
|
|
18608
19043
|
for (const suiteCase of result.cases) {
|
|
18609
19044
|
cases.push(await enrichCase(suiteCase, baselinePath));
|
|
18610
19045
|
}
|
|
18611
|
-
const artifactsDir =
|
|
19046
|
+
const artifactsDir = path32__default.default.join(path32__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
|
|
18612
19047
|
return {
|
|
18613
19048
|
suiteName: result.suiteName,
|
|
18614
19049
|
configPath: result.configPath,
|
|
@@ -18804,19 +19239,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
18804
19239
|
}
|
|
18805
19240
|
var INDEX_DIR_NAME = "index";
|
|
18806
19241
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
18807
|
-
const projectRoot =
|
|
18808
|
-
const workspaceDir =
|
|
19242
|
+
const projectRoot = path32__default.default.resolve(cwd);
|
|
19243
|
+
const workspaceDir = path32__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
18809
19244
|
return {
|
|
18810
19245
|
projectRoot,
|
|
18811
19246
|
workspaceDir,
|
|
18812
|
-
manifestPath:
|
|
19247
|
+
manifestPath: path32__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
18813
19248
|
};
|
|
18814
19249
|
}
|
|
18815
19250
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
18816
|
-
const base =
|
|
18817
|
-
const resolved =
|
|
18818
|
-
const rel =
|
|
18819
|
-
if (rel === "" || rel === "." || !rel.startsWith("..") && !
|
|
19251
|
+
const base = path32__default.default.resolve(workspaceDir);
|
|
19252
|
+
const resolved = path32__default.default.resolve(base, relative);
|
|
19253
|
+
const rel = path32__default.default.relative(base, resolved);
|
|
19254
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path32__default.default.isAbsolute(rel)) {
|
|
18820
19255
|
return resolved;
|
|
18821
19256
|
}
|
|
18822
19257
|
throw new Error(
|
|
@@ -18885,7 +19320,7 @@ async function createWorkspace(options = {}) {
|
|
|
18885
19320
|
created = false;
|
|
18886
19321
|
adopted = true;
|
|
18887
19322
|
} else {
|
|
18888
|
-
const project = options.project?.trim() ||
|
|
19323
|
+
const project = options.project?.trim() || path32__default.default.basename(location.projectRoot) || "workspace";
|
|
18889
19324
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
18890
19325
|
manifest = createDefaultWorkspaceManifest({
|
|
18891
19326
|
project,
|
|
@@ -19024,7 +19459,7 @@ async function doctorWorkspace(location) {
|
|
|
19024
19459
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
19025
19460
|
for (const file of await listJsonl(abs)) {
|
|
19026
19461
|
try {
|
|
19027
|
-
const s = await promises.stat(
|
|
19462
|
+
const s = await promises.stat(path32__default.default.join(abs, file));
|
|
19028
19463
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
19029
19464
|
} catch {
|
|
19030
19465
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -19072,7 +19507,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
19072
19507
|
const relPath = `${rel}/${entry}`;
|
|
19073
19508
|
removed.push(relPath);
|
|
19074
19509
|
if (!dryRun) {
|
|
19075
|
-
await promises.rm(
|
|
19510
|
+
await promises.rm(path32__default.default.join(abs, entry), { recursive: true, force: true });
|
|
19076
19511
|
}
|
|
19077
19512
|
}
|
|
19078
19513
|
}
|
|
@@ -19081,7 +19516,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
19081
19516
|
|
|
19082
19517
|
// packages/viewer/src/workspace-data.ts
|
|
19083
19518
|
async function loadWorkspaceViewerData(options) {
|
|
19084
|
-
const cwd =
|
|
19519
|
+
const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
|
|
19085
19520
|
const location = resolveWorkspaceLocation(cwd);
|
|
19086
19521
|
const manifestRead = await readWorkspaceManifestFile(location);
|
|
19087
19522
|
if (!manifestRead.ok || manifestRead.manifest === void 0) {
|
|
@@ -19094,7 +19529,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
19094
19529
|
const runs = [];
|
|
19095
19530
|
for (const rel of manifestRead.manifest.traceDirs) {
|
|
19096
19531
|
const traceDir = resolveTraceDir({
|
|
19097
|
-
dir:
|
|
19532
|
+
dir: path32__default.default.join(location.workspaceDir, rel)
|
|
19098
19533
|
});
|
|
19099
19534
|
const td = new TraceDirectory({ dir: traceDir });
|
|
19100
19535
|
const files = await td.list();
|
|
@@ -19108,7 +19543,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
19108
19543
|
runId: meta2.runId,
|
|
19109
19544
|
...meta2.name !== void 0 ? { name: meta2.name } : {},
|
|
19110
19545
|
status: meta2.status,
|
|
19111
|
-
file:
|
|
19546
|
+
file: path32__default.default.basename(meta2.filePath)
|
|
19112
19547
|
});
|
|
19113
19548
|
}
|
|
19114
19549
|
}
|
|
@@ -19119,8 +19554,8 @@ async function loadWorkspaceViewerData(options) {
|
|
|
19119
19554
|
doctor,
|
|
19120
19555
|
runs,
|
|
19121
19556
|
bundleDirs: [
|
|
19122
|
-
|
|
19123
|
-
|
|
19557
|
+
path32__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
|
|
19558
|
+
path32__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
|
|
19124
19559
|
]
|
|
19125
19560
|
};
|
|
19126
19561
|
}
|
|
@@ -19183,7 +19618,7 @@ function createViewerServer(options = {}) {
|
|
|
19183
19618
|
ok: true,
|
|
19184
19619
|
readOnly: true,
|
|
19185
19620
|
mode,
|
|
19186
|
-
traceDir:
|
|
19621
|
+
traceDir: path32__default.default.resolve(traceDir)
|
|
19187
19622
|
});
|
|
19188
19623
|
}
|
|
19189
19624
|
if (pathname === "/api/suite" && mode === "suite") {
|
|
@@ -19212,7 +19647,7 @@ function createViewerServer(options = {}) {
|
|
|
19212
19647
|
runId: meta2.runId,
|
|
19213
19648
|
name: meta2.name,
|
|
19214
19649
|
status: meta2.status,
|
|
19215
|
-
file:
|
|
19650
|
+
file: path32__default.default.basename(meta2.filePath),
|
|
19216
19651
|
startedAt: meta2.startedAt,
|
|
19217
19652
|
durationMs: meta2.durationMs
|
|
19218
19653
|
}))
|
|
@@ -19329,7 +19764,7 @@ function startViewerServer(options = {}) {
|
|
|
19329
19764
|
resolve({
|
|
19330
19765
|
host,
|
|
19331
19766
|
port: resolvedPort,
|
|
19332
|
-
traceDir:
|
|
19767
|
+
traceDir: path32__default.default.resolve(traceDir),
|
|
19333
19768
|
url: `http://${host}:${resolvedPort}/${modeQuery}`,
|
|
19334
19769
|
mode
|
|
19335
19770
|
});
|
|
@@ -19700,10 +20135,10 @@ async function evalRun(input3, options = {}) {
|
|
|
19700
20135
|
diagnostics: []
|
|
19701
20136
|
};
|
|
19702
20137
|
}
|
|
19703
|
-
function evidenceForRun(run,
|
|
19704
|
-
return [{ runId: run.runId, ...
|
|
20138
|
+
function evidenceForRun(run, path43) {
|
|
20139
|
+
return [{ runId: run.runId, ...path43 !== void 0 ? { path: path43 } : {} }];
|
|
19705
20140
|
}
|
|
19706
|
-
function evidenceForEvent(event,
|
|
20141
|
+
function evidenceForEvent(event, path43) {
|
|
19707
20142
|
return [
|
|
19708
20143
|
{
|
|
19709
20144
|
runId: event.runId,
|
|
@@ -19711,7 +20146,7 @@ function evidenceForEvent(event, path41) {
|
|
|
19711
20146
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
19712
20147
|
kind: event.kind,
|
|
19713
20148
|
name: event.name,
|
|
19714
|
-
...
|
|
20149
|
+
...path43 !== void 0 ? { path: path43 } : {}
|
|
19715
20150
|
}
|
|
19716
20151
|
];
|
|
19717
20152
|
}
|
|
@@ -19869,9 +20304,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
19869
20304
|
function tokenize(text) {
|
|
19870
20305
|
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));
|
|
19871
20306
|
}
|
|
19872
|
-
function firstEvidence(fields, run,
|
|
20307
|
+
function firstEvidence(fields, run, path43) {
|
|
19873
20308
|
const first = fields[0];
|
|
19874
|
-
return first === void 0 ? evidenceForRun(run,
|
|
20309
|
+
return first === void 0 ? evidenceForRun(run, path43) : evidenceForEvent(first.node.event, first.path);
|
|
19875
20310
|
}
|
|
19876
20311
|
function collectSourceIds(nodes, keys) {
|
|
19877
20312
|
const wanted = keySet(keys);
|
|
@@ -20248,8 +20683,8 @@ function renderEvalMarkdown(result) {
|
|
|
20248
20683
|
if (result.findings.length > 0) {
|
|
20249
20684
|
lines.push("", "## Findings");
|
|
20250
20685
|
for (const finding of result.findings) {
|
|
20251
|
-
const
|
|
20252
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
20686
|
+
const path43 = finding.evidence[0]?.path;
|
|
20687
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
20253
20688
|
}
|
|
20254
20689
|
}
|
|
20255
20690
|
return `${lines.join("\n")}
|
|
@@ -20296,7 +20731,7 @@ function asConfig2(value) {
|
|
|
20296
20731
|
}
|
|
20297
20732
|
async function loadConfig2(configPath) {
|
|
20298
20733
|
if (configPath === void 0) return {};
|
|
20299
|
-
const extension =
|
|
20734
|
+
const extension = path32__default.default.extname(configPath);
|
|
20300
20735
|
if (TS_CONFIG_EXTENSIONS3.has(extension)) {
|
|
20301
20736
|
throw new Error(
|
|
20302
20737
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -20305,7 +20740,7 @@ async function loadConfig2(configPath) {
|
|
|
20305
20740
|
if (!CONFIG_EXTENSIONS3.has(extension)) {
|
|
20306
20741
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
20307
20742
|
}
|
|
20308
|
-
const absolute =
|
|
20743
|
+
const absolute = path32__default.default.resolve(configPath);
|
|
20309
20744
|
if (extension === ".json") {
|
|
20310
20745
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
20311
20746
|
return asConfig2(JSON.parse(raw));
|
|
@@ -20442,8 +20877,8 @@ function printHuman2(result) {
|
|
|
20442
20877
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
20443
20878
|
}
|
|
20444
20879
|
for (const finding of result.findings) {
|
|
20445
|
-
const
|
|
20446
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
20880
|
+
const path43 = finding.evidence[0]?.path;
|
|
20881
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
20447
20882
|
}
|
|
20448
20883
|
}
|
|
20449
20884
|
function readErrorResult2(error) {
|
|
@@ -20696,14 +21131,14 @@ function exitCodeFor3(result) {
|
|
|
20696
21131
|
return 2;
|
|
20697
21132
|
}
|
|
20698
21133
|
function explainFinding(finding, blocksBundle) {
|
|
20699
|
-
const
|
|
21134
|
+
const path43 = finding.evidence[0]?.path ?? "(unknown path)";
|
|
20700
21135
|
const category = finding.category ?? "structure";
|
|
20701
21136
|
const confidence = finding.confidence ?? "medium";
|
|
20702
21137
|
const detector = finding.detector ?? finding.ruleId;
|
|
20703
21138
|
const action = finding.action ?? "review";
|
|
20704
21139
|
const redactionHint = category === "credential" || category === "personal-data" || category === "raw-content" || action.includes("redact") ? "Usually removable by share/strict redaction before bundling." : "May require omitting the field, lowering limits, or an explicit local override.";
|
|
20705
21140
|
return [
|
|
20706
|
-
` Matched: detector=${detector}; path=${
|
|
21141
|
+
` Matched: detector=${detector}; path=${path43}; category=${category}`,
|
|
20707
21142
|
` Why: ${finding.message}`,
|
|
20708
21143
|
` Confidence: ${confidence}`,
|
|
20709
21144
|
` Redaction: ${redactionHint}`,
|
|
@@ -20745,9 +21180,9 @@ function printHuman3(result, explain = false) {
|
|
|
20745
21180
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
20746
21181
|
}
|
|
20747
21182
|
for (const finding of result.findings) {
|
|
20748
|
-
const
|
|
21183
|
+
const path43 = finding.evidence[0]?.path;
|
|
20749
21184
|
const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
|
|
20750
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
21185
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}${taxonomy}`);
|
|
20751
21186
|
if (explain) {
|
|
20752
21187
|
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
20753
21188
|
for (const line of explainFinding(finding, blocks)) {
|
|
@@ -20862,91 +21297,6 @@ function messageStartsWithDash(error) {
|
|
|
20862
21297
|
return message.startsWith("--");
|
|
20863
21298
|
}
|
|
20864
21299
|
init_advanced();
|
|
20865
|
-
function validateReporterArtifactPath(options) {
|
|
20866
|
-
const outputDir = path30__default.default.resolve(options.outputDir);
|
|
20867
|
-
const diagnostics = [];
|
|
20868
|
-
const rawPath = options.relativePath;
|
|
20869
|
-
if (rawPath.length === 0) {
|
|
20870
|
-
diagnostics.push({
|
|
20871
|
-
code: "artifact_path_empty",
|
|
20872
|
-
severity: "error",
|
|
20873
|
-
message: "Reporter artifact path must not be empty."
|
|
20874
|
-
});
|
|
20875
|
-
return { ok: false, outputDir, diagnostics };
|
|
20876
|
-
}
|
|
20877
|
-
if (rawPath.includes("\0")) {
|
|
20878
|
-
diagnostics.push({
|
|
20879
|
-
code: "invalid_artifact_path",
|
|
20880
|
-
severity: "error",
|
|
20881
|
-
message: "Reporter artifact path must not contain null bytes.",
|
|
20882
|
-
target: rawPath
|
|
20883
|
-
});
|
|
20884
|
-
return { ok: false, outputDir, diagnostics };
|
|
20885
|
-
}
|
|
20886
|
-
if (path30__default.default.isAbsolute(rawPath) || path30__default.default.win32.isAbsolute(rawPath)) {
|
|
20887
|
-
diagnostics.push({
|
|
20888
|
-
code: "artifact_path_absolute",
|
|
20889
|
-
severity: "error",
|
|
20890
|
-
message: "Reporter artifact path must be relative.",
|
|
20891
|
-
target: rawPath
|
|
20892
|
-
});
|
|
20893
|
-
return { ok: false, outputDir, diagnostics };
|
|
20894
|
-
}
|
|
20895
|
-
const normalized = path30__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
20896
|
-
const segments = normalized.split("/");
|
|
20897
|
-
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
20898
|
-
diagnostics.push({
|
|
20899
|
-
code: "artifact_path_escape",
|
|
20900
|
-
severity: "error",
|
|
20901
|
-
message: "Reporter artifact path must stay under the output directory.",
|
|
20902
|
-
target: rawPath
|
|
20903
|
-
});
|
|
20904
|
-
return { ok: false, outputDir, diagnostics };
|
|
20905
|
-
}
|
|
20906
|
-
const absolutePath = path30__default.default.resolve(outputDir, normalized);
|
|
20907
|
-
const relFromOutput = path30__default.default.relative(outputDir, absolutePath);
|
|
20908
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path30__default.default.isAbsolute(relFromOutput)) {
|
|
20909
|
-
diagnostics.push({
|
|
20910
|
-
code: "artifact_path_escape",
|
|
20911
|
-
severity: "error",
|
|
20912
|
-
message: "Reporter artifact path resolved outside the output directory.",
|
|
20913
|
-
target: rawPath
|
|
20914
|
-
});
|
|
20915
|
-
return { ok: false, outputDir, diagnostics };
|
|
20916
|
-
}
|
|
20917
|
-
return {
|
|
20918
|
-
ok: true,
|
|
20919
|
-
outputDir,
|
|
20920
|
-
relativePath: normalized,
|
|
20921
|
-
absolutePath,
|
|
20922
|
-
diagnostics
|
|
20923
|
-
};
|
|
20924
|
-
}
|
|
20925
|
-
var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
20926
|
-
"evidence.html",
|
|
20927
|
-
"evidence.json",
|
|
20928
|
-
"check-results.json",
|
|
20929
|
-
"trace.jsonl"
|
|
20930
|
-
];
|
|
20931
|
-
function createEvidenceCiArtifacts(options) {
|
|
20932
|
-
const profile = options.redactionProfile;
|
|
20933
|
-
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
20934
|
-
const join = (name) => prefix === "" ? name : path30__default.default.posix.join(prefix, name);
|
|
20935
|
-
const formatFor = (name) => {
|
|
20936
|
-
if (name.endsWith(".html")) return "html";
|
|
20937
|
-
if (name.endsWith(".jsonl")) return "jsonl";
|
|
20938
|
-
return "json";
|
|
20939
|
-
};
|
|
20940
|
-
return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
|
|
20941
|
-
kind: "evidence",
|
|
20942
|
-
path: join(name),
|
|
20943
|
-
format: formatFor(name),
|
|
20944
|
-
redactionProfile: profile,
|
|
20945
|
-
title: `Evidence v2 ${name}`
|
|
20946
|
-
}));
|
|
20947
|
-
}
|
|
20948
|
-
|
|
20949
|
-
// packages/cli/src/artifacts.ts
|
|
20950
21300
|
var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
|
|
20951
21301
|
var SAFETY_RULES = [
|
|
20952
21302
|
createSafetyRawContentRule(),
|
|
@@ -21020,8 +21370,8 @@ function renderCheckSection(result) {
|
|
|
21020
21370
|
`Diagnostics: ${result.diagnostics.length}`
|
|
21021
21371
|
];
|
|
21022
21372
|
for (const finding of result.findings.slice(0, 10)) {
|
|
21023
|
-
const
|
|
21024
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
21373
|
+
const path43 = finding.evidence[0]?.path ?? "(run)";
|
|
21374
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path43})`);
|
|
21025
21375
|
}
|
|
21026
21376
|
for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
|
|
21027
21377
|
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
@@ -21099,8 +21449,8 @@ function renderHtml(trace, check, diff) {
|
|
|
21099
21449
|
`;
|
|
21100
21450
|
}
|
|
21101
21451
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
21102
|
-
const outPath =
|
|
21103
|
-
await promises.mkdir(
|
|
21452
|
+
const outPath = path32__default.default.join(outputDir, relativePath);
|
|
21453
|
+
await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
|
|
21104
21454
|
await promises.writeFile(outPath, content, "utf-8");
|
|
21105
21455
|
files.push(relativePath);
|
|
21106
21456
|
}
|
|
@@ -21129,7 +21479,7 @@ function shouldWriteEvidence(options, status) {
|
|
|
21129
21479
|
return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
|
|
21130
21480
|
}
|
|
21131
21481
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
21132
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
21482
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path32__default.default.resolve(options.outputDir.trim()) : "";
|
|
21133
21483
|
if (outputDir === "") {
|
|
21134
21484
|
console.error("--output-dir is required.");
|
|
21135
21485
|
process.exitCode = 1;
|
|
@@ -21269,8 +21619,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
21269
21619
|
}
|
|
21270
21620
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
21271
21621
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
21272
|
-
await promises.mkdir(
|
|
21273
|
-
await promises.appendFile(
|
|
21622
|
+
await promises.mkdir(path32__default.default.dirname(path32__default.default.resolve(summaryTarget)), { recursive: true });
|
|
21623
|
+
await promises.appendFile(path32__default.default.resolve(summaryTarget), `
|
|
21274
21624
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
21275
21625
|
}
|
|
21276
21626
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -21289,10 +21639,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
21289
21639
|
findings: diff?.findings.length ?? 0,
|
|
21290
21640
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
21291
21641
|
},
|
|
21292
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
21642
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path32__default.default.resolve(summaryTarget) } : {},
|
|
21293
21643
|
note: NOTE
|
|
21294
21644
|
};
|
|
21295
|
-
await promises.writeFile(
|
|
21645
|
+
await promises.writeFile(path32__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
21296
21646
|
if (options.json === true) {
|
|
21297
21647
|
console.log(writeJson3(manifest).trimEnd());
|
|
21298
21648
|
} else {
|
|
@@ -21353,8 +21703,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
21353
21703
|
const location = resolveWorkspaceLocation(cwd);
|
|
21354
21704
|
const manifest = await readWorkspaceManifestFile(location);
|
|
21355
21705
|
if (manifest.ok && manifest.manifest) {
|
|
21356
|
-
const rel =
|
|
21357
|
-
if (!rel.startsWith("..") && !
|
|
21706
|
+
const rel = path32__default.default.relative(location.workspaceDir, normalized);
|
|
21707
|
+
if (!rel.startsWith("..") && !path32__default.default.isAbsolute(rel)) {
|
|
21358
21708
|
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
21359
21709
|
}
|
|
21360
21710
|
}
|
|
@@ -21370,7 +21720,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
21370
21720
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
21371
21721
|
const base2 = resolveInsideWorkspace(
|
|
21372
21722
|
location.workspaceDir,
|
|
21373
|
-
|
|
21723
|
+
path32__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
21374
21724
|
);
|
|
21375
21725
|
return format === "zip" ? `${base2}.zip` : base2;
|
|
21376
21726
|
}
|
|
@@ -21775,19 +22125,19 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
21775
22125
|
let sidecarDir = outputDir;
|
|
21776
22126
|
if (outputDir.toLowerCase().endsWith(".html")) {
|
|
21777
22127
|
htmlPath = outputDir;
|
|
21778
|
-
sidecarDir =
|
|
22128
|
+
sidecarDir = path32__default.default.dirname(outputDir);
|
|
21779
22129
|
} else {
|
|
21780
22130
|
await promises.mkdir(outputDir, { recursive: true });
|
|
21781
|
-
htmlPath =
|
|
22131
|
+
htmlPath = path32__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
|
|
21782
22132
|
sidecarDir = outputDir;
|
|
21783
22133
|
}
|
|
21784
22134
|
await promises.mkdir(sidecarDir, { recursive: true });
|
|
21785
22135
|
await promises.writeFile(htmlPath, htmlContent, "utf-8");
|
|
21786
|
-
await promises.writeFile(
|
|
22136
|
+
await promises.writeFile(path32__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
21787
22137
|
outputPath = htmlPath;
|
|
21788
22138
|
} else if (format === "zip") {
|
|
21789
22139
|
const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
|
|
21790
|
-
const zipParent =
|
|
22140
|
+
const zipParent = path32__default.default.dirname(zipPath);
|
|
21791
22141
|
await promises.mkdir(zipParent, { recursive: true });
|
|
21792
22142
|
const entries = [
|
|
21793
22143
|
...[...packaged.entries()].map(([relativePath, content]) => ({
|
|
@@ -21803,10 +22153,10 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
21803
22153
|
await promises.mkdir(outputDir, { recursive: true });
|
|
21804
22154
|
for (const [relativePath, content] of packaged.entries()) {
|
|
21805
22155
|
const outPath = assertBundlePathContained(outputDir, relativePath);
|
|
21806
|
-
await promises.mkdir(
|
|
22156
|
+
await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
|
|
21807
22157
|
await promises.writeFile(outPath, content, "utf-8");
|
|
21808
22158
|
}
|
|
21809
|
-
await promises.writeFile(
|
|
22159
|
+
await promises.writeFile(path32__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
21810
22160
|
if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
|
|
21811
22161
|
files.push(EVIDENCE_MANIFEST_FILENAME);
|
|
21812
22162
|
}
|
|
@@ -21855,7 +22205,7 @@ function writeJson5(value) {
|
|
|
21855
22205
|
`;
|
|
21856
22206
|
}
|
|
21857
22207
|
async function bundleVerifyCommand(targetPath, options = {}) {
|
|
21858
|
-
const root =
|
|
22208
|
+
const root = path32__default.default.resolve(targetPath.trim() || ".");
|
|
21859
22209
|
const result = await verifyEvidenceDirectory(root, {
|
|
21860
22210
|
unexpectedFiles: options.unexpected ?? "fail"
|
|
21861
22211
|
});
|
|
@@ -21888,6 +22238,147 @@ async function bundleVerifyCommand(targetPath, options = {}) {
|
|
|
21888
22238
|
process.exitCode = 1;
|
|
21889
22239
|
}
|
|
21890
22240
|
}
|
|
22241
|
+
|
|
22242
|
+
// packages/cli/src/bundle-open.ts
|
|
22243
|
+
init_advanced();
|
|
22244
|
+
function writeJson6(value) {
|
|
22245
|
+
return `${JSON.stringify(value, null, 2)}
|
|
22246
|
+
`;
|
|
22247
|
+
}
|
|
22248
|
+
async function resolveHtmlPath(root) {
|
|
22249
|
+
const candidates = [
|
|
22250
|
+
path32__default.default.join(root, "evidence.html"),
|
|
22251
|
+
root.toLowerCase().endsWith(".html") ? root : ""
|
|
22252
|
+
].filter(Boolean);
|
|
22253
|
+
for (const candidate of candidates) {
|
|
22254
|
+
try {
|
|
22255
|
+
const info = await promises.stat(candidate);
|
|
22256
|
+
if (info.isFile()) return candidate;
|
|
22257
|
+
} catch {
|
|
22258
|
+
}
|
|
22259
|
+
}
|
|
22260
|
+
throw new Error(
|
|
22261
|
+
`No evidence.html found under ${root}. Pass a bundle directory or .html path.`
|
|
22262
|
+
);
|
|
22263
|
+
}
|
|
22264
|
+
function openLocalFile(filePath) {
|
|
22265
|
+
const fileUrl = url.pathToFileURL(filePath).href;
|
|
22266
|
+
const platform = process.platform;
|
|
22267
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
22268
|
+
const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
22269
|
+
return new Promise((resolve) => {
|
|
22270
|
+
try {
|
|
22271
|
+
const child = child_process.spawn(command, args, {
|
|
22272
|
+
detached: true,
|
|
22273
|
+
stdio: "ignore"
|
|
22274
|
+
});
|
|
22275
|
+
child.on("error", (error) => {
|
|
22276
|
+
resolve({
|
|
22277
|
+
ok: false,
|
|
22278
|
+
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
22279
|
+
});
|
|
22280
|
+
});
|
|
22281
|
+
child.unref();
|
|
22282
|
+
resolve({ ok: true, detail: fileUrl });
|
|
22283
|
+
} catch (error) {
|
|
22284
|
+
resolve({
|
|
22285
|
+
ok: false,
|
|
22286
|
+
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
22287
|
+
});
|
|
22288
|
+
}
|
|
22289
|
+
});
|
|
22290
|
+
}
|
|
22291
|
+
async function bundleOpenCommand(targetPath, options = {}) {
|
|
22292
|
+
const root = path32__default.default.resolve(targetPath.trim() || ".");
|
|
22293
|
+
try {
|
|
22294
|
+
await promises.access(root);
|
|
22295
|
+
} catch {
|
|
22296
|
+
const message = `Evidence path not found: ${root}`;
|
|
22297
|
+
if (options.json) {
|
|
22298
|
+
console.log(writeJson6({ ok: false, error: message }).trimEnd());
|
|
22299
|
+
} else {
|
|
22300
|
+
console.error(`[AgentInspect] ${message}`);
|
|
22301
|
+
}
|
|
22302
|
+
process.exitCode = 1;
|
|
22303
|
+
return;
|
|
22304
|
+
}
|
|
22305
|
+
let verifyRoot = root;
|
|
22306
|
+
try {
|
|
22307
|
+
const info = await promises.stat(root);
|
|
22308
|
+
if (info.isFile() && root.toLowerCase().endsWith(".html")) {
|
|
22309
|
+
verifyRoot = path32__default.default.dirname(root);
|
|
22310
|
+
}
|
|
22311
|
+
} catch {
|
|
22312
|
+
}
|
|
22313
|
+
if (options.skipVerify !== true) {
|
|
22314
|
+
const result = await verifyEvidenceDirectory(verifyRoot, {
|
|
22315
|
+
unexpectedFiles: "fail"
|
|
22316
|
+
});
|
|
22317
|
+
if (!result.ok) {
|
|
22318
|
+
if (options.json) {
|
|
22319
|
+
console.log(
|
|
22320
|
+
writeJson6({
|
|
22321
|
+
ok: false,
|
|
22322
|
+
error: "Evidence verify failed",
|
|
22323
|
+
root: result.root,
|
|
22324
|
+
issues: result.issues
|
|
22325
|
+
}).trimEnd()
|
|
22326
|
+
);
|
|
22327
|
+
} else {
|
|
22328
|
+
console.error(`Evidence verify: fail (${result.issues.length} issue(s))`);
|
|
22329
|
+
for (const issue of result.issues) {
|
|
22330
|
+
console.error(`- [${issue.severity}] ${issue.code}: ${issue.message}`);
|
|
22331
|
+
}
|
|
22332
|
+
console.error("Fix integrity issues or pass --skip-verify (not recommended).");
|
|
22333
|
+
}
|
|
22334
|
+
process.exitCode = 1;
|
|
22335
|
+
return;
|
|
22336
|
+
}
|
|
22337
|
+
}
|
|
22338
|
+
let htmlPath;
|
|
22339
|
+
try {
|
|
22340
|
+
htmlPath = await resolveHtmlPath(
|
|
22341
|
+
root.toLowerCase().endsWith(".html") ? path32__default.default.dirname(root) : root
|
|
22342
|
+
);
|
|
22343
|
+
if (root.toLowerCase().endsWith(".html")) {
|
|
22344
|
+
htmlPath = root;
|
|
22345
|
+
}
|
|
22346
|
+
} catch (error) {
|
|
22347
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22348
|
+
if (options.json) {
|
|
22349
|
+
console.log(writeJson6({ ok: false, error: message }).trimEnd());
|
|
22350
|
+
} else {
|
|
22351
|
+
console.error(`[AgentInspect] ${message}`);
|
|
22352
|
+
}
|
|
22353
|
+
process.exitCode = 1;
|
|
22354
|
+
return;
|
|
22355
|
+
}
|
|
22356
|
+
try {
|
|
22357
|
+
await promises.readFile(path32__default.default.join(path32__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
22358
|
+
} catch {
|
|
22359
|
+
}
|
|
22360
|
+
const opened = await openLocalFile(htmlPath);
|
|
22361
|
+
if (options.json) {
|
|
22362
|
+
console.log(
|
|
22363
|
+
writeJson6({
|
|
22364
|
+
ok: opened.ok,
|
|
22365
|
+
path: htmlPath,
|
|
22366
|
+
opened: opened.ok,
|
|
22367
|
+
detail: opened.detail
|
|
22368
|
+
}).trimEnd()
|
|
22369
|
+
);
|
|
22370
|
+
} else if (opened.ok) {
|
|
22371
|
+
console.log(`Opened local Evidence: ${htmlPath}`);
|
|
22372
|
+
console.log(`URL: ${opened.detail}`);
|
|
22373
|
+
} else {
|
|
22374
|
+
console.error(`[AgentInspect] Could not open browser automatically.`);
|
|
22375
|
+
console.error(`Open this file locally: ${htmlPath}`);
|
|
22376
|
+
console.error(opened.detail);
|
|
22377
|
+
}
|
|
22378
|
+
if (!opened.ok) {
|
|
22379
|
+
process.exitCode = 0;
|
|
22380
|
+
}
|
|
22381
|
+
}
|
|
21891
22382
|
var CLIENTS = [
|
|
21892
22383
|
"cursor",
|
|
21893
22384
|
"claude-code",
|
|
@@ -21948,24 +22439,24 @@ function resolveTargetPath(client, projectLocal) {
|
|
|
21948
22439
|
if (projectLocal) {
|
|
21949
22440
|
switch (client) {
|
|
21950
22441
|
case "cursor":
|
|
21951
|
-
return
|
|
22442
|
+
return path32__default.default.join(".cursor", "mcp.json");
|
|
21952
22443
|
case "claude-code":
|
|
21953
|
-
return
|
|
22444
|
+
return path32__default.default.join(".mcp.json");
|
|
21954
22445
|
case "codex":
|
|
21955
|
-
return
|
|
22446
|
+
return path32__default.default.join(".codex", "config.toml.json");
|
|
21956
22447
|
case "gemini":
|
|
21957
|
-
return
|
|
22448
|
+
return path32__default.default.join(".gemini", "settings.json");
|
|
21958
22449
|
}
|
|
21959
22450
|
}
|
|
21960
22451
|
switch (client) {
|
|
21961
22452
|
case "cursor":
|
|
21962
|
-
return
|
|
22453
|
+
return path32__default.default.join("~", ".cursor", "mcp.json");
|
|
21963
22454
|
case "claude-code":
|
|
21964
|
-
return
|
|
22455
|
+
return path32__default.default.join("~", ".claude.json");
|
|
21965
22456
|
case "codex":
|
|
21966
|
-
return
|
|
22457
|
+
return path32__default.default.join("~", ".codex", "config.toml");
|
|
21967
22458
|
case "gemini":
|
|
21968
|
-
return
|
|
22459
|
+
return path32__default.default.join("~", ".gemini", "settings.json");
|
|
21969
22460
|
}
|
|
21970
22461
|
}
|
|
21971
22462
|
async function mcpConfigureCommand(options) {
|
|
@@ -21989,8 +22480,8 @@ async function mcpConfigureCommand(options) {
|
|
|
21989
22480
|
];
|
|
21990
22481
|
let wrote = false;
|
|
21991
22482
|
if (!dryRun && projectLocal) {
|
|
21992
|
-
const abs =
|
|
21993
|
-
await promises.mkdir(
|
|
22483
|
+
const abs = path32__default.default.resolve(targetPath);
|
|
22484
|
+
await promises.mkdir(path32__default.default.dirname(abs), { recursive: true });
|
|
21994
22485
|
await promises.writeFile(abs, `${JSON.stringify(config, null, 2)}
|
|
21995
22486
|
`, "utf8");
|
|
21996
22487
|
wrote = true;
|
|
@@ -22038,7 +22529,7 @@ function stable8(value) {
|
|
|
22038
22529
|
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable8(record[key])])
|
|
22039
22530
|
);
|
|
22040
22531
|
}
|
|
22041
|
-
function
|
|
22532
|
+
function writeJson7(value) {
|
|
22042
22533
|
return `${JSON.stringify(stable8(value), null, 2)}
|
|
22043
22534
|
`;
|
|
22044
22535
|
}
|
|
@@ -22150,23 +22641,23 @@ function readManifestDocument(value) {
|
|
|
22150
22641
|
};
|
|
22151
22642
|
}
|
|
22152
22643
|
function cwdRelative(filePath) {
|
|
22153
|
-
const relative =
|
|
22154
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
22155
|
-
return
|
|
22644
|
+
const relative = path32__default.default.relative(process.cwd(), path32__default.default.resolve(filePath)).replace(/\\/g, "/");
|
|
22645
|
+
if (relative === "" || relative.startsWith("../") || path32__default.default.isAbsolute(relative)) {
|
|
22646
|
+
return path32__default.default.basename(filePath);
|
|
22156
22647
|
}
|
|
22157
22648
|
return relative;
|
|
22158
22649
|
}
|
|
22159
22650
|
async function readReporterManifest(filePath) {
|
|
22160
|
-
const absolute =
|
|
22651
|
+
const absolute = path32__default.default.resolve(filePath);
|
|
22161
22652
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
22162
22653
|
const document = readManifestDocument(JSON.parse(raw));
|
|
22163
22654
|
const manifest = document.manifest;
|
|
22164
22655
|
const results = manifest.results.map((result) => ({
|
|
22165
22656
|
testId: safeText(result.testId),
|
|
22166
22657
|
name: safeText(result.name),
|
|
22167
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
22658
|
+
...result.file === void 0 ? {} : { file: safeText(path32__default.default.basename(result.file)) },
|
|
22168
22659
|
status: result.status,
|
|
22169
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
22660
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path32__default.default.basename(result.tracePath)) },
|
|
22170
22661
|
artifacts: result.artifacts,
|
|
22171
22662
|
diagnostics: result.diagnostics
|
|
22172
22663
|
}));
|
|
@@ -22305,20 +22796,20 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
22305
22796
|
return;
|
|
22306
22797
|
}
|
|
22307
22798
|
const markdown = renderMarkdown2(result);
|
|
22308
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
22799
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path32__default.default.resolve(options.output.trim()) : void 0;
|
|
22309
22800
|
if (outputPath !== void 0) {
|
|
22310
|
-
await promises.mkdir(
|
|
22801
|
+
await promises.mkdir(path32__default.default.dirname(outputPath), { recursive: true });
|
|
22311
22802
|
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
22312
22803
|
}
|
|
22313
22804
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
22314
22805
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
22315
|
-
const summaryPath =
|
|
22316
|
-
await promises.mkdir(
|
|
22806
|
+
const summaryPath = path32__default.default.resolve(summaryTarget);
|
|
22807
|
+
await promises.mkdir(path32__default.default.dirname(summaryPath), { recursive: true });
|
|
22317
22808
|
await promises.appendFile(summaryPath, `
|
|
22318
22809
|
${markdown}`, "utf-8");
|
|
22319
22810
|
}
|
|
22320
22811
|
if (options.json === true) {
|
|
22321
|
-
console.log(
|
|
22812
|
+
console.log(writeJson7(result).trimEnd());
|
|
22322
22813
|
} else if (outputPath !== void 0) {
|
|
22323
22814
|
console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
|
|
22324
22815
|
console.log(`Status: ${result.status}`);
|
|
@@ -22456,7 +22947,7 @@ console.log("Trace written to .agent-inspect/");
|
|
|
22456
22947
|
`;
|
|
22457
22948
|
}
|
|
22458
22949
|
}
|
|
22459
|
-
function githubWorkflowTemplate() {
|
|
22950
|
+
function githubWorkflowTemplate(demoPath) {
|
|
22460
22951
|
return `name: AgentInspect artifacts
|
|
22461
22952
|
|
|
22462
22953
|
on:
|
|
@@ -22473,19 +22964,32 @@ jobs:
|
|
|
22473
22964
|
with:
|
|
22474
22965
|
node-version: "22"
|
|
22475
22966
|
- run: npm ci
|
|
22476
|
-
-
|
|
22477
|
-
|
|
22967
|
+
- name: Run deterministic agent fixture
|
|
22968
|
+
run: node ${demoPath}
|
|
22969
|
+
- name: Trajectory check with Evidence on failure
|
|
22970
|
+
run: >
|
|
22971
|
+
npx --yes agent-inspect check --dir .agent-inspect
|
|
22972
|
+
--preset trajectory
|
|
22973
|
+
--evidence-on fail
|
|
22974
|
+
--evidence-profile share
|
|
22975
|
+
--evidence-format directory
|
|
22976
|
+
- name: Verify share safety
|
|
22977
|
+
if: always()
|
|
22978
|
+
run: npx --yes agent-inspect verify-safe . --dir .agent-inspect
|
|
22979
|
+
- name: Upload AgentInspect traces and Evidence
|
|
22478
22980
|
if: always()
|
|
22479
22981
|
uses: actions/upload-artifact@v4
|
|
22480
22982
|
with:
|
|
22481
22983
|
name: agent-inspect-traces
|
|
22482
|
-
path:
|
|
22984
|
+
path: |
|
|
22985
|
+
.agent-inspect/**/*.jsonl
|
|
22986
|
+
.agent-inspect/evidence/**
|
|
22483
22987
|
if-no-files-found: ignore
|
|
22484
22988
|
`;
|
|
22485
22989
|
}
|
|
22486
22990
|
async function planInit(options = {}) {
|
|
22487
22991
|
const framework = normalizeFramework(options.framework);
|
|
22488
|
-
const cwd =
|
|
22992
|
+
const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
|
|
22489
22993
|
const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
|
|
22490
22994
|
const candidates = [
|
|
22491
22995
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
@@ -22495,12 +22999,12 @@ async function planInit(options = {}) {
|
|
|
22495
22999
|
if (options.ci === "github") {
|
|
22496
23000
|
candidates.push({
|
|
22497
23001
|
rel: ".github/workflows/agent-inspect-artifacts.yml",
|
|
22498
|
-
content: githubWorkflowTemplate()
|
|
23002
|
+
content: githubWorkflowTemplate(demoPath)
|
|
22499
23003
|
});
|
|
22500
23004
|
}
|
|
22501
23005
|
const files = [];
|
|
22502
23006
|
for (const candidate of candidates) {
|
|
22503
|
-
const abs =
|
|
23007
|
+
const abs = path32__default.default.join(cwd, candidate.rel);
|
|
22504
23008
|
try {
|
|
22505
23009
|
await promises.access(abs);
|
|
22506
23010
|
files.push({
|
|
@@ -22521,20 +23025,21 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
22521
23025
|
if (entry.action === "skip") {
|
|
22522
23026
|
continue;
|
|
22523
23027
|
}
|
|
22524
|
-
const abs =
|
|
23028
|
+
const abs = path32__default.default.join(cwd, entry.path);
|
|
22525
23029
|
if (options.dryRun) {
|
|
22526
23030
|
written.push(entry.path);
|
|
22527
23031
|
continue;
|
|
22528
23032
|
}
|
|
22529
|
-
await promises.mkdir(
|
|
22530
|
-
const
|
|
23033
|
+
await promises.mkdir(path32__default.default.dirname(abs), { recursive: true });
|
|
23034
|
+
const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
|
|
23035
|
+
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
|
|
22531
23036
|
await promises.writeFile(abs, content, "utf-8");
|
|
22532
23037
|
written.push(entry.path);
|
|
22533
23038
|
}
|
|
22534
23039
|
return written;
|
|
22535
23040
|
}
|
|
22536
23041
|
async function initCommand(options = {}) {
|
|
22537
|
-
const cwd =
|
|
23042
|
+
const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
|
|
22538
23043
|
try {
|
|
22539
23044
|
const plan = await planInit({ ...options, cwd });
|
|
22540
23045
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -22626,7 +23131,7 @@ function envCheck(name, optional = true) {
|
|
|
22626
23131
|
};
|
|
22627
23132
|
}
|
|
22628
23133
|
async function traceDirWritable(traceDir) {
|
|
22629
|
-
const resolved =
|
|
23134
|
+
const resolved = path32__default.default.resolve(traceDir);
|
|
22630
23135
|
try {
|
|
22631
23136
|
await promises.mkdir(resolved, { recursive: true });
|
|
22632
23137
|
await promises.access(resolved, promises.constants.W_OK);
|
|
@@ -22647,10 +23152,10 @@ async function traceDirWritable(traceDir) {
|
|
|
22647
23152
|
}
|
|
22648
23153
|
}
|
|
22649
23154
|
function readPackageVersionNearEntry(entryPath, packageName) {
|
|
22650
|
-
let dir =
|
|
22651
|
-
const { root } =
|
|
23155
|
+
let dir = path32__default.default.dirname(path32__default.default.resolve(entryPath));
|
|
23156
|
+
const { root } = path32__default.default.parse(dir);
|
|
22652
23157
|
while (true) {
|
|
22653
|
-
const candidate =
|
|
23158
|
+
const candidate = path32__default.default.join(dir, "package.json");
|
|
22654
23159
|
if (fs.existsSync(candidate)) {
|
|
22655
23160
|
try {
|
|
22656
23161
|
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
@@ -22661,14 +23166,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
|
|
|
22661
23166
|
}
|
|
22662
23167
|
}
|
|
22663
23168
|
if (dir === root) break;
|
|
22664
|
-
const parent =
|
|
23169
|
+
const parent = path32__default.default.dirname(dir);
|
|
22665
23170
|
if (parent === dir) break;
|
|
22666
23171
|
dir = parent;
|
|
22667
23172
|
}
|
|
22668
23173
|
return void 0;
|
|
22669
23174
|
}
|
|
22670
23175
|
function resolveInstalledPackage(cwd, name) {
|
|
22671
|
-
const require2 = module$1.createRequire(
|
|
23176
|
+
const require2 = module$1.createRequire(path32__default.default.join(cwd, "package.json"));
|
|
22672
23177
|
try {
|
|
22673
23178
|
const entry = require2.resolve(name);
|
|
22674
23179
|
let version2;
|
|
@@ -22766,7 +23271,7 @@ function versionMismatchCheck(cwd) {
|
|
|
22766
23271
|
};
|
|
22767
23272
|
}
|
|
22768
23273
|
async function runDoctorChecks(options = {}) {
|
|
22769
|
-
const cwd =
|
|
23274
|
+
const cwd = path32__default.default.resolve(options.cwd ?? process3__default.default.cwd());
|
|
22770
23275
|
const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
22771
23276
|
const checks2 = [
|
|
22772
23277
|
nodeVersionCheck(),
|
|
@@ -23006,7 +23511,7 @@ function parsePluginManifest(input3) {
|
|
|
23006
23511
|
};
|
|
23007
23512
|
}
|
|
23008
23513
|
async function readPluginManifestFile(packageDir) {
|
|
23009
|
-
const manifestPath =
|
|
23514
|
+
const manifestPath = path32__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
|
|
23010
23515
|
try {
|
|
23011
23516
|
const raw = await promises.readFile(manifestPath, "utf8");
|
|
23012
23517
|
const parsed = parsePluginManifest(JSON.parse(raw));
|
|
@@ -23081,7 +23586,7 @@ function createTraceDirectoryIndexer() {
|
|
|
23081
23586
|
// packages/cli/src/plugins.ts
|
|
23082
23587
|
async function readPackageName(packageDir) {
|
|
23083
23588
|
try {
|
|
23084
|
-
const raw = await promises.readFile(
|
|
23589
|
+
const raw = await promises.readFile(path32__default.default.join(packageDir, "package.json"), "utf8");
|
|
23085
23590
|
const parsed = JSON.parse(raw);
|
|
23086
23591
|
return typeof parsed.name === "string" ? parsed.name : void 0;
|
|
23087
23592
|
} catch {
|
|
@@ -23089,7 +23594,7 @@ async function readPackageName(packageDir) {
|
|
|
23089
23594
|
}
|
|
23090
23595
|
}
|
|
23091
23596
|
async function discoverPlugins(cwd = process.cwd()) {
|
|
23092
|
-
const nodeModules =
|
|
23597
|
+
const nodeModules = path32__default.default.join(cwd, "node_modules");
|
|
23093
23598
|
const found = [];
|
|
23094
23599
|
let entries;
|
|
23095
23600
|
try {
|
|
@@ -23100,7 +23605,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
23100
23605
|
for (const entry of entries.sort()) {
|
|
23101
23606
|
if (entry.startsWith("@")) continue;
|
|
23102
23607
|
if (!isPluginPackageName(entry)) continue;
|
|
23103
|
-
const packageDir =
|
|
23608
|
+
const packageDir = path32__default.default.join(nodeModules, entry);
|
|
23104
23609
|
const manifestRead = await readPluginManifestFile(packageDir);
|
|
23105
23610
|
found.push({
|
|
23106
23611
|
packageName: entry,
|
|
@@ -23113,7 +23618,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
23113
23618
|
return found;
|
|
23114
23619
|
}
|
|
23115
23620
|
async function validatePluginPackage(packageRef, cwd = process.cwd()) {
|
|
23116
|
-
const packageDir =
|
|
23621
|
+
const packageDir = path32__default.default.isAbsolute(packageRef) ? packageRef : path32__default.default.join(cwd, "node_modules", packageRef);
|
|
23117
23622
|
const packageName = await readPackageName(packageDir) ?? packageRef;
|
|
23118
23623
|
const errors = [];
|
|
23119
23624
|
const warnings = [];
|
|
@@ -23190,7 +23695,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
|
|
|
23190
23695
|
init_advanced();
|
|
23191
23696
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
23192
23697
|
function traceIndexPath(traceDir) {
|
|
23193
|
-
return
|
|
23698
|
+
return path32__default.default.join(traceDir, INDEX_FILENAME);
|
|
23194
23699
|
}
|
|
23195
23700
|
function parseMaxEntries(raw) {
|
|
23196
23701
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -23336,7 +23841,7 @@ async function newestTraceMtimeMs2(traceDir) {
|
|
|
23336
23841
|
for (const file of files) {
|
|
23337
23842
|
if (!file.endsWith(".jsonl")) continue;
|
|
23338
23843
|
try {
|
|
23339
|
-
const s = await promises.stat(
|
|
23844
|
+
const s = await promises.stat(path32__default.default.join(traceDir, file));
|
|
23340
23845
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
23341
23846
|
} catch {
|
|
23342
23847
|
}
|
|
@@ -23591,11 +24096,11 @@ function printJson5(value) {
|
|
|
23591
24096
|
console.log(JSON.stringify(value, null, 2));
|
|
23592
24097
|
}
|
|
23593
24098
|
function resolveCwd(options) {
|
|
23594
|
-
return
|
|
24099
|
+
return path32__default.default.resolve(options.cwd ?? process.cwd());
|
|
23595
24100
|
}
|
|
23596
24101
|
async function suiteInitCommand(options = {}) {
|
|
23597
24102
|
const cwd = resolveCwd(options);
|
|
23598
|
-
const configPath =
|
|
24103
|
+
const configPath = path32__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
23599
24104
|
const template = options.template?.trim();
|
|
23600
24105
|
const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
|
|
23601
24106
|
if (options.dryRun) {
|
|
@@ -23714,13 +24219,13 @@ async function suiteListCommand(options = {}) {
|
|
|
23714
24219
|
}
|
|
23715
24220
|
async function writeSuiteArtifact(result, configOutputDir, options) {
|
|
23716
24221
|
const cwd = resolveCwd(options);
|
|
23717
|
-
const outputDir =
|
|
24222
|
+
const outputDir = path32__default.default.resolve(
|
|
23718
24223
|
cwd,
|
|
23719
24224
|
options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
|
|
23720
24225
|
);
|
|
23721
24226
|
await promises.mkdir(outputDir, { recursive: true });
|
|
23722
24227
|
const stamp = result.startedAt.replace(/[:.]/g, "-");
|
|
23723
|
-
const filePath =
|
|
24228
|
+
const filePath = path32__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
|
|
23724
24229
|
await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
|
|
23725
24230
|
`, "utf-8");
|
|
23726
24231
|
return filePath;
|
|
@@ -23778,7 +24283,7 @@ async function loadSuiteResultFromInput(options) {
|
|
|
23778
24283
|
if (options.input === void 0 || options.input.trim() === "") {
|
|
23779
24284
|
throw new Error("Pass --input <suite-run.json> from a prior suite run.");
|
|
23780
24285
|
}
|
|
23781
|
-
const inputPath =
|
|
24286
|
+
const inputPath = path32__default.default.resolve(cwd, options.input.trim());
|
|
23782
24287
|
const raw = await promises.readFile(inputPath, "utf-8");
|
|
23783
24288
|
return JSON.parse(raw);
|
|
23784
24289
|
}
|
|
@@ -23815,9 +24320,9 @@ function normalizeMetrics2(raw) {
|
|
|
23815
24320
|
}
|
|
23816
24321
|
async function writeArtifacts(result, outputDir) {
|
|
23817
24322
|
await promises.mkdir(outputDir, { recursive: true });
|
|
23818
|
-
const jsonPath =
|
|
23819
|
-
const markdownPath =
|
|
23820
|
-
const htmlPath =
|
|
24323
|
+
const jsonPath = path32__default.default.join(outputDir, "cohort-results.json");
|
|
24324
|
+
const markdownPath = path32__default.default.join(outputDir, "cohort-summary.md");
|
|
24325
|
+
const htmlPath = path32__default.default.join(outputDir, "cohort-report.html");
|
|
23821
24326
|
await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
23822
24327
|
`, "utf-8");
|
|
23823
24328
|
await promises.writeFile(
|
|
@@ -23845,7 +24350,7 @@ async function cohortCommand(options = {}) {
|
|
|
23845
24350
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
23846
24351
|
let artifacts;
|
|
23847
24352
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
23848
|
-
artifacts = await writeArtifacts(result,
|
|
24353
|
+
artifacts = await writeArtifacts(result, path32__default.default.resolve(options.output.trim()));
|
|
23849
24354
|
}
|
|
23850
24355
|
if (options.json || format === "json") {
|
|
23851
24356
|
console.log(
|
|
@@ -23918,11 +24423,11 @@ function parseDuration2(value) {
|
|
|
23918
24423
|
async function writeArtifacts2(result, outputDir) {
|
|
23919
24424
|
await promises.mkdir(outputDir, { recursive: true });
|
|
23920
24425
|
const paths = {
|
|
23921
|
-
jsonPath:
|
|
23922
|
-
markdownPath:
|
|
23923
|
-
htmlPath:
|
|
23924
|
-
junitPath:
|
|
23925
|
-
githubPath:
|
|
24426
|
+
jsonPath: path32__default.default.join(outputDir, "gate-results.json"),
|
|
24427
|
+
markdownPath: path32__default.default.join(outputDir, "gate-summary.md"),
|
|
24428
|
+
htmlPath: path32__default.default.join(outputDir, "gate-report.html"),
|
|
24429
|
+
junitPath: path32__default.default.join(outputDir, "junit.xml"),
|
|
24430
|
+
githubPath: path32__default.default.join(outputDir, "github-step-summary.md")
|
|
23926
24431
|
};
|
|
23927
24432
|
await promises.writeFile(
|
|
23928
24433
|
paths.jsonPath,
|
|
@@ -23990,7 +24495,57 @@ async function gateCommand(options = {}) {
|
|
|
23990
24495
|
const result = await runGate(runs, gateOptions);
|
|
23991
24496
|
let artifacts;
|
|
23992
24497
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
23993
|
-
artifacts = await writeArtifacts2(result,
|
|
24498
|
+
artifacts = await writeArtifacts2(result, path32__default.default.resolve(options.output.trim()));
|
|
24499
|
+
}
|
|
24500
|
+
const failed = !result.ok;
|
|
24501
|
+
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
24502
|
+
try {
|
|
24503
|
+
const runIds = runs.length > 0 ? runs.map((run) => run.runId) : result.suiteResult?.cases.map((item) => item.runId).filter((id) => typeof id === "string" && id.length > 0) ?? ["gate"];
|
|
24504
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
24505
|
+
for (const run of runs) {
|
|
24506
|
+
if (run.filePath) {
|
|
24507
|
+
try {
|
|
24508
|
+
sourceContents.set(run.runId, await promises.readFile(run.filePath, "utf-8"));
|
|
24509
|
+
} catch {
|
|
24510
|
+
sourceContents.set(run.runId, "");
|
|
24511
|
+
}
|
|
24512
|
+
}
|
|
24513
|
+
}
|
|
24514
|
+
const label = runIds[0] ?? "gate";
|
|
24515
|
+
const outputDir = resolveEvidenceOutputDir(
|
|
24516
|
+
options.evidenceDir,
|
|
24517
|
+
`gate-${label}`
|
|
24518
|
+
);
|
|
24519
|
+
const written = await writeLocalEvidence({
|
|
24520
|
+
outputDir,
|
|
24521
|
+
runIds: runIds.length > 0 ? runIds : ["gate"],
|
|
24522
|
+
sourceContents,
|
|
24523
|
+
...gateOptions.traceDir !== void 0 ? { dir: gateOptions.traceDir } : {},
|
|
24524
|
+
failed,
|
|
24525
|
+
checkResultsJson: `${JSON.stringify(
|
|
24526
|
+
{
|
|
24527
|
+
aggregateStatus: failed ? "UNSAFE" : "SAFE",
|
|
24528
|
+
gate: result
|
|
24529
|
+
},
|
|
24530
|
+
null,
|
|
24531
|
+
2
|
|
24532
|
+
)}
|
|
24533
|
+
`,
|
|
24534
|
+
summaryText: renderGateReport(result, { format: "markdown" }),
|
|
24535
|
+
redactionProfile: parseEvidenceProfile(options.evidenceProfile),
|
|
24536
|
+
format: parseEvidenceFormat(options.evidenceFormat)
|
|
24537
|
+
});
|
|
24538
|
+
if (!options.json && format !== "json") {
|
|
24539
|
+
console.log(`Evidence: ${written}`);
|
|
24540
|
+
}
|
|
24541
|
+
if (artifacts !== void 0) {
|
|
24542
|
+
artifacts = { ...artifacts, evidence: written };
|
|
24543
|
+
}
|
|
24544
|
+
} catch (error) {
|
|
24545
|
+
console.error(
|
|
24546
|
+
`[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
|
|
24547
|
+
);
|
|
24548
|
+
}
|
|
23994
24549
|
}
|
|
23995
24550
|
if (options.json || format === "json") {
|
|
23996
24551
|
console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
|
|
@@ -24167,6 +24722,23 @@ function createCliProgram() {
|
|
|
24167
24722
|
"--circuit <rule>",
|
|
24168
24723
|
"run optional circuit rules (repeatable): same-tool-repetition, max-retries, ...",
|
|
24169
24724
|
(value, previous = []) => [...previous, value]
|
|
24725
|
+
).addOption(
|
|
24726
|
+
new commander.Option("--preset <name>", "additive check preset").choices(["trajectory", "safety", "comprehensive"])
|
|
24727
|
+
).addOption(
|
|
24728
|
+
new commander.Option(
|
|
24729
|
+
"--evidence-on <mode>",
|
|
24730
|
+
"write local Evidence v2 (fail=on failure, always, never; no upload)"
|
|
24731
|
+
).choices(["fail", "always", "never"])
|
|
24732
|
+
).option("--evidence-dir <path>", "local Evidence output directory or base path").addOption(
|
|
24733
|
+
new commander.Option(
|
|
24734
|
+
"--evidence-profile <profile>",
|
|
24735
|
+
"Evidence redaction profile (default share)"
|
|
24736
|
+
).choices(["local", "share", "strict"])
|
|
24737
|
+
).addOption(
|
|
24738
|
+
new commander.Option(
|
|
24739
|
+
"--evidence-format <format>",
|
|
24740
|
+
"Evidence output format (default directory)"
|
|
24741
|
+
).choices(["directory", "html", "zip"])
|
|
24170
24742
|
).action((target, opts) => {
|
|
24171
24743
|
runCommand(() => checkCommand(target, opts));
|
|
24172
24744
|
});
|
|
@@ -24265,6 +24837,9 @@ function createCliProgram() {
|
|
|
24265
24837
|
).option("--json", "print deterministic JSON verify result").action((targetPath, opts) => {
|
|
24266
24838
|
runCommand(() => bundleVerifyCommand(targetPath, opts));
|
|
24267
24839
|
});
|
|
24840
|
+
bundleCmd.command("open").description("Verify then open local Evidence HTML in the platform browser (no network)").argument("<path>", "evidence/bundle directory or evidence.html path").option("--skip-verify", "skip integrity verify before open (not recommended)").option("--json", "print deterministic JSON open result").action((targetPath, opts) => {
|
|
24841
|
+
runCommand(() => bundleOpenCommand(targetPath, opts));
|
|
24842
|
+
});
|
|
24268
24843
|
program.command("ci-summary").description("Summarize local reporter artifact manifests for CI").argument("<manifest...>", "reporter artifact manifest JSON files").option("-o, --output <path>", "write Markdown summary to a local file").option("--github-summary <path>", "append Markdown summary to this local file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON summary").action((manifest, opts) => {
|
|
24269
24844
|
runCommand(() => ciSummaryCommand(manifest, opts));
|
|
24270
24845
|
});
|
|
@@ -24544,7 +25119,22 @@ function createCliProgram() {
|
|
|
24544
25119
|
).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
|
|
24545
25120
|
"-o, --output <dir>",
|
|
24546
25121
|
"write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
|
|
24547
|
-
).option("--json", "print deterministic JSON result").
|
|
25122
|
+
).option("--json", "print deterministic JSON result").addOption(
|
|
25123
|
+
new commander.Option(
|
|
25124
|
+
"--evidence-on <mode>",
|
|
25125
|
+
"write local Evidence v2 (fail=on failure, always, never; no upload)"
|
|
25126
|
+
).choices(["fail", "always", "never"])
|
|
25127
|
+
).option("--evidence-dir <path>", "local Evidence output directory or base path").addOption(
|
|
25128
|
+
new commander.Option(
|
|
25129
|
+
"--evidence-profile <profile>",
|
|
25130
|
+
"Evidence redaction profile (default share)"
|
|
25131
|
+
).choices(["local", "share", "strict"])
|
|
25132
|
+
).addOption(
|
|
25133
|
+
new commander.Option(
|
|
25134
|
+
"--evidence-format <format>",
|
|
25135
|
+
"Evidence output format (default directory)"
|
|
25136
|
+
).choices(["directory", "html", "zip"])
|
|
25137
|
+
).action((opts) => {
|
|
24548
25138
|
runCommand(() => gateCommand(opts));
|
|
24549
25139
|
});
|
|
24550
25140
|
return program;
|
|
@@ -24554,9 +25144,9 @@ function isPrimaryModule() {
|
|
|
24554
25144
|
if (!entry) return false;
|
|
24555
25145
|
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)));
|
|
24556
25146
|
try {
|
|
24557
|
-
return fs.realpathSync(
|
|
25147
|
+
return fs.realpathSync(path32__default.default.resolve(entry)) === fs.realpathSync(path32__default.default.resolve(selfPath));
|
|
24558
25148
|
} catch {
|
|
24559
|
-
return
|
|
25149
|
+
return path32__default.default.resolve(entry) === path32__default.default.resolve(selfPath);
|
|
24560
25150
|
}
|
|
24561
25151
|
}
|
|
24562
25152
|
if (isPrimaryModule()) {
|