agent-inspect 6.17.7 → 6.18.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 +25 -0
- package/README.md +1 -1
- package/SECURITY.md +5 -0
- package/docs/ADAPTERS.md +34 -4
- package/docs/AI-SDK-ADOPTION.md +25 -0
- package/docs/API.md +11 -9
- package/docs/CLI.md +6 -0
- package/docs/COMPARE.md +6 -0
- package/docs/FIRST-TRACE-IN-5-MINUTES.md +3 -1
- package/docs/LIMITATIONS.md +1 -0
- package/docs/OPENAI-AGENTS-LOCAL.md +1 -0
- package/docs/SAFE-TRACE-SHARING.md +2 -2
- package/docs/STANDARDS.md +1 -0
- package/docs/SUPPORT-LEVELS.md +1 -0
- package/docs/USE-CASES.md +1 -1
- package/docs/VSCODE.md +8 -0
- package/package.json +2 -2
- package/packages/cli/dist/{chunk-25LUDS4T.mjs → chunk-S4TLTLXN.mjs} +2 -2
- package/packages/cli/dist/{chunk-25LUDS4T.mjs.map → chunk-S4TLTLXN.mjs.map} +1 -1
- package/packages/cli/dist/index.cjs +1327 -930
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +1245 -857
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-2FS6BLR7.mjs → src-R6V5EZZH.mjs} +3 -3
- package/packages/cli/dist/{src-2FS6BLR7.mjs.map → src-R6V5EZZH.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +180 -0
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +81 -2
- package/packages/core/dist/advanced.d.ts +81 -2
- package/packages/core/dist/advanced.mjs +176 -1
- package/packages/core/dist/advanced.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 path33 = require('path');
|
|
8
8
|
var async_hooks = require('async_hooks');
|
|
9
9
|
var process3 = require('process');
|
|
10
10
|
var tty = require('tty');
|
|
@@ -22,7 +22,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
22
22
|
|
|
23
23
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
24
24
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
25
|
-
var
|
|
25
|
+
var path33__default = /*#__PURE__*/_interopDefault(path33);
|
|
26
26
|
var process3__default = /*#__PURE__*/_interopDefault(process3);
|
|
27
27
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
28
28
|
|
|
@@ -866,7 +866,7 @@ function getDefaultTraceDir() {
|
|
|
866
866
|
if (typeof home !== "string" || home.trim() === "") {
|
|
867
867
|
return FALLBACK_TRACE_DIR;
|
|
868
868
|
}
|
|
869
|
-
return
|
|
869
|
+
return path33__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
870
870
|
} catch {
|
|
871
871
|
return FALLBACK_TRACE_DIR;
|
|
872
872
|
}
|
|
@@ -874,11 +874,11 @@ function getDefaultTraceDir() {
|
|
|
874
874
|
function getTraceFilePath(runId, traceDir) {
|
|
875
875
|
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
876
876
|
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
877
|
-
safeId =
|
|
877
|
+
safeId = path33__default.default.basename(safeId);
|
|
878
878
|
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
879
879
|
safeId = "run_unknown";
|
|
880
880
|
}
|
|
881
|
-
return
|
|
881
|
+
return path33__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
882
882
|
}
|
|
883
883
|
function formatError(error) {
|
|
884
884
|
if (error instanceof Error) {
|
|
@@ -935,7 +935,7 @@ var init_utils = __esm({
|
|
|
935
935
|
init_duration();
|
|
936
936
|
DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
937
937
|
RUNS_DIR_NAME = "runs";
|
|
938
|
-
FALLBACK_TRACE_DIR =
|
|
938
|
+
FALLBACK_TRACE_DIR = path33__default.default.join(
|
|
939
939
|
os__default.default.tmpdir(),
|
|
940
940
|
"agent-inspect",
|
|
941
941
|
RUNS_DIR_NAME
|
|
@@ -1306,6 +1306,14 @@ var init_inspector = __esm({
|
|
|
1306
1306
|
}
|
|
1307
1307
|
});
|
|
1308
1308
|
|
|
1309
|
+
// packages/core/src/adapters/preview-capture.ts
|
|
1310
|
+
var init_preview_capture = __esm({
|
|
1311
|
+
"packages/core/src/adapters/preview-capture.ts"() {
|
|
1312
|
+
init_redactor();
|
|
1313
|
+
init_redaction_profiles();
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1309
1317
|
// node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
1310
1318
|
function assembleStyles() {
|
|
1311
1319
|
const codes = /* @__PURE__ */ new Map();
|
|
@@ -1901,7 +1909,7 @@ var init_trace_directory = __esm({
|
|
|
1901
1909
|
this.#dir = resolveTraceDir(options);
|
|
1902
1910
|
}
|
|
1903
1911
|
getPath(filename) {
|
|
1904
|
-
return filename ?
|
|
1912
|
+
return filename ? path33__default.default.join(this.#dir, filename) : this.#dir;
|
|
1905
1913
|
}
|
|
1906
1914
|
async list() {
|
|
1907
1915
|
try {
|
|
@@ -1930,7 +1938,7 @@ function parseIsoToMs2(value) {
|
|
|
1930
1938
|
}
|
|
1931
1939
|
async function extractMetadata(filePath, _quickScan) {
|
|
1932
1940
|
const stats = await promises.stat(filePath);
|
|
1933
|
-
let runIdFromFile =
|
|
1941
|
+
let runIdFromFile = path33__default.default.basename(filePath);
|
|
1934
1942
|
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1935
1943
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1936
1944
|
}
|
|
@@ -3800,12 +3808,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3800
3808
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3801
3809
|
);
|
|
3802
3810
|
const ordered = [...runs].sort(compareRuns);
|
|
3803
|
-
const
|
|
3811
|
+
const path44 = [];
|
|
3804
3812
|
const visited = /* @__PURE__ */ new Set();
|
|
3805
3813
|
const pushRun = (run, confidence, source) => {
|
|
3806
3814
|
if (visited.has(run.runId)) return;
|
|
3807
3815
|
visited.add(run.runId);
|
|
3808
|
-
|
|
3816
|
+
path44.push({
|
|
3809
3817
|
runId: run.runId,
|
|
3810
3818
|
name: run.name,
|
|
3811
3819
|
startedAt: run.startedAt,
|
|
@@ -3830,7 +3838,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3830
3838
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3831
3839
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3832
3840
|
}
|
|
3833
|
-
return
|
|
3841
|
+
return path44;
|
|
3834
3842
|
}
|
|
3835
3843
|
function metaRunIdMatches(run, token, runById) {
|
|
3836
3844
|
const meta2 = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -4159,7 +4167,7 @@ var init_summary = __esm({
|
|
|
4159
4167
|
});
|
|
4160
4168
|
function sanitizeBundleRunId(runId) {
|
|
4161
4169
|
let safe = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
4162
|
-
safe =
|
|
4170
|
+
safe = path33__default.default.basename(safe);
|
|
4163
4171
|
safe = safe.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
4164
4172
|
if (safe === "" || safe === "." || safe === "..") {
|
|
4165
4173
|
safe = "run_unknown";
|
|
@@ -4169,12 +4177,12 @@ function sanitizeBundleRunId(runId) {
|
|
|
4169
4177
|
function bundleRunAssetRelativePath(runId, extension) {
|
|
4170
4178
|
const safe = sanitizeBundleRunId(runId);
|
|
4171
4179
|
const ext = extension.startsWith(".") ? extension : `.${extension}`;
|
|
4172
|
-
return
|
|
4180
|
+
return path33__default.default.posix.join("assets", "runs", `${safe}${ext}`);
|
|
4173
4181
|
}
|
|
4174
4182
|
function assertBundlePathContained(outputDir, relativePath) {
|
|
4175
|
-
const base =
|
|
4176
|
-
const resolved =
|
|
4177
|
-
if (resolved !== base && !resolved.startsWith(base +
|
|
4183
|
+
const base = path33__default.default.resolve(outputDir);
|
|
4184
|
+
const resolved = path33__default.default.resolve(base, relativePath);
|
|
4185
|
+
if (resolved !== base && !resolved.startsWith(base + path33__default.default.sep)) {
|
|
4178
4186
|
throw new Error(`Bundle path escapes output directory: ${relativePath}`);
|
|
4179
4187
|
}
|
|
4180
4188
|
return resolved;
|
|
@@ -4184,7 +4192,7 @@ function normalizeBundleOutputPath(out, options) {
|
|
|
4184
4192
|
if (trimmed === "") {
|
|
4185
4193
|
throw new Error("--out requires a non-empty path.");
|
|
4186
4194
|
}
|
|
4187
|
-
const resolved =
|
|
4195
|
+
const resolved = path33__default.default.resolve(trimmed);
|
|
4188
4196
|
if (options?.preserveZipExtension !== true && resolved.toLowerCase().endsWith(".zip")) {
|
|
4189
4197
|
return resolved.slice(0, -4);
|
|
4190
4198
|
}
|
|
@@ -4193,7 +4201,7 @@ function normalizeBundleOutputPath(out, options) {
|
|
|
4193
4201
|
function defaultBundleOutputPath(runIds) {
|
|
4194
4202
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
4195
4203
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4196
|
-
return
|
|
4204
|
+
return path33__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
4197
4205
|
}
|
|
4198
4206
|
var init_paths = __esm({
|
|
4199
4207
|
"packages/core/src/bundle/paths.ts"() {
|
|
@@ -4256,7 +4264,7 @@ function assertEvidenceRelativePath(relativePath) {
|
|
|
4256
4264
|
throw new Error("Evidence file path must be a non-empty relative path.");
|
|
4257
4265
|
}
|
|
4258
4266
|
const trimmed = relativePath.trim().replaceAll("\\", "/");
|
|
4259
|
-
if (
|
|
4267
|
+
if (path33__default.default.isAbsolute(trimmed) || trimmed.startsWith("/")) {
|
|
4260
4268
|
throw new Error(`Evidence file path must be relative: ${relativePath}`);
|
|
4261
4269
|
}
|
|
4262
4270
|
const parts = trimmed.split("/").filter((part) => part !== "");
|
|
@@ -5123,13 +5131,13 @@ function pairSteps(left, right) {
|
|
|
5123
5131
|
return pairs;
|
|
5124
5132
|
}
|
|
5125
5133
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
5126
|
-
const
|
|
5134
|
+
const path44 = buildPath(segments);
|
|
5127
5135
|
if (L.name !== R.name) {
|
|
5128
5136
|
out.push({
|
|
5129
5137
|
kind: "structure",
|
|
5130
5138
|
severity: "warning",
|
|
5131
5139
|
message: "Step name differs",
|
|
5132
|
-
path:
|
|
5140
|
+
path: path44,
|
|
5133
5141
|
left: L.name,
|
|
5134
5142
|
right: R.name
|
|
5135
5143
|
});
|
|
@@ -5139,7 +5147,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5139
5147
|
kind: "step-type",
|
|
5140
5148
|
severity: "warning",
|
|
5141
5149
|
message: "Step type differs",
|
|
5142
|
-
path:
|
|
5150
|
+
path: path44,
|
|
5143
5151
|
left: L.type,
|
|
5144
5152
|
right: R.type
|
|
5145
5153
|
});
|
|
@@ -5149,7 +5157,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5149
5157
|
kind: "step-status",
|
|
5150
5158
|
severity: "warning",
|
|
5151
5159
|
message: "Step status differs",
|
|
5152
|
-
path:
|
|
5160
|
+
path: path44,
|
|
5153
5161
|
left: L.status,
|
|
5154
5162
|
right: R.status
|
|
5155
5163
|
});
|
|
@@ -5161,7 +5169,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5161
5169
|
kind: "error",
|
|
5162
5170
|
severity: "error",
|
|
5163
5171
|
message: "Step error message differs",
|
|
5164
|
-
path:
|
|
5172
|
+
path: path44,
|
|
5165
5173
|
left: le || void 0,
|
|
5166
5174
|
right: re || void 0
|
|
5167
5175
|
});
|
|
@@ -5179,7 +5187,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5179
5187
|
kind: "duration",
|
|
5180
5188
|
severity: "info",
|
|
5181
5189
|
message: "Step duration differs",
|
|
5182
|
-
path:
|
|
5190
|
+
path: path44,
|
|
5183
5191
|
left: ld,
|
|
5184
5192
|
right: rd
|
|
5185
5193
|
});
|
|
@@ -5192,7 +5200,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5192
5200
|
kind: "metadata",
|
|
5193
5201
|
severity: "info",
|
|
5194
5202
|
message: "Step metadata differs",
|
|
5195
|
-
path:
|
|
5203
|
+
path: path44,
|
|
5196
5204
|
left: L.metadata,
|
|
5197
5205
|
right: R.metadata
|
|
5198
5206
|
});
|
|
@@ -5204,7 +5212,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
5204
5212
|
kind: "output",
|
|
5205
5213
|
severity: "info",
|
|
5206
5214
|
message: "Output preview differs",
|
|
5207
|
-
path:
|
|
5215
|
+
path: path44,
|
|
5208
5216
|
left: L.outputPreview,
|
|
5209
5217
|
right: R.outputPreview
|
|
5210
5218
|
});
|
|
@@ -5371,11 +5379,11 @@ var init_engine = __esm({
|
|
|
5371
5379
|
});
|
|
5372
5380
|
|
|
5373
5381
|
// packages/core/src/diff/renderer.ts
|
|
5374
|
-
function formatPath(
|
|
5375
|
-
if (
|
|
5382
|
+
function formatPath(path44) {
|
|
5383
|
+
if (path44 === void 0 || path44.path.length === 0) {
|
|
5376
5384
|
return "(run)";
|
|
5377
5385
|
}
|
|
5378
|
-
return
|
|
5386
|
+
return path44.path.map((s) => s.name).join(" > ");
|
|
5379
5387
|
}
|
|
5380
5388
|
function formatValue(v, verbose) {
|
|
5381
5389
|
if (v === void 0) return "(undefined)";
|
|
@@ -5755,11 +5763,11 @@ async function listFilesRecursive(root) {
|
|
|
5755
5763
|
async function walk(dir) {
|
|
5756
5764
|
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
5757
5765
|
for (const entry of entries) {
|
|
5758
|
-
const abs =
|
|
5766
|
+
const abs = path33__default.default.join(dir, entry.name);
|
|
5759
5767
|
if (entry.isDirectory()) {
|
|
5760
5768
|
await walk(abs);
|
|
5761
5769
|
} else if (entry.isFile()) {
|
|
5762
|
-
const rel =
|
|
5770
|
+
const rel = path33__default.default.relative(root, abs).split(path33__default.default.sep).join("/");
|
|
5763
5771
|
out.push(rel);
|
|
5764
5772
|
}
|
|
5765
5773
|
}
|
|
@@ -5769,7 +5777,7 @@ async function listFilesRecursive(root) {
|
|
|
5769
5777
|
}
|
|
5770
5778
|
async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
5771
5779
|
const unexpectedMode = options.unexpectedFiles ?? "fail";
|
|
5772
|
-
const root =
|
|
5780
|
+
const root = path33__default.default.resolve(rootPath);
|
|
5773
5781
|
const issues = [];
|
|
5774
5782
|
let rootStat;
|
|
5775
5783
|
try {
|
|
@@ -5799,7 +5807,7 @@ async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
|
5799
5807
|
checkedFiles: 0
|
|
5800
5808
|
};
|
|
5801
5809
|
}
|
|
5802
|
-
const manifestPath =
|
|
5810
|
+
const manifestPath = path33__default.default.join(root, EVIDENCE_MANIFEST_FILENAME);
|
|
5803
5811
|
let manifestText;
|
|
5804
5812
|
try {
|
|
5805
5813
|
manifestText = await promises.readFile(manifestPath, "utf-8");
|
|
@@ -5885,7 +5893,7 @@ async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
|
5885
5893
|
continue;
|
|
5886
5894
|
}
|
|
5887
5895
|
listed.add(rel);
|
|
5888
|
-
const abs =
|
|
5896
|
+
const abs = path33__default.default.join(root, ...rel.split("/"));
|
|
5889
5897
|
let bytes;
|
|
5890
5898
|
try {
|
|
5891
5899
|
bytes = await promises.readFile(abs);
|
|
@@ -6200,7 +6208,7 @@ function normalizeSuiteConfig(value) {
|
|
|
6200
6208
|
}
|
|
6201
6209
|
async function validateSuiteConfig(config, options) {
|
|
6202
6210
|
const diagnostics = [];
|
|
6203
|
-
const tracesDir =
|
|
6211
|
+
const tracesDir = path33__default.default.resolve(options.configDir, config.traces);
|
|
6204
6212
|
try {
|
|
6205
6213
|
await promises.access(tracesDir);
|
|
6206
6214
|
} catch {
|
|
@@ -6210,7 +6218,7 @@ async function validateSuiteConfig(config, options) {
|
|
|
6210
6218
|
}
|
|
6211
6219
|
for (const suiteCase of config.cases) {
|
|
6212
6220
|
if (suiteCase.input !== void 0) {
|
|
6213
|
-
const inputPath =
|
|
6221
|
+
const inputPath = path33__default.default.resolve(options.configDir, suiteCase.input);
|
|
6214
6222
|
try {
|
|
6215
6223
|
await promises.access(inputPath);
|
|
6216
6224
|
} catch {
|
|
@@ -6243,12 +6251,12 @@ async function fileExists(filePath) {
|
|
|
6243
6251
|
}
|
|
6244
6252
|
}
|
|
6245
6253
|
async function resolveSuiteConfigPath(options = {}) {
|
|
6246
|
-
const cwd =
|
|
6254
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
6247
6255
|
if (options.configPath !== void 0 && options.configPath.trim() !== "") {
|
|
6248
|
-
return
|
|
6256
|
+
return path33__default.default.resolve(cwd, options.configPath.trim());
|
|
6249
6257
|
}
|
|
6250
6258
|
for (const name of DEFAULT_SUITE_CONFIG_NAMES) {
|
|
6251
|
-
const candidate =
|
|
6259
|
+
const candidate = path33__default.default.join(cwd, name);
|
|
6252
6260
|
if (await fileExists(candidate)) return candidate;
|
|
6253
6261
|
}
|
|
6254
6262
|
throw new Error(
|
|
@@ -6265,7 +6273,7 @@ async function loadSuiteConfig(options = {}) {
|
|
|
6265
6273
|
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
6266
6274
|
});
|
|
6267
6275
|
}
|
|
6268
|
-
const extension =
|
|
6276
|
+
const extension = path33__default.default.extname(configPath);
|
|
6269
6277
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
6270
6278
|
const message = "TypeScript suite configs require an explicit precompiled JavaScript config or future --config-loader support.";
|
|
6271
6279
|
throw Object.assign(new Error(message), {
|
|
@@ -6290,7 +6298,7 @@ async function loadSuiteConfig(options = {}) {
|
|
|
6290
6298
|
return {
|
|
6291
6299
|
config,
|
|
6292
6300
|
configPath,
|
|
6293
|
-
configDir:
|
|
6301
|
+
configDir: path33__default.default.dirname(configPath)
|
|
6294
6302
|
};
|
|
6295
6303
|
} catch (error) {
|
|
6296
6304
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -6340,7 +6348,7 @@ async function exists(filePath) {
|
|
|
6340
6348
|
}
|
|
6341
6349
|
async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
6342
6350
|
if (suiteCase.trace !== void 0) {
|
|
6343
|
-
const tracePath =
|
|
6351
|
+
const tracePath = path33__default.default.resolve(options.configDir, suiteCase.trace);
|
|
6344
6352
|
if (await exists(tracePath)) {
|
|
6345
6353
|
return { caseId: suiteCase.id, tracePath, missing: false };
|
|
6346
6354
|
}
|
|
@@ -6356,7 +6364,7 @@ async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
|
6356
6364
|
if (await exists(directPath)) {
|
|
6357
6365
|
return { caseId: suiteCase.id, tracePath: directPath, runId: runKey, missing: false };
|
|
6358
6366
|
}
|
|
6359
|
-
const nestedPath =
|
|
6367
|
+
const nestedPath = path33__default.default.join(options.tracesDir, `${path33__default.default.basename(runKey)}.jsonl`);
|
|
6360
6368
|
if (await exists(nestedPath)) {
|
|
6361
6369
|
return { caseId: suiteCase.id, tracePath: nestedPath, runId: runKey, missing: false };
|
|
6362
6370
|
}
|
|
@@ -7106,7 +7114,7 @@ function stripPrefix(name, prefixes) {
|
|
|
7106
7114
|
}
|
|
7107
7115
|
return name;
|
|
7108
7116
|
}
|
|
7109
|
-
function eventEvidence(event,
|
|
7117
|
+
function eventEvidence(event, path44) {
|
|
7110
7118
|
return {
|
|
7111
7119
|
runId: event.runId,
|
|
7112
7120
|
eventId: event.eventId,
|
|
@@ -7116,7 +7124,7 @@ function eventEvidence(event, path43) {
|
|
|
7116
7124
|
kind: event.kind,
|
|
7117
7125
|
name: event.name,
|
|
7118
7126
|
status: event.status,
|
|
7119
|
-
...
|
|
7127
|
+
...path44 ? { path: path44 } : {}
|
|
7120
7128
|
};
|
|
7121
7129
|
}
|
|
7122
7130
|
function runEvidence(run) {
|
|
@@ -7192,9 +7200,9 @@ function eventEndMs(event) {
|
|
|
7192
7200
|
function normalizedKey(value) {
|
|
7193
7201
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
7194
7202
|
}
|
|
7195
|
-
function lastPathSegment(
|
|
7196
|
-
const parts =
|
|
7197
|
-
return parts[parts.length - 1] ??
|
|
7203
|
+
function lastPathSegment(path44) {
|
|
7204
|
+
const parts = path44.split(".");
|
|
7205
|
+
return parts[parts.length - 1] ?? path44;
|
|
7198
7206
|
}
|
|
7199
7207
|
function valueType(value) {
|
|
7200
7208
|
if (Array.isArray(value)) return "array";
|
|
@@ -7208,12 +7216,12 @@ function serializedByteLength(value) {
|
|
|
7208
7216
|
return void 0;
|
|
7209
7217
|
}
|
|
7210
7218
|
}
|
|
7211
|
-
function pushValueEntries(entries, event, value,
|
|
7212
|
-
entries.push({ event, path:
|
|
7219
|
+
function pushValueEntries(entries, event, value, path44, key, depth = 0) {
|
|
7220
|
+
entries.push({ event, path: path44, key, value });
|
|
7213
7221
|
if (depth >= 8) return;
|
|
7214
7222
|
if (Array.isArray(value)) {
|
|
7215
7223
|
for (const [index, item] of value.entries()) {
|
|
7216
|
-
pushValueEntries(entries, event, item, `${
|
|
7224
|
+
pushValueEntries(entries, event, item, `${path44}.${index}`, String(index), depth + 1);
|
|
7217
7225
|
}
|
|
7218
7226
|
return;
|
|
7219
7227
|
}
|
|
@@ -7223,7 +7231,7 @@ function pushValueEntries(entries, event, value, path43, key, depth = 0) {
|
|
|
7223
7231
|
entries,
|
|
7224
7232
|
event,
|
|
7225
7233
|
value[nestedKey],
|
|
7226
|
-
`${
|
|
7234
|
+
`${path44}.${nestedKey}`,
|
|
7227
7235
|
nestedKey,
|
|
7228
7236
|
depth + 1
|
|
7229
7237
|
);
|
|
@@ -7262,18 +7270,18 @@ function isRawContentKey(key, forbiddenKeys) {
|
|
|
7262
7270
|
const normalized = normalizedKey(key);
|
|
7263
7271
|
return forbiddenKeys.some((forbidden) => normalized === normalizedKey(forbidden));
|
|
7264
7272
|
}
|
|
7265
|
-
function isSafeRawContentMetricPath(
|
|
7266
|
-
const leaf = normalizedKey(key ?? lastPathSegment(
|
|
7273
|
+
function isSafeRawContentMetricPath(path44, key, safePathPrefixes) {
|
|
7274
|
+
const leaf = normalizedKey(key ?? lastPathSegment(path44));
|
|
7267
7275
|
if (!SAFE_USAGE_LEAF_KEYS.has(leaf)) return false;
|
|
7268
|
-
const parts =
|
|
7276
|
+
const parts = path44.split(".").filter(Boolean);
|
|
7269
7277
|
if (parts.length < 2) return false;
|
|
7270
7278
|
const parent = parts[parts.length - 2] ?? "";
|
|
7271
7279
|
const parentNorm = normalizedKey(parent);
|
|
7272
7280
|
return safePathPrefixes.some((prefix) => parentNorm === normalizedKey(prefix));
|
|
7273
7281
|
}
|
|
7274
|
-
function isRawContentPath(
|
|
7275
|
-
if (isSafeRawContentMetricPath(
|
|
7276
|
-
return isRawContentKey(key ?? lastPathSegment(
|
|
7282
|
+
function isRawContentPath(path44, key, forbiddenKeys, safePathPrefixes) {
|
|
7283
|
+
if (isSafeRawContentMetricPath(path44, key, safePathPrefixes)) return false;
|
|
7284
|
+
return isRawContentKey(key ?? lastPathSegment(path44), forbiddenKeys);
|
|
7277
7285
|
}
|
|
7278
7286
|
function parentMarkedUnresolved(event) {
|
|
7279
7287
|
if (booleanAttr(event, [
|
|
@@ -7312,9 +7320,9 @@ function eventDurationMs(event) {
|
|
|
7312
7320
|
}
|
|
7313
7321
|
function treeShape(nodes) {
|
|
7314
7322
|
const lines = [];
|
|
7315
|
-
const visit = (node,
|
|
7316
|
-
lines.push(`${
|
|
7317
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
7323
|
+
const visit = (node, path44) => {
|
|
7324
|
+
lines.push(`${path44}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
7325
|
+
node.children.forEach((child, index) => visit(child, `${path44}.${index}`));
|
|
7318
7326
|
};
|
|
7319
7327
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
7320
7328
|
return lines;
|
|
@@ -7363,9 +7371,9 @@ function retrievalShape(context) {
|
|
|
7363
7371
|
function guardrailShape(context) {
|
|
7364
7372
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
7365
7373
|
}
|
|
7366
|
-
function firstEvidenceForKind(context, kind,
|
|
7374
|
+
function firstEvidenceForKind(context, kind, path44) {
|
|
7367
7375
|
const event = semanticEvents(context).find((candidate) => candidate.kind === kind);
|
|
7368
|
-
return event ? [eventEvidence(event,
|
|
7376
|
+
return event ? [eventEvidence(event, path44)] : runEvidence(context.selectedRun);
|
|
7369
7377
|
}
|
|
7370
7378
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
7371
7379
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -7715,13 +7723,13 @@ function createStructureCycleRule() {
|
|
|
7715
7723
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
7716
7724
|
const findings = [];
|
|
7717
7725
|
for (const event of [...semanticEvents(context)].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
7718
|
-
const
|
|
7726
|
+
const path44 = [];
|
|
7719
7727
|
const seenAt = /* @__PURE__ */ new Map();
|
|
7720
7728
|
let current = event;
|
|
7721
7729
|
while (current) {
|
|
7722
7730
|
const existing = seenAt.get(current.eventId);
|
|
7723
7731
|
if (existing !== void 0) {
|
|
7724
|
-
const cycle =
|
|
7732
|
+
const cycle = path44.slice(existing);
|
|
7725
7733
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
7726
7734
|
if (!seenCycles.has(key)) {
|
|
7727
7735
|
seenCycles.add(key);
|
|
@@ -7737,8 +7745,8 @@ function createStructureCycleRule() {
|
|
|
7737
7745
|
}
|
|
7738
7746
|
break;
|
|
7739
7747
|
}
|
|
7740
|
-
seenAt.set(current.eventId,
|
|
7741
|
-
|
|
7748
|
+
seenAt.set(current.eventId, path44.length);
|
|
7749
|
+
path44.push(current);
|
|
7742
7750
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
7743
7751
|
}
|
|
7744
7752
|
}
|
|
@@ -9117,7 +9125,7 @@ function findReaderByFormat(format, readers) {
|
|
|
9117
9125
|
}
|
|
9118
9126
|
async function jsonlFilesInDirectory(dirPath) {
|
|
9119
9127
|
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
9120
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
9128
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path33__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
9121
9129
|
}
|
|
9122
9130
|
async function resolveInput(input3) {
|
|
9123
9131
|
const cached2 = resolvedInputCache.get(input3);
|
|
@@ -10824,7 +10832,7 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
10824
10832
|
async function runSuite(options = {}) {
|
|
10825
10833
|
const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
|
|
10826
10834
|
const { config, configPath, configDir } = await loadSuiteConfig(options);
|
|
10827
|
-
const tracesDir =
|
|
10835
|
+
const tracesDir = path33__default.default.resolve(configDir, config.traces);
|
|
10828
10836
|
const cases = [];
|
|
10829
10837
|
const diagnostics = [];
|
|
10830
10838
|
for (const suiteCase of config.cases) {
|
|
@@ -11851,7 +11859,7 @@ function validateOptions(options) {
|
|
|
11851
11859
|
}
|
|
11852
11860
|
function isConfigLoadError(error) {
|
|
11853
11861
|
if (!(error instanceof Error)) return false;
|
|
11854
|
-
const ext =
|
|
11862
|
+
const ext = path33__default.default.extname(error.message);
|
|
11855
11863
|
if (error.message.includes("Unsupported suite config extension")) return true;
|
|
11856
11864
|
if (error.message.includes("TypeScript suite configs require")) return true;
|
|
11857
11865
|
if (error.message.includes("No suite config found")) return true;
|
|
@@ -12098,6 +12106,7 @@ var init_advanced = __esm({
|
|
|
12098
12106
|
init_inspector();
|
|
12099
12107
|
init_inspector_runtime();
|
|
12100
12108
|
init_trace_event_safety();
|
|
12109
|
+
init_preview_capture();
|
|
12101
12110
|
init_terminal();
|
|
12102
12111
|
init_utils();
|
|
12103
12112
|
init_types();
|
|
@@ -12245,8 +12254,8 @@ var init_load_sqlite = __esm({
|
|
|
12245
12254
|
}
|
|
12246
12255
|
});
|
|
12247
12256
|
function resolveIndexDbPath(traceDir, dbPath) {
|
|
12248
|
-
if (dbPath && dbPath.trim() !== "") return
|
|
12249
|
-
return
|
|
12257
|
+
if (dbPath && dbPath.trim() !== "") return path33__default.default.resolve(dbPath);
|
|
12258
|
+
return path33__default.default.join(path33__default.default.resolve(traceDir), INDEX_DB_FILENAME);
|
|
12250
12259
|
}
|
|
12251
12260
|
function str(value) {
|
|
12252
12261
|
return typeof value === "string" && value !== "" ? value : null;
|
|
@@ -12338,7 +12347,7 @@ async function buildIndex(options = {}) {
|
|
|
12338
12347
|
warnings.push(`index.unreadable: ${file}`);
|
|
12339
12348
|
}
|
|
12340
12349
|
}
|
|
12341
|
-
await promises.mkdir(
|
|
12350
|
+
await promises.mkdir(path33__default.default.dirname(dbPath), { recursive: true });
|
|
12342
12351
|
await promises.rm(dbPath, { force: true });
|
|
12343
12352
|
const Sqlite = loadBetterSqlite3();
|
|
12344
12353
|
const db = new Sqlite(dbPath);
|
|
@@ -12586,7 +12595,7 @@ var init_src = __esm({
|
|
|
12586
12595
|
});
|
|
12587
12596
|
|
|
12588
12597
|
// package.json
|
|
12589
|
-
var version = "6.
|
|
12598
|
+
var version = "6.18.0";
|
|
12590
12599
|
|
|
12591
12600
|
// packages/cli/src/list.ts
|
|
12592
12601
|
init_advanced();
|
|
@@ -12741,13 +12750,14 @@ async function list(options = {}) {
|
|
|
12741
12750
|
|
|
12742
12751
|
// packages/cli/src/clean.ts
|
|
12743
12752
|
init_advanced();
|
|
12753
|
+
var DECIMAL_INTEGER_PATTERN = /^\d+$/;
|
|
12744
12754
|
function parseKeep(raw) {
|
|
12745
12755
|
const trimmed = typeof raw === "string" ? raw.trim() : "";
|
|
12746
|
-
if (trimmed
|
|
12756
|
+
if (!DECIMAL_INTEGER_PATTERN.test(trimmed)) {
|
|
12747
12757
|
throw new Error(`Invalid --keep value: ${raw}. Provide a positive integer.`);
|
|
12748
12758
|
}
|
|
12749
|
-
const n = Number
|
|
12750
|
-
if (!Number.
|
|
12759
|
+
const n = Number(trimmed);
|
|
12760
|
+
if (!Number.isSafeInteger(n) || n <= 0) {
|
|
12751
12761
|
throw new Error(`Invalid --keep value: ${raw}. Provide a positive integer.`);
|
|
12752
12762
|
}
|
|
12753
12763
|
return n;
|
|
@@ -13083,6 +13093,16 @@ function filterErrorEvents(events) {
|
|
|
13083
13093
|
return false;
|
|
13084
13094
|
});
|
|
13085
13095
|
}
|
|
13096
|
+
function pruneErrorTree(nodes) {
|
|
13097
|
+
const pruned = [];
|
|
13098
|
+
for (const node of nodes) {
|
|
13099
|
+
const children = pruneErrorTree(node.children);
|
|
13100
|
+
if (node.status === "error" || children.length > 0) {
|
|
13101
|
+
pruned.push({ ...node, children });
|
|
13102
|
+
}
|
|
13103
|
+
}
|
|
13104
|
+
return pruned;
|
|
13105
|
+
}
|
|
13086
13106
|
async function view(runId, options = {}) {
|
|
13087
13107
|
try {
|
|
13088
13108
|
const id = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "";
|
|
@@ -13155,11 +13175,44 @@ async function view(runId, options = {}) {
|
|
|
13155
13175
|
const errEvents = filterErrorEvents(events);
|
|
13156
13176
|
if (options.json) {
|
|
13157
13177
|
console.log(JSON.stringify(errEvents, null, 2));
|
|
13158
|
-
|
|
13178
|
+
return;
|
|
13179
|
+
}
|
|
13180
|
+
if (errEvents.length === 0) {
|
|
13159
13181
|
console.log("No errors found in trace");
|
|
13182
|
+
return;
|
|
13183
|
+
}
|
|
13184
|
+
const started2 = events.find(
|
|
13185
|
+
(e) => e.event === "run_started"
|
|
13186
|
+
);
|
|
13187
|
+
const completed2 = events.filter(
|
|
13188
|
+
(e) => e.event === "run_completed"
|
|
13189
|
+
);
|
|
13190
|
+
const last2 = completed2[completed2.length - 1];
|
|
13191
|
+
const status2 = last2 ? last2.status : "running";
|
|
13192
|
+
const durationLine2 = last2 !== void 0 && Number.isFinite(last2.durationMs) ? formatDuration2(last2.durationMs) : "-";
|
|
13193
|
+
const startedTs2 = started2 !== void 0 && Number.isFinite(started2.startTime) ? started2.startTime : started2?.timestamp;
|
|
13194
|
+
const startedLabel2 = startedTs2 !== void 0 ? formatTimestamp(startedTs2) : "-";
|
|
13195
|
+
console.log(`AgentInspect Run: ${started2?.name ?? id}`);
|
|
13196
|
+
console.log(`ID: ${id}`);
|
|
13197
|
+
console.log(`Status: ${status2}`);
|
|
13198
|
+
console.log(`Duration: ${durationLine2}`);
|
|
13199
|
+
console.log(`Started: ${startedLabel2}`);
|
|
13200
|
+
console.log("");
|
|
13201
|
+
console.log("Error Tree:");
|
|
13202
|
+
const pruned = pruneErrorTree(buildStepTree(events));
|
|
13203
|
+
if (pruned.length === 0) {
|
|
13204
|
+
if (last2?.status === "error") {
|
|
13205
|
+
console.log(
|
|
13206
|
+
renderErrorLine(
|
|
13207
|
+
last2.error ?? { message: "Run completed with error status" },
|
|
13208
|
+
0
|
|
13209
|
+
)
|
|
13210
|
+
);
|
|
13211
|
+
} else {
|
|
13212
|
+
console.log("No error steps recorded");
|
|
13213
|
+
}
|
|
13160
13214
|
} else {
|
|
13161
|
-
|
|
13162
|
-
console.log(JSON.stringify(errEvents, null, 2));
|
|
13215
|
+
printStepTree(pruned, 0, options.verbose === true);
|
|
13163
13216
|
}
|
|
13164
13217
|
return;
|
|
13165
13218
|
}
|
|
@@ -15614,9 +15667,9 @@ Trace directory: ${traceDir}`);
|
|
|
15614
15667
|
process.exitCode = 1;
|
|
15615
15668
|
}
|
|
15616
15669
|
const resolvedOutput = resolveOutputOption(options);
|
|
15617
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
15670
|
+
const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
|
|
15618
15671
|
if (outPath !== void 0) {
|
|
15619
|
-
await promises.mkdir(
|
|
15672
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
15620
15673
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
15621
15674
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
15622
15675
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -15975,7 +16028,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
15975
16028
|
endedAt: row.endedAt ?? void 0,
|
|
15976
16029
|
durationMs: row.durationMs ?? void 0,
|
|
15977
16030
|
eventCount: 0,
|
|
15978
|
-
filePath:
|
|
16031
|
+
filePath: path33__default.default.join(traceDir, row.file),
|
|
15979
16032
|
fileSize: 0,
|
|
15980
16033
|
createdAt: new Date(row.mtimeMs)
|
|
15981
16034
|
};
|
|
@@ -16457,9 +16510,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
16457
16510
|
...options.section ? { section: options.section } : {}
|
|
16458
16511
|
});
|
|
16459
16512
|
const resolvedOutput = resolveOutputOption(options);
|
|
16460
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
16513
|
+
const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
|
|
16461
16514
|
if (outPath !== void 0) {
|
|
16462
|
-
await promises.mkdir(
|
|
16515
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
16463
16516
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
16464
16517
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
16465
16518
|
}
|
|
@@ -16657,8 +16710,8 @@ function passesLuhn(value) {
|
|
|
16657
16710
|
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;
|
|
16658
16711
|
var EPOCH_MS_RE = /^1[0-9]{12}$/;
|
|
16659
16712
|
var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
16660
|
-
function pathSuggestsNonCard(
|
|
16661
|
-
const normalized =
|
|
16713
|
+
function pathSuggestsNonCard(path44) {
|
|
16714
|
+
const normalized = path44.toLowerCase().replace(/[^a-z0-9._]/g, "");
|
|
16662
16715
|
return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
|
|
16663
16716
|
normalized
|
|
16664
16717
|
) || /(^|\.)ts(\.|$)/.test(normalized);
|
|
@@ -16854,17 +16907,17 @@ function applyRule(rule, value, replacement) {
|
|
|
16854
16907
|
}
|
|
16855
16908
|
return value;
|
|
16856
16909
|
}
|
|
16857
|
-
function childPath(
|
|
16910
|
+
function childPath(path44, key) {
|
|
16858
16911
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
16859
|
-
return
|
|
16912
|
+
return path44 ? `${path44}.${key}` : key;
|
|
16860
16913
|
}
|
|
16861
|
-
return `${
|
|
16914
|
+
return `${path44 || "$"}[${JSON.stringify(key)}]`;
|
|
16862
16915
|
}
|
|
16863
|
-
function indexPath(
|
|
16864
|
-
return `${
|
|
16916
|
+
function indexPath(path44, index) {
|
|
16917
|
+
return `${path44 || "$"}[${index}]`;
|
|
16865
16918
|
}
|
|
16866
|
-
function makeFinding(
|
|
16867
|
-
return preview === void 0 ? { path:
|
|
16919
|
+
function makeFinding(path44, detector, action, matchKind, severity = "warning", preview) {
|
|
16920
|
+
return preview === void 0 ? { path: path44, detector, action, severity, matchKind } : { path: path44, detector, action, severity, matchKind, preview };
|
|
16868
16921
|
}
|
|
16869
16922
|
function createRedactionProfile(profile = "local") {
|
|
16870
16923
|
switch (profile) {
|
|
@@ -16933,11 +16986,11 @@ var Redactor2 = class {
|
|
|
16933
16986
|
#recordFinding(state, finding) {
|
|
16934
16987
|
if (this.#collectFindings) state.findings.push(finding);
|
|
16935
16988
|
}
|
|
16936
|
-
#redactValue(value, key,
|
|
16989
|
+
#redactValue(value, key, path44, depth, state) {
|
|
16937
16990
|
if (depth > this.#maxDepth) {
|
|
16938
16991
|
this.#recordFinding(
|
|
16939
16992
|
state,
|
|
16940
|
-
makeFinding(
|
|
16993
|
+
makeFinding(path44, "structure.maxDepth", "truncate", "value", "warning")
|
|
16941
16994
|
);
|
|
16942
16995
|
return "[Truncated]";
|
|
16943
16996
|
}
|
|
@@ -16946,19 +16999,19 @@ var Redactor2 = class {
|
|
|
16946
16999
|
if (rule) {
|
|
16947
17000
|
this.#recordFinding(
|
|
16948
17001
|
state,
|
|
16949
|
-
makeFinding(
|
|
17002
|
+
makeFinding(path44, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
16950
17003
|
);
|
|
16951
17004
|
return applyRule(rule, value, this.#replacement);
|
|
16952
17005
|
}
|
|
16953
17006
|
}
|
|
16954
17007
|
for (const detector of this.#detectors) {
|
|
16955
|
-
const detections = detector.detect({ path:
|
|
17008
|
+
const detections = detector.detect({ path: path44, key, value });
|
|
16956
17009
|
for (const detection of detections) {
|
|
16957
17010
|
const action = detection.action ?? "replace";
|
|
16958
17011
|
this.#recordFinding(
|
|
16959
17012
|
state,
|
|
16960
17013
|
makeFinding(
|
|
16961
|
-
|
|
17014
|
+
path44,
|
|
16962
17015
|
detector.id,
|
|
16963
17016
|
action,
|
|
16964
17017
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -16976,7 +17029,7 @@ var Redactor2 = class {
|
|
|
16976
17029
|
const out = [];
|
|
16977
17030
|
state.seen.set(value, out);
|
|
16978
17031
|
value.forEach((item, index) => {
|
|
16979
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
17032
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path44, index), depth + 1, state);
|
|
16980
17033
|
});
|
|
16981
17034
|
return out;
|
|
16982
17035
|
}
|
|
@@ -16988,7 +17041,7 @@ var Redactor2 = class {
|
|
|
16988
17041
|
out[entryKey] = this.#redactValue(
|
|
16989
17042
|
entryValue,
|
|
16990
17043
|
entryKey,
|
|
16991
|
-
childPath(
|
|
17044
|
+
childPath(path44 === "$" ? "" : path44, entryKey),
|
|
16992
17045
|
depth + 1,
|
|
16993
17046
|
state
|
|
16994
17047
|
);
|
|
@@ -17004,6 +17057,233 @@ function createRedactor(options) {
|
|
|
17004
17057
|
function redact(value, options) {
|
|
17005
17058
|
return createRedactor(options).redact(value);
|
|
17006
17059
|
}
|
|
17060
|
+
var REDACTION_POLICY_LIMITS = {
|
|
17061
|
+
maxExtraKeys: 64,
|
|
17062
|
+
maxKeyLength: 64,
|
|
17063
|
+
maxPatterns: 32,
|
|
17064
|
+
maxPatternLength: 128,
|
|
17065
|
+
maxPatternIdLength: 64,
|
|
17066
|
+
maxTypedQuantifier: 64
|
|
17067
|
+
};
|
|
17068
|
+
var SAFE_TYPED_PATTERN = /^[A-Za-z0-9_@./:=<>\-[\]()|+*?{},\\\s^$]+$/;
|
|
17069
|
+
function isRecord16(value) {
|
|
17070
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
17071
|
+
}
|
|
17072
|
+
function escapeRegExp(value) {
|
|
17073
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17074
|
+
}
|
|
17075
|
+
function rejectRemotePolicyPath(policyPath) {
|
|
17076
|
+
const trimmed = policyPath.trim();
|
|
17077
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
|
|
17078
|
+
throw new Error(
|
|
17079
|
+
`--policy must be a local JSON file path (got a URL-like value). Remote policy fetch is not supported.`
|
|
17080
|
+
);
|
|
17081
|
+
}
|
|
17082
|
+
}
|
|
17083
|
+
function parseSeverity(value, label) {
|
|
17084
|
+
if (value === void 0) return "error";
|
|
17085
|
+
if (value === "info" || value === "warning" || value === "error") return value;
|
|
17086
|
+
throw new Error(`${label} severity must be info, warning, or error.`);
|
|
17087
|
+
}
|
|
17088
|
+
function validateExtraKey(key, index) {
|
|
17089
|
+
const label = `extraKeys[${index}]`;
|
|
17090
|
+
if (key.length === 0) throw new Error(`${label} must be a non-empty string.`);
|
|
17091
|
+
if (key.length > REDACTION_POLICY_LIMITS.maxKeyLength) {
|
|
17092
|
+
throw new Error(
|
|
17093
|
+
`${label} exceeds max length ${REDACTION_POLICY_LIMITS.maxKeyLength}.`
|
|
17094
|
+
);
|
|
17095
|
+
}
|
|
17096
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(key)) {
|
|
17097
|
+
throw new Error(
|
|
17098
|
+
`${label} must be an identifier-like key (letters, digits, _, ., -).`
|
|
17099
|
+
);
|
|
17100
|
+
}
|
|
17101
|
+
return key;
|
|
17102
|
+
}
|
|
17103
|
+
function assertBoundedTypedPattern(pattern, label) {
|
|
17104
|
+
if (pattern.length === 0) throw new Error(`${label} must be non-empty.`);
|
|
17105
|
+
if (pattern.length > REDACTION_POLICY_LIMITS.maxPatternLength) {
|
|
17106
|
+
throw new Error(
|
|
17107
|
+
`${label} exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternLength}.`
|
|
17108
|
+
);
|
|
17109
|
+
}
|
|
17110
|
+
if (!SAFE_TYPED_PATTERN.test(pattern)) {
|
|
17111
|
+
throw new Error(
|
|
17112
|
+
`${label} contains unsupported characters for bounded typed patterns.`
|
|
17113
|
+
);
|
|
17114
|
+
}
|
|
17115
|
+
if (/\(\?/.test(pattern) || /\\[1-9]/.test(pattern)) {
|
|
17116
|
+
throw new Error(
|
|
17117
|
+
`${label} rejects lookaround, backreferences, and nested quantifiers.`
|
|
17118
|
+
);
|
|
17119
|
+
}
|
|
17120
|
+
if (/\([^)]*[+*{][^)]*\)[+*{]/.test(pattern) || /\[[^\]]*[+*{][^\]]*\][+*{]/.test(pattern)) {
|
|
17121
|
+
throw new Error(`${label} rejects nested quantifiers.`);
|
|
17122
|
+
}
|
|
17123
|
+
if (/\.[*+]/.test(pattern) || /[*+]\{/.test(pattern)) {
|
|
17124
|
+
throw new Error(`${label} rejects unbounded .* / .+ style quantifiers.`);
|
|
17125
|
+
}
|
|
17126
|
+
for (const match of pattern.matchAll(/\{(\d+)(?:,(\d*))?\}/g)) {
|
|
17127
|
+
const min = Number(match[1]);
|
|
17128
|
+
const maxRaw = match[2];
|
|
17129
|
+
const max = maxRaw === void 0 || maxRaw === "" ? min : Number(maxRaw);
|
|
17130
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || min > REDACTION_POLICY_LIMITS.maxTypedQuantifier || max > REDACTION_POLICY_LIMITS.maxTypedQuantifier) {
|
|
17131
|
+
throw new Error(
|
|
17132
|
+
`${label} quantifiers must be <= ${REDACTION_POLICY_LIMITS.maxTypedQuantifier}.`
|
|
17133
|
+
);
|
|
17134
|
+
}
|
|
17135
|
+
}
|
|
17136
|
+
}
|
|
17137
|
+
function compilePatternDetector(input3, index) {
|
|
17138
|
+
const label = `patterns[${index}]`;
|
|
17139
|
+
if (!isRecord16(input3)) throw new Error(`${label} must be an object.`);
|
|
17140
|
+
const idRaw = input3.id;
|
|
17141
|
+
if (typeof idRaw !== "string" || idRaw.trim() === "") {
|
|
17142
|
+
throw new Error(`${label}.id must be a non-empty string.`);
|
|
17143
|
+
}
|
|
17144
|
+
const id = idRaw.trim();
|
|
17145
|
+
if (id.length > REDACTION_POLICY_LIMITS.maxPatternIdLength) {
|
|
17146
|
+
throw new Error(
|
|
17147
|
+
`${label}.id exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternIdLength}.`
|
|
17148
|
+
);
|
|
17149
|
+
}
|
|
17150
|
+
if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(id)) {
|
|
17151
|
+
throw new Error(`${label}.id must be an identifier-like detector id.`);
|
|
17152
|
+
}
|
|
17153
|
+
const type = input3.type;
|
|
17154
|
+
if (type !== "literal" && type !== "prefix" && type !== "typed") {
|
|
17155
|
+
throw new Error(`${label}.type must be literal, prefix, or typed.`);
|
|
17156
|
+
}
|
|
17157
|
+
const severity = parseSeverity(input3.severity, label);
|
|
17158
|
+
let source;
|
|
17159
|
+
if (type === "typed") {
|
|
17160
|
+
if (typeof input3.pattern !== "string") {
|
|
17161
|
+
throw new Error(`${label}.pattern must be a string for typed patterns.`);
|
|
17162
|
+
}
|
|
17163
|
+
assertBoundedTypedPattern(input3.pattern, `${label}.pattern`);
|
|
17164
|
+
source = input3.pattern;
|
|
17165
|
+
} else {
|
|
17166
|
+
if (typeof input3.value !== "string") {
|
|
17167
|
+
throw new Error(`${label}.value must be a string for ${type} patterns.`);
|
|
17168
|
+
}
|
|
17169
|
+
if (input3.value.length === 0) {
|
|
17170
|
+
throw new Error(`${label}.value must be non-empty.`);
|
|
17171
|
+
}
|
|
17172
|
+
if (input3.value.length > REDACTION_POLICY_LIMITS.maxPatternLength) {
|
|
17173
|
+
throw new Error(
|
|
17174
|
+
`${label}.value exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternLength}.`
|
|
17175
|
+
);
|
|
17176
|
+
}
|
|
17177
|
+
const escaped = escapeRegExp(input3.value);
|
|
17178
|
+
source = type === "prefix" ? `^${escaped}` : escaped;
|
|
17179
|
+
}
|
|
17180
|
+
let regex;
|
|
17181
|
+
try {
|
|
17182
|
+
regex = new RegExp(source);
|
|
17183
|
+
} catch (error) {
|
|
17184
|
+
throw new Error(
|
|
17185
|
+
`${label} failed to compile: ${error instanceof Error ? error.message : String(error)}`
|
|
17186
|
+
);
|
|
17187
|
+
}
|
|
17188
|
+
return {
|
|
17189
|
+
id: `policy.${id}`,
|
|
17190
|
+
severity,
|
|
17191
|
+
matchKind: "custom",
|
|
17192
|
+
detect({ value }) {
|
|
17193
|
+
if (typeof value !== "string") return [];
|
|
17194
|
+
regex.lastIndex = 0;
|
|
17195
|
+
return regex.test(value) ? [{ action: "replace", severity, matchKind: "custom" }] : [];
|
|
17196
|
+
}
|
|
17197
|
+
};
|
|
17198
|
+
}
|
|
17199
|
+
function compileRedactionPolicy(raw, policyPath) {
|
|
17200
|
+
if (!isRecord16(raw)) {
|
|
17201
|
+
throw new Error(`Redaction policy must be a JSON object (${policyPath}).`);
|
|
17202
|
+
}
|
|
17203
|
+
const diagnostics = [];
|
|
17204
|
+
if (raw.version !== void 0 && raw.version !== 1) {
|
|
17205
|
+
throw new Error(`Unsupported redaction policy version (supported: 1).`);
|
|
17206
|
+
}
|
|
17207
|
+
const extraKeysRaw = raw.extraKeys;
|
|
17208
|
+
const extraKeys = [];
|
|
17209
|
+
if (extraKeysRaw !== void 0) {
|
|
17210
|
+
if (!Array.isArray(extraKeysRaw)) {
|
|
17211
|
+
throw new Error(`extraKeys must be an array of strings.`);
|
|
17212
|
+
}
|
|
17213
|
+
if (extraKeysRaw.length > REDACTION_POLICY_LIMITS.maxExtraKeys) {
|
|
17214
|
+
throw new Error(
|
|
17215
|
+
`extraKeys exceeds max count ${REDACTION_POLICY_LIMITS.maxExtraKeys}.`
|
|
17216
|
+
);
|
|
17217
|
+
}
|
|
17218
|
+
for (let i = 0; i < extraKeysRaw.length; i += 1) {
|
|
17219
|
+
const key = extraKeysRaw[i];
|
|
17220
|
+
if (typeof key !== "string") {
|
|
17221
|
+
throw new Error(`extraKeys[${i}] must be a string.`);
|
|
17222
|
+
}
|
|
17223
|
+
extraKeys.push(validateExtraKey(key, i));
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
const patternsRaw = raw.patterns;
|
|
17227
|
+
const detectors = [];
|
|
17228
|
+
if (patternsRaw !== void 0) {
|
|
17229
|
+
if (!Array.isArray(patternsRaw)) {
|
|
17230
|
+
throw new Error(`patterns must be an array.`);
|
|
17231
|
+
}
|
|
17232
|
+
if (patternsRaw.length > REDACTION_POLICY_LIMITS.maxPatterns) {
|
|
17233
|
+
throw new Error(
|
|
17234
|
+
`patterns exceeds max count ${REDACTION_POLICY_LIMITS.maxPatterns}.`
|
|
17235
|
+
);
|
|
17236
|
+
}
|
|
17237
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
17238
|
+
for (let i = 0; i < patternsRaw.length; i += 1) {
|
|
17239
|
+
const detector = compilePatternDetector(
|
|
17240
|
+
patternsRaw[i],
|
|
17241
|
+
i
|
|
17242
|
+
);
|
|
17243
|
+
if (seenIds.has(detector.id)) {
|
|
17244
|
+
throw new Error(`Duplicate pattern id "${detector.id}".`);
|
|
17245
|
+
}
|
|
17246
|
+
seenIds.add(detector.id);
|
|
17247
|
+
detectors.push(detector);
|
|
17248
|
+
}
|
|
17249
|
+
}
|
|
17250
|
+
if (extraKeys.length === 0 && detectors.length === 0) {
|
|
17251
|
+
diagnostics.push({
|
|
17252
|
+
code: "AI_POLICY_EMPTY",
|
|
17253
|
+
message: "Redaction policy contained no extraKeys or patterns."
|
|
17254
|
+
});
|
|
17255
|
+
}
|
|
17256
|
+
return {
|
|
17257
|
+
path: policyPath,
|
|
17258
|
+
extraKeys,
|
|
17259
|
+
detectors,
|
|
17260
|
+
diagnostics
|
|
17261
|
+
};
|
|
17262
|
+
}
|
|
17263
|
+
async function loadRedactionPolicy(policyPath) {
|
|
17264
|
+
rejectRemotePolicyPath(policyPath);
|
|
17265
|
+
const resolved = path33__default.default.resolve(policyPath);
|
|
17266
|
+
let text;
|
|
17267
|
+
try {
|
|
17268
|
+
text = await promises.readFile(resolved, "utf-8");
|
|
17269
|
+
} catch (error) {
|
|
17270
|
+
throw new Error(
|
|
17271
|
+
`Failed to read --policy file "${resolved}": ${error instanceof Error ? error.message : String(error)}`
|
|
17272
|
+
);
|
|
17273
|
+
}
|
|
17274
|
+
let parsed;
|
|
17275
|
+
try {
|
|
17276
|
+
parsed = JSON.parse(text);
|
|
17277
|
+
} catch (error) {
|
|
17278
|
+
throw new Error(
|
|
17279
|
+
`Invalid JSON in --policy file "${resolved}": ${error instanceof Error ? error.message : String(error)}`
|
|
17280
|
+
);
|
|
17281
|
+
}
|
|
17282
|
+
return compileRedactionPolicy(parsed, resolved);
|
|
17283
|
+
}
|
|
17284
|
+
|
|
17285
|
+
// packages/core/src/entries/checks.ts
|
|
17286
|
+
init_checks2();
|
|
17007
17287
|
|
|
17008
17288
|
// packages/cli/src/trace-input.ts
|
|
17009
17289
|
init_advanced();
|
|
@@ -17035,12 +17315,19 @@ async function inputFromTarget(target, options, stdin) {
|
|
|
17035
17315
|
return { type: "file", path: runPath };
|
|
17036
17316
|
}
|
|
17037
17317
|
|
|
17038
|
-
// packages/cli/src/
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17318
|
+
// packages/cli/src/safety.ts
|
|
17319
|
+
var BEST_EFFORT_NOTE = "Best-effort local safety verification only; not a compliance, privacy, security, or regulatory certification.";
|
|
17320
|
+
var DEFAULT_MAX_STRING_LENGTH = 16384;
|
|
17321
|
+
var DEFAULT_MAX_ARRAY_LENGTH = 1e3;
|
|
17322
|
+
var DEFAULT_MAX_OBJECT_KEYS = 200;
|
|
17323
|
+
var DEFAULT_MAX_SERIALIZED_BYTES = 128 * 1024;
|
|
17324
|
+
function parseLimit3(value, label) {
|
|
17325
|
+
if (value === void 0) return void 0;
|
|
17326
|
+
const parsed = Number(value);
|
|
17327
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
17328
|
+
throw new Error(`${label} must be a non-negative number.`);
|
|
17042
17329
|
}
|
|
17043
|
-
|
|
17330
|
+
return parsed;
|
|
17044
17331
|
}
|
|
17045
17332
|
function stable2(value) {
|
|
17046
17333
|
if (Array.isArray(value)) return value.map(stable2);
|
|
@@ -17050,103 +17337,585 @@ function stable2(value) {
|
|
|
17050
17337
|
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable2(record[key])])
|
|
17051
17338
|
);
|
|
17052
17339
|
}
|
|
17053
|
-
function
|
|
17054
|
-
return
|
|
17340
|
+
function safetyDiagnostic(code, message, severity = "error") {
|
|
17341
|
+
return { code, message, severity };
|
|
17055
17342
|
}
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
|
|
17071
|
-
|
|
17072
|
-
|
|
17073
|
-
}
|
|
17074
|
-
return { content: await promises.readFile(runPath, "utf-8"), source: runPath };
|
|
17343
|
+
function warningDiagnostics(warnings, unsupportedFields) {
|
|
17344
|
+
return [
|
|
17345
|
+
...warnings.map(
|
|
17346
|
+
(warning) => safetyDiagnostic(
|
|
17347
|
+
warning.code,
|
|
17348
|
+
warning.message,
|
|
17349
|
+
warning.severity === "error" ? "error" : "warning"
|
|
17350
|
+
)
|
|
17351
|
+
),
|
|
17352
|
+
...unsupportedFields.map(
|
|
17353
|
+
(field) => safetyDiagnostic(
|
|
17354
|
+
"unsupported_field",
|
|
17355
|
+
`Reader reported unsupported field: ${field}`,
|
|
17356
|
+
"warning"
|
|
17357
|
+
)
|
|
17358
|
+
)
|
|
17359
|
+
];
|
|
17075
17360
|
}
|
|
17076
|
-
function
|
|
17077
|
-
|
|
17078
|
-
|
|
17361
|
+
function diagnosticFromCheck(item) {
|
|
17362
|
+
return safetyDiagnostic(item.code, item.message, item.severity);
|
|
17363
|
+
}
|
|
17364
|
+
function statusFrom(findings, diagnostics) {
|
|
17365
|
+
if (diagnostics.some((item) => item.severity === "error")) return "UNKNOWN";
|
|
17366
|
+
if (findings.some((item) => item.severity === "error")) return "UNSAFE";
|
|
17367
|
+
if (diagnostics.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
|
|
17368
|
+
if (findings.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
|
|
17369
|
+
return "SAFE";
|
|
17370
|
+
}
|
|
17371
|
+
function resultFromParts(parts) {
|
|
17372
|
+
const findings = [...parts.findings ?? []];
|
|
17373
|
+
const diagnostics = [...parts.diagnostics ?? []];
|
|
17374
|
+
const warnings = [...parts.warnings ?? []];
|
|
17375
|
+
const unsupportedFields = [...parts.unsupportedFields ?? []];
|
|
17376
|
+
const status = parts.status ?? statusFrom(findings, diagnostics);
|
|
17079
17377
|
return {
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17378
|
+
ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
|
|
17379
|
+
command: parts.command,
|
|
17380
|
+
status,
|
|
17381
|
+
format: parts.format,
|
|
17382
|
+
...parts.runId !== void 0 ? { runId: parts.runId } : {},
|
|
17383
|
+
summary: {
|
|
17384
|
+
findings: findings.length,
|
|
17385
|
+
warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
|
|
17386
|
+
errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
|
|
17387
|
+
},
|
|
17388
|
+
findings,
|
|
17389
|
+
diagnostics,
|
|
17390
|
+
warnings,
|
|
17391
|
+
unsupportedFields,
|
|
17392
|
+
note: BEST_EFFORT_NOTE,
|
|
17393
|
+
...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
|
|
17394
|
+
...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
|
|
17395
|
+
...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
|
|
17083
17396
|
};
|
|
17084
17397
|
}
|
|
17085
|
-
function
|
|
17086
|
-
const lines = content.split(/\r?\n/);
|
|
17087
|
-
const out = [];
|
|
17088
|
-
const findings = [];
|
|
17089
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
17090
|
-
const line = lines[index] ?? "";
|
|
17091
|
-
if (line.trim() === "") continue;
|
|
17092
|
-
let parsed;
|
|
17093
|
-
try {
|
|
17094
|
-
parsed = JSON.parse(line);
|
|
17095
|
-
} catch {
|
|
17096
|
-
throw new Error(`Input is not valid JSON or JSONL at line ${index + 1}.`);
|
|
17097
|
-
}
|
|
17098
|
-
const result = redact(parsed, { profile });
|
|
17099
|
-
out.push(JSON.stringify(result.value));
|
|
17100
|
-
findings.push(
|
|
17101
|
-
...result.findings.map((finding) => ({
|
|
17102
|
-
...finding,
|
|
17103
|
-
path: `line:${index + 1}:${finding.path}`
|
|
17104
|
-
}))
|
|
17105
|
-
);
|
|
17106
|
-
}
|
|
17398
|
+
function layerFromResult(result) {
|
|
17107
17399
|
return {
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
findings
|
|
17400
|
+
status: result.status,
|
|
17401
|
+
summary: result.summary,
|
|
17402
|
+
findings: result.findings
|
|
17111
17403
|
};
|
|
17112
17404
|
}
|
|
17113
|
-
function
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
}
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
}
|
|
17405
|
+
function readErrorResult(command, error) {
|
|
17406
|
+
if (error instanceof TraceReadError) {
|
|
17407
|
+
const code = error.code === "unsupported_format" ? "AI_SAFETY_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_SAFETY_AMBIGUOUS_FORMAT" : "AI_SAFETY_TRACE_UNREADABLE";
|
|
17408
|
+
return resultFromParts({
|
|
17409
|
+
command,
|
|
17410
|
+
format: "unknown",
|
|
17411
|
+
diagnostics: [safetyDiagnostic(code, error.message)],
|
|
17412
|
+
warnings: error.warnings
|
|
17413
|
+
});
|
|
17414
|
+
}
|
|
17415
|
+
return resultFromParts({
|
|
17416
|
+
command,
|
|
17417
|
+
format: "unknown",
|
|
17418
|
+
diagnostics: [
|
|
17419
|
+
safetyDiagnostic(
|
|
17420
|
+
"AI_SAFETY_TRACE_UNREADABLE",
|
|
17421
|
+
error instanceof Error ? error.message : String(error)
|
|
17422
|
+
)
|
|
17423
|
+
]
|
|
17424
|
+
});
|
|
17425
|
+
}
|
|
17426
|
+
function invalidArgumentResult(command, error) {
|
|
17427
|
+
return resultFromParts({
|
|
17428
|
+
command,
|
|
17429
|
+
format: "unknown",
|
|
17430
|
+
diagnostics: [
|
|
17431
|
+
safetyDiagnostic(
|
|
17432
|
+
"AI_SAFETY_INVALID_ARGUMENTS",
|
|
17433
|
+
error instanceof Error ? error.message : String(error)
|
|
17434
|
+
)
|
|
17435
|
+
]
|
|
17436
|
+
});
|
|
17437
|
+
}
|
|
17438
|
+
function buildSafetyRules(options) {
|
|
17439
|
+
const maxStringLength2 = parseLimit3(options.maxStringLength, "--max-string-length") ?? DEFAULT_MAX_STRING_LENGTH;
|
|
17440
|
+
const maxArrayLength = parseLimit3(options.maxArrayLength, "--max-array-length") ?? DEFAULT_MAX_ARRAY_LENGTH;
|
|
17441
|
+
const maxObjectKeys = parseLimit3(options.maxObjectKeys, "--max-object-keys") ?? DEFAULT_MAX_OBJECT_KEYS;
|
|
17442
|
+
const maxSerializedBytes = parseLimit3(options.maxSerializedBytes, "--max-serialized-bytes") ?? DEFAULT_MAX_SERIALIZED_BYTES;
|
|
17443
|
+
return [
|
|
17444
|
+
createSafetyRawContentRule(),
|
|
17445
|
+
createSafetyRedactionRule(),
|
|
17446
|
+
createSafetySecretPatternRule(),
|
|
17447
|
+
createSafetyOversizedAttributeRule({
|
|
17448
|
+
maxStringLength: maxStringLength2,
|
|
17449
|
+
maxArrayLength,
|
|
17450
|
+
maxObjectKeys,
|
|
17451
|
+
maxSerializedBytes
|
|
17452
|
+
})
|
|
17453
|
+
];
|
|
17454
|
+
}
|
|
17455
|
+
function flattenNodes2(nodes) {
|
|
17456
|
+
return nodes.flatMap((node) => [
|
|
17457
|
+
node,
|
|
17458
|
+
...flattenNodes2(
|
|
17459
|
+
node.children
|
|
17460
|
+
)
|
|
17461
|
+
]);
|
|
17462
|
+
}
|
|
17463
|
+
function detectorSeverity(finding) {
|
|
17464
|
+
return finding.severity;
|
|
17465
|
+
}
|
|
17466
|
+
function classifyRedactionDetector(detector) {
|
|
17467
|
+
if (detector === "value.creditCard" || detector === "value.email" || detector === "value.phone") {
|
|
17468
|
+
return { category: "personal-data", confidence: "high" };
|
|
17469
|
+
}
|
|
17470
|
+
if (detector === "value.ipv4" || detector === "value.ipv6") {
|
|
17471
|
+
return { category: "identifier", confidence: "medium" };
|
|
17472
|
+
}
|
|
17473
|
+
if (detector.startsWith("value.") && (detector.includes("Token") || detector.includes("Key") || detector.includes("jwt") || detector.includes("authorization") || detector.includes("bearer") || detector.includes("cookie") || detector.includes("privateKey") || detector.includes("github") || detector.includes("aws") || detector.includes("provider"))) {
|
|
17474
|
+
return { category: "credential", confidence: "high" };
|
|
17475
|
+
}
|
|
17476
|
+
if (detector.startsWith("key.")) {
|
|
17477
|
+
return { category: "credential", confidence: "medium" };
|
|
17478
|
+
}
|
|
17479
|
+
return { category: "credential", confidence: "medium" };
|
|
17480
|
+
}
|
|
17481
|
+
function redactionOptionsFromPolicy(policy) {
|
|
17482
|
+
if (policy === void 0) return {};
|
|
17483
|
+
return {
|
|
17484
|
+
...policy.extraKeys.length > 0 ? { extraKeys: [...policy.extraKeys] } : {},
|
|
17485
|
+
...policy.detectors.length > 0 ? { detectors: [...policy.detectors] } : {}
|
|
17486
|
+
};
|
|
17487
|
+
}
|
|
17488
|
+
function redactionDetectorFindings(read, runId, policy) {
|
|
17489
|
+
const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
|
|
17490
|
+
const out = [];
|
|
17491
|
+
const policyOptions = redactionOptionsFromPolicy(policy);
|
|
17492
|
+
for (const run of runs) {
|
|
17493
|
+
for (const node of flattenNodes2(run.children)) {
|
|
17494
|
+
const attrs = node.event.attributes;
|
|
17495
|
+
if (attrs === void 0) continue;
|
|
17496
|
+
const result = createRedactor({
|
|
17497
|
+
profile: "share",
|
|
17498
|
+
...policyOptions
|
|
17499
|
+
}).redact(attrs);
|
|
17500
|
+
for (const finding of result.findings) {
|
|
17501
|
+
if (finding.action === "keep") continue;
|
|
17502
|
+
const taxonomy = classifyRedactionDetector(finding.detector);
|
|
17503
|
+
out.push({
|
|
17504
|
+
ruleId: "safety.redactDetector",
|
|
17505
|
+
severity: detectorSeverity(finding),
|
|
17506
|
+
status: finding.severity === "error" ? "fail" : "warning",
|
|
17507
|
+
message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
|
|
17508
|
+
expected: "redacted trace content",
|
|
17509
|
+
actual: finding.detector,
|
|
17510
|
+
evidence: [
|
|
17511
|
+
{
|
|
17512
|
+
runId: node.event.runId,
|
|
17513
|
+
eventId: node.event.eventId,
|
|
17514
|
+
...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
|
|
17515
|
+
kind: node.event.kind,
|
|
17516
|
+
name: node.event.name,
|
|
17517
|
+
...node.event.status !== void 0 ? { status: node.event.status } : {},
|
|
17518
|
+
path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
|
|
17519
|
+
}
|
|
17520
|
+
],
|
|
17521
|
+
category: taxonomy.category,
|
|
17522
|
+
confidence: taxonomy.confidence,
|
|
17523
|
+
detector: finding.detector,
|
|
17524
|
+
action: finding.action
|
|
17525
|
+
});
|
|
17526
|
+
}
|
|
17527
|
+
}
|
|
17528
|
+
}
|
|
17529
|
+
return out.sort((a, b) => {
|
|
17530
|
+
const aEvidence = a.evidence[0];
|
|
17531
|
+
const bEvidence = b.evidence[0];
|
|
17532
|
+
return (aEvidence?.runId ?? "").localeCompare(bEvidence?.runId ?? "") || (aEvidence?.eventId ?? "").localeCompare(bEvidence?.eventId ?? "") || (aEvidence?.path ?? "").localeCompare(bEvidence?.path ?? "") || a.message.localeCompare(b.message);
|
|
17533
|
+
});
|
|
17534
|
+
}
|
|
17535
|
+
function exitCodeFor(result) {
|
|
17536
|
+
if (result.status === "SAFE" || result.status === "SAFE WITH WARNINGS") return 0;
|
|
17537
|
+
if (result.status === "UNSAFE") return 1;
|
|
17538
|
+
return 2;
|
|
17539
|
+
}
|
|
17540
|
+
function toResidualStatus(status) {
|
|
17541
|
+
if (status === "SAFE WITH WARNINGS") return "SAFE_WITH_WARNINGS";
|
|
17542
|
+
return status;
|
|
17543
|
+
}
|
|
17544
|
+
function toResidualSafetyAssessment(result) {
|
|
17545
|
+
const codes = [
|
|
17546
|
+
.../* @__PURE__ */ new Set([
|
|
17547
|
+
...result.diagnostics.map((item) => item.code),
|
|
17548
|
+
...result.findings.map((item) => item.ruleId)
|
|
17549
|
+
])
|
|
17550
|
+
].sort((a, b) => a.localeCompare(b));
|
|
17551
|
+
return {
|
|
17552
|
+
status: toResidualStatus(result.status),
|
|
17553
|
+
findings: result.summary.findings,
|
|
17554
|
+
warnings: result.summary.warnings,
|
|
17555
|
+
errors: result.summary.errors,
|
|
17556
|
+
codes,
|
|
17557
|
+
note: BEST_EFFORT_NOTE
|
|
17558
|
+
};
|
|
17559
|
+
}
|
|
17560
|
+
async function assessResidualFromContent(content, options = {}) {
|
|
17561
|
+
try {
|
|
17562
|
+
const policy = options.compiledPolicy ?? (options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0);
|
|
17563
|
+
const read = await openTrace(
|
|
17564
|
+
{ type: "string", content },
|
|
17565
|
+
{ format: options.format ?? "agent-inspect-jsonl" }
|
|
17566
|
+
);
|
|
17567
|
+
const result = assessOpenedTrace(read, {
|
|
17568
|
+
...options,
|
|
17569
|
+
...policy !== void 0 ? { compiledPolicy: policy } : {}
|
|
17570
|
+
});
|
|
17571
|
+
return toResidualSafetyAssessment(result);
|
|
17572
|
+
} catch (error) {
|
|
17573
|
+
if (error instanceof TraceReadError) {
|
|
17574
|
+
return toResidualSafetyAssessment(readErrorResult("verify-safe", error));
|
|
17575
|
+
}
|
|
17576
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17577
|
+
return {
|
|
17578
|
+
status: "UNKNOWN",
|
|
17579
|
+
findings: 0,
|
|
17580
|
+
warnings: 0,
|
|
17581
|
+
errors: 1,
|
|
17582
|
+
codes: ["AI_SAFETY_TRACE_UNREADABLE"],
|
|
17583
|
+
note: `${BEST_EFFORT_NOTE} Residual assessment requires a supported AgentInspect trace; ${message}`
|
|
17584
|
+
};
|
|
17585
|
+
}
|
|
17586
|
+
}
|
|
17587
|
+
function explainFinding(finding, blocksBundle) {
|
|
17588
|
+
const path44 = finding.evidence[0]?.path ?? "(unknown path)";
|
|
17589
|
+
const category = finding.category ?? "structure";
|
|
17590
|
+
const confidence = finding.confidence ?? "medium";
|
|
17591
|
+
const detector = finding.detector ?? finding.ruleId;
|
|
17592
|
+
const action = finding.action ?? "review";
|
|
17593
|
+
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.";
|
|
17594
|
+
return [
|
|
17595
|
+
` Matched: detector=${detector}; path=${path44}; category=${category}`,
|
|
17596
|
+
` Why: ${finding.message}`,
|
|
17597
|
+
` Confidence: ${confidence}`,
|
|
17598
|
+
` Redaction: ${redactionHint}`,
|
|
17599
|
+
` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
|
|
17600
|
+
` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
|
|
17601
|
+
];
|
|
17602
|
+
}
|
|
17603
|
+
function findingExplanation(finding) {
|
|
17604
|
+
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
17605
|
+
return {
|
|
17606
|
+
ruleId: finding.ruleId,
|
|
17607
|
+
detector: finding.detector ?? finding.ruleId,
|
|
17608
|
+
path: finding.evidence[0]?.path,
|
|
17609
|
+
category: finding.category,
|
|
17610
|
+
confidence: finding.confidence,
|
|
17611
|
+
action: finding.action,
|
|
17612
|
+
blocksBundle: blocks,
|
|
17613
|
+
// Never include matched secret/PII values.
|
|
17614
|
+
message: finding.message
|
|
17615
|
+
};
|
|
17616
|
+
}
|
|
17617
|
+
function printHuman(result, explain = false) {
|
|
17618
|
+
console.log(`Safety status: ${result.status}`);
|
|
17619
|
+
console.log(`Format: ${result.format}`);
|
|
17620
|
+
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
17621
|
+
if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
|
|
17622
|
+
console.log(`Source assessment: ${result.sourceAssessment.status}`);
|
|
17623
|
+
console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
|
|
17624
|
+
if (result.redactionSummary !== void 0) {
|
|
17625
|
+
console.log(
|
|
17626
|
+
`Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
|
|
17627
|
+
);
|
|
17628
|
+
}
|
|
17629
|
+
}
|
|
17630
|
+
console.log(
|
|
17631
|
+
`Summary: ${result.summary.findings} finding(s), ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
17632
|
+
);
|
|
17633
|
+
for (const diagnostic7 of result.diagnostics) {
|
|
17634
|
+
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
17635
|
+
}
|
|
17636
|
+
for (const finding of result.findings) {
|
|
17637
|
+
const path44 = finding.evidence[0]?.path;
|
|
17638
|
+
const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
|
|
17639
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}${taxonomy}`);
|
|
17640
|
+
if (explain) {
|
|
17641
|
+
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
17642
|
+
for (const line of explainFinding(finding, blocks)) {
|
|
17643
|
+
console.log(line);
|
|
17644
|
+
}
|
|
17645
|
+
}
|
|
17646
|
+
}
|
|
17647
|
+
console.log(`Note: ${result.note}`);
|
|
17648
|
+
}
|
|
17649
|
+
function printJson(result, explain = false) {
|
|
17650
|
+
const payload = explain === true ? { ...result, explanations: result.findings.map(findingExplanation) } : result;
|
|
17651
|
+
console.log(JSON.stringify(stable2(payload), null, 2));
|
|
17652
|
+
}
|
|
17653
|
+
async function safetyCommand(command, target, options, stdin) {
|
|
17654
|
+
let result;
|
|
17655
|
+
try {
|
|
17656
|
+
const policy = options.compiledPolicy ?? (options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0);
|
|
17657
|
+
const optionsWithPolicy = {
|
|
17658
|
+
...options,
|
|
17659
|
+
...policy !== void 0 ? { compiledPolicy: policy } : {}
|
|
17660
|
+
};
|
|
17661
|
+
const input3 = await inputFromTarget(target, optionsWithPolicy, stdin);
|
|
17662
|
+
const read = await openTrace(input3, {
|
|
17663
|
+
...options.format !== void 0 ? { format: options.format } : {}
|
|
17664
|
+
});
|
|
17665
|
+
const source = assessOpenedTrace(read, {
|
|
17666
|
+
...optionsWithPolicy,
|
|
17667
|
+
...options.run !== void 0 ? { runId: options.run } : {}
|
|
17668
|
+
});
|
|
17669
|
+
if (command === "scan") {
|
|
17670
|
+
result = { ...source, command: "scan" };
|
|
17671
|
+
} else {
|
|
17672
|
+
const profile = options.redactionProfile ?? "share";
|
|
17673
|
+
const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
|
|
17674
|
+
if (rawContent === void 0) {
|
|
17675
|
+
result = {
|
|
17676
|
+
...source,
|
|
17677
|
+
command: "verify-safe",
|
|
17678
|
+
sourceAssessment: layerFromResult(source)
|
|
17679
|
+
};
|
|
17680
|
+
} else {
|
|
17681
|
+
const redacted = redactTraceContent(rawContent, profile, policy);
|
|
17682
|
+
const artifactRead = await openTrace(
|
|
17683
|
+
{ type: "string", content: redacted.content },
|
|
17684
|
+
{ format: options.format ?? "agent-inspect-jsonl" }
|
|
17685
|
+
);
|
|
17686
|
+
const artifact = assessOpenedTrace(artifactRead, {
|
|
17687
|
+
...optionsWithPolicy,
|
|
17688
|
+
...options.run !== void 0 ? { runId: options.run } : {}
|
|
17689
|
+
});
|
|
17690
|
+
const detectors = [
|
|
17691
|
+
...new Set(redacted.findings.map((finding) => finding.detector))
|
|
17692
|
+
].sort((a, b) => a.localeCompare(b));
|
|
17693
|
+
result = resultFromParts({
|
|
17694
|
+
command: "verify-safe",
|
|
17695
|
+
format: artifact.format,
|
|
17696
|
+
runId: artifact.runId ?? source.runId,
|
|
17697
|
+
findings: artifact.findings,
|
|
17698
|
+
diagnostics: artifact.diagnostics,
|
|
17699
|
+
warnings: artifact.warnings,
|
|
17700
|
+
unsupportedFields: artifact.unsupportedFields,
|
|
17701
|
+
status: artifact.status,
|
|
17702
|
+
sourceAssessment: layerFromResult(source),
|
|
17703
|
+
artifactAssessment: layerFromResult(artifact),
|
|
17704
|
+
redactionSummary: {
|
|
17705
|
+
profile,
|
|
17706
|
+
findings: redacted.findings.length,
|
|
17707
|
+
detectors
|
|
17708
|
+
}
|
|
17709
|
+
});
|
|
17710
|
+
}
|
|
17711
|
+
}
|
|
17712
|
+
} catch (error) {
|
|
17713
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17714
|
+
result = message.startsWith("--") || message.includes("--policy") ? invalidArgumentResult(command, error) : readErrorResult(command, error);
|
|
17715
|
+
}
|
|
17716
|
+
process.exitCode = exitCodeFor(result);
|
|
17717
|
+
if (options.json) printJson(result, options.explain === true);
|
|
17718
|
+
else printHuman(result, options.explain === true);
|
|
17719
|
+
}
|
|
17720
|
+
function scanCommand(target, options = {}, stdin = process.stdin) {
|
|
17721
|
+
return safetyCommand("scan", target, options, stdin);
|
|
17722
|
+
}
|
|
17723
|
+
function verifySafeCommand(target, options = {}, stdin = process.stdin) {
|
|
17724
|
+
return safetyCommand("verify-safe", target, options, stdin);
|
|
17725
|
+
}
|
|
17726
|
+
function assessOpenedTrace(read, options = {}) {
|
|
17727
|
+
try {
|
|
17728
|
+
const rules = buildSafetyRules(options);
|
|
17729
|
+
const checkResult = runTraceChecks(
|
|
17730
|
+
{ read },
|
|
17731
|
+
{
|
|
17732
|
+
rules,
|
|
17733
|
+
...options.runId !== void 0 ? { runId: options.runId } : {},
|
|
17734
|
+
...options.run !== void 0 ? { runId: options.run } : {}
|
|
17735
|
+
}
|
|
17736
|
+
);
|
|
17737
|
+
const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId, options.compiledPolicy) : [];
|
|
17738
|
+
return resultFromParts({
|
|
17739
|
+
command: "verify-safe",
|
|
17740
|
+
format: checkResult.format,
|
|
17741
|
+
runId: checkResult.runId,
|
|
17742
|
+
findings: [...checkResult.findings, ...detectorFindings],
|
|
17743
|
+
diagnostics: [
|
|
17744
|
+
...checkResult.diagnostics.map(diagnosticFromCheck),
|
|
17745
|
+
...warningDiagnostics(read.warnings, read.unsupportedFields)
|
|
17746
|
+
],
|
|
17747
|
+
warnings: read.warnings,
|
|
17748
|
+
unsupportedFields: read.unsupportedFields
|
|
17749
|
+
});
|
|
17750
|
+
} catch (error) {
|
|
17751
|
+
return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult("verify-safe", error);
|
|
17752
|
+
}
|
|
17753
|
+
}
|
|
17754
|
+
function messageStartsWithDash(error) {
|
|
17755
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17756
|
+
return message.startsWith("--");
|
|
17757
|
+
}
|
|
17758
|
+
|
|
17759
|
+
// packages/cli/src/redact.ts
|
|
17760
|
+
function parseRedactionProfile3(value) {
|
|
17761
|
+
if (value === void 0 || value === "local" || value === "share" || value === "strict") {
|
|
17762
|
+
return value ?? "share";
|
|
17763
|
+
}
|
|
17764
|
+
throw new Error(`Unsupported --profile "${value}". Use local, share, or strict.`);
|
|
17765
|
+
}
|
|
17766
|
+
function stable3(value) {
|
|
17767
|
+
if (Array.isArray(value)) return value.map(stable3);
|
|
17768
|
+
if (value === null || typeof value !== "object") return value;
|
|
17769
|
+
const record = value;
|
|
17770
|
+
return Object.fromEntries(
|
|
17771
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
|
|
17772
|
+
);
|
|
17773
|
+
}
|
|
17774
|
+
function isMissingFileError3(error) {
|
|
17775
|
+
return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
|
|
17776
|
+
}
|
|
17777
|
+
async function contentFromTarget(target, options, stdin) {
|
|
17778
|
+
if (target === "-") {
|
|
17779
|
+
return { content: await readStdin(stdin), source: "stdin" };
|
|
17780
|
+
}
|
|
17781
|
+
try {
|
|
17782
|
+
const stats2 = await promises.stat(target);
|
|
17783
|
+
if (stats2.isDirectory()) {
|
|
17784
|
+
throw new Error("redact requires a trace file, JSON file, stdin, or run id.");
|
|
17785
|
+
}
|
|
17786
|
+
return { content: await promises.readFile(target, "utf-8"), source: target };
|
|
17787
|
+
} catch (error) {
|
|
17788
|
+
if (!isMissingFileError3(error)) throw error;
|
|
17789
|
+
}
|
|
17790
|
+
const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
|
|
17791
|
+
const stats = await promises.stat(runPath);
|
|
17792
|
+
if (stats.isDirectory()) {
|
|
17793
|
+
throw new Error("redact requires a trace file, JSON file, stdin, or run id.");
|
|
17794
|
+
}
|
|
17795
|
+
return { content: await promises.readFile(runPath, "utf-8"), source: runPath };
|
|
17796
|
+
}
|
|
17797
|
+
function applyRedact(value, profile, policy) {
|
|
17798
|
+
const result = createRedactor({
|
|
17799
|
+
profile,
|
|
17800
|
+
...policy?.extraKeys.length ? { extraKeys: [...policy.extraKeys] } : {},
|
|
17801
|
+
...policy?.detectors.length ? { detectors: [...policy.detectors] } : {}
|
|
17802
|
+
}).redact(value);
|
|
17803
|
+
return { value: result.value, findings: result.findings };
|
|
17804
|
+
}
|
|
17805
|
+
function redactJsonText(content, profile, policy) {
|
|
17806
|
+
const parsed = JSON.parse(content);
|
|
17807
|
+
const result = applyRedact(parsed, profile, policy);
|
|
17808
|
+
return {
|
|
17809
|
+
content: `${JSON.stringify(result.value, null, 2)}
|
|
17810
|
+
`,
|
|
17811
|
+
findings: result.findings
|
|
17812
|
+
};
|
|
17813
|
+
}
|
|
17814
|
+
function redactJsonlText(content, profile, policy) {
|
|
17815
|
+
const lines = content.split(/\r?\n/);
|
|
17816
|
+
const out = [];
|
|
17817
|
+
const findings = [];
|
|
17818
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
17819
|
+
const line = lines[index] ?? "";
|
|
17820
|
+
if (line.trim() === "") continue;
|
|
17821
|
+
let parsed;
|
|
17822
|
+
try {
|
|
17823
|
+
parsed = JSON.parse(line);
|
|
17824
|
+
} catch {
|
|
17825
|
+
throw new Error(`Input is not valid JSON or JSONL at line ${index + 1}.`);
|
|
17826
|
+
}
|
|
17827
|
+
const result = applyRedact(parsed, profile, policy);
|
|
17828
|
+
out.push(JSON.stringify(result.value));
|
|
17829
|
+
findings.push(
|
|
17830
|
+
...result.findings.map((finding) => ({
|
|
17831
|
+
...finding,
|
|
17832
|
+
path: `line:${index + 1}:${finding.path}`
|
|
17833
|
+
}))
|
|
17834
|
+
);
|
|
17835
|
+
}
|
|
17836
|
+
return {
|
|
17837
|
+
content: out.length === 0 ? "" : `${out.join("\n")}
|
|
17838
|
+
`,
|
|
17839
|
+
findings
|
|
17840
|
+
};
|
|
17841
|
+
}
|
|
17842
|
+
function redactDocument(content, profile, policy) {
|
|
17843
|
+
const trimmed = content.trim();
|
|
17844
|
+
if (trimmed.startsWith("{")) {
|
|
17845
|
+
try {
|
|
17846
|
+
const parsed = JSON.parse(trimmed);
|
|
17847
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed)) {
|
|
17848
|
+
return redactJsonlText(content, profile, policy);
|
|
17849
|
+
}
|
|
17850
|
+
} catch {
|
|
17851
|
+
}
|
|
17852
|
+
}
|
|
17853
|
+
try {
|
|
17854
|
+
return redactJsonText(content, profile, policy);
|
|
17855
|
+
} catch {
|
|
17856
|
+
return redactJsonlText(content, profile, policy);
|
|
17857
|
+
}
|
|
17858
|
+
}
|
|
17859
|
+
function redactTraceContent(content, profile, policy) {
|
|
17860
|
+
return redactDocument(content, profile, policy);
|
|
17861
|
+
}
|
|
17862
|
+
function looksLikeAgentInspectTrace(content) {
|
|
17863
|
+
const trimmed = content.trim();
|
|
17864
|
+
if (!trimmed.startsWith("{")) return false;
|
|
17865
|
+
try {
|
|
17866
|
+
const firstLine = trimmed.split(/\r?\n/).find((line) => line.trim() !== "") ?? trimmed;
|
|
17867
|
+
const parsed = JSON.parse(firstLine);
|
|
17868
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed);
|
|
17869
|
+
} catch {
|
|
17870
|
+
return false;
|
|
17871
|
+
}
|
|
17872
|
+
}
|
|
17873
|
+
function printResidualWarning(assessment, sourceLooksLikeTrace) {
|
|
17874
|
+
if (assessment.status === "SAFE") return;
|
|
17875
|
+
if (assessment.status === "UNKNOWN" && !sourceLooksLikeTrace) return;
|
|
17876
|
+
const codes = assessment.codes.length > 0 ? ` codes=${assessment.codes.join(",")}` : "";
|
|
17877
|
+
console.error(
|
|
17878
|
+
`Residual safety: ${assessment.status} (findings=${assessment.findings}, warnings=${assessment.warnings}, errors=${assessment.errors})${codes}. Redact does not certify safe sharing; run verify-safe before publishing.`
|
|
17879
|
+
);
|
|
17880
|
+
}
|
|
17881
|
+
function residualExitCode(assessment) {
|
|
17882
|
+
if (assessment.status === "UNSAFE") return 1;
|
|
17883
|
+
if (assessment.status === "UNKNOWN") return 2;
|
|
17884
|
+
return 0;
|
|
17885
|
+
}
|
|
17133
17886
|
async function redactCommand(target, options = {}, stdin = process.stdin) {
|
|
17134
17887
|
const profile = parseRedactionProfile3(resolveRedactionProfileOption(options));
|
|
17888
|
+
const policy = options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0;
|
|
17135
17889
|
const source = await contentFromTarget(target, options, stdin);
|
|
17136
|
-
const redacted = redactDocument(source.content, profile);
|
|
17890
|
+
const redacted = redactDocument(source.content, profile, policy);
|
|
17137
17891
|
const outputPath = resolveOutputOption(options);
|
|
17892
|
+
const residualAssessment = await assessResidualFromContent(redacted.content, {
|
|
17893
|
+
compiledPolicy: policy
|
|
17894
|
+
});
|
|
17138
17895
|
if (outputPath !== void 0) {
|
|
17139
17896
|
await promises.writeFile(outputPath, redacted.content, "utf-8");
|
|
17140
17897
|
}
|
|
17898
|
+
if (options.failOnResidual === true) {
|
|
17899
|
+
process.exitCode = residualExitCode(residualAssessment);
|
|
17900
|
+
}
|
|
17141
17901
|
if (options.json) {
|
|
17142
17902
|
console.log(
|
|
17143
17903
|
JSON.stringify(
|
|
17144
|
-
|
|
17904
|
+
stable3({
|
|
17145
17905
|
ok: true,
|
|
17146
17906
|
profile,
|
|
17147
17907
|
source: source.source,
|
|
17148
17908
|
output: outputPath,
|
|
17149
17909
|
findings: redacted.findings,
|
|
17910
|
+
residualAssessment,
|
|
17911
|
+
...policy !== void 0 ? {
|
|
17912
|
+
policy: {
|
|
17913
|
+
path: policy.path,
|
|
17914
|
+
extraKeys: policy.extraKeys.length,
|
|
17915
|
+
patterns: policy.detectors.length,
|
|
17916
|
+
diagnostics: policy.diagnostics
|
|
17917
|
+
}
|
|
17918
|
+
} : {},
|
|
17150
17919
|
content: outputPath === void 0 ? redacted.content : void 0
|
|
17151
17920
|
}),
|
|
17152
17921
|
null,
|
|
@@ -17155,6 +17924,7 @@ async function redactCommand(target, options = {}, stdin = process.stdin) {
|
|
|
17155
17924
|
);
|
|
17156
17925
|
return;
|
|
17157
17926
|
}
|
|
17927
|
+
printResidualWarning(residualAssessment, looksLikeAgentInspectTrace(redacted.content));
|
|
17158
17928
|
if (outputPath === void 0) {
|
|
17159
17929
|
process.stdout.write(redacted.content);
|
|
17160
17930
|
}
|
|
@@ -17437,7 +18207,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
|
17437
18207
|
|
|
17438
18208
|
// packages/cli/src/migrate.ts
|
|
17439
18209
|
init_advanced();
|
|
17440
|
-
function
|
|
18210
|
+
function isRecord17(value) {
|
|
17441
18211
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17442
18212
|
}
|
|
17443
18213
|
function parseTarget(value) {
|
|
@@ -17446,7 +18216,7 @@ function parseTarget(value) {
|
|
|
17446
18216
|
throw new Error('Unsupported migration target. Use "--to 1.0".');
|
|
17447
18217
|
}
|
|
17448
18218
|
function formatOf(value) {
|
|
17449
|
-
if (!
|
|
18219
|
+
if (!isRecord17(value)) return "unknown";
|
|
17450
18220
|
if (value.schemaVersion === "0.1") return "0.1";
|
|
17451
18221
|
if (value.schemaVersion === "0.2") return "0.2";
|
|
17452
18222
|
if (value.schemaVersion === "1.0") return "1.0";
|
|
@@ -17459,14 +18229,14 @@ function uniqueSorted(values) {
|
|
|
17459
18229
|
return [...new Set(values)].sort();
|
|
17460
18230
|
}
|
|
17461
18231
|
function isWithinDirectory(child, parent) {
|
|
17462
|
-
const relative =
|
|
17463
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
18232
|
+
const relative = path33__default.default.relative(parent, child);
|
|
18233
|
+
return relative === "" || !relative.startsWith("..") && !path33__default.default.isAbsolute(relative);
|
|
17464
18234
|
}
|
|
17465
18235
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
17466
18236
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
17467
|
-
const inputAbs =
|
|
17468
|
-
const outputAbs =
|
|
17469
|
-
const inputDir =
|
|
18237
|
+
const inputAbs = path33__default.default.resolve(inputPath);
|
|
18238
|
+
const outputAbs = path33__default.default.resolve(output2.trim());
|
|
18239
|
+
const inputDir = path33__default.default.dirname(inputAbs);
|
|
17470
18240
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
17471
18241
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
17472
18242
|
}
|
|
@@ -17587,7 +18357,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17587
18357
|
process.exitCode = 1;
|
|
17588
18358
|
return;
|
|
17589
18359
|
}
|
|
17590
|
-
const inputPath =
|
|
18360
|
+
const inputPath = path33__default.default.resolve(input3.trim());
|
|
17591
18361
|
const dryRun = options.dryRun === true;
|
|
17592
18362
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
17593
18363
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -17606,7 +18376,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17606
18376
|
);
|
|
17607
18377
|
const result = await buildMigration(inputPath, outputPath);
|
|
17608
18378
|
if (!dryRun && outputPath !== void 0) {
|
|
17609
|
-
await promises.mkdir(
|
|
18379
|
+
await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
|
|
17610
18380
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
17611
18381
|
}
|
|
17612
18382
|
printSummary2(result, dryRun);
|
|
@@ -17615,16 +18385,13 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17615
18385
|
console.error(`[AgentInspect] migrate failed: ${msg}`);
|
|
17616
18386
|
process.exitCode = 1;
|
|
17617
18387
|
}
|
|
17618
|
-
}
|
|
17619
|
-
init_advanced();
|
|
17620
|
-
|
|
17621
|
-
// packages/core/src/entries/checks.ts
|
|
17622
|
-
init_checks2();
|
|
18388
|
+
}
|
|
18389
|
+
init_advanced();
|
|
17623
18390
|
|
|
17624
18391
|
// packages/cli/src/evidence-on.ts
|
|
17625
18392
|
init_advanced();
|
|
17626
18393
|
function validateReporterArtifactPath(options) {
|
|
17627
|
-
const outputDir =
|
|
18394
|
+
const outputDir = path33__default.default.resolve(options.outputDir);
|
|
17628
18395
|
const diagnostics = [];
|
|
17629
18396
|
const rawPath = options.relativePath;
|
|
17630
18397
|
if (rawPath.length === 0) {
|
|
@@ -17644,7 +18411,7 @@ function validateReporterArtifactPath(options) {
|
|
|
17644
18411
|
});
|
|
17645
18412
|
return { ok: false, outputDir, diagnostics };
|
|
17646
18413
|
}
|
|
17647
|
-
if (
|
|
18414
|
+
if (path33__default.default.isAbsolute(rawPath) || path33__default.default.win32.isAbsolute(rawPath)) {
|
|
17648
18415
|
diagnostics.push({
|
|
17649
18416
|
code: "artifact_path_absolute",
|
|
17650
18417
|
severity: "error",
|
|
@@ -17653,7 +18420,7 @@ function validateReporterArtifactPath(options) {
|
|
|
17653
18420
|
});
|
|
17654
18421
|
return { ok: false, outputDir, diagnostics };
|
|
17655
18422
|
}
|
|
17656
|
-
const normalized =
|
|
18423
|
+
const normalized = path33__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
17657
18424
|
const segments = normalized.split("/");
|
|
17658
18425
|
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
17659
18426
|
diagnostics.push({
|
|
@@ -17664,9 +18431,9 @@ function validateReporterArtifactPath(options) {
|
|
|
17664
18431
|
});
|
|
17665
18432
|
return { ok: false, outputDir, diagnostics };
|
|
17666
18433
|
}
|
|
17667
|
-
const absolutePath =
|
|
17668
|
-
const relFromOutput =
|
|
17669
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") ||
|
|
18434
|
+
const absolutePath = path33__default.default.resolve(outputDir, normalized);
|
|
18435
|
+
const relFromOutput = path33__default.default.relative(outputDir, absolutePath);
|
|
18436
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path33__default.default.isAbsolute(relFromOutput)) {
|
|
17670
18437
|
diagnostics.push({
|
|
17671
18438
|
code: "artifact_path_escape",
|
|
17672
18439
|
severity: "error",
|
|
@@ -17692,7 +18459,7 @@ var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
|
17692
18459
|
function createEvidenceCiArtifacts(options) {
|
|
17693
18460
|
const profile = options.redactionProfile ?? "share";
|
|
17694
18461
|
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
17695
|
-
const join = (name) => prefix === "" ? name :
|
|
18462
|
+
const join = (name) => prefix === "" ? name : path33__default.default.posix.join(prefix, name);
|
|
17696
18463
|
const formatFor = (name) => {
|
|
17697
18464
|
if (name.endsWith(".html")) return "html";
|
|
17698
18465
|
if (name.endsWith(".jsonl")) return "jsonl";
|
|
@@ -17741,9 +18508,9 @@ function stableJson2(value) {
|
|
|
17741
18508
|
async function writeLocalEvidence(input3) {
|
|
17742
18509
|
const profile = input3.redactionProfile ?? "share";
|
|
17743
18510
|
const format = input3.format ?? "directory";
|
|
17744
|
-
const baseDir =
|
|
18511
|
+
const baseDir = path33__default.default.resolve(input3.outputDir);
|
|
17745
18512
|
await promises.mkdir(
|
|
17746
|
-
format === "zip" && baseDir.toLowerCase().endsWith(".zip") ?
|
|
18513
|
+
format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path33__default.default.dirname(baseDir) : baseDir,
|
|
17747
18514
|
{ recursive: true }
|
|
17748
18515
|
);
|
|
17749
18516
|
const sourceContents = /* @__PURE__ */ new Map();
|
|
@@ -17799,7 +18566,7 @@ async function writeLocalEvidence(input3) {
|
|
|
17799
18566
|
}
|
|
17800
18567
|
if (format === "zip") {
|
|
17801
18568
|
const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
|
|
17802
|
-
await promises.mkdir(
|
|
18569
|
+
await promises.mkdir(path33__default.default.dirname(zipPath), { recursive: true });
|
|
17803
18570
|
const archive = buildZipArchive(
|
|
17804
18571
|
files.map(([relativePath, content]) => ({
|
|
17805
18572
|
path: relativePath,
|
|
@@ -17814,16 +18581,16 @@ async function writeLocalEvidence(input3) {
|
|
|
17814
18581
|
let sidecarDir = baseDir;
|
|
17815
18582
|
if (baseDir.toLowerCase().endsWith(".html")) {
|
|
17816
18583
|
htmlPath = baseDir;
|
|
17817
|
-
sidecarDir =
|
|
18584
|
+
sidecarDir = path33__default.default.dirname(baseDir);
|
|
17818
18585
|
} else {
|
|
17819
18586
|
await promises.mkdir(baseDir, { recursive: true });
|
|
17820
|
-
htmlPath =
|
|
18587
|
+
htmlPath = path33__default.default.join(baseDir, "evidence.html");
|
|
17821
18588
|
sidecarDir = baseDir;
|
|
17822
18589
|
}
|
|
17823
18590
|
await promises.mkdir(sidecarDir, { recursive: true });
|
|
17824
18591
|
await promises.writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
|
|
17825
18592
|
await promises.writeFile(
|
|
17826
|
-
|
|
18593
|
+
path33__default.default.join(sidecarDir, "evidence.json"),
|
|
17827
18594
|
evidencePackage["evidence.json"],
|
|
17828
18595
|
"utf-8"
|
|
17829
18596
|
);
|
|
@@ -17831,7 +18598,7 @@ async function writeLocalEvidence(input3) {
|
|
|
17831
18598
|
}
|
|
17832
18599
|
await promises.mkdir(baseDir, { recursive: true });
|
|
17833
18600
|
for (const [name, content] of files) {
|
|
17834
|
-
await promises.writeFile(
|
|
18601
|
+
await promises.writeFile(path33__default.default.join(baseDir, name), content, "utf-8");
|
|
17835
18602
|
}
|
|
17836
18603
|
return baseDir;
|
|
17837
18604
|
}
|
|
@@ -17855,11 +18622,11 @@ function checkResultToEvidenceJson(result, runIds) {
|
|
|
17855
18622
|
}
|
|
17856
18623
|
function defaultEvidenceDir(label) {
|
|
17857
18624
|
const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
|
|
17858
|
-
return
|
|
18625
|
+
return path33__default.default.join(".agent-inspect", "evidence", safe);
|
|
17859
18626
|
}
|
|
17860
18627
|
function resolveEvidenceOutputDir(evidenceDir, label) {
|
|
17861
18628
|
if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
|
|
17862
|
-
return
|
|
18629
|
+
return path33__default.default.resolve(evidenceDir.trim());
|
|
17863
18630
|
}
|
|
17864
18631
|
return defaultEvidenceDir(label);
|
|
17865
18632
|
}
|
|
@@ -18183,23 +18950,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
18183
18950
|
}
|
|
18184
18951
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
18185
18952
|
}
|
|
18186
|
-
function validateSchemaField(value, field,
|
|
18953
|
+
function validateSchemaField(value, field, path44, evidence) {
|
|
18187
18954
|
const ruleId = "guardrail.structured-output";
|
|
18188
18955
|
if (field.type) {
|
|
18189
18956
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
18190
18957
|
if (actual !== field.type) {
|
|
18191
|
-
evidence.push({ ruleId, path:
|
|
18958
|
+
evidence.push({ ruleId, path: path44, preview: `expected ${field.type}, got ${actual}` });
|
|
18192
18959
|
return;
|
|
18193
18960
|
}
|
|
18194
18961
|
}
|
|
18195
18962
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
18196
|
-
evidence.push({ ruleId, path:
|
|
18963
|
+
evidence.push({ ruleId, path: path44, preview: "value not in enum" });
|
|
18197
18964
|
}
|
|
18198
18965
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
18199
18966
|
const record = value;
|
|
18200
18967
|
for (const key of field.required) {
|
|
18201
18968
|
if (!(key in record)) {
|
|
18202
|
-
evidence.push({ ruleId, path: `${
|
|
18969
|
+
evidence.push({ ruleId, path: `${path44}.${key}`, preview: "missing required key" });
|
|
18203
18970
|
}
|
|
18204
18971
|
}
|
|
18205
18972
|
}
|
|
@@ -18928,7 +19695,7 @@ function parseCheckConfig(value) {
|
|
|
18928
19695
|
}
|
|
18929
19696
|
async function loadConfig(configPath) {
|
|
18930
19697
|
if (configPath === void 0) return {};
|
|
18931
|
-
const extension =
|
|
19698
|
+
const extension = path33__default.default.extname(configPath);
|
|
18932
19699
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
18933
19700
|
throw new CheckConfigError(
|
|
18934
19701
|
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
@@ -18941,7 +19708,7 @@ async function loadConfig(configPath) {
|
|
|
18941
19708
|
"Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
|
|
18942
19709
|
);
|
|
18943
19710
|
}
|
|
18944
|
-
const absolute =
|
|
19711
|
+
const absolute = path33__default.default.resolve(configPath);
|
|
18945
19712
|
try {
|
|
18946
19713
|
if (extension === ".json") {
|
|
18947
19714
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
@@ -19135,7 +19902,7 @@ function buildRules(config, options, presetSelect = []) {
|
|
|
19135
19902
|
diagnostics
|
|
19136
19903
|
};
|
|
19137
19904
|
}
|
|
19138
|
-
function
|
|
19905
|
+
function exitCodeFor2(result) {
|
|
19139
19906
|
if (result.status === "pass") return 0;
|
|
19140
19907
|
if (result.status === "fail") return 1;
|
|
19141
19908
|
const codes = result.diagnostics.map((item) => item.code);
|
|
@@ -19156,16 +19923,16 @@ function exitCodeFor(result) {
|
|
|
19156
19923
|
}
|
|
19157
19924
|
return 1;
|
|
19158
19925
|
}
|
|
19159
|
-
function
|
|
19160
|
-
if (Array.isArray(value)) return value.map(
|
|
19926
|
+
function stable4(value) {
|
|
19927
|
+
if (Array.isArray(value)) return value.map(stable4);
|
|
19161
19928
|
if (value === null || typeof value !== "object") return value;
|
|
19162
19929
|
const record = value;
|
|
19163
19930
|
return Object.fromEntries(
|
|
19164
|
-
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key,
|
|
19931
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
|
|
19165
19932
|
);
|
|
19166
19933
|
}
|
|
19167
|
-
function
|
|
19168
|
-
console.log(JSON.stringify(
|
|
19934
|
+
function printJson2(result) {
|
|
19935
|
+
console.log(JSON.stringify(stable4(result), null, 2));
|
|
19169
19936
|
}
|
|
19170
19937
|
function isSafetyFinding(ruleId) {
|
|
19171
19938
|
return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
|
|
@@ -19202,7 +19969,7 @@ function printPresetClassSummary(result, preset) {
|
|
|
19202
19969
|
`Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
19203
19970
|
);
|
|
19204
19971
|
}
|
|
19205
|
-
function
|
|
19972
|
+
function printHuman2(result, options = {}) {
|
|
19206
19973
|
const scoped = result;
|
|
19207
19974
|
if (scoped.scopeLabel) {
|
|
19208
19975
|
console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
|
|
@@ -19222,13 +19989,13 @@ function printHuman(result, options = {}) {
|
|
|
19222
19989
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
19223
19990
|
}
|
|
19224
19991
|
for (const finding of result.findings) {
|
|
19225
|
-
const
|
|
19992
|
+
const path44 = finding.evidence[0]?.path;
|
|
19226
19993
|
const run = finding.evidence[0]?.runId;
|
|
19227
19994
|
const runPrefix = run ? `[${run}] ` : "";
|
|
19228
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
19995
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
|
|
19229
19996
|
}
|
|
19230
19997
|
}
|
|
19231
|
-
function
|
|
19998
|
+
function readErrorResult2(error) {
|
|
19232
19999
|
if (error instanceof TraceReadError) {
|
|
19233
20000
|
const code = error.code === "unsupported_format" ? "AI_CHECK_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_CHECK_AMBIGUOUS_FORMAT" : "AI_CHECK_TRACE_UNREADABLE";
|
|
19234
20001
|
return errorResult2(code, error.message);
|
|
@@ -19255,9 +20022,9 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
19255
20022
|
"AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
|
|
19256
20023
|
"Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
|
|
19257
20024
|
);
|
|
19258
|
-
if (options.json)
|
|
19259
|
-
else
|
|
19260
|
-
process.exitCode =
|
|
20025
|
+
if (options.json) printJson2(result);
|
|
20026
|
+
else printHuman2(result, options);
|
|
20027
|
+
process.exitCode = exitCodeFor2(result);
|
|
19261
20028
|
return;
|
|
19262
20029
|
}
|
|
19263
20030
|
let effectiveOptions = options;
|
|
@@ -19387,10 +20154,10 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
19387
20154
|
result = errorResult2(code, message);
|
|
19388
20155
|
}
|
|
19389
20156
|
} else {
|
|
19390
|
-
result =
|
|
20157
|
+
result = readErrorResult2(error);
|
|
19391
20158
|
}
|
|
19392
20159
|
}
|
|
19393
|
-
process.exitCode =
|
|
20160
|
+
process.exitCode = exitCodeFor2(result);
|
|
19394
20161
|
const failed = result.status !== "pass";
|
|
19395
20162
|
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
19396
20163
|
try {
|
|
@@ -19430,8 +20197,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
19430
20197
|
);
|
|
19431
20198
|
}
|
|
19432
20199
|
}
|
|
19433
|
-
if (options.json)
|
|
19434
|
-
else
|
|
20200
|
+
if (options.json) printJson2(result);
|
|
20201
|
+
else printHuman2(result, options);
|
|
19435
20202
|
}
|
|
19436
20203
|
|
|
19437
20204
|
// packages/viewer/src/server.ts
|
|
@@ -19588,7 +20355,7 @@ async function loadSuiteViewerData(options) {
|
|
|
19588
20355
|
for (const suiteCase of result.cases) {
|
|
19589
20356
|
cases.push(await enrichCase(suiteCase, baselinePath));
|
|
19590
20357
|
}
|
|
19591
|
-
const artifactsDir =
|
|
20358
|
+
const artifactsDir = path33__default.default.join(path33__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
|
|
19592
20359
|
return {
|
|
19593
20360
|
suiteName: result.suiteName,
|
|
19594
20361
|
configPath: result.configPath,
|
|
@@ -19784,19 +20551,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
19784
20551
|
}
|
|
19785
20552
|
var INDEX_DIR_NAME = "index";
|
|
19786
20553
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
19787
|
-
const projectRoot =
|
|
19788
|
-
const workspaceDir =
|
|
20554
|
+
const projectRoot = path33__default.default.resolve(cwd);
|
|
20555
|
+
const workspaceDir = path33__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
19789
20556
|
return {
|
|
19790
20557
|
projectRoot,
|
|
19791
20558
|
workspaceDir,
|
|
19792
|
-
manifestPath:
|
|
20559
|
+
manifestPath: path33__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
19793
20560
|
};
|
|
19794
20561
|
}
|
|
19795
20562
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
19796
|
-
const base =
|
|
19797
|
-
const resolved =
|
|
19798
|
-
const rel =
|
|
19799
|
-
if (rel === "" || rel === "." || !rel.startsWith("..") && !
|
|
20563
|
+
const base = path33__default.default.resolve(workspaceDir);
|
|
20564
|
+
const resolved = path33__default.default.resolve(base, relative);
|
|
20565
|
+
const rel = path33__default.default.relative(base, resolved);
|
|
20566
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
|
|
19800
20567
|
return resolved;
|
|
19801
20568
|
}
|
|
19802
20569
|
throw new Error(
|
|
@@ -19865,7 +20632,7 @@ async function createWorkspace(options = {}) {
|
|
|
19865
20632
|
created = false;
|
|
19866
20633
|
adopted = true;
|
|
19867
20634
|
} else {
|
|
19868
|
-
const project = options.project?.trim() ||
|
|
20635
|
+
const project = options.project?.trim() || path33__default.default.basename(location.projectRoot) || "workspace";
|
|
19869
20636
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
19870
20637
|
manifest = createDefaultWorkspaceManifest({
|
|
19871
20638
|
project,
|
|
@@ -20004,7 +20771,7 @@ async function doctorWorkspace(location) {
|
|
|
20004
20771
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
20005
20772
|
for (const file of await listJsonl(abs)) {
|
|
20006
20773
|
try {
|
|
20007
|
-
const s = await promises.stat(
|
|
20774
|
+
const s = await promises.stat(path33__default.default.join(abs, file));
|
|
20008
20775
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
20009
20776
|
} catch {
|
|
20010
20777
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -20052,7 +20819,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
20052
20819
|
const relPath = `${rel}/${entry}`;
|
|
20053
20820
|
removed.push(relPath);
|
|
20054
20821
|
if (!dryRun) {
|
|
20055
|
-
await promises.rm(
|
|
20822
|
+
await promises.rm(path33__default.default.join(abs, entry), { recursive: true, force: true });
|
|
20056
20823
|
}
|
|
20057
20824
|
}
|
|
20058
20825
|
}
|
|
@@ -20061,7 +20828,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
20061
20828
|
|
|
20062
20829
|
// packages/viewer/src/workspace-data.ts
|
|
20063
20830
|
async function loadWorkspaceViewerData(options) {
|
|
20064
|
-
const cwd =
|
|
20831
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
20065
20832
|
const location = resolveWorkspaceLocation(cwd);
|
|
20066
20833
|
const manifestRead = await readWorkspaceManifestFile(location);
|
|
20067
20834
|
if (!manifestRead.ok || manifestRead.manifest === void 0) {
|
|
@@ -20074,7 +20841,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
20074
20841
|
const runs = [];
|
|
20075
20842
|
for (const rel of manifestRead.manifest.traceDirs) {
|
|
20076
20843
|
const traceDir = resolveTraceDir({
|
|
20077
|
-
dir:
|
|
20844
|
+
dir: path33__default.default.join(location.workspaceDir, rel)
|
|
20078
20845
|
});
|
|
20079
20846
|
const td = new TraceDirectory({ dir: traceDir });
|
|
20080
20847
|
const files = await td.list();
|
|
@@ -20088,7 +20855,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
20088
20855
|
runId: meta2.runId,
|
|
20089
20856
|
...meta2.name !== void 0 ? { name: meta2.name } : {},
|
|
20090
20857
|
status: meta2.status,
|
|
20091
|
-
file:
|
|
20858
|
+
file: path33__default.default.basename(meta2.filePath)
|
|
20092
20859
|
});
|
|
20093
20860
|
}
|
|
20094
20861
|
}
|
|
@@ -20099,8 +20866,8 @@ async function loadWorkspaceViewerData(options) {
|
|
|
20099
20866
|
doctor,
|
|
20100
20867
|
runs,
|
|
20101
20868
|
bundleDirs: [
|
|
20102
|
-
|
|
20103
|
-
|
|
20869
|
+
path33__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
|
|
20870
|
+
path33__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
|
|
20104
20871
|
]
|
|
20105
20872
|
};
|
|
20106
20873
|
}
|
|
@@ -20163,7 +20930,7 @@ function createViewerServer(options = {}) {
|
|
|
20163
20930
|
ok: true,
|
|
20164
20931
|
readOnly: true,
|
|
20165
20932
|
mode,
|
|
20166
|
-
traceDir:
|
|
20933
|
+
traceDir: path33__default.default.resolve(traceDir)
|
|
20167
20934
|
});
|
|
20168
20935
|
}
|
|
20169
20936
|
if (pathname === "/api/suite" && mode === "suite") {
|
|
@@ -20192,7 +20959,7 @@ function createViewerServer(options = {}) {
|
|
|
20192
20959
|
runId: meta2.runId,
|
|
20193
20960
|
name: meta2.name,
|
|
20194
20961
|
status: meta2.status,
|
|
20195
|
-
file:
|
|
20962
|
+
file: path33__default.default.basename(meta2.filePath),
|
|
20196
20963
|
startedAt: meta2.startedAt,
|
|
20197
20964
|
durationMs: meta2.durationMs
|
|
20198
20965
|
}))
|
|
@@ -20309,7 +21076,7 @@ function startViewerServer(options = {}) {
|
|
|
20309
21076
|
resolve({
|
|
20310
21077
|
host,
|
|
20311
21078
|
port: resolvedPort,
|
|
20312
|
-
traceDir:
|
|
21079
|
+
traceDir: path33__default.default.resolve(traceDir),
|
|
20313
21080
|
url: `http://${host}:${resolvedPort}/${modeQuery}`,
|
|
20314
21081
|
mode
|
|
20315
21082
|
});
|
|
@@ -20720,10 +21487,10 @@ async function evalRun(input3, options = {}) {
|
|
|
20720
21487
|
diagnostics: []
|
|
20721
21488
|
};
|
|
20722
21489
|
}
|
|
20723
|
-
function evidenceForRun(run,
|
|
20724
|
-
return [{ runId: run.runId, ...
|
|
21490
|
+
function evidenceForRun(run, path44) {
|
|
21491
|
+
return [{ runId: run.runId, ...path44 !== void 0 ? { path: path44 } : {} }];
|
|
20725
21492
|
}
|
|
20726
|
-
function evidenceForEvent(event,
|
|
21493
|
+
function evidenceForEvent(event, path44) {
|
|
20727
21494
|
return [
|
|
20728
21495
|
{
|
|
20729
21496
|
runId: event.runId,
|
|
@@ -20731,7 +21498,7 @@ function evidenceForEvent(event, path43) {
|
|
|
20731
21498
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
20732
21499
|
kind: event.kind,
|
|
20733
21500
|
name: event.name,
|
|
20734
|
-
...
|
|
21501
|
+
...path44 !== void 0 ? { path: path44 } : {}
|
|
20735
21502
|
}
|
|
20736
21503
|
];
|
|
20737
21504
|
}
|
|
@@ -20889,9 +21656,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
20889
21656
|
function tokenize(text) {
|
|
20890
21657
|
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));
|
|
20891
21658
|
}
|
|
20892
|
-
function firstEvidence(fields, run,
|
|
21659
|
+
function firstEvidence(fields, run, path44) {
|
|
20893
21660
|
const first = fields[0];
|
|
20894
|
-
return first === void 0 ? evidenceForRun(run,
|
|
21661
|
+
return first === void 0 ? evidenceForRun(run, path44) : evidenceForEvent(first.node.event, first.path);
|
|
20895
21662
|
}
|
|
20896
21663
|
function collectSourceIds(nodes, keys) {
|
|
20897
21664
|
const wanted = keySet(keys);
|
|
@@ -21244,273 +22011,55 @@ var checks = {
|
|
|
21244
22011
|
"Answer contained banned unsupported-answer phrasing.",
|
|
21245
22012
|
firstEvidence(answers, context.run, "attributes.answer"),
|
|
21246
22013
|
{ bannedPhraseCount: banned.length },
|
|
21247
|
-
{ matchedPhraseCount: matches.length }
|
|
21248
|
-
)
|
|
21249
|
-
] : [];
|
|
21250
|
-
});
|
|
21251
|
-
}
|
|
21252
|
-
};
|
|
21253
|
-
function renderEvalMarkdown(result) {
|
|
21254
|
-
const lines = [
|
|
21255
|
-
`# AgentInspect Eval`,
|
|
21256
|
-
"",
|
|
21257
|
-
`Status: ${result.status}`,
|
|
21258
|
-
`Format: ${result.format}`,
|
|
21259
|
-
...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
|
|
21260
|
-
`Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
|
|
21261
|
-
];
|
|
21262
|
-
if (result.diagnostics.length > 0) {
|
|
21263
|
-
lines.push("", "## Diagnostics");
|
|
21264
|
-
for (const diagnostic7 of result.diagnostics) {
|
|
21265
|
-
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21266
|
-
}
|
|
21267
|
-
}
|
|
21268
|
-
if (result.findings.length > 0) {
|
|
21269
|
-
lines.push("", "## Findings");
|
|
21270
|
-
for (const finding of result.findings) {
|
|
21271
|
-
const path43 = finding.evidence[0]?.path;
|
|
21272
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
21273
|
-
}
|
|
21274
|
-
}
|
|
21275
|
-
return `${lines.join("\n")}
|
|
21276
|
-
`;
|
|
21277
|
-
}
|
|
21278
|
-
|
|
21279
|
-
// packages/cli/src/eval.ts
|
|
21280
|
-
var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
21281
|
-
var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
|
|
21282
|
-
function diagnostic6(code, message, severity = "error") {
|
|
21283
|
-
return { code, message, severity };
|
|
21284
|
-
}
|
|
21285
|
-
function errorResult4(code, message, format = "unknown") {
|
|
21286
|
-
return {
|
|
21287
|
-
ok: false,
|
|
21288
|
-
status: "error",
|
|
21289
|
-
format,
|
|
21290
|
-
summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
|
|
21291
|
-
findings: [],
|
|
21292
|
-
diagnostics: [diagnostic6(code, message)]
|
|
21293
|
-
};
|
|
21294
|
-
}
|
|
21295
|
-
function parseNumber2(value, label) {
|
|
21296
|
-
if (value === void 0) return void 0;
|
|
21297
|
-
const parsed = Number(value);
|
|
21298
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
21299
|
-
throw new Error(`${label} must be a non-negative number.`);
|
|
21300
|
-
}
|
|
21301
|
-
return parsed;
|
|
21302
|
-
}
|
|
21303
|
-
function asStringArray3(value, label) {
|
|
21304
|
-
if (value === void 0) return void 0;
|
|
21305
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
21306
|
-
throw new Error(`${label} must be an array of strings.`);
|
|
21307
|
-
}
|
|
21308
|
-
return value;
|
|
21309
|
-
}
|
|
21310
|
-
function asConfig(value) {
|
|
21311
|
-
if (value === void 0 || value === null) return {};
|
|
21312
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
21313
|
-
throw new Error("Config must export an object.");
|
|
21314
|
-
}
|
|
21315
|
-
return value;
|
|
21316
|
-
}
|
|
21317
|
-
async function loadConfig2(configPath) {
|
|
21318
|
-
if (configPath === void 0) return {};
|
|
21319
|
-
const extension = path32__default.default.extname(configPath);
|
|
21320
|
-
if (TS_CONFIG_EXTENSIONS3.has(extension)) {
|
|
21321
|
-
throw new Error(
|
|
21322
|
-
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
21323
|
-
);
|
|
21324
|
-
}
|
|
21325
|
-
if (!CONFIG_EXTENSIONS3.has(extension)) {
|
|
21326
|
-
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
21327
|
-
}
|
|
21328
|
-
const absolute = path32__default.default.resolve(configPath);
|
|
21329
|
-
if (extension === ".json") {
|
|
21330
|
-
const raw = await promises.readFile(absolute, "utf-8");
|
|
21331
|
-
return asConfig(JSON.parse(raw));
|
|
21332
|
-
}
|
|
21333
|
-
const mod = await import(url.pathToFileURL(absolute).href);
|
|
21334
|
-
return asConfig("default" in mod ? mod.default : mod);
|
|
21335
|
-
}
|
|
21336
|
-
function normalizeConfig2(config) {
|
|
21337
|
-
if (config.eval === void 0) return {};
|
|
21338
|
-
if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
|
|
21339
|
-
throw new Error("eval config must be an object.");
|
|
21340
|
-
}
|
|
21341
|
-
return config.eval;
|
|
21342
|
-
}
|
|
21343
|
-
function maybeAdd(rules, value, makeRule) {
|
|
21344
|
-
if (value !== void 0) rules.push(makeRule(value));
|
|
21345
|
-
}
|
|
21346
|
-
function optionObject(value) {
|
|
21347
|
-
if (value === void 0 || value === false) return void 0;
|
|
21348
|
-
if (value === true) return {};
|
|
21349
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
21350
|
-
throw new Error("Eval heuristic config must be a boolean or object.");
|
|
21351
|
-
}
|
|
21352
|
-
return value;
|
|
21353
|
-
}
|
|
21354
|
-
function sourceIdsFromConfig(value) {
|
|
21355
|
-
if (value === void 0) return void 0;
|
|
21356
|
-
if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
|
|
21357
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
21358
|
-
throw new Error("eval.requiredSourceIds must be an array or object.");
|
|
21359
|
-
}
|
|
21360
|
-
const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
|
|
21361
|
-
return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
|
|
21362
|
-
}
|
|
21363
|
-
function buildRules2(config, options) {
|
|
21364
|
-
const evalConfig = normalizeConfig2(config);
|
|
21365
|
-
const rules = [];
|
|
21366
|
-
if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
|
|
21367
|
-
const requiredTools = [
|
|
21368
|
-
...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
|
|
21369
|
-
...options.requiredTool ?? []
|
|
21370
|
-
];
|
|
21371
|
-
if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
|
|
21372
|
-
const forbiddenTools = [
|
|
21373
|
-
...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
|
|
21374
|
-
...options.forbidTool ?? [],
|
|
21375
|
-
...options.forbiddenTool ?? []
|
|
21376
|
-
];
|
|
21377
|
-
if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
|
|
21378
|
-
const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
|
|
21379
|
-
maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
|
|
21380
|
-
const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
|
|
21381
|
-
maybeAdd(rules, maxDepth, checks.maxDepth);
|
|
21382
|
-
const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
|
|
21383
|
-
maybeAdd(rules, maxRetries, checks.maxRetries);
|
|
21384
|
-
const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
|
|
21385
|
-
maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
|
|
21386
|
-
if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
|
|
21387
|
-
rules.push(checks.requiredRetrievalBeforeGeneration());
|
|
21388
|
-
}
|
|
21389
|
-
const requiredDecisionMetadata = [
|
|
21390
|
-
...asStringArray3(
|
|
21391
|
-
evalConfig.requiredDecisionMetadata,
|
|
21392
|
-
"eval.requiredDecisionMetadata"
|
|
21393
|
-
) ?? [],
|
|
21394
|
-
...options.requiredDecisionMetadata ?? []
|
|
21395
|
-
];
|
|
21396
|
-
if (requiredDecisionMetadata.length > 0) {
|
|
21397
|
-
rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
|
|
21398
|
-
}
|
|
21399
|
-
const contextOverlap = optionObject(evalConfig.contextOverlap);
|
|
21400
|
-
const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
|
|
21401
|
-
const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
|
|
21402
|
-
if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
|
|
21403
|
-
rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
|
|
21404
|
-
}
|
|
21405
|
-
const quoteOverlap = optionObject(evalConfig.quoteOverlap);
|
|
21406
|
-
if (quoteOverlap !== void 0 || options.quoteOverlap) {
|
|
21407
|
-
rules.push(checks.quoteOverlap(quoteOverlap));
|
|
21408
|
-
}
|
|
21409
|
-
const citationPresence = optionObject(evalConfig.citationPresence);
|
|
21410
|
-
if (citationPresence !== void 0 || options.citationPresence) {
|
|
21411
|
-
rules.push(checks.citationPresence(citationPresence));
|
|
21412
|
-
}
|
|
21413
|
-
const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
|
|
21414
|
-
const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
|
|
21415
|
-
if (requiredSourceIds.length > 0) {
|
|
21416
|
-
rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
|
|
21417
|
-
}
|
|
21418
|
-
const cliAnswerLength = {
|
|
21419
|
-
minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
|
|
21420
|
-
maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
|
|
21421
|
-
minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
|
|
21422
|
-
maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
|
|
21423
|
-
};
|
|
21424
|
-
const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
|
|
21425
|
-
if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
|
|
21426
|
-
rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
|
|
21427
|
-
}
|
|
21428
|
-
const bannedPhrases = [
|
|
21429
|
-
...asStringArray3(
|
|
21430
|
-
evalConfig.bannedUnsupportedPhrases,
|
|
21431
|
-
"eval.bannedUnsupportedPhrases"
|
|
21432
|
-
) ?? [],
|
|
21433
|
-
...options.bannedPhrase ?? []
|
|
21434
|
-
];
|
|
21435
|
-
if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
|
|
21436
|
-
return rules.length > 0 ? rules : void 0;
|
|
21437
|
-
}
|
|
21438
|
-
function exitCodeFor2(result) {
|
|
21439
|
-
if (result.status === "pass") return 0;
|
|
21440
|
-
if (result.status === "fail") return 1;
|
|
21441
|
-
return 2;
|
|
21442
|
-
}
|
|
21443
|
-
function stable4(value) {
|
|
21444
|
-
if (Array.isArray(value)) return value.map(stable4);
|
|
21445
|
-
if (value === null || typeof value !== "object") return value;
|
|
21446
|
-
const record = value;
|
|
21447
|
-
return Object.fromEntries(
|
|
21448
|
-
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
|
|
21449
|
-
);
|
|
21450
|
-
}
|
|
21451
|
-
function printJson2(result) {
|
|
21452
|
-
console.log(JSON.stringify(stable4(result), null, 2));
|
|
21453
|
-
}
|
|
21454
|
-
function printHuman2(result) {
|
|
21455
|
-
console.log(`Eval status: ${result.status}`);
|
|
21456
|
-
console.log(`Format: ${result.format}`);
|
|
21457
|
-
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
21458
|
-
console.log(
|
|
21459
|
-
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
21460
|
-
);
|
|
21461
|
-
for (const diagnostic7 of result.diagnostics) {
|
|
21462
|
-
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21463
|
-
}
|
|
21464
|
-
for (const finding of result.findings) {
|
|
21465
|
-
const path43 = finding.evidence[0]?.path;
|
|
21466
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
21467
|
-
}
|
|
21468
|
-
}
|
|
21469
|
-
function readErrorResult2(error) {
|
|
21470
|
-
if (error instanceof TraceReadError) {
|
|
21471
|
-
const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
|
|
21472
|
-
return errorResult4(code, error.message);
|
|
21473
|
-
}
|
|
21474
|
-
return errorResult4(
|
|
21475
|
-
"AI_EVAL_TRACE_UNREADABLE",
|
|
21476
|
-
error instanceof Error ? error.message : String(error)
|
|
21477
|
-
);
|
|
21478
|
-
}
|
|
21479
|
-
async function evalCommand(target, options = {}, stdin = process.stdin) {
|
|
21480
|
-
let result;
|
|
21481
|
-
let phase = "config";
|
|
21482
|
-
try {
|
|
21483
|
-
const config = await loadConfig2(options.config);
|
|
21484
|
-
const rules = buildRules2(config, options);
|
|
21485
|
-
phase = "read";
|
|
21486
|
-
const input3 = await inputFromTarget(target, options, stdin);
|
|
21487
|
-
const read = await openTrace(input3, {
|
|
21488
|
-
...options.format !== void 0 ? { format: options.format } : {}
|
|
21489
|
-
});
|
|
21490
|
-
result = await evalRun(read, {
|
|
21491
|
-
...rules !== void 0 ? { checks: rules } : {},
|
|
21492
|
-
...options.run !== void 0 ? { runId: options.run } : {}
|
|
22014
|
+
{ matchedPhraseCount: matches.length }
|
|
22015
|
+
)
|
|
22016
|
+
] : [];
|
|
21493
22017
|
});
|
|
21494
|
-
}
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
22018
|
+
}
|
|
22019
|
+
};
|
|
22020
|
+
function renderEvalMarkdown(result) {
|
|
22021
|
+
const lines = [
|
|
22022
|
+
`# AgentInspect Eval`,
|
|
22023
|
+
"",
|
|
22024
|
+
`Status: ${result.status}`,
|
|
22025
|
+
`Format: ${result.format}`,
|
|
22026
|
+
...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
|
|
22027
|
+
`Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
|
|
22028
|
+
];
|
|
22029
|
+
if (result.diagnostics.length > 0) {
|
|
22030
|
+
lines.push("", "## Diagnostics");
|
|
22031
|
+
for (const diagnostic7 of result.diagnostics) {
|
|
22032
|
+
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21501
22033
|
}
|
|
21502
22034
|
}
|
|
21503
|
-
|
|
21504
|
-
|
|
21505
|
-
|
|
21506
|
-
|
|
22035
|
+
if (result.findings.length > 0) {
|
|
22036
|
+
lines.push("", "## Findings");
|
|
22037
|
+
for (const finding of result.findings) {
|
|
22038
|
+
const path44 = finding.evidence[0]?.path;
|
|
22039
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
|
|
22040
|
+
}
|
|
22041
|
+
}
|
|
22042
|
+
return `${lines.join("\n")}
|
|
22043
|
+
`;
|
|
21507
22044
|
}
|
|
21508
|
-
|
|
21509
|
-
|
|
21510
|
-
var
|
|
21511
|
-
var
|
|
21512
|
-
|
|
21513
|
-
|
|
22045
|
+
|
|
22046
|
+
// packages/cli/src/eval.ts
|
|
22047
|
+
var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
22048
|
+
var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
|
|
22049
|
+
function diagnostic6(code, message, severity = "error") {
|
|
22050
|
+
return { code, message, severity };
|
|
22051
|
+
}
|
|
22052
|
+
function errorResult4(code, message, format = "unknown") {
|
|
22053
|
+
return {
|
|
22054
|
+
ok: false,
|
|
22055
|
+
status: "error",
|
|
22056
|
+
format,
|
|
22057
|
+
summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
|
|
22058
|
+
findings: [],
|
|
22059
|
+
diagnostics: [diagnostic6(code, message)]
|
|
22060
|
+
};
|
|
22061
|
+
}
|
|
22062
|
+
function parseNumber2(value, label) {
|
|
21514
22063
|
if (value === void 0) return void 0;
|
|
21515
22064
|
const parsed = Number(value);
|
|
21516
22065
|
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
@@ -21518,368 +22067,210 @@ function parseLimit3(value, label) {
|
|
|
21518
22067
|
}
|
|
21519
22068
|
return parsed;
|
|
21520
22069
|
}
|
|
21521
|
-
function
|
|
21522
|
-
if (
|
|
21523
|
-
if (value
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
);
|
|
21528
|
-
}
|
|
21529
|
-
function safetyDiagnostic(code, message, severity = "error") {
|
|
21530
|
-
return { code, message, severity };
|
|
21531
|
-
}
|
|
21532
|
-
function warningDiagnostics(warnings, unsupportedFields) {
|
|
21533
|
-
return [
|
|
21534
|
-
...warnings.map(
|
|
21535
|
-
(warning) => safetyDiagnostic(
|
|
21536
|
-
warning.code,
|
|
21537
|
-
warning.message,
|
|
21538
|
-
warning.severity === "error" ? "error" : "warning"
|
|
21539
|
-
)
|
|
21540
|
-
),
|
|
21541
|
-
...unsupportedFields.map(
|
|
21542
|
-
(field) => safetyDiagnostic(
|
|
21543
|
-
"unsupported_field",
|
|
21544
|
-
`Reader reported unsupported field: ${field}`,
|
|
21545
|
-
"warning"
|
|
21546
|
-
)
|
|
21547
|
-
)
|
|
21548
|
-
];
|
|
22070
|
+
function asStringArray3(value, label) {
|
|
22071
|
+
if (value === void 0) return void 0;
|
|
22072
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
22073
|
+
throw new Error(`${label} must be an array of strings.`);
|
|
22074
|
+
}
|
|
22075
|
+
return value;
|
|
21549
22076
|
}
|
|
21550
|
-
function
|
|
21551
|
-
|
|
22077
|
+
function asConfig(value) {
|
|
22078
|
+
if (value === void 0 || value === null) return {};
|
|
22079
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
22080
|
+
throw new Error("Config must export an object.");
|
|
22081
|
+
}
|
|
22082
|
+
return value;
|
|
21552
22083
|
}
|
|
21553
|
-
function
|
|
21554
|
-
if (
|
|
21555
|
-
|
|
21556
|
-
if (
|
|
21557
|
-
|
|
21558
|
-
|
|
22084
|
+
async function loadConfig2(configPath) {
|
|
22085
|
+
if (configPath === void 0) return {};
|
|
22086
|
+
const extension = path33__default.default.extname(configPath);
|
|
22087
|
+
if (TS_CONFIG_EXTENSIONS3.has(extension)) {
|
|
22088
|
+
throw new Error(
|
|
22089
|
+
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
22090
|
+
);
|
|
22091
|
+
}
|
|
22092
|
+
if (!CONFIG_EXTENSIONS3.has(extension)) {
|
|
22093
|
+
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
22094
|
+
}
|
|
22095
|
+
const absolute = path33__default.default.resolve(configPath);
|
|
22096
|
+
if (extension === ".json") {
|
|
22097
|
+
const raw = await promises.readFile(absolute, "utf-8");
|
|
22098
|
+
return asConfig(JSON.parse(raw));
|
|
22099
|
+
}
|
|
22100
|
+
const mod = await import(url.pathToFileURL(absolute).href);
|
|
22101
|
+
return asConfig("default" in mod ? mod.default : mod);
|
|
21559
22102
|
}
|
|
21560
|
-
function
|
|
21561
|
-
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21566
|
-
return {
|
|
21567
|
-
ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
|
|
21568
|
-
command: parts.command,
|
|
21569
|
-
status,
|
|
21570
|
-
format: parts.format,
|
|
21571
|
-
...parts.runId !== void 0 ? { runId: parts.runId } : {},
|
|
21572
|
-
summary: {
|
|
21573
|
-
findings: findings.length,
|
|
21574
|
-
warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
|
|
21575
|
-
errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
|
|
21576
|
-
},
|
|
21577
|
-
findings,
|
|
21578
|
-
diagnostics,
|
|
21579
|
-
warnings,
|
|
21580
|
-
unsupportedFields,
|
|
21581
|
-
note: BEST_EFFORT_NOTE,
|
|
21582
|
-
...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
|
|
21583
|
-
...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
|
|
21584
|
-
...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
|
|
21585
|
-
};
|
|
22103
|
+
function normalizeConfig2(config) {
|
|
22104
|
+
if (config.eval === void 0) return {};
|
|
22105
|
+
if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
|
|
22106
|
+
throw new Error("eval config must be an object.");
|
|
22107
|
+
}
|
|
22108
|
+
return config.eval;
|
|
21586
22109
|
}
|
|
21587
|
-
function
|
|
21588
|
-
|
|
21589
|
-
status: result.status,
|
|
21590
|
-
summary: result.summary,
|
|
21591
|
-
findings: result.findings
|
|
21592
|
-
};
|
|
22110
|
+
function maybeAdd(rules, value, makeRule) {
|
|
22111
|
+
if (value !== void 0) rules.push(makeRule(value));
|
|
21593
22112
|
}
|
|
21594
|
-
function
|
|
21595
|
-
if (
|
|
21596
|
-
|
|
21597
|
-
|
|
21598
|
-
|
|
21599
|
-
format: "unknown",
|
|
21600
|
-
diagnostics: [safetyDiagnostic(code, error.message)],
|
|
21601
|
-
warnings: error.warnings
|
|
21602
|
-
});
|
|
22113
|
+
function optionObject(value) {
|
|
22114
|
+
if (value === void 0 || value === false) return void 0;
|
|
22115
|
+
if (value === true) return {};
|
|
22116
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
22117
|
+
throw new Error("Eval heuristic config must be a boolean or object.");
|
|
21603
22118
|
}
|
|
21604
|
-
return
|
|
21605
|
-
command,
|
|
21606
|
-
format: "unknown",
|
|
21607
|
-
diagnostics: [
|
|
21608
|
-
safetyDiagnostic(
|
|
21609
|
-
"AI_SAFETY_TRACE_UNREADABLE",
|
|
21610
|
-
error instanceof Error ? error.message : String(error)
|
|
21611
|
-
)
|
|
21612
|
-
]
|
|
21613
|
-
});
|
|
22119
|
+
return value;
|
|
21614
22120
|
}
|
|
21615
|
-
function
|
|
21616
|
-
return
|
|
21617
|
-
|
|
21618
|
-
|
|
21619
|
-
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
|
|
21623
|
-
)
|
|
21624
|
-
]
|
|
21625
|
-
});
|
|
22121
|
+
function sourceIdsFromConfig(value) {
|
|
22122
|
+
if (value === void 0) return void 0;
|
|
22123
|
+
if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
|
|
22124
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
22125
|
+
throw new Error("eval.requiredSourceIds must be an array or object.");
|
|
22126
|
+
}
|
|
22127
|
+
const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
|
|
22128
|
+
return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
|
|
21626
22129
|
}
|
|
21627
|
-
function
|
|
21628
|
-
const
|
|
21629
|
-
const
|
|
21630
|
-
|
|
21631
|
-
const
|
|
21632
|
-
|
|
21633
|
-
|
|
21634
|
-
createSafetyRedactionRule(),
|
|
21635
|
-
createSafetySecretPatternRule(),
|
|
21636
|
-
createSafetyOversizedAttributeRule({
|
|
21637
|
-
maxStringLength: maxStringLength2,
|
|
21638
|
-
maxArrayLength,
|
|
21639
|
-
maxObjectKeys,
|
|
21640
|
-
maxSerializedBytes
|
|
21641
|
-
})
|
|
22130
|
+
function buildRules2(config, options) {
|
|
22131
|
+
const evalConfig = normalizeConfig2(config);
|
|
22132
|
+
const rules = [];
|
|
22133
|
+
if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
|
|
22134
|
+
const requiredTools = [
|
|
22135
|
+
...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
|
|
22136
|
+
...options.requiredTool ?? []
|
|
21642
22137
|
];
|
|
21643
|
-
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
...
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
|
|
21657
|
-
|
|
22138
|
+
if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
|
|
22139
|
+
const forbiddenTools = [
|
|
22140
|
+
...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
|
|
22141
|
+
...options.forbidTool ?? [],
|
|
22142
|
+
...options.forbiddenTool ?? []
|
|
22143
|
+
];
|
|
22144
|
+
if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
|
|
22145
|
+
const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
|
|
22146
|
+
maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
|
|
22147
|
+
const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
|
|
22148
|
+
maybeAdd(rules, maxDepth, checks.maxDepth);
|
|
22149
|
+
const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
|
|
22150
|
+
maybeAdd(rules, maxRetries, checks.maxRetries);
|
|
22151
|
+
const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
|
|
22152
|
+
maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
|
|
22153
|
+
if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
|
|
22154
|
+
rules.push(checks.requiredRetrievalBeforeGeneration());
|
|
21658
22155
|
}
|
|
21659
|
-
|
|
21660
|
-
|
|
22156
|
+
const requiredDecisionMetadata = [
|
|
22157
|
+
...asStringArray3(
|
|
22158
|
+
evalConfig.requiredDecisionMetadata,
|
|
22159
|
+
"eval.requiredDecisionMetadata"
|
|
22160
|
+
) ?? [],
|
|
22161
|
+
...options.requiredDecisionMetadata ?? []
|
|
22162
|
+
];
|
|
22163
|
+
if (requiredDecisionMetadata.length > 0) {
|
|
22164
|
+
rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
|
|
21661
22165
|
}
|
|
21662
|
-
|
|
21663
|
-
|
|
22166
|
+
const contextOverlap = optionObject(evalConfig.contextOverlap);
|
|
22167
|
+
const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
|
|
22168
|
+
const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
|
|
22169
|
+
if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
|
|
22170
|
+
rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
|
|
21664
22171
|
}
|
|
21665
|
-
|
|
21666
|
-
|
|
22172
|
+
const quoteOverlap = optionObject(evalConfig.quoteOverlap);
|
|
22173
|
+
if (quoteOverlap !== void 0 || options.quoteOverlap) {
|
|
22174
|
+
rules.push(checks.quoteOverlap(quoteOverlap));
|
|
21667
22175
|
}
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
|
|
21671
|
-
const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
|
|
21672
|
-
const out = [];
|
|
21673
|
-
for (const run of runs) {
|
|
21674
|
-
for (const node of flattenNodes2(run.children)) {
|
|
21675
|
-
const attrs = node.event.attributes;
|
|
21676
|
-
if (attrs === void 0) continue;
|
|
21677
|
-
const result = redact(attrs, { profile: "share" });
|
|
21678
|
-
for (const finding of result.findings) {
|
|
21679
|
-
if (finding.action === "keep") continue;
|
|
21680
|
-
const taxonomy = classifyRedactionDetector(finding.detector);
|
|
21681
|
-
out.push({
|
|
21682
|
-
ruleId: "safety.redactDetector",
|
|
21683
|
-
severity: detectorSeverity(finding),
|
|
21684
|
-
status: finding.severity === "error" ? "fail" : "warning",
|
|
21685
|
-
message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
|
|
21686
|
-
expected: "redacted trace content",
|
|
21687
|
-
actual: finding.detector,
|
|
21688
|
-
evidence: [
|
|
21689
|
-
{
|
|
21690
|
-
runId: node.event.runId,
|
|
21691
|
-
eventId: node.event.eventId,
|
|
21692
|
-
...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
|
|
21693
|
-
kind: node.event.kind,
|
|
21694
|
-
name: node.event.name,
|
|
21695
|
-
...node.event.status !== void 0 ? { status: node.event.status } : {},
|
|
21696
|
-
path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
|
|
21697
|
-
}
|
|
21698
|
-
],
|
|
21699
|
-
category: taxonomy.category,
|
|
21700
|
-
confidence: taxonomy.confidence,
|
|
21701
|
-
detector: finding.detector,
|
|
21702
|
-
action: finding.action
|
|
21703
|
-
});
|
|
21704
|
-
}
|
|
21705
|
-
}
|
|
22176
|
+
const citationPresence = optionObject(evalConfig.citationPresence);
|
|
22177
|
+
if (citationPresence !== void 0 || options.citationPresence) {
|
|
22178
|
+
rules.push(checks.citationPresence(citationPresence));
|
|
21706
22179
|
}
|
|
21707
|
-
|
|
21708
|
-
|
|
21709
|
-
|
|
21710
|
-
|
|
21711
|
-
}
|
|
22180
|
+
const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
|
|
22181
|
+
const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
|
|
22182
|
+
if (requiredSourceIds.length > 0) {
|
|
22183
|
+
rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
|
|
22184
|
+
}
|
|
22185
|
+
const cliAnswerLength = {
|
|
22186
|
+
minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
|
|
22187
|
+
maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
|
|
22188
|
+
minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
|
|
22189
|
+
maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
|
|
22190
|
+
};
|
|
22191
|
+
const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
|
|
22192
|
+
if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
|
|
22193
|
+
rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
|
|
22194
|
+
}
|
|
22195
|
+
const bannedPhrases = [
|
|
22196
|
+
...asStringArray3(
|
|
22197
|
+
evalConfig.bannedUnsupportedPhrases,
|
|
22198
|
+
"eval.bannedUnsupportedPhrases"
|
|
22199
|
+
) ?? [],
|
|
22200
|
+
...options.bannedPhrase ?? []
|
|
22201
|
+
];
|
|
22202
|
+
if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
|
|
22203
|
+
return rules.length > 0 ? rules : void 0;
|
|
21712
22204
|
}
|
|
21713
22205
|
function exitCodeFor3(result) {
|
|
21714
|
-
if (result.status === "
|
|
21715
|
-
if (result.status === "
|
|
22206
|
+
if (result.status === "pass") return 0;
|
|
22207
|
+
if (result.status === "fail") return 1;
|
|
21716
22208
|
return 2;
|
|
21717
22209
|
}
|
|
21718
|
-
function
|
|
21719
|
-
|
|
21720
|
-
|
|
21721
|
-
const
|
|
21722
|
-
|
|
21723
|
-
|
|
21724
|
-
|
|
21725
|
-
return [
|
|
21726
|
-
` Matched: detector=${detector}; path=${path43}; category=${category}`,
|
|
21727
|
-
` Why: ${finding.message}`,
|
|
21728
|
-
` Confidence: ${confidence}`,
|
|
21729
|
-
` Redaction: ${redactionHint}`,
|
|
21730
|
-
` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
|
|
21731
|
-
` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
|
|
21732
|
-
];
|
|
22210
|
+
function stable5(value) {
|
|
22211
|
+
if (Array.isArray(value)) return value.map(stable5);
|
|
22212
|
+
if (value === null || typeof value !== "object") return value;
|
|
22213
|
+
const record = value;
|
|
22214
|
+
return Object.fromEntries(
|
|
22215
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable5(record[key])])
|
|
22216
|
+
);
|
|
21733
22217
|
}
|
|
21734
|
-
function
|
|
21735
|
-
|
|
21736
|
-
return {
|
|
21737
|
-
ruleId: finding.ruleId,
|
|
21738
|
-
detector: finding.detector ?? finding.ruleId,
|
|
21739
|
-
path: finding.evidence[0]?.path,
|
|
21740
|
-
category: finding.category,
|
|
21741
|
-
confidence: finding.confidence,
|
|
21742
|
-
action: finding.action,
|
|
21743
|
-
blocksBundle: blocks,
|
|
21744
|
-
// Never include matched secret/PII values.
|
|
21745
|
-
message: finding.message
|
|
21746
|
-
};
|
|
22218
|
+
function printJson3(result) {
|
|
22219
|
+
console.log(JSON.stringify(stable5(result), null, 2));
|
|
21747
22220
|
}
|
|
21748
|
-
function printHuman3(result
|
|
21749
|
-
console.log(`
|
|
22221
|
+
function printHuman3(result) {
|
|
22222
|
+
console.log(`Eval status: ${result.status}`);
|
|
21750
22223
|
console.log(`Format: ${result.format}`);
|
|
21751
22224
|
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
21752
|
-
if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
|
|
21753
|
-
console.log(`Source assessment: ${result.sourceAssessment.status}`);
|
|
21754
|
-
console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
|
|
21755
|
-
if (result.redactionSummary !== void 0) {
|
|
21756
|
-
console.log(
|
|
21757
|
-
`Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
|
|
21758
|
-
);
|
|
21759
|
-
}
|
|
21760
|
-
}
|
|
21761
22225
|
console.log(
|
|
21762
|
-
`Summary: ${result.summary.
|
|
22226
|
+
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
21763
22227
|
);
|
|
21764
22228
|
for (const diagnostic7 of result.diagnostics) {
|
|
21765
22229
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21766
22230
|
}
|
|
21767
22231
|
for (const finding of result.findings) {
|
|
21768
|
-
const
|
|
21769
|
-
|
|
21770
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}${taxonomy}`);
|
|
21771
|
-
if (explain) {
|
|
21772
|
-
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
21773
|
-
for (const line of explainFinding(finding, blocks)) {
|
|
21774
|
-
console.log(line);
|
|
21775
|
-
}
|
|
21776
|
-
}
|
|
22232
|
+
const path44 = finding.evidence[0]?.path;
|
|
22233
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
|
|
21777
22234
|
}
|
|
21778
|
-
console.log(`Note: ${result.note}`);
|
|
21779
22235
|
}
|
|
21780
|
-
function
|
|
21781
|
-
|
|
21782
|
-
|
|
22236
|
+
function readErrorResult3(error) {
|
|
22237
|
+
if (error instanceof TraceReadError) {
|
|
22238
|
+
const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
|
|
22239
|
+
return errorResult4(code, error.message);
|
|
22240
|
+
}
|
|
22241
|
+
return errorResult4(
|
|
22242
|
+
"AI_EVAL_TRACE_UNREADABLE",
|
|
22243
|
+
error instanceof Error ? error.message : String(error)
|
|
22244
|
+
);
|
|
21783
22245
|
}
|
|
21784
|
-
async function
|
|
22246
|
+
async function evalCommand(target, options = {}, stdin = process.stdin) {
|
|
21785
22247
|
let result;
|
|
22248
|
+
let phase = "config";
|
|
21786
22249
|
try {
|
|
22250
|
+
const config = await loadConfig2(options.config);
|
|
22251
|
+
const rules = buildRules2(config, options);
|
|
22252
|
+
phase = "read";
|
|
21787
22253
|
const input3 = await inputFromTarget(target, options, stdin);
|
|
21788
22254
|
const read = await openTrace(input3, {
|
|
21789
22255
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
21790
22256
|
});
|
|
21791
|
-
|
|
21792
|
-
...
|
|
22257
|
+
result = await evalRun(read, {
|
|
22258
|
+
...rules !== void 0 ? { checks: rules } : {},
|
|
21793
22259
|
...options.run !== void 0 ? { runId: options.run } : {}
|
|
21794
22260
|
});
|
|
21795
|
-
|
|
21796
|
-
|
|
22261
|
+
} catch (error) {
|
|
22262
|
+
if (phase === "config") {
|
|
22263
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22264
|
+
const code = message.startsWith("--") ? "AI_EVAL_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported eval config extension") || message.includes("TypeScript eval configs") || message.includes("Config must") || message.includes("eval config") || message.includes("must be an array") ? "AI_EVAL_INVALID_CONFIG" : "AI_EVAL_CONFIG_LOAD_FAILED";
|
|
22265
|
+
result = errorResult4(code, message);
|
|
21797
22266
|
} else {
|
|
21798
|
-
|
|
21799
|
-
const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
|
|
21800
|
-
if (rawContent === void 0) {
|
|
21801
|
-
result = {
|
|
21802
|
-
...source,
|
|
21803
|
-
command: "verify-safe",
|
|
21804
|
-
sourceAssessment: layerFromResult(source)
|
|
21805
|
-
};
|
|
21806
|
-
} else {
|
|
21807
|
-
const redacted = redactTraceContent(rawContent, profile);
|
|
21808
|
-
const artifactRead = await openTrace(
|
|
21809
|
-
{ type: "string", content: redacted.content },
|
|
21810
|
-
{ format: options.format ?? "agent-inspect-jsonl" }
|
|
21811
|
-
);
|
|
21812
|
-
const artifact = assessOpenedTrace(artifactRead, {
|
|
21813
|
-
...options,
|
|
21814
|
-
...options.run !== void 0 ? { runId: options.run } : {}
|
|
21815
|
-
});
|
|
21816
|
-
const detectors = [
|
|
21817
|
-
...new Set(redacted.findings.map((finding) => finding.detector))
|
|
21818
|
-
].sort((a, b) => a.localeCompare(b));
|
|
21819
|
-
result = resultFromParts({
|
|
21820
|
-
command: "verify-safe",
|
|
21821
|
-
format: artifact.format,
|
|
21822
|
-
runId: artifact.runId ?? source.runId,
|
|
21823
|
-
findings: artifact.findings,
|
|
21824
|
-
diagnostics: artifact.diagnostics,
|
|
21825
|
-
warnings: artifact.warnings,
|
|
21826
|
-
unsupportedFields: artifact.unsupportedFields,
|
|
21827
|
-
status: artifact.status,
|
|
21828
|
-
sourceAssessment: layerFromResult(source),
|
|
21829
|
-
artifactAssessment: layerFromResult(artifact),
|
|
21830
|
-
redactionSummary: {
|
|
21831
|
-
profile,
|
|
21832
|
-
findings: redacted.findings.length,
|
|
21833
|
-
detectors
|
|
21834
|
-
}
|
|
21835
|
-
});
|
|
21836
|
-
}
|
|
22267
|
+
result = readErrorResult3(error);
|
|
21837
22268
|
}
|
|
21838
|
-
} catch (error) {
|
|
21839
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
21840
|
-
result = message.startsWith("--") ? invalidArgumentResult(command, error) : readErrorResult3(command, error);
|
|
21841
22269
|
}
|
|
21842
22270
|
process.exitCode = exitCodeFor3(result);
|
|
21843
|
-
if (options.json) printJson3(result
|
|
21844
|
-
else
|
|
21845
|
-
|
|
21846
|
-
function scanCommand(target, options = {}, stdin = process.stdin) {
|
|
21847
|
-
return safetyCommand("scan", target, options, stdin);
|
|
21848
|
-
}
|
|
21849
|
-
function verifySafeCommand(target, options = {}, stdin = process.stdin) {
|
|
21850
|
-
return safetyCommand("verify-safe", target, options, stdin);
|
|
21851
|
-
}
|
|
21852
|
-
function assessOpenedTrace(read, options = {}) {
|
|
21853
|
-
try {
|
|
21854
|
-
const rules = buildSafetyRules(options);
|
|
21855
|
-
const checkResult = runTraceChecks(
|
|
21856
|
-
{ read },
|
|
21857
|
-
{
|
|
21858
|
-
rules,
|
|
21859
|
-
...options.runId !== void 0 ? { runId: options.runId } : {},
|
|
21860
|
-
...options.run !== void 0 ? { runId: options.run } : {}
|
|
21861
|
-
}
|
|
21862
|
-
);
|
|
21863
|
-
const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId) : [];
|
|
21864
|
-
return resultFromParts({
|
|
21865
|
-
command: "verify-safe",
|
|
21866
|
-
format: checkResult.format,
|
|
21867
|
-
runId: checkResult.runId,
|
|
21868
|
-
findings: [...checkResult.findings, ...detectorFindings],
|
|
21869
|
-
diagnostics: [
|
|
21870
|
-
...checkResult.diagnostics.map(diagnosticFromCheck),
|
|
21871
|
-
...warningDiagnostics(read.warnings, read.unsupportedFields)
|
|
21872
|
-
],
|
|
21873
|
-
warnings: read.warnings,
|
|
21874
|
-
unsupportedFields: read.unsupportedFields
|
|
21875
|
-
});
|
|
21876
|
-
} catch (error) {
|
|
21877
|
-
return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult3("verify-safe", error);
|
|
21878
|
-
}
|
|
21879
|
-
}
|
|
21880
|
-
function messageStartsWithDash(error) {
|
|
21881
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
21882
|
-
return message.startsWith("--");
|
|
22271
|
+
if (options.json) printJson3(result);
|
|
22272
|
+
else if (options.markdown) console.log(renderEvalMarkdown(result).trimEnd());
|
|
22273
|
+
else printHuman3(result);
|
|
21883
22274
|
}
|
|
21884
22275
|
init_advanced();
|
|
21885
22276
|
var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
|
|
@@ -21955,8 +22346,8 @@ function renderCheckSection(result) {
|
|
|
21955
22346
|
`Diagnostics: ${result.diagnostics.length}`
|
|
21956
22347
|
];
|
|
21957
22348
|
for (const finding of result.findings.slice(0, 10)) {
|
|
21958
|
-
const
|
|
21959
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
22349
|
+
const path44 = finding.evidence[0]?.path ?? "(run)";
|
|
22350
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path44})`);
|
|
21960
22351
|
}
|
|
21961
22352
|
for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
|
|
21962
22353
|
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
@@ -22034,8 +22425,8 @@ function renderHtml(trace, check, diff) {
|
|
|
22034
22425
|
`;
|
|
22035
22426
|
}
|
|
22036
22427
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
22037
|
-
const outPath =
|
|
22038
|
-
await promises.mkdir(
|
|
22428
|
+
const outPath = path33__default.default.join(outputDir, relativePath);
|
|
22429
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
22039
22430
|
await promises.writeFile(outPath, content, "utf-8");
|
|
22040
22431
|
files.push(relativePath);
|
|
22041
22432
|
}
|
|
@@ -22064,7 +22455,7 @@ function shouldWriteEvidence(options, status) {
|
|
|
22064
22455
|
return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
|
|
22065
22456
|
}
|
|
22066
22457
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
22067
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
22458
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path33__default.default.resolve(options.outputDir.trim()) : "";
|
|
22068
22459
|
if (outputDir === "") {
|
|
22069
22460
|
console.error("--output-dir is required.");
|
|
22070
22461
|
process.exitCode = 1;
|
|
@@ -22204,8 +22595,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
22204
22595
|
}
|
|
22205
22596
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
22206
22597
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
22207
|
-
await promises.mkdir(
|
|
22208
|
-
await promises.appendFile(
|
|
22598
|
+
await promises.mkdir(path33__default.default.dirname(path33__default.default.resolve(summaryTarget)), { recursive: true });
|
|
22599
|
+
await promises.appendFile(path33__default.default.resolve(summaryTarget), `
|
|
22209
22600
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
22210
22601
|
}
|
|
22211
22602
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -22224,10 +22615,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
22224
22615
|
findings: diff?.findings.length ?? 0,
|
|
22225
22616
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
22226
22617
|
},
|
|
22227
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
22618
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path33__default.default.resolve(summaryTarget) } : {},
|
|
22228
22619
|
note: NOTE
|
|
22229
22620
|
};
|
|
22230
|
-
await promises.writeFile(
|
|
22621
|
+
await promises.writeFile(path33__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
22231
22622
|
if (options.json === true) {
|
|
22232
22623
|
console.log(writeJson3(manifest).trimEnd());
|
|
22233
22624
|
} else {
|
|
@@ -22288,8 +22679,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
22288
22679
|
const location = resolveWorkspaceLocation(cwd);
|
|
22289
22680
|
const manifest = await readWorkspaceManifestFile(location);
|
|
22290
22681
|
if (manifest.ok && manifest.manifest) {
|
|
22291
|
-
const rel =
|
|
22292
|
-
if (!rel.startsWith("..") && !
|
|
22682
|
+
const rel = path33__default.default.relative(location.workspaceDir, normalized);
|
|
22683
|
+
if (!rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
|
|
22293
22684
|
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
22294
22685
|
}
|
|
22295
22686
|
}
|
|
@@ -22305,7 +22696,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
22305
22696
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
22306
22697
|
const base2 = resolveInsideWorkspace(
|
|
22307
22698
|
location.workspaceDir,
|
|
22308
|
-
|
|
22699
|
+
path33__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
22309
22700
|
);
|
|
22310
22701
|
return format === "zip" ? `${base2}.zip` : base2;
|
|
22311
22702
|
}
|
|
@@ -22710,19 +23101,19 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
22710
23101
|
let sidecarDir = outputDir;
|
|
22711
23102
|
if (outputDir.toLowerCase().endsWith(".html")) {
|
|
22712
23103
|
htmlPath = outputDir;
|
|
22713
|
-
sidecarDir =
|
|
23104
|
+
sidecarDir = path33__default.default.dirname(outputDir);
|
|
22714
23105
|
} else {
|
|
22715
23106
|
await promises.mkdir(outputDir, { recursive: true });
|
|
22716
|
-
htmlPath =
|
|
23107
|
+
htmlPath = path33__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
|
|
22717
23108
|
sidecarDir = outputDir;
|
|
22718
23109
|
}
|
|
22719
23110
|
await promises.mkdir(sidecarDir, { recursive: true });
|
|
22720
23111
|
await promises.writeFile(htmlPath, htmlContent, "utf-8");
|
|
22721
|
-
await promises.writeFile(
|
|
23112
|
+
await promises.writeFile(path33__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
22722
23113
|
outputPath = htmlPath;
|
|
22723
23114
|
} else if (format === "zip") {
|
|
22724
23115
|
const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
|
|
22725
|
-
const zipParent =
|
|
23116
|
+
const zipParent = path33__default.default.dirname(zipPath);
|
|
22726
23117
|
await promises.mkdir(zipParent, { recursive: true });
|
|
22727
23118
|
const entries = [
|
|
22728
23119
|
...[...packaged.entries()].map(([relativePath, content]) => ({
|
|
@@ -22738,10 +23129,10 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
22738
23129
|
await promises.mkdir(outputDir, { recursive: true });
|
|
22739
23130
|
for (const [relativePath, content] of packaged.entries()) {
|
|
22740
23131
|
const outPath = assertBundlePathContained(outputDir, relativePath);
|
|
22741
|
-
await promises.mkdir(
|
|
23132
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
22742
23133
|
await promises.writeFile(outPath, content, "utf-8");
|
|
22743
23134
|
}
|
|
22744
|
-
await promises.writeFile(
|
|
23135
|
+
await promises.writeFile(path33__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
22745
23136
|
if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
|
|
22746
23137
|
files.push(EVIDENCE_MANIFEST_FILENAME);
|
|
22747
23138
|
}
|
|
@@ -22790,7 +23181,7 @@ function writeJson5(value) {
|
|
|
22790
23181
|
`;
|
|
22791
23182
|
}
|
|
22792
23183
|
async function bundleVerifyCommand(targetPath, options = {}) {
|
|
22793
|
-
const root =
|
|
23184
|
+
const root = path33__default.default.resolve(targetPath.trim() || ".");
|
|
22794
23185
|
const result = await verifyEvidenceDirectory(root, {
|
|
22795
23186
|
unexpectedFiles: options.unexpected ?? "fail"
|
|
22796
23187
|
});
|
|
@@ -22832,7 +23223,7 @@ function writeJson6(value) {
|
|
|
22832
23223
|
}
|
|
22833
23224
|
async function resolveHtmlPath(root) {
|
|
22834
23225
|
const candidates = [
|
|
22835
|
-
|
|
23226
|
+
path33__default.default.join(root, "evidence.html"),
|
|
22836
23227
|
root.toLowerCase().endsWith(".html") ? root : ""
|
|
22837
23228
|
].filter(Boolean);
|
|
22838
23229
|
for (const candidate of candidates) {
|
|
@@ -22847,7 +23238,7 @@ async function resolveHtmlPath(root) {
|
|
|
22847
23238
|
);
|
|
22848
23239
|
}
|
|
22849
23240
|
async function bundleOpenCommand(targetPath, options = {}) {
|
|
22850
|
-
const root =
|
|
23241
|
+
const root = path33__default.default.resolve(targetPath.trim() || ".");
|
|
22851
23242
|
try {
|
|
22852
23243
|
await promises.access(root);
|
|
22853
23244
|
} catch {
|
|
@@ -22864,7 +23255,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22864
23255
|
try {
|
|
22865
23256
|
const info = await promises.stat(root);
|
|
22866
23257
|
if (info.isFile() && root.toLowerCase().endsWith(".html")) {
|
|
22867
|
-
verifyRoot =
|
|
23258
|
+
verifyRoot = path33__default.default.dirname(root);
|
|
22868
23259
|
}
|
|
22869
23260
|
} catch {
|
|
22870
23261
|
}
|
|
@@ -22896,7 +23287,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22896
23287
|
let htmlPath;
|
|
22897
23288
|
try {
|
|
22898
23289
|
htmlPath = await resolveHtmlPath(
|
|
22899
|
-
root.toLowerCase().endsWith(".html") ?
|
|
23290
|
+
root.toLowerCase().endsWith(".html") ? path33__default.default.dirname(root) : root
|
|
22900
23291
|
);
|
|
22901
23292
|
if (root.toLowerCase().endsWith(".html")) {
|
|
22902
23293
|
htmlPath = root;
|
|
@@ -22912,7 +23303,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22912
23303
|
return;
|
|
22913
23304
|
}
|
|
22914
23305
|
try {
|
|
22915
|
-
await promises.readFile(
|
|
23306
|
+
await promises.readFile(path33__default.default.join(path33__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
22916
23307
|
} catch {
|
|
22917
23308
|
}
|
|
22918
23309
|
const fileUrl = url.pathToFileURL(htmlPath).href;
|
|
@@ -22998,24 +23389,24 @@ function resolveTargetPath(client, projectLocal) {
|
|
|
22998
23389
|
if (projectLocal) {
|
|
22999
23390
|
switch (client) {
|
|
23000
23391
|
case "cursor":
|
|
23001
|
-
return
|
|
23392
|
+
return path33__default.default.join(".cursor", "mcp.json");
|
|
23002
23393
|
case "claude-code":
|
|
23003
|
-
return
|
|
23394
|
+
return path33__default.default.join(".mcp.json");
|
|
23004
23395
|
case "codex":
|
|
23005
|
-
return
|
|
23396
|
+
return path33__default.default.join(".codex", "config.toml.json");
|
|
23006
23397
|
case "gemini":
|
|
23007
|
-
return
|
|
23398
|
+
return path33__default.default.join(".gemini", "settings.json");
|
|
23008
23399
|
}
|
|
23009
23400
|
}
|
|
23010
23401
|
switch (client) {
|
|
23011
23402
|
case "cursor":
|
|
23012
|
-
return
|
|
23403
|
+
return path33__default.default.join("~", ".cursor", "mcp.json");
|
|
23013
23404
|
case "claude-code":
|
|
23014
|
-
return
|
|
23405
|
+
return path33__default.default.join("~", ".claude.json");
|
|
23015
23406
|
case "codex":
|
|
23016
|
-
return
|
|
23407
|
+
return path33__default.default.join("~", ".codex", "config.toml");
|
|
23017
23408
|
case "gemini":
|
|
23018
|
-
return
|
|
23409
|
+
return path33__default.default.join("~", ".gemini", "settings.json");
|
|
23019
23410
|
}
|
|
23020
23411
|
}
|
|
23021
23412
|
async function mcpConfigureCommand(options) {
|
|
@@ -23039,8 +23430,8 @@ async function mcpConfigureCommand(options) {
|
|
|
23039
23430
|
];
|
|
23040
23431
|
let wrote = false;
|
|
23041
23432
|
if (!dryRun && projectLocal) {
|
|
23042
|
-
const abs =
|
|
23043
|
-
await promises.mkdir(
|
|
23433
|
+
const abs = path33__default.default.resolve(targetPath);
|
|
23434
|
+
await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
|
|
23044
23435
|
await promises.writeFile(abs, `${JSON.stringify(config, null, 2)}
|
|
23045
23436
|
`, "utf8");
|
|
23046
23437
|
wrote = true;
|
|
@@ -23200,23 +23591,23 @@ function readManifestDocument(value) {
|
|
|
23200
23591
|
};
|
|
23201
23592
|
}
|
|
23202
23593
|
function cwdRelative(filePath) {
|
|
23203
|
-
const relative =
|
|
23204
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
23205
|
-
return
|
|
23594
|
+
const relative = path33__default.default.relative(process.cwd(), path33__default.default.resolve(filePath)).replace(/\\/g, "/");
|
|
23595
|
+
if (relative === "" || relative.startsWith("../") || path33__default.default.isAbsolute(relative)) {
|
|
23596
|
+
return path33__default.default.basename(filePath);
|
|
23206
23597
|
}
|
|
23207
23598
|
return relative;
|
|
23208
23599
|
}
|
|
23209
23600
|
async function readReporterManifest(filePath) {
|
|
23210
|
-
const absolute =
|
|
23601
|
+
const absolute = path33__default.default.resolve(filePath);
|
|
23211
23602
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
23212
23603
|
const document = readManifestDocument(JSON.parse(raw));
|
|
23213
23604
|
const manifest = document.manifest;
|
|
23214
23605
|
const results = manifest.results.map((result) => ({
|
|
23215
23606
|
testId: safeText(result.testId),
|
|
23216
23607
|
name: safeText(result.name),
|
|
23217
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
23608
|
+
...result.file === void 0 ? {} : { file: safeText(path33__default.default.basename(result.file)) },
|
|
23218
23609
|
status: result.status,
|
|
23219
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
23610
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path33__default.default.basename(result.tracePath)) },
|
|
23220
23611
|
artifacts: result.artifacts,
|
|
23221
23612
|
diagnostics: result.diagnostics
|
|
23222
23613
|
}));
|
|
@@ -23355,15 +23746,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
23355
23746
|
return;
|
|
23356
23747
|
}
|
|
23357
23748
|
const markdown = renderMarkdown2(result);
|
|
23358
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
23749
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path33__default.default.resolve(options.output.trim()) : void 0;
|
|
23359
23750
|
if (outputPath !== void 0) {
|
|
23360
|
-
await promises.mkdir(
|
|
23751
|
+
await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
|
|
23361
23752
|
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
23362
23753
|
}
|
|
23363
23754
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
23364
23755
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
23365
|
-
const summaryPath =
|
|
23366
|
-
await promises.mkdir(
|
|
23756
|
+
const summaryPath = path33__default.default.resolve(summaryTarget);
|
|
23757
|
+
await promises.mkdir(path33__default.default.dirname(summaryPath), { recursive: true });
|
|
23367
23758
|
await promises.appendFile(summaryPath, `
|
|
23368
23759
|
${markdown}`, "utf-8");
|
|
23369
23760
|
}
|
|
@@ -23548,7 +23939,7 @@ jobs:
|
|
|
23548
23939
|
}
|
|
23549
23940
|
async function planInit(options = {}) {
|
|
23550
23941
|
const framework = normalizeFramework(options.framework);
|
|
23551
|
-
const cwd =
|
|
23942
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
23552
23943
|
const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
|
|
23553
23944
|
const candidates = [
|
|
23554
23945
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
@@ -23563,7 +23954,7 @@ async function planInit(options = {}) {
|
|
|
23563
23954
|
}
|
|
23564
23955
|
const files = [];
|
|
23565
23956
|
for (const candidate of candidates) {
|
|
23566
|
-
const abs =
|
|
23957
|
+
const abs = path33__default.default.join(cwd, candidate.rel);
|
|
23567
23958
|
try {
|
|
23568
23959
|
await promises.access(abs);
|
|
23569
23960
|
files.push({
|
|
@@ -23584,12 +23975,12 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
23584
23975
|
if (entry.action === "skip") {
|
|
23585
23976
|
continue;
|
|
23586
23977
|
}
|
|
23587
|
-
const abs =
|
|
23978
|
+
const abs = path33__default.default.join(cwd, entry.path);
|
|
23588
23979
|
if (options.dryRun) {
|
|
23589
23980
|
written.push(entry.path);
|
|
23590
23981
|
continue;
|
|
23591
23982
|
}
|
|
23592
|
-
await promises.mkdir(
|
|
23983
|
+
await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
|
|
23593
23984
|
const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
|
|
23594
23985
|
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
|
|
23595
23986
|
await promises.writeFile(abs, content, "utf-8");
|
|
@@ -23598,7 +23989,7 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
23598
23989
|
return written;
|
|
23599
23990
|
}
|
|
23600
23991
|
async function initCommand(options = {}) {
|
|
23601
|
-
const cwd =
|
|
23992
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
23602
23993
|
try {
|
|
23603
23994
|
const plan = await planInit({ ...options, cwd });
|
|
23604
23995
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -23647,6 +24038,9 @@ async function initCommand(options = {}) {
|
|
|
23647
24038
|
process.exitCode = 1;
|
|
23648
24039
|
}
|
|
23649
24040
|
}
|
|
24041
|
+
var DOCS_BASE = "https://github.com/rajudandigam/agent-inspect/blob/main/docs";
|
|
24042
|
+
var AGENT_INSPECT_NOT_RESOLVABLE_MESSAGE = "agent-inspect does not resolve from this project. A global CLI install is not enough \u2014 the package must be a dependency here.";
|
|
24043
|
+
var AGENT_INSPECT_NOT_RESOLVABLE_REMEDIATION = `Install it in this project: npm install agent-inspect (or pnpm add agent-inspect). See ${DOCS_BASE}/FIRST-TRACE-IN-5-MINUTES.md`;
|
|
23650
24044
|
var OPTIONAL_PACKAGES = {
|
|
23651
24045
|
custom: [],
|
|
23652
24046
|
"ai-sdk": ["@agent-inspect/ai-sdk"],
|
|
@@ -23661,7 +24055,7 @@ function nodeVersionCheck() {
|
|
|
23661
24055
|
id: "node-version",
|
|
23662
24056
|
status: "fail",
|
|
23663
24057
|
message: `Node ${process3__default.default.versions.node} is below the supported minimum (20).`,
|
|
23664
|
-
remediation:
|
|
24058
|
+
remediation: `Upgrade to Node 20 LTS or newer, then reinstall. See ${DOCS_BASE}/GETTING-STARTED.md`,
|
|
23665
24059
|
evidence: process3__default.default.versions.node
|
|
23666
24060
|
};
|
|
23667
24061
|
}
|
|
@@ -23690,7 +24084,7 @@ function envCheck(name, optional = true) {
|
|
|
23690
24084
|
};
|
|
23691
24085
|
}
|
|
23692
24086
|
async function traceDirWritable(traceDir) {
|
|
23693
|
-
const resolved =
|
|
24087
|
+
const resolved = path33__default.default.resolve(traceDir);
|
|
23694
24088
|
try {
|
|
23695
24089
|
await promises.mkdir(resolved, { recursive: true });
|
|
23696
24090
|
await promises.access(resolved, promises.constants.W_OK);
|
|
@@ -23705,16 +24099,16 @@ async function traceDirWritable(traceDir) {
|
|
|
23705
24099
|
id: "trace-dir-writable",
|
|
23706
24100
|
status: "fail",
|
|
23707
24101
|
message: `Trace directory is not writable: ${resolved}`,
|
|
23708
|
-
remediation:
|
|
24102
|
+
remediation: `Create the directory or set AGENT_INSPECT_TRACE_DIR to a writable path. See ${DOCS_BASE}/GETTING-STARTED.md`,
|
|
23709
24103
|
evidence: error instanceof Error ? error.message : String(error)
|
|
23710
24104
|
};
|
|
23711
24105
|
}
|
|
23712
24106
|
}
|
|
23713
24107
|
function readPackageVersionNearEntry(entryPath, packageName) {
|
|
23714
|
-
let dir =
|
|
23715
|
-
const { root } =
|
|
24108
|
+
let dir = path33__default.default.dirname(path33__default.default.resolve(entryPath));
|
|
24109
|
+
const { root } = path33__default.default.parse(dir);
|
|
23716
24110
|
while (true) {
|
|
23717
|
-
const candidate =
|
|
24111
|
+
const candidate = path33__default.default.join(dir, "package.json");
|
|
23718
24112
|
if (fs.existsSync(candidate)) {
|
|
23719
24113
|
try {
|
|
23720
24114
|
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
@@ -23725,14 +24119,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
|
|
|
23725
24119
|
}
|
|
23726
24120
|
}
|
|
23727
24121
|
if (dir === root) break;
|
|
23728
|
-
const parent =
|
|
24122
|
+
const parent = path33__default.default.dirname(dir);
|
|
23729
24123
|
if (parent === dir) break;
|
|
23730
24124
|
dir = parent;
|
|
23731
24125
|
}
|
|
23732
24126
|
return void 0;
|
|
23733
24127
|
}
|
|
23734
24128
|
function resolveInstalledPackage(cwd, name) {
|
|
23735
|
-
const require2 = module$1.createRequire(
|
|
24129
|
+
const require2 = module$1.createRequire(path33__default.default.join(cwd, "package.json"));
|
|
23736
24130
|
try {
|
|
23737
24131
|
const entry = require2.resolve(name);
|
|
23738
24132
|
let version2;
|
|
@@ -23768,8 +24162,8 @@ function importSmoke(cwd) {
|
|
|
23768
24162
|
results.push({
|
|
23769
24163
|
id: "import-agent-inspect",
|
|
23770
24164
|
status: "warn",
|
|
23771
|
-
message:
|
|
23772
|
-
remediation:
|
|
24165
|
+
message: AGENT_INSPECT_NOT_RESOLVABLE_MESSAGE,
|
|
24166
|
+
remediation: AGENT_INSPECT_NOT_RESOLVABLE_REMEDIATION
|
|
23773
24167
|
});
|
|
23774
24168
|
results.push({
|
|
23775
24169
|
id: "import-agent-inspect-cjs",
|
|
@@ -23818,8 +24212,8 @@ function versionMismatchCheck(cwd) {
|
|
|
23818
24212
|
return {
|
|
23819
24213
|
id: "version-alignment",
|
|
23820
24214
|
status: "warn",
|
|
23821
|
-
message: `CLI version ${version} differs from local agent-inspect@${root.version}.`,
|
|
23822
|
-
remediation:
|
|
24215
|
+
message: `CLI version ${version} differs from local agent-inspect@${root.version}. A packed consumer can hit this when npx uses a cached global CLI.`,
|
|
24216
|
+
remediation: `Align versions with npm install agent-inspect@${version}, or run via the local binary. See ${DOCS_BASE}/KNOWN-ISSUES.md`,
|
|
23823
24217
|
evidence: `cli=${version};local=${root.version}`
|
|
23824
24218
|
};
|
|
23825
24219
|
}
|
|
@@ -23830,7 +24224,7 @@ function versionMismatchCheck(cwd) {
|
|
|
23830
24224
|
};
|
|
23831
24225
|
}
|
|
23832
24226
|
async function runDoctorChecks(options = {}) {
|
|
23833
|
-
const cwd =
|
|
24227
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process3__default.default.cwd());
|
|
23834
24228
|
const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
23835
24229
|
const checks2 = [
|
|
23836
24230
|
nodeVersionCheck(),
|
|
@@ -24070,7 +24464,7 @@ function parsePluginManifest(input3) {
|
|
|
24070
24464
|
};
|
|
24071
24465
|
}
|
|
24072
24466
|
async function readPluginManifestFile(packageDir) {
|
|
24073
|
-
const manifestPath =
|
|
24467
|
+
const manifestPath = path33__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
|
|
24074
24468
|
try {
|
|
24075
24469
|
const raw = await promises.readFile(manifestPath, "utf8");
|
|
24076
24470
|
const parsed = parsePluginManifest(JSON.parse(raw));
|
|
@@ -24145,7 +24539,7 @@ function createTraceDirectoryIndexer() {
|
|
|
24145
24539
|
// packages/cli/src/plugins.ts
|
|
24146
24540
|
async function readPackageName(packageDir) {
|
|
24147
24541
|
try {
|
|
24148
|
-
const raw = await promises.readFile(
|
|
24542
|
+
const raw = await promises.readFile(path33__default.default.join(packageDir, "package.json"), "utf8");
|
|
24149
24543
|
const parsed = JSON.parse(raw);
|
|
24150
24544
|
return typeof parsed.name === "string" ? parsed.name : void 0;
|
|
24151
24545
|
} catch {
|
|
@@ -24153,7 +24547,7 @@ async function readPackageName(packageDir) {
|
|
|
24153
24547
|
}
|
|
24154
24548
|
}
|
|
24155
24549
|
async function discoverPlugins(cwd = process.cwd()) {
|
|
24156
|
-
const nodeModules =
|
|
24550
|
+
const nodeModules = path33__default.default.join(cwd, "node_modules");
|
|
24157
24551
|
const found = [];
|
|
24158
24552
|
let entries;
|
|
24159
24553
|
try {
|
|
@@ -24164,7 +24558,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
24164
24558
|
for (const entry of entries.sort()) {
|
|
24165
24559
|
if (entry.startsWith("@")) continue;
|
|
24166
24560
|
if (!isPluginPackageName(entry)) continue;
|
|
24167
|
-
const packageDir =
|
|
24561
|
+
const packageDir = path33__default.default.join(nodeModules, entry);
|
|
24168
24562
|
const manifestRead = await readPluginManifestFile(packageDir);
|
|
24169
24563
|
found.push({
|
|
24170
24564
|
packageName: entry,
|
|
@@ -24177,7 +24571,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
24177
24571
|
return found;
|
|
24178
24572
|
}
|
|
24179
24573
|
async function validatePluginPackage(packageRef, cwd = process.cwd()) {
|
|
24180
|
-
const packageDir =
|
|
24574
|
+
const packageDir = path33__default.default.isAbsolute(packageRef) ? packageRef : path33__default.default.join(cwd, "node_modules", packageRef);
|
|
24181
24575
|
const packageName = await readPackageName(packageDir) ?? packageRef;
|
|
24182
24576
|
const errors = [];
|
|
24183
24577
|
const warnings = [];
|
|
@@ -24254,7 +24648,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
|
|
|
24254
24648
|
init_advanced();
|
|
24255
24649
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
24256
24650
|
function traceIndexPath(traceDir) {
|
|
24257
|
-
return
|
|
24651
|
+
return path33__default.default.join(traceDir, INDEX_FILENAME);
|
|
24258
24652
|
}
|
|
24259
24653
|
function parseMaxEntries(raw) {
|
|
24260
24654
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -24400,7 +24794,7 @@ async function newestTraceMtimeMs2(traceDir) {
|
|
|
24400
24794
|
for (const file of files) {
|
|
24401
24795
|
if (!file.endsWith(".jsonl")) continue;
|
|
24402
24796
|
try {
|
|
24403
|
-
const s = await promises.stat(
|
|
24797
|
+
const s = await promises.stat(path33__default.default.join(traceDir, file));
|
|
24404
24798
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
24405
24799
|
} catch {
|
|
24406
24800
|
}
|
|
@@ -24655,11 +25049,11 @@ function printJson5(value) {
|
|
|
24655
25049
|
console.log(JSON.stringify(value, null, 2));
|
|
24656
25050
|
}
|
|
24657
25051
|
function resolveCwd(options) {
|
|
24658
|
-
return
|
|
25052
|
+
return path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
24659
25053
|
}
|
|
24660
25054
|
async function suiteInitCommand(options = {}) {
|
|
24661
25055
|
const cwd = resolveCwd(options);
|
|
24662
|
-
const configPath =
|
|
25056
|
+
const configPath = path33__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
24663
25057
|
const template = options.template?.trim();
|
|
24664
25058
|
const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
|
|
24665
25059
|
if (options.dryRun) {
|
|
@@ -24778,13 +25172,13 @@ async function suiteListCommand(options = {}) {
|
|
|
24778
25172
|
}
|
|
24779
25173
|
async function writeSuiteArtifact(result, configOutputDir, options) {
|
|
24780
25174
|
const cwd = resolveCwd(options);
|
|
24781
|
-
const outputDir =
|
|
25175
|
+
const outputDir = path33__default.default.resolve(
|
|
24782
25176
|
cwd,
|
|
24783
25177
|
options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
|
|
24784
25178
|
);
|
|
24785
25179
|
await promises.mkdir(outputDir, { recursive: true });
|
|
24786
25180
|
const stamp = result.startedAt.replace(/[:.]/g, "-");
|
|
24787
|
-
const filePath =
|
|
25181
|
+
const filePath = path33__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
|
|
24788
25182
|
await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
|
|
24789
25183
|
`, "utf-8");
|
|
24790
25184
|
return filePath;
|
|
@@ -24842,7 +25236,7 @@ async function loadSuiteResultFromInput(options) {
|
|
|
24842
25236
|
if (options.input === void 0 || options.input.trim() === "") {
|
|
24843
25237
|
throw new Error("Pass --input <suite-run.json> from a prior suite run.");
|
|
24844
25238
|
}
|
|
24845
|
-
const inputPath =
|
|
25239
|
+
const inputPath = path33__default.default.resolve(cwd, options.input.trim());
|
|
24846
25240
|
const raw = await promises.readFile(inputPath, "utf-8");
|
|
24847
25241
|
return JSON.parse(raw);
|
|
24848
25242
|
}
|
|
@@ -24885,9 +25279,9 @@ function normalizeMetrics2(raw) {
|
|
|
24885
25279
|
}
|
|
24886
25280
|
async function writeArtifacts(result, outputDir) {
|
|
24887
25281
|
await promises.mkdir(outputDir, { recursive: true });
|
|
24888
|
-
const jsonPath =
|
|
24889
|
-
const markdownPath =
|
|
24890
|
-
const htmlPath =
|
|
25282
|
+
const jsonPath = path33__default.default.join(outputDir, "cohort-results.json");
|
|
25283
|
+
const markdownPath = path33__default.default.join(outputDir, "cohort-summary.md");
|
|
25284
|
+
const htmlPath = path33__default.default.join(outputDir, "cohort-report.html");
|
|
24891
25285
|
await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
24892
25286
|
`, "utf-8");
|
|
24893
25287
|
await promises.writeFile(
|
|
@@ -24916,7 +25310,7 @@ async function cohortCommand(options = {}) {
|
|
|
24916
25310
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
24917
25311
|
let artifacts;
|
|
24918
25312
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
24919
|
-
artifacts = await writeArtifacts(result,
|
|
25313
|
+
artifacts = await writeArtifacts(result, path33__default.default.resolve(options.output.trim()));
|
|
24920
25314
|
}
|
|
24921
25315
|
if (options.json || format === "json") {
|
|
24922
25316
|
console.log(
|
|
@@ -24989,11 +25383,11 @@ function parseDuration2(value) {
|
|
|
24989
25383
|
async function writeArtifacts2(result, outputDir) {
|
|
24990
25384
|
await promises.mkdir(outputDir, { recursive: true });
|
|
24991
25385
|
const paths = {
|
|
24992
|
-
jsonPath:
|
|
24993
|
-
markdownPath:
|
|
24994
|
-
htmlPath:
|
|
24995
|
-
junitPath:
|
|
24996
|
-
githubPath:
|
|
25386
|
+
jsonPath: path33__default.default.join(outputDir, "gate-results.json"),
|
|
25387
|
+
markdownPath: path33__default.default.join(outputDir, "gate-summary.md"),
|
|
25388
|
+
htmlPath: path33__default.default.join(outputDir, "gate-report.html"),
|
|
25389
|
+
junitPath: path33__default.default.join(outputDir, "junit.xml"),
|
|
25390
|
+
githubPath: path33__default.default.join(outputDir, "github-step-summary.md")
|
|
24997
25391
|
};
|
|
24998
25392
|
await promises.writeFile(
|
|
24999
25393
|
paths.jsonPath,
|
|
@@ -25061,7 +25455,7 @@ async function gateCommand(options = {}) {
|
|
|
25061
25455
|
const result = await runGate(runs, gateOptions);
|
|
25062
25456
|
let artifacts;
|
|
25063
25457
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
25064
|
-
artifacts = await writeArtifacts2(result,
|
|
25458
|
+
artifacts = await writeArtifacts2(result, path33__default.default.resolve(options.output.trim()));
|
|
25065
25459
|
}
|
|
25066
25460
|
const failed = !result.ok;
|
|
25067
25461
|
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
@@ -25368,7 +25762,7 @@ function createCliProgram() {
|
|
|
25368
25762
|
"openinference-json",
|
|
25369
25763
|
"otlp-json"
|
|
25370
25764
|
])
|
|
25371
|
-
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").action((target, opts) => {
|
|
25765
|
+
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").option("--policy <path>", "local JSON redaction policy (extraKeys + bounded patterns)").action((target, opts) => {
|
|
25372
25766
|
runCommand(() => scanCommand(target, opts));
|
|
25373
25767
|
});
|
|
25374
25768
|
program.command("verify-safe").description("Best-effort local trace safety verification").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
|
|
@@ -25377,7 +25771,7 @@ function createCliProgram() {
|
|
|
25377
25771
|
"openinference-json",
|
|
25378
25772
|
"otlp-json"
|
|
25379
25773
|
])
|
|
25380
|
-
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").action((target, opts) => {
|
|
25774
|
+
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").option("--policy <path>", "local JSON redaction policy (extraKeys + bounded patterns)").action((target, opts) => {
|
|
25381
25775
|
runCommand(() => verifySafeCommand(target, opts));
|
|
25382
25776
|
});
|
|
25383
25777
|
program.command("artifacts").description("Create safe local CI trace artifacts").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").requiredOption("--output-dir <path>", "directory for generated artifacts").option("--dir <path>", "trace directory for run-id lookup").addOption(
|
|
@@ -25537,7 +25931,10 @@ function createCliProgram() {
|
|
|
25537
25931
|
"--redaction-profile <profile>",
|
|
25538
25932
|
"alias for --profile (canonical spelling)"
|
|
25539
25933
|
).choices(["local", "share", "strict"])
|
|
25540
|
-
).option("-o, --output <path>", "write redacted content to a file").option("--out <path>", "alias for --output").option("--json", "print deterministic JSON wrapper with findings").
|
|
25934
|
+
).option("-o, --output <path>", "write redacted content to a file").option("--out <path>", "alias for --output").option("--json", "print deterministic JSON wrapper with findings").option("--policy <path>", "local JSON redaction policy (extraKeys + bounded patterns)").option(
|
|
25935
|
+
"--fail-on-residual",
|
|
25936
|
+
"exit non-zero when residual safety is UNSAFE or UNKNOWN (opt-in)"
|
|
25937
|
+
).action((target, opts) => {
|
|
25541
25938
|
runCommand(() => redactCommand(target, opts));
|
|
25542
25939
|
});
|
|
25543
25940
|
program.command("explain").description("Explain a local trace with deterministic facts (no provider calls)").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
|
|
@@ -25719,9 +26116,9 @@ function isPrimaryModule() {
|
|
|
25719
26116
|
if (!entry) return false;
|
|
25720
26117
|
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)));
|
|
25721
26118
|
try {
|
|
25722
|
-
return fs.realpathSync(
|
|
26119
|
+
return fs.realpathSync(path33__default.default.resolve(entry)) === fs.realpathSync(path33__default.default.resolve(selfPath));
|
|
25723
26120
|
} catch {
|
|
25724
|
-
return
|
|
26121
|
+
return path33__default.default.resolve(entry) === path33__default.default.resolve(selfPath);
|
|
25725
26122
|
}
|
|
25726
26123
|
}
|
|
25727
26124
|
if (isPrimaryModule()) {
|