agent-inspect 6.17.8 → 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 +17 -0
- package/README.md +1 -1
- 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/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 +1308 -915
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +1233 -849
- 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();
|
|
@@ -13084,6 +13093,16 @@ function filterErrorEvents(events) {
|
|
|
13084
13093
|
return false;
|
|
13085
13094
|
});
|
|
13086
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
|
+
}
|
|
13087
13106
|
async function view(runId, options = {}) {
|
|
13088
13107
|
try {
|
|
13089
13108
|
const id = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "";
|
|
@@ -13156,11 +13175,44 @@ async function view(runId, options = {}) {
|
|
|
13156
13175
|
const errEvents = filterErrorEvents(events);
|
|
13157
13176
|
if (options.json) {
|
|
13158
13177
|
console.log(JSON.stringify(errEvents, null, 2));
|
|
13159
|
-
|
|
13178
|
+
return;
|
|
13179
|
+
}
|
|
13180
|
+
if (errEvents.length === 0) {
|
|
13160
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
|
+
}
|
|
13161
13214
|
} else {
|
|
13162
|
-
|
|
13163
|
-
console.log(JSON.stringify(errEvents, null, 2));
|
|
13215
|
+
printStepTree(pruned, 0, options.verbose === true);
|
|
13164
13216
|
}
|
|
13165
13217
|
return;
|
|
13166
13218
|
}
|
|
@@ -15615,9 +15667,9 @@ Trace directory: ${traceDir}`);
|
|
|
15615
15667
|
process.exitCode = 1;
|
|
15616
15668
|
}
|
|
15617
15669
|
const resolvedOutput = resolveOutputOption(options);
|
|
15618
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
15670
|
+
const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
|
|
15619
15671
|
if (outPath !== void 0) {
|
|
15620
|
-
await promises.mkdir(
|
|
15672
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
15621
15673
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
15622
15674
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
15623
15675
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -15976,7 +16028,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
15976
16028
|
endedAt: row.endedAt ?? void 0,
|
|
15977
16029
|
durationMs: row.durationMs ?? void 0,
|
|
15978
16030
|
eventCount: 0,
|
|
15979
|
-
filePath:
|
|
16031
|
+
filePath: path33__default.default.join(traceDir, row.file),
|
|
15980
16032
|
fileSize: 0,
|
|
15981
16033
|
createdAt: new Date(row.mtimeMs)
|
|
15982
16034
|
};
|
|
@@ -16458,9 +16510,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
16458
16510
|
...options.section ? { section: options.section } : {}
|
|
16459
16511
|
});
|
|
16460
16512
|
const resolvedOutput = resolveOutputOption(options);
|
|
16461
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
16513
|
+
const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
|
|
16462
16514
|
if (outPath !== void 0) {
|
|
16463
|
-
await promises.mkdir(
|
|
16515
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
16464
16516
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
16465
16517
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
16466
16518
|
}
|
|
@@ -16658,8 +16710,8 @@ function passesLuhn(value) {
|
|
|
16658
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;
|
|
16659
16711
|
var EPOCH_MS_RE = /^1[0-9]{12}$/;
|
|
16660
16712
|
var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
16661
|
-
function pathSuggestsNonCard(
|
|
16662
|
-
const normalized =
|
|
16713
|
+
function pathSuggestsNonCard(path44) {
|
|
16714
|
+
const normalized = path44.toLowerCase().replace(/[^a-z0-9._]/g, "");
|
|
16663
16715
|
return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
|
|
16664
16716
|
normalized
|
|
16665
16717
|
) || /(^|\.)ts(\.|$)/.test(normalized);
|
|
@@ -16855,17 +16907,17 @@ function applyRule(rule, value, replacement) {
|
|
|
16855
16907
|
}
|
|
16856
16908
|
return value;
|
|
16857
16909
|
}
|
|
16858
|
-
function childPath(
|
|
16910
|
+
function childPath(path44, key) {
|
|
16859
16911
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
16860
|
-
return
|
|
16912
|
+
return path44 ? `${path44}.${key}` : key;
|
|
16861
16913
|
}
|
|
16862
|
-
return `${
|
|
16914
|
+
return `${path44 || "$"}[${JSON.stringify(key)}]`;
|
|
16863
16915
|
}
|
|
16864
|
-
function indexPath(
|
|
16865
|
-
return `${
|
|
16916
|
+
function indexPath(path44, index) {
|
|
16917
|
+
return `${path44 || "$"}[${index}]`;
|
|
16866
16918
|
}
|
|
16867
|
-
function makeFinding(
|
|
16868
|
-
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 };
|
|
16869
16921
|
}
|
|
16870
16922
|
function createRedactionProfile(profile = "local") {
|
|
16871
16923
|
switch (profile) {
|
|
@@ -16934,11 +16986,11 @@ var Redactor2 = class {
|
|
|
16934
16986
|
#recordFinding(state, finding) {
|
|
16935
16987
|
if (this.#collectFindings) state.findings.push(finding);
|
|
16936
16988
|
}
|
|
16937
|
-
#redactValue(value, key,
|
|
16989
|
+
#redactValue(value, key, path44, depth, state) {
|
|
16938
16990
|
if (depth > this.#maxDepth) {
|
|
16939
16991
|
this.#recordFinding(
|
|
16940
16992
|
state,
|
|
16941
|
-
makeFinding(
|
|
16993
|
+
makeFinding(path44, "structure.maxDepth", "truncate", "value", "warning")
|
|
16942
16994
|
);
|
|
16943
16995
|
return "[Truncated]";
|
|
16944
16996
|
}
|
|
@@ -16947,19 +16999,19 @@ var Redactor2 = class {
|
|
|
16947
16999
|
if (rule) {
|
|
16948
17000
|
this.#recordFinding(
|
|
16949
17001
|
state,
|
|
16950
|
-
makeFinding(
|
|
17002
|
+
makeFinding(path44, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
16951
17003
|
);
|
|
16952
17004
|
return applyRule(rule, value, this.#replacement);
|
|
16953
17005
|
}
|
|
16954
17006
|
}
|
|
16955
17007
|
for (const detector of this.#detectors) {
|
|
16956
|
-
const detections = detector.detect({ path:
|
|
17008
|
+
const detections = detector.detect({ path: path44, key, value });
|
|
16957
17009
|
for (const detection of detections) {
|
|
16958
17010
|
const action = detection.action ?? "replace";
|
|
16959
17011
|
this.#recordFinding(
|
|
16960
17012
|
state,
|
|
16961
17013
|
makeFinding(
|
|
16962
|
-
|
|
17014
|
+
path44,
|
|
16963
17015
|
detector.id,
|
|
16964
17016
|
action,
|
|
16965
17017
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -16977,7 +17029,7 @@ var Redactor2 = class {
|
|
|
16977
17029
|
const out = [];
|
|
16978
17030
|
state.seen.set(value, out);
|
|
16979
17031
|
value.forEach((item, index) => {
|
|
16980
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
17032
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path44, index), depth + 1, state);
|
|
16981
17033
|
});
|
|
16982
17034
|
return out;
|
|
16983
17035
|
}
|
|
@@ -16989,7 +17041,7 @@ var Redactor2 = class {
|
|
|
16989
17041
|
out[entryKey] = this.#redactValue(
|
|
16990
17042
|
entryValue,
|
|
16991
17043
|
entryKey,
|
|
16992
|
-
childPath(
|
|
17044
|
+
childPath(path44 === "$" ? "" : path44, entryKey),
|
|
16993
17045
|
depth + 1,
|
|
16994
17046
|
state
|
|
16995
17047
|
);
|
|
@@ -17005,6 +17057,233 @@ function createRedactor(options) {
|
|
|
17005
17057
|
function redact(value, options) {
|
|
17006
17058
|
return createRedactor(options).redact(value);
|
|
17007
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();
|
|
17008
17287
|
|
|
17009
17288
|
// packages/cli/src/trace-input.ts
|
|
17010
17289
|
init_advanced();
|
|
@@ -17036,12 +17315,19 @@ async function inputFromTarget(target, options, stdin) {
|
|
|
17036
17315
|
return { type: "file", path: runPath };
|
|
17037
17316
|
}
|
|
17038
17317
|
|
|
17039
|
-
// packages/cli/src/
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
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.`);
|
|
17043
17329
|
}
|
|
17044
|
-
|
|
17330
|
+
return parsed;
|
|
17045
17331
|
}
|
|
17046
17332
|
function stable2(value) {
|
|
17047
17333
|
if (Array.isArray(value)) return value.map(stable2);
|
|
@@ -17051,103 +17337,585 @@ function stable2(value) {
|
|
|
17051
17337
|
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable2(record[key])])
|
|
17052
17338
|
);
|
|
17053
17339
|
}
|
|
17054
|
-
function
|
|
17055
|
-
return
|
|
17340
|
+
function safetyDiagnostic(code, message, severity = "error") {
|
|
17341
|
+
return { code, message, severity };
|
|
17056
17342
|
}
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
|
|
17071
|
-
|
|
17072
|
-
|
|
17073
|
-
|
|
17074
|
-
}
|
|
17075
|
-
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
|
+
];
|
|
17076
17360
|
}
|
|
17077
|
-
function
|
|
17078
|
-
|
|
17079
|
-
|
|
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);
|
|
17080
17377
|
return {
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
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 } : {}
|
|
17084
17396
|
};
|
|
17085
17397
|
}
|
|
17086
|
-
function
|
|
17087
|
-
const lines = content.split(/\r?\n/);
|
|
17088
|
-
const out = [];
|
|
17089
|
-
const findings = [];
|
|
17090
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
17091
|
-
const line = lines[index] ?? "";
|
|
17092
|
-
if (line.trim() === "") continue;
|
|
17093
|
-
let parsed;
|
|
17094
|
-
try {
|
|
17095
|
-
parsed = JSON.parse(line);
|
|
17096
|
-
} catch {
|
|
17097
|
-
throw new Error(`Input is not valid JSON or JSONL at line ${index + 1}.`);
|
|
17098
|
-
}
|
|
17099
|
-
const result = redact(parsed, { profile });
|
|
17100
|
-
out.push(JSON.stringify(result.value));
|
|
17101
|
-
findings.push(
|
|
17102
|
-
...result.findings.map((finding) => ({
|
|
17103
|
-
...finding,
|
|
17104
|
-
path: `line:${index + 1}:${finding.path}`
|
|
17105
|
-
}))
|
|
17106
|
-
);
|
|
17107
|
-
}
|
|
17398
|
+
function layerFromResult(result) {
|
|
17108
17399
|
return {
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
findings
|
|
17400
|
+
status: result.status,
|
|
17401
|
+
summary: result.summary,
|
|
17402
|
+
findings: result.findings
|
|
17112
17403
|
};
|
|
17113
17404
|
}
|
|
17114
|
-
function
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
}
|
|
17123
|
-
}
|
|
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
|
+
});
|
|
17124
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;
|
|
17125
17865
|
try {
|
|
17126
|
-
|
|
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);
|
|
17127
17869
|
} catch {
|
|
17128
|
-
return
|
|
17870
|
+
return false;
|
|
17129
17871
|
}
|
|
17130
17872
|
}
|
|
17131
|
-
function
|
|
17132
|
-
|
|
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;
|
|
17133
17885
|
}
|
|
17134
17886
|
async function redactCommand(target, options = {}, stdin = process.stdin) {
|
|
17135
17887
|
const profile = parseRedactionProfile3(resolveRedactionProfileOption(options));
|
|
17888
|
+
const policy = options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0;
|
|
17136
17889
|
const source = await contentFromTarget(target, options, stdin);
|
|
17137
|
-
const redacted = redactDocument(source.content, profile);
|
|
17890
|
+
const redacted = redactDocument(source.content, profile, policy);
|
|
17138
17891
|
const outputPath = resolveOutputOption(options);
|
|
17892
|
+
const residualAssessment = await assessResidualFromContent(redacted.content, {
|
|
17893
|
+
compiledPolicy: policy
|
|
17894
|
+
});
|
|
17139
17895
|
if (outputPath !== void 0) {
|
|
17140
17896
|
await promises.writeFile(outputPath, redacted.content, "utf-8");
|
|
17141
17897
|
}
|
|
17898
|
+
if (options.failOnResidual === true) {
|
|
17899
|
+
process.exitCode = residualExitCode(residualAssessment);
|
|
17900
|
+
}
|
|
17142
17901
|
if (options.json) {
|
|
17143
17902
|
console.log(
|
|
17144
17903
|
JSON.stringify(
|
|
17145
|
-
|
|
17904
|
+
stable3({
|
|
17146
17905
|
ok: true,
|
|
17147
17906
|
profile,
|
|
17148
17907
|
source: source.source,
|
|
17149
17908
|
output: outputPath,
|
|
17150
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
|
+
} : {},
|
|
17151
17919
|
content: outputPath === void 0 ? redacted.content : void 0
|
|
17152
17920
|
}),
|
|
17153
17921
|
null,
|
|
@@ -17156,6 +17924,7 @@ async function redactCommand(target, options = {}, stdin = process.stdin) {
|
|
|
17156
17924
|
);
|
|
17157
17925
|
return;
|
|
17158
17926
|
}
|
|
17927
|
+
printResidualWarning(residualAssessment, looksLikeAgentInspectTrace(redacted.content));
|
|
17159
17928
|
if (outputPath === void 0) {
|
|
17160
17929
|
process.stdout.write(redacted.content);
|
|
17161
17930
|
}
|
|
@@ -17438,7 +18207,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
|
17438
18207
|
|
|
17439
18208
|
// packages/cli/src/migrate.ts
|
|
17440
18209
|
init_advanced();
|
|
17441
|
-
function
|
|
18210
|
+
function isRecord17(value) {
|
|
17442
18211
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17443
18212
|
}
|
|
17444
18213
|
function parseTarget(value) {
|
|
@@ -17447,7 +18216,7 @@ function parseTarget(value) {
|
|
|
17447
18216
|
throw new Error('Unsupported migration target. Use "--to 1.0".');
|
|
17448
18217
|
}
|
|
17449
18218
|
function formatOf(value) {
|
|
17450
|
-
if (!
|
|
18219
|
+
if (!isRecord17(value)) return "unknown";
|
|
17451
18220
|
if (value.schemaVersion === "0.1") return "0.1";
|
|
17452
18221
|
if (value.schemaVersion === "0.2") return "0.2";
|
|
17453
18222
|
if (value.schemaVersion === "1.0") return "1.0";
|
|
@@ -17460,14 +18229,14 @@ function uniqueSorted(values) {
|
|
|
17460
18229
|
return [...new Set(values)].sort();
|
|
17461
18230
|
}
|
|
17462
18231
|
function isWithinDirectory(child, parent) {
|
|
17463
|
-
const relative =
|
|
17464
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
18232
|
+
const relative = path33__default.default.relative(parent, child);
|
|
18233
|
+
return relative === "" || !relative.startsWith("..") && !path33__default.default.isAbsolute(relative);
|
|
17465
18234
|
}
|
|
17466
18235
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
17467
18236
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
17468
|
-
const inputAbs =
|
|
17469
|
-
const outputAbs =
|
|
17470
|
-
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);
|
|
17471
18240
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
17472
18241
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
17473
18242
|
}
|
|
@@ -17588,7 +18357,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17588
18357
|
process.exitCode = 1;
|
|
17589
18358
|
return;
|
|
17590
18359
|
}
|
|
17591
|
-
const inputPath =
|
|
18360
|
+
const inputPath = path33__default.default.resolve(input3.trim());
|
|
17592
18361
|
const dryRun = options.dryRun === true;
|
|
17593
18362
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
17594
18363
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -17607,7 +18376,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17607
18376
|
);
|
|
17608
18377
|
const result = await buildMigration(inputPath, outputPath);
|
|
17609
18378
|
if (!dryRun && outputPath !== void 0) {
|
|
17610
|
-
await promises.mkdir(
|
|
18379
|
+
await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
|
|
17611
18380
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
17612
18381
|
}
|
|
17613
18382
|
printSummary2(result, dryRun);
|
|
@@ -17616,16 +18385,13 @@ async function migrateCommand(input3, options = {}) {
|
|
|
17616
18385
|
console.error(`[AgentInspect] migrate failed: ${msg}`);
|
|
17617
18386
|
process.exitCode = 1;
|
|
17618
18387
|
}
|
|
17619
|
-
}
|
|
17620
|
-
init_advanced();
|
|
17621
|
-
|
|
17622
|
-
// packages/core/src/entries/checks.ts
|
|
17623
|
-
init_checks2();
|
|
18388
|
+
}
|
|
18389
|
+
init_advanced();
|
|
17624
18390
|
|
|
17625
18391
|
// packages/cli/src/evidence-on.ts
|
|
17626
18392
|
init_advanced();
|
|
17627
18393
|
function validateReporterArtifactPath(options) {
|
|
17628
|
-
const outputDir =
|
|
18394
|
+
const outputDir = path33__default.default.resolve(options.outputDir);
|
|
17629
18395
|
const diagnostics = [];
|
|
17630
18396
|
const rawPath = options.relativePath;
|
|
17631
18397
|
if (rawPath.length === 0) {
|
|
@@ -17645,7 +18411,7 @@ function validateReporterArtifactPath(options) {
|
|
|
17645
18411
|
});
|
|
17646
18412
|
return { ok: false, outputDir, diagnostics };
|
|
17647
18413
|
}
|
|
17648
|
-
if (
|
|
18414
|
+
if (path33__default.default.isAbsolute(rawPath) || path33__default.default.win32.isAbsolute(rawPath)) {
|
|
17649
18415
|
diagnostics.push({
|
|
17650
18416
|
code: "artifact_path_absolute",
|
|
17651
18417
|
severity: "error",
|
|
@@ -17654,7 +18420,7 @@ function validateReporterArtifactPath(options) {
|
|
|
17654
18420
|
});
|
|
17655
18421
|
return { ok: false, outputDir, diagnostics };
|
|
17656
18422
|
}
|
|
17657
|
-
const normalized =
|
|
18423
|
+
const normalized = path33__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
17658
18424
|
const segments = normalized.split("/");
|
|
17659
18425
|
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
17660
18426
|
diagnostics.push({
|
|
@@ -17665,9 +18431,9 @@ function validateReporterArtifactPath(options) {
|
|
|
17665
18431
|
});
|
|
17666
18432
|
return { ok: false, outputDir, diagnostics };
|
|
17667
18433
|
}
|
|
17668
|
-
const absolutePath =
|
|
17669
|
-
const relFromOutput =
|
|
17670
|
-
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)) {
|
|
17671
18437
|
diagnostics.push({
|
|
17672
18438
|
code: "artifact_path_escape",
|
|
17673
18439
|
severity: "error",
|
|
@@ -17693,7 +18459,7 @@ var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
|
17693
18459
|
function createEvidenceCiArtifacts(options) {
|
|
17694
18460
|
const profile = options.redactionProfile ?? "share";
|
|
17695
18461
|
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
17696
|
-
const join = (name) => prefix === "" ? name :
|
|
18462
|
+
const join = (name) => prefix === "" ? name : path33__default.default.posix.join(prefix, name);
|
|
17697
18463
|
const formatFor = (name) => {
|
|
17698
18464
|
if (name.endsWith(".html")) return "html";
|
|
17699
18465
|
if (name.endsWith(".jsonl")) return "jsonl";
|
|
@@ -17742,9 +18508,9 @@ function stableJson2(value) {
|
|
|
17742
18508
|
async function writeLocalEvidence(input3) {
|
|
17743
18509
|
const profile = input3.redactionProfile ?? "share";
|
|
17744
18510
|
const format = input3.format ?? "directory";
|
|
17745
|
-
const baseDir =
|
|
18511
|
+
const baseDir = path33__default.default.resolve(input3.outputDir);
|
|
17746
18512
|
await promises.mkdir(
|
|
17747
|
-
format === "zip" && baseDir.toLowerCase().endsWith(".zip") ?
|
|
18513
|
+
format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path33__default.default.dirname(baseDir) : baseDir,
|
|
17748
18514
|
{ recursive: true }
|
|
17749
18515
|
);
|
|
17750
18516
|
const sourceContents = /* @__PURE__ */ new Map();
|
|
@@ -17800,7 +18566,7 @@ async function writeLocalEvidence(input3) {
|
|
|
17800
18566
|
}
|
|
17801
18567
|
if (format === "zip") {
|
|
17802
18568
|
const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
|
|
17803
|
-
await promises.mkdir(
|
|
18569
|
+
await promises.mkdir(path33__default.default.dirname(zipPath), { recursive: true });
|
|
17804
18570
|
const archive = buildZipArchive(
|
|
17805
18571
|
files.map(([relativePath, content]) => ({
|
|
17806
18572
|
path: relativePath,
|
|
@@ -17815,16 +18581,16 @@ async function writeLocalEvidence(input3) {
|
|
|
17815
18581
|
let sidecarDir = baseDir;
|
|
17816
18582
|
if (baseDir.toLowerCase().endsWith(".html")) {
|
|
17817
18583
|
htmlPath = baseDir;
|
|
17818
|
-
sidecarDir =
|
|
18584
|
+
sidecarDir = path33__default.default.dirname(baseDir);
|
|
17819
18585
|
} else {
|
|
17820
18586
|
await promises.mkdir(baseDir, { recursive: true });
|
|
17821
|
-
htmlPath =
|
|
18587
|
+
htmlPath = path33__default.default.join(baseDir, "evidence.html");
|
|
17822
18588
|
sidecarDir = baseDir;
|
|
17823
18589
|
}
|
|
17824
18590
|
await promises.mkdir(sidecarDir, { recursive: true });
|
|
17825
18591
|
await promises.writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
|
|
17826
18592
|
await promises.writeFile(
|
|
17827
|
-
|
|
18593
|
+
path33__default.default.join(sidecarDir, "evidence.json"),
|
|
17828
18594
|
evidencePackage["evidence.json"],
|
|
17829
18595
|
"utf-8"
|
|
17830
18596
|
);
|
|
@@ -17832,7 +18598,7 @@ async function writeLocalEvidence(input3) {
|
|
|
17832
18598
|
}
|
|
17833
18599
|
await promises.mkdir(baseDir, { recursive: true });
|
|
17834
18600
|
for (const [name, content] of files) {
|
|
17835
|
-
await promises.writeFile(
|
|
18601
|
+
await promises.writeFile(path33__default.default.join(baseDir, name), content, "utf-8");
|
|
17836
18602
|
}
|
|
17837
18603
|
return baseDir;
|
|
17838
18604
|
}
|
|
@@ -17856,11 +18622,11 @@ function checkResultToEvidenceJson(result, runIds) {
|
|
|
17856
18622
|
}
|
|
17857
18623
|
function defaultEvidenceDir(label) {
|
|
17858
18624
|
const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
|
|
17859
|
-
return
|
|
18625
|
+
return path33__default.default.join(".agent-inspect", "evidence", safe);
|
|
17860
18626
|
}
|
|
17861
18627
|
function resolveEvidenceOutputDir(evidenceDir, label) {
|
|
17862
18628
|
if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
|
|
17863
|
-
return
|
|
18629
|
+
return path33__default.default.resolve(evidenceDir.trim());
|
|
17864
18630
|
}
|
|
17865
18631
|
return defaultEvidenceDir(label);
|
|
17866
18632
|
}
|
|
@@ -18184,23 +18950,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
18184
18950
|
}
|
|
18185
18951
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
18186
18952
|
}
|
|
18187
|
-
function validateSchemaField(value, field,
|
|
18953
|
+
function validateSchemaField(value, field, path44, evidence) {
|
|
18188
18954
|
const ruleId = "guardrail.structured-output";
|
|
18189
18955
|
if (field.type) {
|
|
18190
18956
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
18191
18957
|
if (actual !== field.type) {
|
|
18192
|
-
evidence.push({ ruleId, path:
|
|
18958
|
+
evidence.push({ ruleId, path: path44, preview: `expected ${field.type}, got ${actual}` });
|
|
18193
18959
|
return;
|
|
18194
18960
|
}
|
|
18195
18961
|
}
|
|
18196
18962
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
18197
|
-
evidence.push({ ruleId, path:
|
|
18963
|
+
evidence.push({ ruleId, path: path44, preview: "value not in enum" });
|
|
18198
18964
|
}
|
|
18199
18965
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
18200
18966
|
const record = value;
|
|
18201
18967
|
for (const key of field.required) {
|
|
18202
18968
|
if (!(key in record)) {
|
|
18203
|
-
evidence.push({ ruleId, path: `${
|
|
18969
|
+
evidence.push({ ruleId, path: `${path44}.${key}`, preview: "missing required key" });
|
|
18204
18970
|
}
|
|
18205
18971
|
}
|
|
18206
18972
|
}
|
|
@@ -18929,7 +19695,7 @@ function parseCheckConfig(value) {
|
|
|
18929
19695
|
}
|
|
18930
19696
|
async function loadConfig(configPath) {
|
|
18931
19697
|
if (configPath === void 0) return {};
|
|
18932
|
-
const extension =
|
|
19698
|
+
const extension = path33__default.default.extname(configPath);
|
|
18933
19699
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
18934
19700
|
throw new CheckConfigError(
|
|
18935
19701
|
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
@@ -18942,7 +19708,7 @@ async function loadConfig(configPath) {
|
|
|
18942
19708
|
"Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
|
|
18943
19709
|
);
|
|
18944
19710
|
}
|
|
18945
|
-
const absolute =
|
|
19711
|
+
const absolute = path33__default.default.resolve(configPath);
|
|
18946
19712
|
try {
|
|
18947
19713
|
if (extension === ".json") {
|
|
18948
19714
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
@@ -19136,7 +19902,7 @@ function buildRules(config, options, presetSelect = []) {
|
|
|
19136
19902
|
diagnostics
|
|
19137
19903
|
};
|
|
19138
19904
|
}
|
|
19139
|
-
function
|
|
19905
|
+
function exitCodeFor2(result) {
|
|
19140
19906
|
if (result.status === "pass") return 0;
|
|
19141
19907
|
if (result.status === "fail") return 1;
|
|
19142
19908
|
const codes = result.diagnostics.map((item) => item.code);
|
|
@@ -19157,16 +19923,16 @@ function exitCodeFor(result) {
|
|
|
19157
19923
|
}
|
|
19158
19924
|
return 1;
|
|
19159
19925
|
}
|
|
19160
|
-
function
|
|
19161
|
-
if (Array.isArray(value)) return value.map(
|
|
19926
|
+
function stable4(value) {
|
|
19927
|
+
if (Array.isArray(value)) return value.map(stable4);
|
|
19162
19928
|
if (value === null || typeof value !== "object") return value;
|
|
19163
19929
|
const record = value;
|
|
19164
19930
|
return Object.fromEntries(
|
|
19165
|
-
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])])
|
|
19166
19932
|
);
|
|
19167
19933
|
}
|
|
19168
|
-
function
|
|
19169
|
-
console.log(JSON.stringify(
|
|
19934
|
+
function printJson2(result) {
|
|
19935
|
+
console.log(JSON.stringify(stable4(result), null, 2));
|
|
19170
19936
|
}
|
|
19171
19937
|
function isSafetyFinding(ruleId) {
|
|
19172
19938
|
return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
|
|
@@ -19203,7 +19969,7 @@ function printPresetClassSummary(result, preset) {
|
|
|
19203
19969
|
`Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
19204
19970
|
);
|
|
19205
19971
|
}
|
|
19206
|
-
function
|
|
19972
|
+
function printHuman2(result, options = {}) {
|
|
19207
19973
|
const scoped = result;
|
|
19208
19974
|
if (scoped.scopeLabel) {
|
|
19209
19975
|
console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
|
|
@@ -19223,13 +19989,13 @@ function printHuman(result, options = {}) {
|
|
|
19223
19989
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
19224
19990
|
}
|
|
19225
19991
|
for (const finding of result.findings) {
|
|
19226
|
-
const
|
|
19992
|
+
const path44 = finding.evidence[0]?.path;
|
|
19227
19993
|
const run = finding.evidence[0]?.runId;
|
|
19228
19994
|
const runPrefix = run ? `[${run}] ` : "";
|
|
19229
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
19995
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
|
|
19230
19996
|
}
|
|
19231
19997
|
}
|
|
19232
|
-
function
|
|
19998
|
+
function readErrorResult2(error) {
|
|
19233
19999
|
if (error instanceof TraceReadError) {
|
|
19234
20000
|
const code = error.code === "unsupported_format" ? "AI_CHECK_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_CHECK_AMBIGUOUS_FORMAT" : "AI_CHECK_TRACE_UNREADABLE";
|
|
19235
20001
|
return errorResult2(code, error.message);
|
|
@@ -19256,9 +20022,9 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
19256
20022
|
"AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
|
|
19257
20023
|
"Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
|
|
19258
20024
|
);
|
|
19259
|
-
if (options.json)
|
|
19260
|
-
else
|
|
19261
|
-
process.exitCode =
|
|
20025
|
+
if (options.json) printJson2(result);
|
|
20026
|
+
else printHuman2(result, options);
|
|
20027
|
+
process.exitCode = exitCodeFor2(result);
|
|
19262
20028
|
return;
|
|
19263
20029
|
}
|
|
19264
20030
|
let effectiveOptions = options;
|
|
@@ -19388,10 +20154,10 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
19388
20154
|
result = errorResult2(code, message);
|
|
19389
20155
|
}
|
|
19390
20156
|
} else {
|
|
19391
|
-
result =
|
|
20157
|
+
result = readErrorResult2(error);
|
|
19392
20158
|
}
|
|
19393
20159
|
}
|
|
19394
|
-
process.exitCode =
|
|
20160
|
+
process.exitCode = exitCodeFor2(result);
|
|
19395
20161
|
const failed = result.status !== "pass";
|
|
19396
20162
|
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
19397
20163
|
try {
|
|
@@ -19431,8 +20197,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
19431
20197
|
);
|
|
19432
20198
|
}
|
|
19433
20199
|
}
|
|
19434
|
-
if (options.json)
|
|
19435
|
-
else
|
|
20200
|
+
if (options.json) printJson2(result);
|
|
20201
|
+
else printHuman2(result, options);
|
|
19436
20202
|
}
|
|
19437
20203
|
|
|
19438
20204
|
// packages/viewer/src/server.ts
|
|
@@ -19589,7 +20355,7 @@ async function loadSuiteViewerData(options) {
|
|
|
19589
20355
|
for (const suiteCase of result.cases) {
|
|
19590
20356
|
cases.push(await enrichCase(suiteCase, baselinePath));
|
|
19591
20357
|
}
|
|
19592
|
-
const artifactsDir =
|
|
20358
|
+
const artifactsDir = path33__default.default.join(path33__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
|
|
19593
20359
|
return {
|
|
19594
20360
|
suiteName: result.suiteName,
|
|
19595
20361
|
configPath: result.configPath,
|
|
@@ -19785,19 +20551,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
19785
20551
|
}
|
|
19786
20552
|
var INDEX_DIR_NAME = "index";
|
|
19787
20553
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
19788
|
-
const projectRoot =
|
|
19789
|
-
const workspaceDir =
|
|
20554
|
+
const projectRoot = path33__default.default.resolve(cwd);
|
|
20555
|
+
const workspaceDir = path33__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
19790
20556
|
return {
|
|
19791
20557
|
projectRoot,
|
|
19792
20558
|
workspaceDir,
|
|
19793
|
-
manifestPath:
|
|
20559
|
+
manifestPath: path33__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
19794
20560
|
};
|
|
19795
20561
|
}
|
|
19796
20562
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
19797
|
-
const base =
|
|
19798
|
-
const resolved =
|
|
19799
|
-
const rel =
|
|
19800
|
-
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)) {
|
|
19801
20567
|
return resolved;
|
|
19802
20568
|
}
|
|
19803
20569
|
throw new Error(
|
|
@@ -19866,7 +20632,7 @@ async function createWorkspace(options = {}) {
|
|
|
19866
20632
|
created = false;
|
|
19867
20633
|
adopted = true;
|
|
19868
20634
|
} else {
|
|
19869
|
-
const project = options.project?.trim() ||
|
|
20635
|
+
const project = options.project?.trim() || path33__default.default.basename(location.projectRoot) || "workspace";
|
|
19870
20636
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
19871
20637
|
manifest = createDefaultWorkspaceManifest({
|
|
19872
20638
|
project,
|
|
@@ -20005,7 +20771,7 @@ async function doctorWorkspace(location) {
|
|
|
20005
20771
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
20006
20772
|
for (const file of await listJsonl(abs)) {
|
|
20007
20773
|
try {
|
|
20008
|
-
const s = await promises.stat(
|
|
20774
|
+
const s = await promises.stat(path33__default.default.join(abs, file));
|
|
20009
20775
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
20010
20776
|
} catch {
|
|
20011
20777
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -20053,7 +20819,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
20053
20819
|
const relPath = `${rel}/${entry}`;
|
|
20054
20820
|
removed.push(relPath);
|
|
20055
20821
|
if (!dryRun) {
|
|
20056
|
-
await promises.rm(
|
|
20822
|
+
await promises.rm(path33__default.default.join(abs, entry), { recursive: true, force: true });
|
|
20057
20823
|
}
|
|
20058
20824
|
}
|
|
20059
20825
|
}
|
|
@@ -20062,7 +20828,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
20062
20828
|
|
|
20063
20829
|
// packages/viewer/src/workspace-data.ts
|
|
20064
20830
|
async function loadWorkspaceViewerData(options) {
|
|
20065
|
-
const cwd =
|
|
20831
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
20066
20832
|
const location = resolveWorkspaceLocation(cwd);
|
|
20067
20833
|
const manifestRead = await readWorkspaceManifestFile(location);
|
|
20068
20834
|
if (!manifestRead.ok || manifestRead.manifest === void 0) {
|
|
@@ -20075,7 +20841,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
20075
20841
|
const runs = [];
|
|
20076
20842
|
for (const rel of manifestRead.manifest.traceDirs) {
|
|
20077
20843
|
const traceDir = resolveTraceDir({
|
|
20078
|
-
dir:
|
|
20844
|
+
dir: path33__default.default.join(location.workspaceDir, rel)
|
|
20079
20845
|
});
|
|
20080
20846
|
const td = new TraceDirectory({ dir: traceDir });
|
|
20081
20847
|
const files = await td.list();
|
|
@@ -20089,7 +20855,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
20089
20855
|
runId: meta2.runId,
|
|
20090
20856
|
...meta2.name !== void 0 ? { name: meta2.name } : {},
|
|
20091
20857
|
status: meta2.status,
|
|
20092
|
-
file:
|
|
20858
|
+
file: path33__default.default.basename(meta2.filePath)
|
|
20093
20859
|
});
|
|
20094
20860
|
}
|
|
20095
20861
|
}
|
|
@@ -20100,8 +20866,8 @@ async function loadWorkspaceViewerData(options) {
|
|
|
20100
20866
|
doctor,
|
|
20101
20867
|
runs,
|
|
20102
20868
|
bundleDirs: [
|
|
20103
|
-
|
|
20104
|
-
|
|
20869
|
+
path33__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
|
|
20870
|
+
path33__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
|
|
20105
20871
|
]
|
|
20106
20872
|
};
|
|
20107
20873
|
}
|
|
@@ -20164,7 +20930,7 @@ function createViewerServer(options = {}) {
|
|
|
20164
20930
|
ok: true,
|
|
20165
20931
|
readOnly: true,
|
|
20166
20932
|
mode,
|
|
20167
|
-
traceDir:
|
|
20933
|
+
traceDir: path33__default.default.resolve(traceDir)
|
|
20168
20934
|
});
|
|
20169
20935
|
}
|
|
20170
20936
|
if (pathname === "/api/suite" && mode === "suite") {
|
|
@@ -20193,7 +20959,7 @@ function createViewerServer(options = {}) {
|
|
|
20193
20959
|
runId: meta2.runId,
|
|
20194
20960
|
name: meta2.name,
|
|
20195
20961
|
status: meta2.status,
|
|
20196
|
-
file:
|
|
20962
|
+
file: path33__default.default.basename(meta2.filePath),
|
|
20197
20963
|
startedAt: meta2.startedAt,
|
|
20198
20964
|
durationMs: meta2.durationMs
|
|
20199
20965
|
}))
|
|
@@ -20310,7 +21076,7 @@ function startViewerServer(options = {}) {
|
|
|
20310
21076
|
resolve({
|
|
20311
21077
|
host,
|
|
20312
21078
|
port: resolvedPort,
|
|
20313
|
-
traceDir:
|
|
21079
|
+
traceDir: path33__default.default.resolve(traceDir),
|
|
20314
21080
|
url: `http://${host}:${resolvedPort}/${modeQuery}`,
|
|
20315
21081
|
mode
|
|
20316
21082
|
});
|
|
@@ -20721,10 +21487,10 @@ async function evalRun(input3, options = {}) {
|
|
|
20721
21487
|
diagnostics: []
|
|
20722
21488
|
};
|
|
20723
21489
|
}
|
|
20724
|
-
function evidenceForRun(run,
|
|
20725
|
-
return [{ runId: run.runId, ...
|
|
21490
|
+
function evidenceForRun(run, path44) {
|
|
21491
|
+
return [{ runId: run.runId, ...path44 !== void 0 ? { path: path44 } : {} }];
|
|
20726
21492
|
}
|
|
20727
|
-
function evidenceForEvent(event,
|
|
21493
|
+
function evidenceForEvent(event, path44) {
|
|
20728
21494
|
return [
|
|
20729
21495
|
{
|
|
20730
21496
|
runId: event.runId,
|
|
@@ -20732,7 +21498,7 @@ function evidenceForEvent(event, path43) {
|
|
|
20732
21498
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
20733
21499
|
kind: event.kind,
|
|
20734
21500
|
name: event.name,
|
|
20735
|
-
...
|
|
21501
|
+
...path44 !== void 0 ? { path: path44 } : {}
|
|
20736
21502
|
}
|
|
20737
21503
|
];
|
|
20738
21504
|
}
|
|
@@ -20890,9 +21656,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
20890
21656
|
function tokenize(text) {
|
|
20891
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));
|
|
20892
21658
|
}
|
|
20893
|
-
function firstEvidence(fields, run,
|
|
21659
|
+
function firstEvidence(fields, run, path44) {
|
|
20894
21660
|
const first = fields[0];
|
|
20895
|
-
return first === void 0 ? evidenceForRun(run,
|
|
21661
|
+
return first === void 0 ? evidenceForRun(run, path44) : evidenceForEvent(first.node.event, first.path);
|
|
20896
21662
|
}
|
|
20897
21663
|
function collectSourceIds(nodes, keys) {
|
|
20898
21664
|
const wanted = keySet(keys);
|
|
@@ -21245,273 +22011,55 @@ var checks = {
|
|
|
21245
22011
|
"Answer contained banned unsupported-answer phrasing.",
|
|
21246
22012
|
firstEvidence(answers, context.run, "attributes.answer"),
|
|
21247
22013
|
{ bannedPhraseCount: banned.length },
|
|
21248
|
-
{ matchedPhraseCount: matches.length }
|
|
21249
|
-
)
|
|
21250
|
-
] : [];
|
|
21251
|
-
});
|
|
21252
|
-
}
|
|
21253
|
-
};
|
|
21254
|
-
function renderEvalMarkdown(result) {
|
|
21255
|
-
const lines = [
|
|
21256
|
-
`# AgentInspect Eval`,
|
|
21257
|
-
"",
|
|
21258
|
-
`Status: ${result.status}`,
|
|
21259
|
-
`Format: ${result.format}`,
|
|
21260
|
-
...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
|
|
21261
|
-
`Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
|
|
21262
|
-
];
|
|
21263
|
-
if (result.diagnostics.length > 0) {
|
|
21264
|
-
lines.push("", "## Diagnostics");
|
|
21265
|
-
for (const diagnostic7 of result.diagnostics) {
|
|
21266
|
-
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21267
|
-
}
|
|
21268
|
-
}
|
|
21269
|
-
if (result.findings.length > 0) {
|
|
21270
|
-
lines.push("", "## Findings");
|
|
21271
|
-
for (const finding of result.findings) {
|
|
21272
|
-
const path43 = finding.evidence[0]?.path;
|
|
21273
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
21274
|
-
}
|
|
21275
|
-
}
|
|
21276
|
-
return `${lines.join("\n")}
|
|
21277
|
-
`;
|
|
21278
|
-
}
|
|
21279
|
-
|
|
21280
|
-
// packages/cli/src/eval.ts
|
|
21281
|
-
var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
21282
|
-
var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
|
|
21283
|
-
function diagnostic6(code, message, severity = "error") {
|
|
21284
|
-
return { code, message, severity };
|
|
21285
|
-
}
|
|
21286
|
-
function errorResult4(code, message, format = "unknown") {
|
|
21287
|
-
return {
|
|
21288
|
-
ok: false,
|
|
21289
|
-
status: "error",
|
|
21290
|
-
format,
|
|
21291
|
-
summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
|
|
21292
|
-
findings: [],
|
|
21293
|
-
diagnostics: [diagnostic6(code, message)]
|
|
21294
|
-
};
|
|
21295
|
-
}
|
|
21296
|
-
function parseNumber2(value, label) {
|
|
21297
|
-
if (value === void 0) return void 0;
|
|
21298
|
-
const parsed = Number(value);
|
|
21299
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
21300
|
-
throw new Error(`${label} must be a non-negative number.`);
|
|
21301
|
-
}
|
|
21302
|
-
return parsed;
|
|
21303
|
-
}
|
|
21304
|
-
function asStringArray3(value, label) {
|
|
21305
|
-
if (value === void 0) return void 0;
|
|
21306
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
21307
|
-
throw new Error(`${label} must be an array of strings.`);
|
|
21308
|
-
}
|
|
21309
|
-
return value;
|
|
21310
|
-
}
|
|
21311
|
-
function asConfig(value) {
|
|
21312
|
-
if (value === void 0 || value === null) return {};
|
|
21313
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
21314
|
-
throw new Error("Config must export an object.");
|
|
21315
|
-
}
|
|
21316
|
-
return value;
|
|
21317
|
-
}
|
|
21318
|
-
async function loadConfig2(configPath) {
|
|
21319
|
-
if (configPath === void 0) return {};
|
|
21320
|
-
const extension = path32__default.default.extname(configPath);
|
|
21321
|
-
if (TS_CONFIG_EXTENSIONS3.has(extension)) {
|
|
21322
|
-
throw new Error(
|
|
21323
|
-
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
21324
|
-
);
|
|
21325
|
-
}
|
|
21326
|
-
if (!CONFIG_EXTENSIONS3.has(extension)) {
|
|
21327
|
-
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
21328
|
-
}
|
|
21329
|
-
const absolute = path32__default.default.resolve(configPath);
|
|
21330
|
-
if (extension === ".json") {
|
|
21331
|
-
const raw = await promises.readFile(absolute, "utf-8");
|
|
21332
|
-
return asConfig(JSON.parse(raw));
|
|
21333
|
-
}
|
|
21334
|
-
const mod = await import(url.pathToFileURL(absolute).href);
|
|
21335
|
-
return asConfig("default" in mod ? mod.default : mod);
|
|
21336
|
-
}
|
|
21337
|
-
function normalizeConfig2(config) {
|
|
21338
|
-
if (config.eval === void 0) return {};
|
|
21339
|
-
if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
|
|
21340
|
-
throw new Error("eval config must be an object.");
|
|
21341
|
-
}
|
|
21342
|
-
return config.eval;
|
|
21343
|
-
}
|
|
21344
|
-
function maybeAdd(rules, value, makeRule) {
|
|
21345
|
-
if (value !== void 0) rules.push(makeRule(value));
|
|
21346
|
-
}
|
|
21347
|
-
function optionObject(value) {
|
|
21348
|
-
if (value === void 0 || value === false) return void 0;
|
|
21349
|
-
if (value === true) return {};
|
|
21350
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
21351
|
-
throw new Error("Eval heuristic config must be a boolean or object.");
|
|
21352
|
-
}
|
|
21353
|
-
return value;
|
|
21354
|
-
}
|
|
21355
|
-
function sourceIdsFromConfig(value) {
|
|
21356
|
-
if (value === void 0) return void 0;
|
|
21357
|
-
if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
|
|
21358
|
-
if (typeof value !== "object" || Array.isArray(value)) {
|
|
21359
|
-
throw new Error("eval.requiredSourceIds must be an array or object.");
|
|
21360
|
-
}
|
|
21361
|
-
const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
|
|
21362
|
-
return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
|
|
21363
|
-
}
|
|
21364
|
-
function buildRules2(config, options) {
|
|
21365
|
-
const evalConfig = normalizeConfig2(config);
|
|
21366
|
-
const rules = [];
|
|
21367
|
-
if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
|
|
21368
|
-
const requiredTools = [
|
|
21369
|
-
...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
|
|
21370
|
-
...options.requiredTool ?? []
|
|
21371
|
-
];
|
|
21372
|
-
if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
|
|
21373
|
-
const forbiddenTools = [
|
|
21374
|
-
...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
|
|
21375
|
-
...options.forbidTool ?? [],
|
|
21376
|
-
...options.forbiddenTool ?? []
|
|
21377
|
-
];
|
|
21378
|
-
if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
|
|
21379
|
-
const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
|
|
21380
|
-
maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
|
|
21381
|
-
const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
|
|
21382
|
-
maybeAdd(rules, maxDepth, checks.maxDepth);
|
|
21383
|
-
const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
|
|
21384
|
-
maybeAdd(rules, maxRetries, checks.maxRetries);
|
|
21385
|
-
const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
|
|
21386
|
-
maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
|
|
21387
|
-
if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
|
|
21388
|
-
rules.push(checks.requiredRetrievalBeforeGeneration());
|
|
21389
|
-
}
|
|
21390
|
-
const requiredDecisionMetadata = [
|
|
21391
|
-
...asStringArray3(
|
|
21392
|
-
evalConfig.requiredDecisionMetadata,
|
|
21393
|
-
"eval.requiredDecisionMetadata"
|
|
21394
|
-
) ?? [],
|
|
21395
|
-
...options.requiredDecisionMetadata ?? []
|
|
21396
|
-
];
|
|
21397
|
-
if (requiredDecisionMetadata.length > 0) {
|
|
21398
|
-
rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
|
|
21399
|
-
}
|
|
21400
|
-
const contextOverlap = optionObject(evalConfig.contextOverlap);
|
|
21401
|
-
const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
|
|
21402
|
-
const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
|
|
21403
|
-
if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
|
|
21404
|
-
rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
|
|
21405
|
-
}
|
|
21406
|
-
const quoteOverlap = optionObject(evalConfig.quoteOverlap);
|
|
21407
|
-
if (quoteOverlap !== void 0 || options.quoteOverlap) {
|
|
21408
|
-
rules.push(checks.quoteOverlap(quoteOverlap));
|
|
21409
|
-
}
|
|
21410
|
-
const citationPresence = optionObject(evalConfig.citationPresence);
|
|
21411
|
-
if (citationPresence !== void 0 || options.citationPresence) {
|
|
21412
|
-
rules.push(checks.citationPresence(citationPresence));
|
|
21413
|
-
}
|
|
21414
|
-
const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
|
|
21415
|
-
const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
|
|
21416
|
-
if (requiredSourceIds.length > 0) {
|
|
21417
|
-
rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
|
|
21418
|
-
}
|
|
21419
|
-
const cliAnswerLength = {
|
|
21420
|
-
minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
|
|
21421
|
-
maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
|
|
21422
|
-
minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
|
|
21423
|
-
maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
|
|
21424
|
-
};
|
|
21425
|
-
const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
|
|
21426
|
-
if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
|
|
21427
|
-
rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
|
|
21428
|
-
}
|
|
21429
|
-
const bannedPhrases = [
|
|
21430
|
-
...asStringArray3(
|
|
21431
|
-
evalConfig.bannedUnsupportedPhrases,
|
|
21432
|
-
"eval.bannedUnsupportedPhrases"
|
|
21433
|
-
) ?? [],
|
|
21434
|
-
...options.bannedPhrase ?? []
|
|
21435
|
-
];
|
|
21436
|
-
if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
|
|
21437
|
-
return rules.length > 0 ? rules : void 0;
|
|
21438
|
-
}
|
|
21439
|
-
function exitCodeFor2(result) {
|
|
21440
|
-
if (result.status === "pass") return 0;
|
|
21441
|
-
if (result.status === "fail") return 1;
|
|
21442
|
-
return 2;
|
|
21443
|
-
}
|
|
21444
|
-
function stable4(value) {
|
|
21445
|
-
if (Array.isArray(value)) return value.map(stable4);
|
|
21446
|
-
if (value === null || typeof value !== "object") return value;
|
|
21447
|
-
const record = value;
|
|
21448
|
-
return Object.fromEntries(
|
|
21449
|
-
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
|
|
21450
|
-
);
|
|
21451
|
-
}
|
|
21452
|
-
function printJson2(result) {
|
|
21453
|
-
console.log(JSON.stringify(stable4(result), null, 2));
|
|
21454
|
-
}
|
|
21455
|
-
function printHuman2(result) {
|
|
21456
|
-
console.log(`Eval status: ${result.status}`);
|
|
21457
|
-
console.log(`Format: ${result.format}`);
|
|
21458
|
-
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
21459
|
-
console.log(
|
|
21460
|
-
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
21461
|
-
);
|
|
21462
|
-
for (const diagnostic7 of result.diagnostics) {
|
|
21463
|
-
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21464
|
-
}
|
|
21465
|
-
for (const finding of result.findings) {
|
|
21466
|
-
const path43 = finding.evidence[0]?.path;
|
|
21467
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
|
|
21468
|
-
}
|
|
21469
|
-
}
|
|
21470
|
-
function readErrorResult2(error) {
|
|
21471
|
-
if (error instanceof TraceReadError) {
|
|
21472
|
-
const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
|
|
21473
|
-
return errorResult4(code, error.message);
|
|
21474
|
-
}
|
|
21475
|
-
return errorResult4(
|
|
21476
|
-
"AI_EVAL_TRACE_UNREADABLE",
|
|
21477
|
-
error instanceof Error ? error.message : String(error)
|
|
21478
|
-
);
|
|
21479
|
-
}
|
|
21480
|
-
async function evalCommand(target, options = {}, stdin = process.stdin) {
|
|
21481
|
-
let result;
|
|
21482
|
-
let phase = "config";
|
|
21483
|
-
try {
|
|
21484
|
-
const config = await loadConfig2(options.config);
|
|
21485
|
-
const rules = buildRules2(config, options);
|
|
21486
|
-
phase = "read";
|
|
21487
|
-
const input3 = await inputFromTarget(target, options, stdin);
|
|
21488
|
-
const read = await openTrace(input3, {
|
|
21489
|
-
...options.format !== void 0 ? { format: options.format } : {}
|
|
21490
|
-
});
|
|
21491
|
-
result = await evalRun(read, {
|
|
21492
|
-
...rules !== void 0 ? { checks: rules } : {},
|
|
21493
|
-
...options.run !== void 0 ? { runId: options.run } : {}
|
|
22014
|
+
{ matchedPhraseCount: matches.length }
|
|
22015
|
+
)
|
|
22016
|
+
] : [];
|
|
21494
22017
|
});
|
|
21495
|
-
}
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
21501
|
-
|
|
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}`);
|
|
21502
22033
|
}
|
|
21503
22034
|
}
|
|
21504
|
-
|
|
21505
|
-
|
|
21506
|
-
|
|
21507
|
-
|
|
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
|
+
`;
|
|
21508
22044
|
}
|
|
21509
|
-
|
|
21510
|
-
|
|
21511
|
-
var
|
|
21512
|
-
var
|
|
21513
|
-
|
|
21514
|
-
|
|
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) {
|
|
21515
22063
|
if (value === void 0) return void 0;
|
|
21516
22064
|
const parsed = Number(value);
|
|
21517
22065
|
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
@@ -21519,368 +22067,210 @@ function parseLimit3(value, label) {
|
|
|
21519
22067
|
}
|
|
21520
22068
|
return parsed;
|
|
21521
22069
|
}
|
|
21522
|
-
function
|
|
21523
|
-
if (
|
|
21524
|
-
if (value
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
);
|
|
21529
|
-
}
|
|
21530
|
-
function safetyDiagnostic(code, message, severity = "error") {
|
|
21531
|
-
return { code, message, severity };
|
|
21532
|
-
}
|
|
21533
|
-
function warningDiagnostics(warnings, unsupportedFields) {
|
|
21534
|
-
return [
|
|
21535
|
-
...warnings.map(
|
|
21536
|
-
(warning) => safetyDiagnostic(
|
|
21537
|
-
warning.code,
|
|
21538
|
-
warning.message,
|
|
21539
|
-
warning.severity === "error" ? "error" : "warning"
|
|
21540
|
-
)
|
|
21541
|
-
),
|
|
21542
|
-
...unsupportedFields.map(
|
|
21543
|
-
(field) => safetyDiagnostic(
|
|
21544
|
-
"unsupported_field",
|
|
21545
|
-
`Reader reported unsupported field: ${field}`,
|
|
21546
|
-
"warning"
|
|
21547
|
-
)
|
|
21548
|
-
)
|
|
21549
|
-
];
|
|
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;
|
|
21550
22076
|
}
|
|
21551
|
-
function
|
|
21552
|
-
|
|
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;
|
|
21553
22083
|
}
|
|
21554
|
-
function
|
|
21555
|
-
if (
|
|
21556
|
-
|
|
21557
|
-
if (
|
|
21558
|
-
|
|
21559
|
-
|
|
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);
|
|
21560
22102
|
}
|
|
21561
|
-
function
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21566
|
-
|
|
21567
|
-
return {
|
|
21568
|
-
ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
|
|
21569
|
-
command: parts.command,
|
|
21570
|
-
status,
|
|
21571
|
-
format: parts.format,
|
|
21572
|
-
...parts.runId !== void 0 ? { runId: parts.runId } : {},
|
|
21573
|
-
summary: {
|
|
21574
|
-
findings: findings.length,
|
|
21575
|
-
warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
|
|
21576
|
-
errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
|
|
21577
|
-
},
|
|
21578
|
-
findings,
|
|
21579
|
-
diagnostics,
|
|
21580
|
-
warnings,
|
|
21581
|
-
unsupportedFields,
|
|
21582
|
-
note: BEST_EFFORT_NOTE,
|
|
21583
|
-
...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
|
|
21584
|
-
...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
|
|
21585
|
-
...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
|
|
21586
|
-
};
|
|
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;
|
|
21587
22109
|
}
|
|
21588
|
-
function
|
|
21589
|
-
|
|
21590
|
-
status: result.status,
|
|
21591
|
-
summary: result.summary,
|
|
21592
|
-
findings: result.findings
|
|
21593
|
-
};
|
|
22110
|
+
function maybeAdd(rules, value, makeRule) {
|
|
22111
|
+
if (value !== void 0) rules.push(makeRule(value));
|
|
21594
22112
|
}
|
|
21595
|
-
function
|
|
21596
|
-
if (
|
|
21597
|
-
|
|
21598
|
-
|
|
21599
|
-
|
|
21600
|
-
format: "unknown",
|
|
21601
|
-
diagnostics: [safetyDiagnostic(code, error.message)],
|
|
21602
|
-
warnings: error.warnings
|
|
21603
|
-
});
|
|
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.");
|
|
21604
22118
|
}
|
|
21605
|
-
return
|
|
21606
|
-
command,
|
|
21607
|
-
format: "unknown",
|
|
21608
|
-
diagnostics: [
|
|
21609
|
-
safetyDiagnostic(
|
|
21610
|
-
"AI_SAFETY_TRACE_UNREADABLE",
|
|
21611
|
-
error instanceof Error ? error.message : String(error)
|
|
21612
|
-
)
|
|
21613
|
-
]
|
|
21614
|
-
});
|
|
22119
|
+
return value;
|
|
21615
22120
|
}
|
|
21616
|
-
function
|
|
21617
|
-
return
|
|
21618
|
-
|
|
21619
|
-
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
|
|
21623
|
-
|
|
21624
|
-
)
|
|
21625
|
-
]
|
|
21626
|
-
});
|
|
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 } };
|
|
21627
22129
|
}
|
|
21628
|
-
function
|
|
21629
|
-
const
|
|
21630
|
-
const
|
|
21631
|
-
|
|
21632
|
-
const
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
createSafetyRedactionRule(),
|
|
21636
|
-
createSafetySecretPatternRule(),
|
|
21637
|
-
createSafetyOversizedAttributeRule({
|
|
21638
|
-
maxStringLength: maxStringLength2,
|
|
21639
|
-
maxArrayLength,
|
|
21640
|
-
maxObjectKeys,
|
|
21641
|
-
maxSerializedBytes
|
|
21642
|
-
})
|
|
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 ?? []
|
|
21643
22137
|
];
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
...
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
|
|
21657
|
-
|
|
21658
|
-
|
|
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());
|
|
21659
22155
|
}
|
|
21660
|
-
|
|
21661
|
-
|
|
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));
|
|
21662
22165
|
}
|
|
21663
|
-
|
|
21664
|
-
|
|
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 }));
|
|
21665
22171
|
}
|
|
21666
|
-
|
|
21667
|
-
|
|
22172
|
+
const quoteOverlap = optionObject(evalConfig.quoteOverlap);
|
|
22173
|
+
if (quoteOverlap !== void 0 || options.quoteOverlap) {
|
|
22174
|
+
rules.push(checks.quoteOverlap(quoteOverlap));
|
|
21668
22175
|
}
|
|
21669
|
-
|
|
21670
|
-
|
|
21671
|
-
|
|
21672
|
-
const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
|
|
21673
|
-
const out = [];
|
|
21674
|
-
for (const run of runs) {
|
|
21675
|
-
for (const node of flattenNodes2(run.children)) {
|
|
21676
|
-
const attrs = node.event.attributes;
|
|
21677
|
-
if (attrs === void 0) continue;
|
|
21678
|
-
const result = redact(attrs, { profile: "share" });
|
|
21679
|
-
for (const finding of result.findings) {
|
|
21680
|
-
if (finding.action === "keep") continue;
|
|
21681
|
-
const taxonomy = classifyRedactionDetector(finding.detector);
|
|
21682
|
-
out.push({
|
|
21683
|
-
ruleId: "safety.redactDetector",
|
|
21684
|
-
severity: detectorSeverity(finding),
|
|
21685
|
-
status: finding.severity === "error" ? "fail" : "warning",
|
|
21686
|
-
message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
|
|
21687
|
-
expected: "redacted trace content",
|
|
21688
|
-
actual: finding.detector,
|
|
21689
|
-
evidence: [
|
|
21690
|
-
{
|
|
21691
|
-
runId: node.event.runId,
|
|
21692
|
-
eventId: node.event.eventId,
|
|
21693
|
-
...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
|
|
21694
|
-
kind: node.event.kind,
|
|
21695
|
-
name: node.event.name,
|
|
21696
|
-
...node.event.status !== void 0 ? { status: node.event.status } : {},
|
|
21697
|
-
path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
|
|
21698
|
-
}
|
|
21699
|
-
],
|
|
21700
|
-
category: taxonomy.category,
|
|
21701
|
-
confidence: taxonomy.confidence,
|
|
21702
|
-
detector: finding.detector,
|
|
21703
|
-
action: finding.action
|
|
21704
|
-
});
|
|
21705
|
-
}
|
|
21706
|
-
}
|
|
22176
|
+
const citationPresence = optionObject(evalConfig.citationPresence);
|
|
22177
|
+
if (citationPresence !== void 0 || options.citationPresence) {
|
|
22178
|
+
rules.push(checks.citationPresence(citationPresence));
|
|
21707
22179
|
}
|
|
21708
|
-
|
|
21709
|
-
|
|
21710
|
-
|
|
21711
|
-
|
|
21712
|
-
}
|
|
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;
|
|
21713
22204
|
}
|
|
21714
22205
|
function exitCodeFor3(result) {
|
|
21715
|
-
if (result.status === "
|
|
21716
|
-
if (result.status === "
|
|
22206
|
+
if (result.status === "pass") return 0;
|
|
22207
|
+
if (result.status === "fail") return 1;
|
|
21717
22208
|
return 2;
|
|
21718
22209
|
}
|
|
21719
|
-
function
|
|
21720
|
-
|
|
21721
|
-
|
|
21722
|
-
const
|
|
21723
|
-
|
|
21724
|
-
|
|
21725
|
-
|
|
21726
|
-
return [
|
|
21727
|
-
` Matched: detector=${detector}; path=${path43}; category=${category}`,
|
|
21728
|
-
` Why: ${finding.message}`,
|
|
21729
|
-
` Confidence: ${confidence}`,
|
|
21730
|
-
` Redaction: ${redactionHint}`,
|
|
21731
|
-
` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
|
|
21732
|
-
` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
|
|
21733
|
-
];
|
|
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
|
+
);
|
|
21734
22217
|
}
|
|
21735
|
-
function
|
|
21736
|
-
|
|
21737
|
-
return {
|
|
21738
|
-
ruleId: finding.ruleId,
|
|
21739
|
-
detector: finding.detector ?? finding.ruleId,
|
|
21740
|
-
path: finding.evidence[0]?.path,
|
|
21741
|
-
category: finding.category,
|
|
21742
|
-
confidence: finding.confidence,
|
|
21743
|
-
action: finding.action,
|
|
21744
|
-
blocksBundle: blocks,
|
|
21745
|
-
// Never include matched secret/PII values.
|
|
21746
|
-
message: finding.message
|
|
21747
|
-
};
|
|
22218
|
+
function printJson3(result) {
|
|
22219
|
+
console.log(JSON.stringify(stable5(result), null, 2));
|
|
21748
22220
|
}
|
|
21749
|
-
function printHuman3(result
|
|
21750
|
-
console.log(`
|
|
22221
|
+
function printHuman3(result) {
|
|
22222
|
+
console.log(`Eval status: ${result.status}`);
|
|
21751
22223
|
console.log(`Format: ${result.format}`);
|
|
21752
22224
|
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
21753
|
-
if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
|
|
21754
|
-
console.log(`Source assessment: ${result.sourceAssessment.status}`);
|
|
21755
|
-
console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
|
|
21756
|
-
if (result.redactionSummary !== void 0) {
|
|
21757
|
-
console.log(
|
|
21758
|
-
`Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
|
|
21759
|
-
);
|
|
21760
|
-
}
|
|
21761
|
-
}
|
|
21762
22225
|
console.log(
|
|
21763
|
-
`Summary: ${result.summary.
|
|
22226
|
+
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
21764
22227
|
);
|
|
21765
22228
|
for (const diagnostic7 of result.diagnostics) {
|
|
21766
22229
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
21767
22230
|
}
|
|
21768
22231
|
for (const finding of result.findings) {
|
|
21769
|
-
const
|
|
21770
|
-
|
|
21771
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}${taxonomy}`);
|
|
21772
|
-
if (explain) {
|
|
21773
|
-
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
21774
|
-
for (const line of explainFinding(finding, blocks)) {
|
|
21775
|
-
console.log(line);
|
|
21776
|
-
}
|
|
21777
|
-
}
|
|
22232
|
+
const path44 = finding.evidence[0]?.path;
|
|
22233
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
|
|
21778
22234
|
}
|
|
21779
|
-
console.log(`Note: ${result.note}`);
|
|
21780
22235
|
}
|
|
21781
|
-
function
|
|
21782
|
-
|
|
21783
|
-
|
|
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
|
+
);
|
|
21784
22245
|
}
|
|
21785
|
-
async function
|
|
22246
|
+
async function evalCommand(target, options = {}, stdin = process.stdin) {
|
|
21786
22247
|
let result;
|
|
22248
|
+
let phase = "config";
|
|
21787
22249
|
try {
|
|
22250
|
+
const config = await loadConfig2(options.config);
|
|
22251
|
+
const rules = buildRules2(config, options);
|
|
22252
|
+
phase = "read";
|
|
21788
22253
|
const input3 = await inputFromTarget(target, options, stdin);
|
|
21789
22254
|
const read = await openTrace(input3, {
|
|
21790
22255
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
21791
22256
|
});
|
|
21792
|
-
|
|
21793
|
-
...
|
|
22257
|
+
result = await evalRun(read, {
|
|
22258
|
+
...rules !== void 0 ? { checks: rules } : {},
|
|
21794
22259
|
...options.run !== void 0 ? { runId: options.run } : {}
|
|
21795
22260
|
});
|
|
21796
|
-
|
|
21797
|
-
|
|
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);
|
|
21798
22266
|
} else {
|
|
21799
|
-
|
|
21800
|
-
const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
|
|
21801
|
-
if (rawContent === void 0) {
|
|
21802
|
-
result = {
|
|
21803
|
-
...source,
|
|
21804
|
-
command: "verify-safe",
|
|
21805
|
-
sourceAssessment: layerFromResult(source)
|
|
21806
|
-
};
|
|
21807
|
-
} else {
|
|
21808
|
-
const redacted = redactTraceContent(rawContent, profile);
|
|
21809
|
-
const artifactRead = await openTrace(
|
|
21810
|
-
{ type: "string", content: redacted.content },
|
|
21811
|
-
{ format: options.format ?? "agent-inspect-jsonl" }
|
|
21812
|
-
);
|
|
21813
|
-
const artifact = assessOpenedTrace(artifactRead, {
|
|
21814
|
-
...options,
|
|
21815
|
-
...options.run !== void 0 ? { runId: options.run } : {}
|
|
21816
|
-
});
|
|
21817
|
-
const detectors = [
|
|
21818
|
-
...new Set(redacted.findings.map((finding) => finding.detector))
|
|
21819
|
-
].sort((a, b) => a.localeCompare(b));
|
|
21820
|
-
result = resultFromParts({
|
|
21821
|
-
command: "verify-safe",
|
|
21822
|
-
format: artifact.format,
|
|
21823
|
-
runId: artifact.runId ?? source.runId,
|
|
21824
|
-
findings: artifact.findings,
|
|
21825
|
-
diagnostics: artifact.diagnostics,
|
|
21826
|
-
warnings: artifact.warnings,
|
|
21827
|
-
unsupportedFields: artifact.unsupportedFields,
|
|
21828
|
-
status: artifact.status,
|
|
21829
|
-
sourceAssessment: layerFromResult(source),
|
|
21830
|
-
artifactAssessment: layerFromResult(artifact),
|
|
21831
|
-
redactionSummary: {
|
|
21832
|
-
profile,
|
|
21833
|
-
findings: redacted.findings.length,
|
|
21834
|
-
detectors
|
|
21835
|
-
}
|
|
21836
|
-
});
|
|
21837
|
-
}
|
|
22267
|
+
result = readErrorResult3(error);
|
|
21838
22268
|
}
|
|
21839
|
-
} catch (error) {
|
|
21840
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
21841
|
-
result = message.startsWith("--") ? invalidArgumentResult(command, error) : readErrorResult3(command, error);
|
|
21842
22269
|
}
|
|
21843
22270
|
process.exitCode = exitCodeFor3(result);
|
|
21844
|
-
if (options.json) printJson3(result
|
|
21845
|
-
else
|
|
21846
|
-
|
|
21847
|
-
function scanCommand(target, options = {}, stdin = process.stdin) {
|
|
21848
|
-
return safetyCommand("scan", target, options, stdin);
|
|
21849
|
-
}
|
|
21850
|
-
function verifySafeCommand(target, options = {}, stdin = process.stdin) {
|
|
21851
|
-
return safetyCommand("verify-safe", target, options, stdin);
|
|
21852
|
-
}
|
|
21853
|
-
function assessOpenedTrace(read, options = {}) {
|
|
21854
|
-
try {
|
|
21855
|
-
const rules = buildSafetyRules(options);
|
|
21856
|
-
const checkResult = runTraceChecks(
|
|
21857
|
-
{ read },
|
|
21858
|
-
{
|
|
21859
|
-
rules,
|
|
21860
|
-
...options.runId !== void 0 ? { runId: options.runId } : {},
|
|
21861
|
-
...options.run !== void 0 ? { runId: options.run } : {}
|
|
21862
|
-
}
|
|
21863
|
-
);
|
|
21864
|
-
const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId) : [];
|
|
21865
|
-
return resultFromParts({
|
|
21866
|
-
command: "verify-safe",
|
|
21867
|
-
format: checkResult.format,
|
|
21868
|
-
runId: checkResult.runId,
|
|
21869
|
-
findings: [...checkResult.findings, ...detectorFindings],
|
|
21870
|
-
diagnostics: [
|
|
21871
|
-
...checkResult.diagnostics.map(diagnosticFromCheck),
|
|
21872
|
-
...warningDiagnostics(read.warnings, read.unsupportedFields)
|
|
21873
|
-
],
|
|
21874
|
-
warnings: read.warnings,
|
|
21875
|
-
unsupportedFields: read.unsupportedFields
|
|
21876
|
-
});
|
|
21877
|
-
} catch (error) {
|
|
21878
|
-
return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult3("verify-safe", error);
|
|
21879
|
-
}
|
|
21880
|
-
}
|
|
21881
|
-
function messageStartsWithDash(error) {
|
|
21882
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
21883
|
-
return message.startsWith("--");
|
|
22271
|
+
if (options.json) printJson3(result);
|
|
22272
|
+
else if (options.markdown) console.log(renderEvalMarkdown(result).trimEnd());
|
|
22273
|
+
else printHuman3(result);
|
|
21884
22274
|
}
|
|
21885
22275
|
init_advanced();
|
|
21886
22276
|
var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
|
|
@@ -21956,8 +22346,8 @@ function renderCheckSection(result) {
|
|
|
21956
22346
|
`Diagnostics: ${result.diagnostics.length}`
|
|
21957
22347
|
];
|
|
21958
22348
|
for (const finding of result.findings.slice(0, 10)) {
|
|
21959
|
-
const
|
|
21960
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
22349
|
+
const path44 = finding.evidence[0]?.path ?? "(run)";
|
|
22350
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path44})`);
|
|
21961
22351
|
}
|
|
21962
22352
|
for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
|
|
21963
22353
|
lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
@@ -22035,8 +22425,8 @@ function renderHtml(trace, check, diff) {
|
|
|
22035
22425
|
`;
|
|
22036
22426
|
}
|
|
22037
22427
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
22038
|
-
const outPath =
|
|
22039
|
-
await promises.mkdir(
|
|
22428
|
+
const outPath = path33__default.default.join(outputDir, relativePath);
|
|
22429
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
22040
22430
|
await promises.writeFile(outPath, content, "utf-8");
|
|
22041
22431
|
files.push(relativePath);
|
|
22042
22432
|
}
|
|
@@ -22065,7 +22455,7 @@ function shouldWriteEvidence(options, status) {
|
|
|
22065
22455
|
return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
|
|
22066
22456
|
}
|
|
22067
22457
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
22068
|
-
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()) : "";
|
|
22069
22459
|
if (outputDir === "") {
|
|
22070
22460
|
console.error("--output-dir is required.");
|
|
22071
22461
|
process.exitCode = 1;
|
|
@@ -22205,8 +22595,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
22205
22595
|
}
|
|
22206
22596
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
22207
22597
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
22208
|
-
await promises.mkdir(
|
|
22209
|
-
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), `
|
|
22210
22600
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
22211
22601
|
}
|
|
22212
22602
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -22225,10 +22615,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
22225
22615
|
findings: diff?.findings.length ?? 0,
|
|
22226
22616
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
22227
22617
|
},
|
|
22228
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
22618
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path33__default.default.resolve(summaryTarget) } : {},
|
|
22229
22619
|
note: NOTE
|
|
22230
22620
|
};
|
|
22231
|
-
await promises.writeFile(
|
|
22621
|
+
await promises.writeFile(path33__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
22232
22622
|
if (options.json === true) {
|
|
22233
22623
|
console.log(writeJson3(manifest).trimEnd());
|
|
22234
22624
|
} else {
|
|
@@ -22289,8 +22679,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
22289
22679
|
const location = resolveWorkspaceLocation(cwd);
|
|
22290
22680
|
const manifest = await readWorkspaceManifestFile(location);
|
|
22291
22681
|
if (manifest.ok && manifest.manifest) {
|
|
22292
|
-
const rel =
|
|
22293
|
-
if (!rel.startsWith("..") && !
|
|
22682
|
+
const rel = path33__default.default.relative(location.workspaceDir, normalized);
|
|
22683
|
+
if (!rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
|
|
22294
22684
|
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
22295
22685
|
}
|
|
22296
22686
|
}
|
|
@@ -22306,7 +22696,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
22306
22696
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
22307
22697
|
const base2 = resolveInsideWorkspace(
|
|
22308
22698
|
location.workspaceDir,
|
|
22309
|
-
|
|
22699
|
+
path33__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
22310
22700
|
);
|
|
22311
22701
|
return format === "zip" ? `${base2}.zip` : base2;
|
|
22312
22702
|
}
|
|
@@ -22711,19 +23101,19 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
22711
23101
|
let sidecarDir = outputDir;
|
|
22712
23102
|
if (outputDir.toLowerCase().endsWith(".html")) {
|
|
22713
23103
|
htmlPath = outputDir;
|
|
22714
|
-
sidecarDir =
|
|
23104
|
+
sidecarDir = path33__default.default.dirname(outputDir);
|
|
22715
23105
|
} else {
|
|
22716
23106
|
await promises.mkdir(outputDir, { recursive: true });
|
|
22717
|
-
htmlPath =
|
|
23107
|
+
htmlPath = path33__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
|
|
22718
23108
|
sidecarDir = outputDir;
|
|
22719
23109
|
}
|
|
22720
23110
|
await promises.mkdir(sidecarDir, { recursive: true });
|
|
22721
23111
|
await promises.writeFile(htmlPath, htmlContent, "utf-8");
|
|
22722
|
-
await promises.writeFile(
|
|
23112
|
+
await promises.writeFile(path33__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
22723
23113
|
outputPath = htmlPath;
|
|
22724
23114
|
} else if (format === "zip") {
|
|
22725
23115
|
const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
|
|
22726
|
-
const zipParent =
|
|
23116
|
+
const zipParent = path33__default.default.dirname(zipPath);
|
|
22727
23117
|
await promises.mkdir(zipParent, { recursive: true });
|
|
22728
23118
|
const entries = [
|
|
22729
23119
|
...[...packaged.entries()].map(([relativePath, content]) => ({
|
|
@@ -22739,10 +23129,10 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
22739
23129
|
await promises.mkdir(outputDir, { recursive: true });
|
|
22740
23130
|
for (const [relativePath, content] of packaged.entries()) {
|
|
22741
23131
|
const outPath = assertBundlePathContained(outputDir, relativePath);
|
|
22742
|
-
await promises.mkdir(
|
|
23132
|
+
await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
|
|
22743
23133
|
await promises.writeFile(outPath, content, "utf-8");
|
|
22744
23134
|
}
|
|
22745
|
-
await promises.writeFile(
|
|
23135
|
+
await promises.writeFile(path33__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
22746
23136
|
if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
|
|
22747
23137
|
files.push(EVIDENCE_MANIFEST_FILENAME);
|
|
22748
23138
|
}
|
|
@@ -22791,7 +23181,7 @@ function writeJson5(value) {
|
|
|
22791
23181
|
`;
|
|
22792
23182
|
}
|
|
22793
23183
|
async function bundleVerifyCommand(targetPath, options = {}) {
|
|
22794
|
-
const root =
|
|
23184
|
+
const root = path33__default.default.resolve(targetPath.trim() || ".");
|
|
22795
23185
|
const result = await verifyEvidenceDirectory(root, {
|
|
22796
23186
|
unexpectedFiles: options.unexpected ?? "fail"
|
|
22797
23187
|
});
|
|
@@ -22833,7 +23223,7 @@ function writeJson6(value) {
|
|
|
22833
23223
|
}
|
|
22834
23224
|
async function resolveHtmlPath(root) {
|
|
22835
23225
|
const candidates = [
|
|
22836
|
-
|
|
23226
|
+
path33__default.default.join(root, "evidence.html"),
|
|
22837
23227
|
root.toLowerCase().endsWith(".html") ? root : ""
|
|
22838
23228
|
].filter(Boolean);
|
|
22839
23229
|
for (const candidate of candidates) {
|
|
@@ -22848,7 +23238,7 @@ async function resolveHtmlPath(root) {
|
|
|
22848
23238
|
);
|
|
22849
23239
|
}
|
|
22850
23240
|
async function bundleOpenCommand(targetPath, options = {}) {
|
|
22851
|
-
const root =
|
|
23241
|
+
const root = path33__default.default.resolve(targetPath.trim() || ".");
|
|
22852
23242
|
try {
|
|
22853
23243
|
await promises.access(root);
|
|
22854
23244
|
} catch {
|
|
@@ -22865,7 +23255,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22865
23255
|
try {
|
|
22866
23256
|
const info = await promises.stat(root);
|
|
22867
23257
|
if (info.isFile() && root.toLowerCase().endsWith(".html")) {
|
|
22868
|
-
verifyRoot =
|
|
23258
|
+
verifyRoot = path33__default.default.dirname(root);
|
|
22869
23259
|
}
|
|
22870
23260
|
} catch {
|
|
22871
23261
|
}
|
|
@@ -22897,7 +23287,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22897
23287
|
let htmlPath;
|
|
22898
23288
|
try {
|
|
22899
23289
|
htmlPath = await resolveHtmlPath(
|
|
22900
|
-
root.toLowerCase().endsWith(".html") ?
|
|
23290
|
+
root.toLowerCase().endsWith(".html") ? path33__default.default.dirname(root) : root
|
|
22901
23291
|
);
|
|
22902
23292
|
if (root.toLowerCase().endsWith(".html")) {
|
|
22903
23293
|
htmlPath = root;
|
|
@@ -22913,7 +23303,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22913
23303
|
return;
|
|
22914
23304
|
}
|
|
22915
23305
|
try {
|
|
22916
|
-
await promises.readFile(
|
|
23306
|
+
await promises.readFile(path33__default.default.join(path33__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
22917
23307
|
} catch {
|
|
22918
23308
|
}
|
|
22919
23309
|
const fileUrl = url.pathToFileURL(htmlPath).href;
|
|
@@ -22999,24 +23389,24 @@ function resolveTargetPath(client, projectLocal) {
|
|
|
22999
23389
|
if (projectLocal) {
|
|
23000
23390
|
switch (client) {
|
|
23001
23391
|
case "cursor":
|
|
23002
|
-
return
|
|
23392
|
+
return path33__default.default.join(".cursor", "mcp.json");
|
|
23003
23393
|
case "claude-code":
|
|
23004
|
-
return
|
|
23394
|
+
return path33__default.default.join(".mcp.json");
|
|
23005
23395
|
case "codex":
|
|
23006
|
-
return
|
|
23396
|
+
return path33__default.default.join(".codex", "config.toml.json");
|
|
23007
23397
|
case "gemini":
|
|
23008
|
-
return
|
|
23398
|
+
return path33__default.default.join(".gemini", "settings.json");
|
|
23009
23399
|
}
|
|
23010
23400
|
}
|
|
23011
23401
|
switch (client) {
|
|
23012
23402
|
case "cursor":
|
|
23013
|
-
return
|
|
23403
|
+
return path33__default.default.join("~", ".cursor", "mcp.json");
|
|
23014
23404
|
case "claude-code":
|
|
23015
|
-
return
|
|
23405
|
+
return path33__default.default.join("~", ".claude.json");
|
|
23016
23406
|
case "codex":
|
|
23017
|
-
return
|
|
23407
|
+
return path33__default.default.join("~", ".codex", "config.toml");
|
|
23018
23408
|
case "gemini":
|
|
23019
|
-
return
|
|
23409
|
+
return path33__default.default.join("~", ".gemini", "settings.json");
|
|
23020
23410
|
}
|
|
23021
23411
|
}
|
|
23022
23412
|
async function mcpConfigureCommand(options) {
|
|
@@ -23040,8 +23430,8 @@ async function mcpConfigureCommand(options) {
|
|
|
23040
23430
|
];
|
|
23041
23431
|
let wrote = false;
|
|
23042
23432
|
if (!dryRun && projectLocal) {
|
|
23043
|
-
const abs =
|
|
23044
|
-
await promises.mkdir(
|
|
23433
|
+
const abs = path33__default.default.resolve(targetPath);
|
|
23434
|
+
await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
|
|
23045
23435
|
await promises.writeFile(abs, `${JSON.stringify(config, null, 2)}
|
|
23046
23436
|
`, "utf8");
|
|
23047
23437
|
wrote = true;
|
|
@@ -23201,23 +23591,23 @@ function readManifestDocument(value) {
|
|
|
23201
23591
|
};
|
|
23202
23592
|
}
|
|
23203
23593
|
function cwdRelative(filePath) {
|
|
23204
|
-
const relative =
|
|
23205
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
23206
|
-
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);
|
|
23207
23597
|
}
|
|
23208
23598
|
return relative;
|
|
23209
23599
|
}
|
|
23210
23600
|
async function readReporterManifest(filePath) {
|
|
23211
|
-
const absolute =
|
|
23601
|
+
const absolute = path33__default.default.resolve(filePath);
|
|
23212
23602
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
23213
23603
|
const document = readManifestDocument(JSON.parse(raw));
|
|
23214
23604
|
const manifest = document.manifest;
|
|
23215
23605
|
const results = manifest.results.map((result) => ({
|
|
23216
23606
|
testId: safeText(result.testId),
|
|
23217
23607
|
name: safeText(result.name),
|
|
23218
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
23608
|
+
...result.file === void 0 ? {} : { file: safeText(path33__default.default.basename(result.file)) },
|
|
23219
23609
|
status: result.status,
|
|
23220
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
23610
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path33__default.default.basename(result.tracePath)) },
|
|
23221
23611
|
artifacts: result.artifacts,
|
|
23222
23612
|
diagnostics: result.diagnostics
|
|
23223
23613
|
}));
|
|
@@ -23356,15 +23746,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
23356
23746
|
return;
|
|
23357
23747
|
}
|
|
23358
23748
|
const markdown = renderMarkdown2(result);
|
|
23359
|
-
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;
|
|
23360
23750
|
if (outputPath !== void 0) {
|
|
23361
|
-
await promises.mkdir(
|
|
23751
|
+
await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
|
|
23362
23752
|
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
23363
23753
|
}
|
|
23364
23754
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
23365
23755
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
23366
|
-
const summaryPath =
|
|
23367
|
-
await promises.mkdir(
|
|
23756
|
+
const summaryPath = path33__default.default.resolve(summaryTarget);
|
|
23757
|
+
await promises.mkdir(path33__default.default.dirname(summaryPath), { recursive: true });
|
|
23368
23758
|
await promises.appendFile(summaryPath, `
|
|
23369
23759
|
${markdown}`, "utf-8");
|
|
23370
23760
|
}
|
|
@@ -23549,7 +23939,7 @@ jobs:
|
|
|
23549
23939
|
}
|
|
23550
23940
|
async function planInit(options = {}) {
|
|
23551
23941
|
const framework = normalizeFramework(options.framework);
|
|
23552
|
-
const cwd =
|
|
23942
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
23553
23943
|
const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
|
|
23554
23944
|
const candidates = [
|
|
23555
23945
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
@@ -23564,7 +23954,7 @@ async function planInit(options = {}) {
|
|
|
23564
23954
|
}
|
|
23565
23955
|
const files = [];
|
|
23566
23956
|
for (const candidate of candidates) {
|
|
23567
|
-
const abs =
|
|
23957
|
+
const abs = path33__default.default.join(cwd, candidate.rel);
|
|
23568
23958
|
try {
|
|
23569
23959
|
await promises.access(abs);
|
|
23570
23960
|
files.push({
|
|
@@ -23585,12 +23975,12 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
23585
23975
|
if (entry.action === "skip") {
|
|
23586
23976
|
continue;
|
|
23587
23977
|
}
|
|
23588
|
-
const abs =
|
|
23978
|
+
const abs = path33__default.default.join(cwd, entry.path);
|
|
23589
23979
|
if (options.dryRun) {
|
|
23590
23980
|
written.push(entry.path);
|
|
23591
23981
|
continue;
|
|
23592
23982
|
}
|
|
23593
|
-
await promises.mkdir(
|
|
23983
|
+
await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
|
|
23594
23984
|
const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
|
|
23595
23985
|
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
|
|
23596
23986
|
await promises.writeFile(abs, content, "utf-8");
|
|
@@ -23599,7 +23989,7 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
23599
23989
|
return written;
|
|
23600
23990
|
}
|
|
23601
23991
|
async function initCommand(options = {}) {
|
|
23602
|
-
const cwd =
|
|
23992
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
23603
23993
|
try {
|
|
23604
23994
|
const plan = await planInit({ ...options, cwd });
|
|
23605
23995
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -23694,7 +24084,7 @@ function envCheck(name, optional = true) {
|
|
|
23694
24084
|
};
|
|
23695
24085
|
}
|
|
23696
24086
|
async function traceDirWritable(traceDir) {
|
|
23697
|
-
const resolved =
|
|
24087
|
+
const resolved = path33__default.default.resolve(traceDir);
|
|
23698
24088
|
try {
|
|
23699
24089
|
await promises.mkdir(resolved, { recursive: true });
|
|
23700
24090
|
await promises.access(resolved, promises.constants.W_OK);
|
|
@@ -23715,10 +24105,10 @@ async function traceDirWritable(traceDir) {
|
|
|
23715
24105
|
}
|
|
23716
24106
|
}
|
|
23717
24107
|
function readPackageVersionNearEntry(entryPath, packageName) {
|
|
23718
|
-
let dir =
|
|
23719
|
-
const { root } =
|
|
24108
|
+
let dir = path33__default.default.dirname(path33__default.default.resolve(entryPath));
|
|
24109
|
+
const { root } = path33__default.default.parse(dir);
|
|
23720
24110
|
while (true) {
|
|
23721
|
-
const candidate =
|
|
24111
|
+
const candidate = path33__default.default.join(dir, "package.json");
|
|
23722
24112
|
if (fs.existsSync(candidate)) {
|
|
23723
24113
|
try {
|
|
23724
24114
|
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
@@ -23729,14 +24119,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
|
|
|
23729
24119
|
}
|
|
23730
24120
|
}
|
|
23731
24121
|
if (dir === root) break;
|
|
23732
|
-
const parent =
|
|
24122
|
+
const parent = path33__default.default.dirname(dir);
|
|
23733
24123
|
if (parent === dir) break;
|
|
23734
24124
|
dir = parent;
|
|
23735
24125
|
}
|
|
23736
24126
|
return void 0;
|
|
23737
24127
|
}
|
|
23738
24128
|
function resolveInstalledPackage(cwd, name) {
|
|
23739
|
-
const require2 = module$1.createRequire(
|
|
24129
|
+
const require2 = module$1.createRequire(path33__default.default.join(cwd, "package.json"));
|
|
23740
24130
|
try {
|
|
23741
24131
|
const entry = require2.resolve(name);
|
|
23742
24132
|
let version2;
|
|
@@ -23834,7 +24224,7 @@ function versionMismatchCheck(cwd) {
|
|
|
23834
24224
|
};
|
|
23835
24225
|
}
|
|
23836
24226
|
async function runDoctorChecks(options = {}) {
|
|
23837
|
-
const cwd =
|
|
24227
|
+
const cwd = path33__default.default.resolve(options.cwd ?? process3__default.default.cwd());
|
|
23838
24228
|
const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
23839
24229
|
const checks2 = [
|
|
23840
24230
|
nodeVersionCheck(),
|
|
@@ -24074,7 +24464,7 @@ function parsePluginManifest(input3) {
|
|
|
24074
24464
|
};
|
|
24075
24465
|
}
|
|
24076
24466
|
async function readPluginManifestFile(packageDir) {
|
|
24077
|
-
const manifestPath =
|
|
24467
|
+
const manifestPath = path33__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
|
|
24078
24468
|
try {
|
|
24079
24469
|
const raw = await promises.readFile(manifestPath, "utf8");
|
|
24080
24470
|
const parsed = parsePluginManifest(JSON.parse(raw));
|
|
@@ -24149,7 +24539,7 @@ function createTraceDirectoryIndexer() {
|
|
|
24149
24539
|
// packages/cli/src/plugins.ts
|
|
24150
24540
|
async function readPackageName(packageDir) {
|
|
24151
24541
|
try {
|
|
24152
|
-
const raw = await promises.readFile(
|
|
24542
|
+
const raw = await promises.readFile(path33__default.default.join(packageDir, "package.json"), "utf8");
|
|
24153
24543
|
const parsed = JSON.parse(raw);
|
|
24154
24544
|
return typeof parsed.name === "string" ? parsed.name : void 0;
|
|
24155
24545
|
} catch {
|
|
@@ -24157,7 +24547,7 @@ async function readPackageName(packageDir) {
|
|
|
24157
24547
|
}
|
|
24158
24548
|
}
|
|
24159
24549
|
async function discoverPlugins(cwd = process.cwd()) {
|
|
24160
|
-
const nodeModules =
|
|
24550
|
+
const nodeModules = path33__default.default.join(cwd, "node_modules");
|
|
24161
24551
|
const found = [];
|
|
24162
24552
|
let entries;
|
|
24163
24553
|
try {
|
|
@@ -24168,7 +24558,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
24168
24558
|
for (const entry of entries.sort()) {
|
|
24169
24559
|
if (entry.startsWith("@")) continue;
|
|
24170
24560
|
if (!isPluginPackageName(entry)) continue;
|
|
24171
|
-
const packageDir =
|
|
24561
|
+
const packageDir = path33__default.default.join(nodeModules, entry);
|
|
24172
24562
|
const manifestRead = await readPluginManifestFile(packageDir);
|
|
24173
24563
|
found.push({
|
|
24174
24564
|
packageName: entry,
|
|
@@ -24181,7 +24571,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
24181
24571
|
return found;
|
|
24182
24572
|
}
|
|
24183
24573
|
async function validatePluginPackage(packageRef, cwd = process.cwd()) {
|
|
24184
|
-
const packageDir =
|
|
24574
|
+
const packageDir = path33__default.default.isAbsolute(packageRef) ? packageRef : path33__default.default.join(cwd, "node_modules", packageRef);
|
|
24185
24575
|
const packageName = await readPackageName(packageDir) ?? packageRef;
|
|
24186
24576
|
const errors = [];
|
|
24187
24577
|
const warnings = [];
|
|
@@ -24258,7 +24648,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
|
|
|
24258
24648
|
init_advanced();
|
|
24259
24649
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
24260
24650
|
function traceIndexPath(traceDir) {
|
|
24261
|
-
return
|
|
24651
|
+
return path33__default.default.join(traceDir, INDEX_FILENAME);
|
|
24262
24652
|
}
|
|
24263
24653
|
function parseMaxEntries(raw) {
|
|
24264
24654
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -24404,7 +24794,7 @@ async function newestTraceMtimeMs2(traceDir) {
|
|
|
24404
24794
|
for (const file of files) {
|
|
24405
24795
|
if (!file.endsWith(".jsonl")) continue;
|
|
24406
24796
|
try {
|
|
24407
|
-
const s = await promises.stat(
|
|
24797
|
+
const s = await promises.stat(path33__default.default.join(traceDir, file));
|
|
24408
24798
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
24409
24799
|
} catch {
|
|
24410
24800
|
}
|
|
@@ -24659,11 +25049,11 @@ function printJson5(value) {
|
|
|
24659
25049
|
console.log(JSON.stringify(value, null, 2));
|
|
24660
25050
|
}
|
|
24661
25051
|
function resolveCwd(options) {
|
|
24662
|
-
return
|
|
25052
|
+
return path33__default.default.resolve(options.cwd ?? process.cwd());
|
|
24663
25053
|
}
|
|
24664
25054
|
async function suiteInitCommand(options = {}) {
|
|
24665
25055
|
const cwd = resolveCwd(options);
|
|
24666
|
-
const configPath =
|
|
25056
|
+
const configPath = path33__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
24667
25057
|
const template = options.template?.trim();
|
|
24668
25058
|
const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
|
|
24669
25059
|
if (options.dryRun) {
|
|
@@ -24782,13 +25172,13 @@ async function suiteListCommand(options = {}) {
|
|
|
24782
25172
|
}
|
|
24783
25173
|
async function writeSuiteArtifact(result, configOutputDir, options) {
|
|
24784
25174
|
const cwd = resolveCwd(options);
|
|
24785
|
-
const outputDir =
|
|
25175
|
+
const outputDir = path33__default.default.resolve(
|
|
24786
25176
|
cwd,
|
|
24787
25177
|
options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
|
|
24788
25178
|
);
|
|
24789
25179
|
await promises.mkdir(outputDir, { recursive: true });
|
|
24790
25180
|
const stamp = result.startedAt.replace(/[:.]/g, "-");
|
|
24791
|
-
const filePath =
|
|
25181
|
+
const filePath = path33__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
|
|
24792
25182
|
await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
|
|
24793
25183
|
`, "utf-8");
|
|
24794
25184
|
return filePath;
|
|
@@ -24846,7 +25236,7 @@ async function loadSuiteResultFromInput(options) {
|
|
|
24846
25236
|
if (options.input === void 0 || options.input.trim() === "") {
|
|
24847
25237
|
throw new Error("Pass --input <suite-run.json> from a prior suite run.");
|
|
24848
25238
|
}
|
|
24849
|
-
const inputPath =
|
|
25239
|
+
const inputPath = path33__default.default.resolve(cwd, options.input.trim());
|
|
24850
25240
|
const raw = await promises.readFile(inputPath, "utf-8");
|
|
24851
25241
|
return JSON.parse(raw);
|
|
24852
25242
|
}
|
|
@@ -24889,9 +25279,9 @@ function normalizeMetrics2(raw) {
|
|
|
24889
25279
|
}
|
|
24890
25280
|
async function writeArtifacts(result, outputDir) {
|
|
24891
25281
|
await promises.mkdir(outputDir, { recursive: true });
|
|
24892
|
-
const jsonPath =
|
|
24893
|
-
const markdownPath =
|
|
24894
|
-
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");
|
|
24895
25285
|
await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
24896
25286
|
`, "utf-8");
|
|
24897
25287
|
await promises.writeFile(
|
|
@@ -24920,7 +25310,7 @@ async function cohortCommand(options = {}) {
|
|
|
24920
25310
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
24921
25311
|
let artifacts;
|
|
24922
25312
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
24923
|
-
artifacts = await writeArtifacts(result,
|
|
25313
|
+
artifacts = await writeArtifacts(result, path33__default.default.resolve(options.output.trim()));
|
|
24924
25314
|
}
|
|
24925
25315
|
if (options.json || format === "json") {
|
|
24926
25316
|
console.log(
|
|
@@ -24993,11 +25383,11 @@ function parseDuration2(value) {
|
|
|
24993
25383
|
async function writeArtifacts2(result, outputDir) {
|
|
24994
25384
|
await promises.mkdir(outputDir, { recursive: true });
|
|
24995
25385
|
const paths = {
|
|
24996
|
-
jsonPath:
|
|
24997
|
-
markdownPath:
|
|
24998
|
-
htmlPath:
|
|
24999
|
-
junitPath:
|
|
25000
|
-
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")
|
|
25001
25391
|
};
|
|
25002
25392
|
await promises.writeFile(
|
|
25003
25393
|
paths.jsonPath,
|
|
@@ -25065,7 +25455,7 @@ async function gateCommand(options = {}) {
|
|
|
25065
25455
|
const result = await runGate(runs, gateOptions);
|
|
25066
25456
|
let artifacts;
|
|
25067
25457
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
25068
|
-
artifacts = await writeArtifacts2(result,
|
|
25458
|
+
artifacts = await writeArtifacts2(result, path33__default.default.resolve(options.output.trim()));
|
|
25069
25459
|
}
|
|
25070
25460
|
const failed = !result.ok;
|
|
25071
25461
|
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
@@ -25372,7 +25762,7 @@ function createCliProgram() {
|
|
|
25372
25762
|
"openinference-json",
|
|
25373
25763
|
"otlp-json"
|
|
25374
25764
|
])
|
|
25375
|
-
).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) => {
|
|
25376
25766
|
runCommand(() => scanCommand(target, opts));
|
|
25377
25767
|
});
|
|
25378
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(
|
|
@@ -25381,7 +25771,7 @@ function createCliProgram() {
|
|
|
25381
25771
|
"openinference-json",
|
|
25382
25772
|
"otlp-json"
|
|
25383
25773
|
])
|
|
25384
|
-
).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) => {
|
|
25385
25775
|
runCommand(() => verifySafeCommand(target, opts));
|
|
25386
25776
|
});
|
|
25387
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(
|
|
@@ -25541,7 +25931,10 @@ function createCliProgram() {
|
|
|
25541
25931
|
"--redaction-profile <profile>",
|
|
25542
25932
|
"alias for --profile (canonical spelling)"
|
|
25543
25933
|
).choices(["local", "share", "strict"])
|
|
25544
|
-
).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) => {
|
|
25545
25938
|
runCommand(() => redactCommand(target, opts));
|
|
25546
25939
|
});
|
|
25547
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(
|
|
@@ -25723,9 +26116,9 @@ function isPrimaryModule() {
|
|
|
25723
26116
|
if (!entry) return false;
|
|
25724
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)));
|
|
25725
26118
|
try {
|
|
25726
|
-
return fs.realpathSync(
|
|
26119
|
+
return fs.realpathSync(path33__default.default.resolve(entry)) === fs.realpathSync(path33__default.default.resolve(selfPath));
|
|
25727
26120
|
} catch {
|
|
25728
|
-
return
|
|
26121
|
+
return path33__default.default.resolve(entry) === path33__default.default.resolve(selfPath);
|
|
25729
26122
|
}
|
|
25730
26123
|
}
|
|
25731
26124
|
if (isPrimaryModule()) {
|