agent-inspect 6.17.3 → 6.17.5
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 +12 -0
- package/README.md +1 -1
- package/docs/ADAPTER-CONFORMANCE.md +24 -0
- package/docs/ADAPTERS.md +3 -3
- package/docs/API.md +13 -7
- package/docs/CI-ARTIFACTS.md +2 -1
- package/docs/CLI.md +2 -0
- package/docs/LIMITATIONS.md +1 -0
- package/docs/OPENAI-AGENTS-LOCAL.md +14 -0
- package/docs/SAFE-TRACE-SHARING.md +1 -0
- package/docs/SELF-HOSTING.md +2 -0
- package/docs/STANDARDS.md +15 -0
- package/docs/SUPPORT-LEVELS.md +23 -0
- package/docs/TRACE-CONTRACTS.md +90 -0
- package/package.json +7 -3
- package/packages/cli/dist/{chunk-5GGYDIZD.mjs → chunk-GOHYSE7W.mjs} +93 -19
- package/packages/cli/dist/chunk-GOHYSE7W.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +505 -88
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +417 -74
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-IDMCWKRH.mjs → src-OYGG7QAZ.mjs} +3 -3
- package/packages/cli/dist/{src-IDMCWKRH.mjs.map → src-OYGG7QAZ.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +86 -17
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +1 -1
- package/packages/core/dist/advanced.d.ts +1 -1
- package/packages/core/dist/advanced.mjs +15 -5
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.cjs +126 -28
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.d.cts +28 -2
- package/packages/core/dist/checks.d.ts +28 -2
- package/packages/core/dist/checks.mjs +1 -1
- package/packages/core/dist/{chunk-UFP54T7F.mjs → chunk-DIZPIPY2.mjs} +128 -30
- package/packages/core/dist/chunk-DIZPIPY2.mjs.map +1 -0
- package/packages/core/dist/{index-Xk9X-yjY.d.cts → index-DWu54Y28.d.cts} +107 -122
- package/packages/core/dist/{index-BsCcOKxy.d.ts → index-DlwbVqEs.d.ts} +107 -122
- package/packages/cli/dist/chunk-5GGYDIZD.mjs.map +0 -1
- package/packages/core/dist/chunk-UFP54T7F.mjs.map +0 -1
|
@@ -3565,14 +3565,15 @@ var init_cohort = __esm({
|
|
|
3565
3565
|
|
|
3566
3566
|
// packages/core/src/sessions/checks.ts
|
|
3567
3567
|
function emptySummary() {
|
|
3568
|
-
return { passed: 0, failed: 0, warnings: 0, errors: 0 };
|
|
3568
|
+
return { passed: 0, failed: 0, warnings: 0, errors: 0, rulesEvaluated: 0 };
|
|
3569
3569
|
}
|
|
3570
3570
|
function mergeSummary(target, source) {
|
|
3571
3571
|
return {
|
|
3572
3572
|
passed: target.passed + source.passed,
|
|
3573
3573
|
failed: target.failed + source.failed,
|
|
3574
3574
|
warnings: target.warnings + source.warnings,
|
|
3575
|
-
errors: target.errors + source.errors
|
|
3575
|
+
errors: target.errors + source.errors,
|
|
3576
|
+
rulesEvaluated: target.rulesEvaluated + source.rulesEvaluated
|
|
3576
3577
|
};
|
|
3577
3578
|
}
|
|
3578
3579
|
function sessionDiagnostic(code, message) {
|
|
@@ -3596,6 +3597,7 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3596
3597
|
`${scope.scopeKind} not found: ${scope.scopeLabel}`
|
|
3597
3598
|
)
|
|
3598
3599
|
],
|
|
3600
|
+
ruleExecutions: [],
|
|
3599
3601
|
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
3600
3602
|
};
|
|
3601
3603
|
}
|
|
@@ -3616,17 +3618,20 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3616
3618
|
`No readable traces in ${scope.scopeKind}: ${scope.scopeLabel}`
|
|
3617
3619
|
)
|
|
3618
3620
|
],
|
|
3621
|
+
ruleExecutions: [],
|
|
3619
3622
|
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
3620
3623
|
};
|
|
3621
3624
|
}
|
|
3622
3625
|
let summary = emptySummary();
|
|
3623
3626
|
const findings = [];
|
|
3624
3627
|
const diagnostics = [];
|
|
3628
|
+
const ruleExecutions = [];
|
|
3625
3629
|
const runResults = [];
|
|
3626
3630
|
for (const result of perRun) {
|
|
3627
3631
|
summary = mergeSummary(summary, result.summary);
|
|
3628
3632
|
findings.push(...result.findings);
|
|
3629
3633
|
diagnostics.push(...result.diagnostics);
|
|
3634
|
+
ruleExecutions.push(...result.ruleExecutions ?? []);
|
|
3630
3635
|
if (result.runId) {
|
|
3631
3636
|
runResults.push({ runId: result.runId, status: result.status });
|
|
3632
3637
|
}
|
|
@@ -3639,6 +3644,11 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3639
3644
|
if (runCmp !== 0) return runCmp;
|
|
3640
3645
|
return a.ruleId.localeCompare(b.ruleId);
|
|
3641
3646
|
});
|
|
3647
|
+
ruleExecutions.sort((a, b) => {
|
|
3648
|
+
const runCmp = (a.runId ?? "").localeCompare(b.runId ?? "");
|
|
3649
|
+
if (runCmp !== 0) return runCmp;
|
|
3650
|
+
return a.ruleId.localeCompare(b.ruleId);
|
|
3651
|
+
});
|
|
3642
3652
|
const hasErrors = diagnostics.some((item) => item.severity === "error");
|
|
3643
3653
|
const status = hasErrors ? "error" : summary.failed > 0 ? "fail" : "pass";
|
|
3644
3654
|
return {
|
|
@@ -3652,6 +3662,7 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3652
3662
|
summary,
|
|
3653
3663
|
findings,
|
|
3654
3664
|
diagnostics,
|
|
3665
|
+
ruleExecutions,
|
|
3655
3666
|
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
3656
3667
|
};
|
|
3657
3668
|
}
|
|
@@ -6419,8 +6430,11 @@ var init_programmatic = __esm({
|
|
|
6419
6430
|
});
|
|
6420
6431
|
|
|
6421
6432
|
// packages/core/src/safety/sensitive-key.ts
|
|
6433
|
+
function keyHasExplicitSeparator(value) {
|
|
6434
|
+
return /[_\-.]/.test(value);
|
|
6435
|
+
}
|
|
6422
6436
|
function normalizeSensitiveKey(value) {
|
|
6423
|
-
return value.toLowerCase().replace(/[^a-z0-
|
|
6437
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
6424
6438
|
}
|
|
6425
6439
|
function isTokenCredentialKey(normalized) {
|
|
6426
6440
|
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
@@ -6433,6 +6447,7 @@ function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSIT
|
|
|
6433
6447
|
const normalized = normalizeSensitiveKey(key);
|
|
6434
6448
|
if (!normalized) return false;
|
|
6435
6449
|
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
6450
|
+
const allowPrefixCompound = keyHasExplicitSeparator(key);
|
|
6436
6451
|
for (const sensitive of sensitiveKeys) {
|
|
6437
6452
|
const s = normalizeSensitiveKey(sensitive);
|
|
6438
6453
|
if (!s) continue;
|
|
@@ -6441,7 +6456,8 @@ function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSIT
|
|
|
6441
6456
|
continue;
|
|
6442
6457
|
}
|
|
6443
6458
|
if (normalized === s) return true;
|
|
6444
|
-
if (normalized.endsWith(`_${s}`)
|
|
6459
|
+
if (normalized.endsWith(`_${s}`)) return true;
|
|
6460
|
+
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
6445
6461
|
}
|
|
6446
6462
|
return false;
|
|
6447
6463
|
}
|
|
@@ -6852,10 +6868,11 @@ function emptySummary2() {
|
|
|
6852
6868
|
passed: 0,
|
|
6853
6869
|
failed: 0,
|
|
6854
6870
|
warnings: 0,
|
|
6855
|
-
errors: 0
|
|
6871
|
+
errors: 0,
|
|
6872
|
+
rulesEvaluated: 0
|
|
6856
6873
|
};
|
|
6857
6874
|
}
|
|
6858
|
-
function errorResult(input3, diagnostics, selectedRun) {
|
|
6875
|
+
function errorResult(input3, diagnostics, selectedRun, ruleExecutions = []) {
|
|
6859
6876
|
return {
|
|
6860
6877
|
ok: false,
|
|
6861
6878
|
status: "error",
|
|
@@ -6863,10 +6880,12 @@ function errorResult(input3, diagnostics, selectedRun) {
|
|
|
6863
6880
|
...selectedRun ? { runId: selectedRun.runId } : {},
|
|
6864
6881
|
summary: {
|
|
6865
6882
|
...emptySummary2(),
|
|
6866
|
-
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
6883
|
+
errors: diagnostics.filter((item) => item.severity === "error").length,
|
|
6884
|
+
rulesEvaluated: ruleExecutions.length
|
|
6867
6885
|
},
|
|
6868
6886
|
findings: [],
|
|
6869
|
-
diagnostics: [...diagnostics]
|
|
6887
|
+
diagnostics: [...diagnostics],
|
|
6888
|
+
ruleExecutions: [...ruleExecutions]
|
|
6870
6889
|
};
|
|
6871
6890
|
}
|
|
6872
6891
|
function flattenNodes(nodes) {
|
|
@@ -7022,7 +7041,7 @@ function normalizeFinding(rule, finding) {
|
|
|
7022
7041
|
...finding.action !== void 0 ? { action: finding.action } : {}
|
|
7023
7042
|
};
|
|
7024
7043
|
}
|
|
7025
|
-
function summarize(findings, diagnostics) {
|
|
7044
|
+
function summarize(findings, diagnostics, rulesEvaluated) {
|
|
7026
7045
|
return {
|
|
7027
7046
|
passed: findings.filter((finding) => finding.status === "pass").length,
|
|
7028
7047
|
failed: findings.filter(
|
|
@@ -7031,9 +7050,21 @@ function summarize(findings, diagnostics) {
|
|
|
7031
7050
|
warnings: findings.filter(
|
|
7032
7051
|
(finding) => finding.status === "warning" || finding.severity === "warning"
|
|
7033
7052
|
).length,
|
|
7034
|
-
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
7053
|
+
errors: diagnostics.filter((item) => item.severity === "error").length,
|
|
7054
|
+
rulesEvaluated
|
|
7035
7055
|
};
|
|
7036
7056
|
}
|
|
7057
|
+
function classifyRuleExecution(findings, threw) {
|
|
7058
|
+
if (findings.some((finding) => finding.status === "fail" && finding.severity === "error")) {
|
|
7059
|
+
return "fail";
|
|
7060
|
+
}
|
|
7061
|
+
if (findings.some(
|
|
7062
|
+
(finding) => finding.status === "warning" || finding.severity === "warning"
|
|
7063
|
+
)) {
|
|
7064
|
+
return "warning";
|
|
7065
|
+
}
|
|
7066
|
+
return "pass";
|
|
7067
|
+
}
|
|
7037
7068
|
function stringAttr(event, keys) {
|
|
7038
7069
|
for (const key of keys) {
|
|
7039
7070
|
const value = event.attributes?.[key];
|
|
@@ -7130,6 +7161,9 @@ function finishedEvents(context, kind) {
|
|
|
7130
7161
|
(event) => (kind === void 0 || event.kind === kind) && event.status !== "running"
|
|
7131
7162
|
);
|
|
7132
7163
|
}
|
|
7164
|
+
function toolInvocationEvents(context) {
|
|
7165
|
+
return semanticEvents(context).filter((event) => event.kind === "TOOL");
|
|
7166
|
+
}
|
|
7133
7167
|
function isRecord8(value) {
|
|
7134
7168
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7135
7169
|
}
|
|
@@ -7530,7 +7564,7 @@ function createToolUsageRule(options) {
|
|
|
7530
7564
|
category: "tool",
|
|
7531
7565
|
defaultSeverity: "error",
|
|
7532
7566
|
evaluate(context) {
|
|
7533
|
-
const tools =
|
|
7567
|
+
const tools = toolInvocationEvents(context);
|
|
7534
7568
|
const names = tools.map(toolName);
|
|
7535
7569
|
const nameSet = new Set(names);
|
|
7536
7570
|
const findings = [];
|
|
@@ -8180,12 +8214,24 @@ function createBaselineRegressionRule(options) {
|
|
|
8180
8214
|
}
|
|
8181
8215
|
function createObservedOutcomeRule(options = {}) {
|
|
8182
8216
|
const failOn = options.failOn ?? ["failed"];
|
|
8217
|
+
const requireAny = options.requireAny === true;
|
|
8183
8218
|
return {
|
|
8184
8219
|
id: "outcome.status",
|
|
8185
8220
|
category: "run",
|
|
8186
8221
|
defaultSeverity: "error",
|
|
8187
8222
|
evaluate(context) {
|
|
8188
8223
|
const outcomes = extractOutcomesFromPersistedEvents(context.events);
|
|
8224
|
+
if (requireAny && outcomes.length === 0) {
|
|
8225
|
+
return [
|
|
8226
|
+
failFinding(
|
|
8227
|
+
"outcome.status",
|
|
8228
|
+
"Expected at least one observed outcome.",
|
|
8229
|
+
runEvidence(context.selectedRun),
|
|
8230
|
+
{ requireAny: true, expected: "at least one observed outcome" },
|
|
8231
|
+
{ code: "outcome.missing", actual: 0 }
|
|
8232
|
+
)
|
|
8233
|
+
];
|
|
8234
|
+
}
|
|
8189
8235
|
const matching = outcomesMatchingStatus(outcomes, failOn);
|
|
8190
8236
|
if (matching.length === 0) return [];
|
|
8191
8237
|
return [
|
|
@@ -8221,6 +8267,18 @@ function runTraceChecks(input3, options = {}) {
|
|
|
8221
8267
|
if (rules.diagnostics.length > 0) {
|
|
8222
8268
|
return errorResult(input3, rules.diagnostics, selected.run);
|
|
8223
8269
|
}
|
|
8270
|
+
if (rules.rules.length === 0) {
|
|
8271
|
+
return errorResult(
|
|
8272
|
+
input3,
|
|
8273
|
+
[
|
|
8274
|
+
diagnostic3(
|
|
8275
|
+
"AI_CHECK_NO_RULES_EVALUATED",
|
|
8276
|
+
"No trace check rules were evaluated. Configure at least one rule, contract, or CLI check option."
|
|
8277
|
+
)
|
|
8278
|
+
],
|
|
8279
|
+
selected.run
|
|
8280
|
+
);
|
|
8281
|
+
}
|
|
8224
8282
|
const facts = buildFacts2(input3, selected.run);
|
|
8225
8283
|
const context = {
|
|
8226
8284
|
...facts,
|
|
@@ -8229,22 +8287,38 @@ function runTraceChecks(input3, options = {}) {
|
|
|
8229
8287
|
};
|
|
8230
8288
|
const diagnostics = [];
|
|
8231
8289
|
const findings = [];
|
|
8290
|
+
const ruleExecutions = [];
|
|
8232
8291
|
for (const rule of rules.rules) {
|
|
8233
8292
|
try {
|
|
8234
|
-
|
|
8293
|
+
const ruleFindings = rule.evaluate(context).map((finding) => normalizeFinding(rule, finding));
|
|
8294
|
+
findings.push(...ruleFindings);
|
|
8295
|
+
ruleExecutions.push({
|
|
8296
|
+
ruleId: rule.id,
|
|
8297
|
+
category: rule.category,
|
|
8298
|
+
status: classifyRuleExecution(ruleFindings, false),
|
|
8299
|
+
findingCount: ruleFindings.length,
|
|
8300
|
+
...selected.run ? { runId: selected.run.runId } : {}
|
|
8301
|
+
});
|
|
8235
8302
|
} catch (error) {
|
|
8236
8303
|
const message = error instanceof Error ? error.message : String(error);
|
|
8237
8304
|
diagnostics.push(
|
|
8238
8305
|
diagnostic3("AI_CHECK_INTERNAL_ERROR", `Rule ${rule.id} failed: ${message}`, rule.id)
|
|
8239
8306
|
);
|
|
8307
|
+
ruleExecutions.push({
|
|
8308
|
+
ruleId: rule.id,
|
|
8309
|
+
category: rule.category,
|
|
8310
|
+
status: "error",
|
|
8311
|
+
findingCount: 0,
|
|
8312
|
+
...selected.run ? { runId: selected.run.runId } : {}
|
|
8313
|
+
});
|
|
8240
8314
|
}
|
|
8241
8315
|
}
|
|
8242
8316
|
if (diagnostics.length > 0) {
|
|
8243
|
-
return errorResult(input3, diagnostics, selected.run);
|
|
8317
|
+
return errorResult(input3, diagnostics, selected.run, ruleExecutions);
|
|
8244
8318
|
}
|
|
8245
8319
|
const eventById = new Map(input3.read.events.map((event) => [event.eventId, event]));
|
|
8246
8320
|
const sortedFindings = findings.sort(compareFindings(eventById));
|
|
8247
|
-
const summary = summarize(sortedFindings, diagnostics);
|
|
8321
|
+
const summary = summarize(sortedFindings, diagnostics, ruleExecutions.length);
|
|
8248
8322
|
const status = summary.failed > 0 ? "fail" : "pass";
|
|
8249
8323
|
return {
|
|
8250
8324
|
ok: status === "pass",
|
|
@@ -8253,7 +8327,8 @@ function runTraceChecks(input3, options = {}) {
|
|
|
8253
8327
|
...selected.run ? { runId: selected.run.runId } : {},
|
|
8254
8328
|
summary,
|
|
8255
8329
|
findings: sortedFindings,
|
|
8256
|
-
diagnostics
|
|
8330
|
+
diagnostics,
|
|
8331
|
+
ruleExecutions
|
|
8257
8332
|
};
|
|
8258
8333
|
}
|
|
8259
8334
|
var SEVERITY_RANK, STATUS_RANK, CONFIDENCE_RANK, DEFAULT_SENSITIVE_KEYS, DEFAULT_RAW_CONTENT_KEYS, DEFAULT_SAFE_RAW_CONTENT_PATH_PREFIXES, SAFE_USAGE_LEAF_KEYS, DEFAULT_SECRET_PATTERNS;
|
|
@@ -10702,8 +10777,7 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
10702
10777
|
status: "pass",
|
|
10703
10778
|
format: read.format,
|
|
10704
10779
|
findings: [],
|
|
10705
|
-
diagnostics: []
|
|
10706
|
-
};
|
|
10780
|
+
diagnostics: []};
|
|
10707
10781
|
const observationResult = validateExpectedObservations(suiteCase, read);
|
|
10708
10782
|
const diagnostics = [
|
|
10709
10783
|
...checkResult.diagnostics.map(
|
|
@@ -12506,7 +12580,7 @@ var init_src = __esm({
|
|
|
12506
12580
|
});
|
|
12507
12581
|
|
|
12508
12582
|
// package.json
|
|
12509
|
-
var version = "6.17.
|
|
12583
|
+
var version = "6.17.5";
|
|
12510
12584
|
|
|
12511
12585
|
// packages/cli/src/list.ts
|
|
12512
12586
|
init_advanced();
|
|
@@ -14075,6 +14149,11 @@ async function followFile(filePath, options, onLine, shouldStop) {
|
|
|
14075
14149
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14076
14150
|
throw new Error(`Failed to stat file: ${filePath} (${msg})`);
|
|
14077
14151
|
}
|
|
14152
|
+
if (next.size < pos) {
|
|
14153
|
+
pos = 0;
|
|
14154
|
+
carry = "";
|
|
14155
|
+
lineNumber = 0;
|
|
14156
|
+
}
|
|
14078
14157
|
if (next.size > pos) {
|
|
14079
14158
|
const fh = await promises.open(filePath, "r");
|
|
14080
14159
|
try {
|
|
@@ -16399,8 +16478,11 @@ async function reportCommand(runId, options = {}) {
|
|
|
16399
16478
|
init_advanced();
|
|
16400
16479
|
|
|
16401
16480
|
// packages/redact/src/sensitive-key.ts
|
|
16481
|
+
function keyHasExplicitSeparator2(value) {
|
|
16482
|
+
return /[_\-.]/.test(value);
|
|
16483
|
+
}
|
|
16402
16484
|
function normalizeSensitiveKey2(value) {
|
|
16403
|
-
return value.toLowerCase().replace(/[^a-z0-
|
|
16485
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16404
16486
|
}
|
|
16405
16487
|
var NON_CREDENTIAL_TOKEN_CONFIG_KEYS2 = new Set(
|
|
16406
16488
|
[
|
|
@@ -16430,6 +16512,7 @@ function isCredentialSensitiveKey2(key, sensitiveKeys) {
|
|
|
16430
16512
|
const normalized = normalizeSensitiveKey2(key);
|
|
16431
16513
|
if (!normalized) return false;
|
|
16432
16514
|
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS2.has(normalized)) return false;
|
|
16515
|
+
const allowPrefixCompound = keyHasExplicitSeparator2(key);
|
|
16433
16516
|
for (const sensitive of sensitiveKeys) {
|
|
16434
16517
|
const s = normalizeSensitiveKey2(sensitive);
|
|
16435
16518
|
if (!s) continue;
|
|
@@ -16438,7 +16521,8 @@ function isCredentialSensitiveKey2(key, sensitiveKeys) {
|
|
|
16438
16521
|
continue;
|
|
16439
16522
|
}
|
|
16440
16523
|
if (normalized === s) return true;
|
|
16441
|
-
if (normalized.endsWith(`_${s}`)
|
|
16524
|
+
if (normalized.endsWith(`_${s}`)) return true;
|
|
16525
|
+
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
16442
16526
|
}
|
|
16443
16527
|
return false;
|
|
16444
16528
|
}
|
|
@@ -17734,8 +17818,11 @@ function checkResultToEvidenceJson(result, runIds) {
|
|
|
17734
17818
|
status,
|
|
17735
17819
|
errors: result.summary.errors,
|
|
17736
17820
|
warnings: result.summary.warnings,
|
|
17737
|
-
findings: result.findings.length
|
|
17821
|
+
findings: result.findings.length,
|
|
17822
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0
|
|
17738
17823
|
})),
|
|
17824
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0,
|
|
17825
|
+
evaluatedRuleIds: (result.ruleExecutions ?? []).map((item) => item.ruleId),
|
|
17739
17826
|
findings: result.findings,
|
|
17740
17827
|
diagnostics: result.diagnostics
|
|
17741
17828
|
});
|
|
@@ -18360,9 +18447,11 @@ function mergeSafetyExtensions(result, read, options) {
|
|
|
18360
18447
|
passed,
|
|
18361
18448
|
failed,
|
|
18362
18449
|
warnings,
|
|
18363
|
-
errors: result.summary.errors
|
|
18450
|
+
errors: result.summary.errors,
|
|
18451
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0
|
|
18364
18452
|
},
|
|
18365
|
-
findings
|
|
18453
|
+
findings,
|
|
18454
|
+
ruleExecutions: result.ruleExecutions ?? []
|
|
18366
18455
|
};
|
|
18367
18456
|
}
|
|
18368
18457
|
|
|
@@ -18482,10 +18571,12 @@ function errorResult2(code, message, format = "unknown") {
|
|
|
18482
18571
|
passed: 0,
|
|
18483
18572
|
failed: 0,
|
|
18484
18573
|
warnings: 0,
|
|
18485
|
-
errors: 1
|
|
18574
|
+
errors: 1,
|
|
18575
|
+
rulesEvaluated: 0
|
|
18486
18576
|
},
|
|
18487
18577
|
findings: [],
|
|
18488
|
-
diagnostics
|
|
18578
|
+
diagnostics,
|
|
18579
|
+
ruleExecutions: []
|
|
18489
18580
|
};
|
|
18490
18581
|
}
|
|
18491
18582
|
function parseNumber(value, label) {
|
|
@@ -18503,36 +18594,329 @@ function asStringArray2(value) {
|
|
|
18503
18594
|
}
|
|
18504
18595
|
return value;
|
|
18505
18596
|
}
|
|
18506
|
-
|
|
18597
|
+
var CHECKS_KEYS = /* @__PURE__ */ new Set(["select", "run", "tool", "llm", "structure", "safety"]);
|
|
18598
|
+
var RUN_KEYS = /* @__PURE__ */ new Set(["expected", "allowIncomplete", "maxDurationMs", "maxDepth"]);
|
|
18599
|
+
var TOOL_KEYS = /* @__PURE__ */ new Set(["required", "forbidden", "allowed", "minCount", "maxCount"]);
|
|
18600
|
+
var LLM_KEYS = /* @__PURE__ */ new Set([
|
|
18601
|
+
"allowedModels",
|
|
18602
|
+
"allowedProviders",
|
|
18603
|
+
"finishReasons",
|
|
18604
|
+
"maxCalls",
|
|
18605
|
+
"maxTotalTokens",
|
|
18606
|
+
"maxInputTokens",
|
|
18607
|
+
"maxOutputTokens",
|
|
18608
|
+
"maxCachedTokens"
|
|
18609
|
+
]);
|
|
18610
|
+
var STRUCTURE_KEYS = /* @__PURE__ */ new Set([
|
|
18611
|
+
"minConfidence",
|
|
18612
|
+
"requireParentBeforeChild",
|
|
18613
|
+
"requireTraceParentSpan",
|
|
18614
|
+
"orphan",
|
|
18615
|
+
"cycle",
|
|
18616
|
+
"maxChildren",
|
|
18617
|
+
"maxConcurrent"
|
|
18618
|
+
]);
|
|
18619
|
+
var SAFETY_KEYS = /* @__PURE__ */ new Set([
|
|
18620
|
+
"redaction",
|
|
18621
|
+
"rawContent",
|
|
18622
|
+
"secretPattern",
|
|
18623
|
+
"maxStringLength",
|
|
18624
|
+
"maxArrayLength",
|
|
18625
|
+
"maxObjectKeys",
|
|
18626
|
+
"maxSerializedBytes",
|
|
18627
|
+
"maxFindings"
|
|
18628
|
+
]);
|
|
18629
|
+
var RUN_EXPECTED = /* @__PURE__ */ new Set(["ok", "error", "running"]);
|
|
18630
|
+
var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["exact", "high", "medium", "low", "inferred"]);
|
|
18631
|
+
var CheckConfigError = class extends Error {
|
|
18632
|
+
code;
|
|
18633
|
+
constructor(code, message) {
|
|
18634
|
+
super(message);
|
|
18635
|
+
this.name = "CheckConfigError";
|
|
18636
|
+
this.code = code;
|
|
18637
|
+
}
|
|
18638
|
+
};
|
|
18639
|
+
function closestKey(unknown, known) {
|
|
18640
|
+
const lower = unknown.toLowerCase();
|
|
18641
|
+
let best;
|
|
18642
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
18643
|
+
for (const candidate of known) {
|
|
18644
|
+
if (candidate.toLowerCase() === lower) return candidate;
|
|
18645
|
+
let distance = Math.abs(candidate.length - unknown.length);
|
|
18646
|
+
const max = Math.max(candidate.length, unknown.length);
|
|
18647
|
+
for (let i = 0; i < Math.min(candidate.length, unknown.length); i += 1) {
|
|
18648
|
+
if (candidate[i].toLowerCase() !== unknown[i].toLowerCase()) distance += 1;
|
|
18649
|
+
}
|
|
18650
|
+
if (distance < bestDistance && distance <= Math.max(2, Math.floor(max / 3))) {
|
|
18651
|
+
bestDistance = distance;
|
|
18652
|
+
best = candidate;
|
|
18653
|
+
}
|
|
18654
|
+
}
|
|
18655
|
+
return best;
|
|
18656
|
+
}
|
|
18657
|
+
function rejectUnknownKeys(record, allowed, pathPrefix) {
|
|
18658
|
+
for (const key of Object.keys(record)) {
|
|
18659
|
+
if (allowed.has(key)) continue;
|
|
18660
|
+
const suggestion = closestKey(key, [...allowed]);
|
|
18661
|
+
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
18662
|
+
throw new CheckConfigError(
|
|
18663
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
18664
|
+
`Unknown check config key "${pathPrefix}.${key}".${hint}`
|
|
18665
|
+
);
|
|
18666
|
+
}
|
|
18667
|
+
}
|
|
18668
|
+
function requireObject(value, pathPrefix) {
|
|
18669
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
18670
|
+
throw new CheckConfigError(
|
|
18671
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18672
|
+
`${pathPrefix} must be an object.`
|
|
18673
|
+
);
|
|
18674
|
+
}
|
|
18675
|
+
return value;
|
|
18676
|
+
}
|
|
18677
|
+
function requireStringArray(value, pathPrefix) {
|
|
18678
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.trim() === "")) {
|
|
18679
|
+
throw new CheckConfigError(
|
|
18680
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18681
|
+
`${pathPrefix} must be an array of non-empty strings.`
|
|
18682
|
+
);
|
|
18683
|
+
}
|
|
18684
|
+
return value;
|
|
18685
|
+
}
|
|
18686
|
+
function requireNonNegativeNumber(value, pathPrefix) {
|
|
18687
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
18688
|
+
throw new CheckConfigError(
|
|
18689
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18690
|
+
`${pathPrefix} must be a finite non-negative number.`
|
|
18691
|
+
);
|
|
18692
|
+
}
|
|
18693
|
+
return value;
|
|
18694
|
+
}
|
|
18695
|
+
function requireBoolean(value, pathPrefix) {
|
|
18696
|
+
if (typeof value !== "boolean") {
|
|
18697
|
+
throw new CheckConfigError(
|
|
18698
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18699
|
+
`${pathPrefix} must be a boolean.`
|
|
18700
|
+
);
|
|
18701
|
+
}
|
|
18702
|
+
return value;
|
|
18703
|
+
}
|
|
18704
|
+
function parseRunSection(value) {
|
|
18705
|
+
const record = requireObject(value, "checks.run");
|
|
18706
|
+
rejectUnknownKeys(record, RUN_KEYS, "checks.run");
|
|
18707
|
+
const out = {};
|
|
18708
|
+
if (record.expected !== void 0) {
|
|
18709
|
+
if (typeof record.expected !== "string" || !RUN_EXPECTED.has(record.expected)) {
|
|
18710
|
+
throw new CheckConfigError(
|
|
18711
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18712
|
+
`checks.run.expected must be one of: ok, error, running.`
|
|
18713
|
+
);
|
|
18714
|
+
}
|
|
18715
|
+
out.expected = record.expected;
|
|
18716
|
+
}
|
|
18717
|
+
if (record.allowIncomplete !== void 0) {
|
|
18718
|
+
out.allowIncomplete = requireBoolean(record.allowIncomplete, "checks.run.allowIncomplete");
|
|
18719
|
+
}
|
|
18720
|
+
if (record.maxDurationMs !== void 0) {
|
|
18721
|
+
out.maxDurationMs = requireNonNegativeNumber(record.maxDurationMs, "checks.run.maxDurationMs");
|
|
18722
|
+
}
|
|
18723
|
+
if (record.maxDepth !== void 0) {
|
|
18724
|
+
out.maxDepth = requireNonNegativeNumber(record.maxDepth, "checks.run.maxDepth");
|
|
18725
|
+
}
|
|
18726
|
+
return out;
|
|
18727
|
+
}
|
|
18728
|
+
function parseToolSection(value) {
|
|
18729
|
+
const record = requireObject(value, "checks.tool");
|
|
18730
|
+
rejectUnknownKeys(record, TOOL_KEYS, "checks.tool");
|
|
18731
|
+
const out = {};
|
|
18732
|
+
if (record.required !== void 0) out.required = requireStringArray(record.required, "checks.tool.required");
|
|
18733
|
+
if (record.forbidden !== void 0) out.forbidden = requireStringArray(record.forbidden, "checks.tool.forbidden");
|
|
18734
|
+
if (record.allowed !== void 0) out.allowed = requireStringArray(record.allowed, "checks.tool.allowed");
|
|
18735
|
+
if (record.minCount !== void 0) out.minCount = requireNonNegativeNumber(record.minCount, "checks.tool.minCount");
|
|
18736
|
+
if (record.maxCount !== void 0) out.maxCount = requireNonNegativeNumber(record.maxCount, "checks.tool.maxCount");
|
|
18737
|
+
return out;
|
|
18738
|
+
}
|
|
18739
|
+
function parseLlmSection(value) {
|
|
18740
|
+
const record = requireObject(value, "checks.llm");
|
|
18741
|
+
rejectUnknownKeys(record, LLM_KEYS, "checks.llm");
|
|
18742
|
+
const out = {};
|
|
18743
|
+
if (record.allowedModels !== void 0) {
|
|
18744
|
+
out.allowedModels = requireStringArray(record.allowedModels, "checks.llm.allowedModels");
|
|
18745
|
+
}
|
|
18746
|
+
if (record.allowedProviders !== void 0) {
|
|
18747
|
+
out.allowedProviders = requireStringArray(record.allowedProviders, "checks.llm.allowedProviders");
|
|
18748
|
+
}
|
|
18749
|
+
if (record.finishReasons !== void 0) {
|
|
18750
|
+
out.finishReasons = requireStringArray(record.finishReasons, "checks.llm.finishReasons");
|
|
18751
|
+
}
|
|
18752
|
+
if (record.maxCalls !== void 0) out.maxCalls = requireNonNegativeNumber(record.maxCalls, "checks.llm.maxCalls");
|
|
18753
|
+
if (record.maxTotalTokens !== void 0) {
|
|
18754
|
+
out.maxTotalTokens = requireNonNegativeNumber(record.maxTotalTokens, "checks.llm.maxTotalTokens");
|
|
18755
|
+
}
|
|
18756
|
+
if (record.maxInputTokens !== void 0) {
|
|
18757
|
+
out.maxInputTokens = requireNonNegativeNumber(record.maxInputTokens, "checks.llm.maxInputTokens");
|
|
18758
|
+
}
|
|
18759
|
+
if (record.maxOutputTokens !== void 0) {
|
|
18760
|
+
out.maxOutputTokens = requireNonNegativeNumber(record.maxOutputTokens, "checks.llm.maxOutputTokens");
|
|
18761
|
+
}
|
|
18762
|
+
if (record.maxCachedTokens !== void 0) {
|
|
18763
|
+
out.maxCachedTokens = requireNonNegativeNumber(record.maxCachedTokens, "checks.llm.maxCachedTokens");
|
|
18764
|
+
}
|
|
18765
|
+
return out;
|
|
18766
|
+
}
|
|
18767
|
+
function parseStructureSection(value) {
|
|
18768
|
+
const record = requireObject(value, "checks.structure");
|
|
18769
|
+
rejectUnknownKeys(record, STRUCTURE_KEYS, "checks.structure");
|
|
18770
|
+
const out = {};
|
|
18771
|
+
if (record.minConfidence !== void 0) {
|
|
18772
|
+
if (typeof record.minConfidence !== "string" || !CONFIDENCE_VALUES.has(record.minConfidence)) {
|
|
18773
|
+
throw new CheckConfigError(
|
|
18774
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18775
|
+
`checks.structure.minConfidence must be one of: exact, high, medium, low, inferred.`
|
|
18776
|
+
);
|
|
18777
|
+
}
|
|
18778
|
+
out.minConfidence = record.minConfidence;
|
|
18779
|
+
}
|
|
18780
|
+
if (record.requireParentBeforeChild !== void 0) {
|
|
18781
|
+
out.requireParentBeforeChild = requireBoolean(
|
|
18782
|
+
record.requireParentBeforeChild,
|
|
18783
|
+
"checks.structure.requireParentBeforeChild"
|
|
18784
|
+
);
|
|
18785
|
+
}
|
|
18786
|
+
if (record.requireTraceParentSpan !== void 0) {
|
|
18787
|
+
out.requireTraceParentSpan = requireBoolean(
|
|
18788
|
+
record.requireTraceParentSpan,
|
|
18789
|
+
"checks.structure.requireTraceParentSpan"
|
|
18790
|
+
);
|
|
18791
|
+
}
|
|
18792
|
+
if (record.orphan !== void 0) out.orphan = requireBoolean(record.orphan, "checks.structure.orphan");
|
|
18793
|
+
if (record.cycle !== void 0) out.cycle = requireBoolean(record.cycle, "checks.structure.cycle");
|
|
18794
|
+
if (record.maxChildren !== void 0) {
|
|
18795
|
+
out.maxChildren = requireNonNegativeNumber(record.maxChildren, "checks.structure.maxChildren");
|
|
18796
|
+
}
|
|
18797
|
+
if (record.maxConcurrent !== void 0) {
|
|
18798
|
+
out.maxConcurrent = requireNonNegativeNumber(record.maxConcurrent, "checks.structure.maxConcurrent");
|
|
18799
|
+
}
|
|
18800
|
+
return out;
|
|
18801
|
+
}
|
|
18802
|
+
function parseSafetySection(value) {
|
|
18803
|
+
const record = requireObject(value, "checks.safety");
|
|
18804
|
+
rejectUnknownKeys(record, SAFETY_KEYS, "checks.safety");
|
|
18805
|
+
const out = {};
|
|
18806
|
+
if (record.redaction !== void 0) out.redaction = requireBoolean(record.redaction, "checks.safety.redaction");
|
|
18807
|
+
if (record.rawContent !== void 0) out.rawContent = requireBoolean(record.rawContent, "checks.safety.rawContent");
|
|
18808
|
+
if (record.secretPattern !== void 0) {
|
|
18809
|
+
out.secretPattern = requireBoolean(record.secretPattern, "checks.safety.secretPattern");
|
|
18810
|
+
}
|
|
18811
|
+
if (record.maxStringLength !== void 0) {
|
|
18812
|
+
out.maxStringLength = requireNonNegativeNumber(record.maxStringLength, "checks.safety.maxStringLength");
|
|
18813
|
+
}
|
|
18814
|
+
if (record.maxArrayLength !== void 0) {
|
|
18815
|
+
out.maxArrayLength = requireNonNegativeNumber(record.maxArrayLength, "checks.safety.maxArrayLength");
|
|
18816
|
+
}
|
|
18817
|
+
if (record.maxObjectKeys !== void 0) {
|
|
18818
|
+
out.maxObjectKeys = requireNonNegativeNumber(record.maxObjectKeys, "checks.safety.maxObjectKeys");
|
|
18819
|
+
}
|
|
18820
|
+
if (record.maxSerializedBytes !== void 0) {
|
|
18821
|
+
out.maxSerializedBytes = requireNonNegativeNumber(
|
|
18822
|
+
record.maxSerializedBytes,
|
|
18823
|
+
"checks.safety.maxSerializedBytes"
|
|
18824
|
+
);
|
|
18825
|
+
}
|
|
18826
|
+
if (record.maxFindings !== void 0) {
|
|
18827
|
+
out.maxFindings = requireNonNegativeNumber(record.maxFindings, "checks.safety.maxFindings");
|
|
18828
|
+
}
|
|
18829
|
+
return out;
|
|
18830
|
+
}
|
|
18831
|
+
function sectionHasEffect(section) {
|
|
18832
|
+
if (section === void 0) return false;
|
|
18833
|
+
return Object.keys(section).length > 0;
|
|
18834
|
+
}
|
|
18835
|
+
function checkConfigHasEffect(config) {
|
|
18836
|
+
const checks2 = config.checks;
|
|
18837
|
+
if (checks2 === void 0) return false;
|
|
18838
|
+
if ((checks2.select?.length ?? 0) > 0) return true;
|
|
18839
|
+
if (sectionHasEffect(checks2.run)) return true;
|
|
18840
|
+
if (sectionHasEffect(checks2.tool)) return true;
|
|
18841
|
+
if (sectionHasEffect(checks2.llm)) return true;
|
|
18842
|
+
if (sectionHasEffect(checks2.structure)) return true;
|
|
18843
|
+
if (sectionHasEffect(checks2.safety)) return true;
|
|
18844
|
+
return false;
|
|
18845
|
+
}
|
|
18846
|
+
function parseCheckConfig(value) {
|
|
18507
18847
|
if (value === void 0 || value === null) return {};
|
|
18508
18848
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
18509
|
-
throw new
|
|
18849
|
+
throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "Config must export an object.");
|
|
18510
18850
|
}
|
|
18511
|
-
|
|
18851
|
+
const root = value;
|
|
18852
|
+
if ("contract" in root) {
|
|
18853
|
+
throw new CheckConfigError(
|
|
18854
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
18855
|
+
'Top-level "contract" is not supported by `agent-inspect check --config`. Use the TraceContract TypeScript API (`defineTraceContract` / `evaluateTraceContract` from `agent-inspect/checks`), or express tool/run/llm rules under `checks`.'
|
|
18856
|
+
);
|
|
18857
|
+
}
|
|
18858
|
+
const rootKeys = Object.keys(root);
|
|
18859
|
+
for (const key of rootKeys) {
|
|
18860
|
+
if (key === "checks") continue;
|
|
18861
|
+
const suggestion = closestKey(key, ["checks"]);
|
|
18862
|
+
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
18863
|
+
throw new CheckConfigError(
|
|
18864
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
18865
|
+
`Unknown top-level check config key "${key}". Allowed: checks.${hint}`
|
|
18866
|
+
);
|
|
18867
|
+
}
|
|
18868
|
+
if (!("checks" in root)) return {};
|
|
18869
|
+
const checksRecord = requireObject(root.checks, "checks");
|
|
18870
|
+
rejectUnknownKeys(checksRecord, CHECKS_KEYS, "checks");
|
|
18871
|
+
const checks2 = {};
|
|
18872
|
+
if (checksRecord.select !== void 0) {
|
|
18873
|
+
checks2.select = requireStringArray(checksRecord.select, "checks.select");
|
|
18874
|
+
}
|
|
18875
|
+
if (checksRecord.run !== void 0) checks2.run = parseRunSection(checksRecord.run);
|
|
18876
|
+
if (checksRecord.tool !== void 0) checks2.tool = parseToolSection(checksRecord.tool);
|
|
18877
|
+
if (checksRecord.llm !== void 0) checks2.llm = parseLlmSection(checksRecord.llm);
|
|
18878
|
+
if (checksRecord.structure !== void 0) {
|
|
18879
|
+
checks2.structure = parseStructureSection(checksRecord.structure);
|
|
18880
|
+
}
|
|
18881
|
+
if (checksRecord.safety !== void 0) checks2.safety = parseSafetySection(checksRecord.safety);
|
|
18882
|
+
return { checks: checks2 };
|
|
18512
18883
|
}
|
|
18513
18884
|
async function loadConfig(configPath) {
|
|
18514
18885
|
if (configPath === void 0) return {};
|
|
18515
18886
|
const extension = path32__default.default.extname(configPath);
|
|
18516
18887
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
18517
|
-
throw new
|
|
18888
|
+
throw new CheckConfigError(
|
|
18889
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
18518
18890
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
18519
18891
|
);
|
|
18520
18892
|
}
|
|
18521
18893
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
18522
|
-
throw new
|
|
18894
|
+
throw new CheckConfigError(
|
|
18895
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
18896
|
+
"Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
|
|
18897
|
+
);
|
|
18523
18898
|
}
|
|
18524
18899
|
const absolute = path32__default.default.resolve(configPath);
|
|
18525
|
-
|
|
18526
|
-
|
|
18527
|
-
|
|
18900
|
+
try {
|
|
18901
|
+
if (extension === ".json") {
|
|
18902
|
+
const raw = await promises.readFile(absolute, "utf-8");
|
|
18903
|
+
return parseCheckConfig(JSON.parse(raw));
|
|
18904
|
+
}
|
|
18905
|
+
const mod = await import(url.pathToFileURL(absolute).href);
|
|
18906
|
+
return parseCheckConfig("default" in mod ? mod.default : mod);
|
|
18907
|
+
} catch (error) {
|
|
18908
|
+
if (error instanceof CheckConfigError) throw error;
|
|
18909
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18910
|
+
throw new CheckConfigError(
|
|
18911
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
18912
|
+
`Failed to load check config: ${message}`
|
|
18913
|
+
);
|
|
18528
18914
|
}
|
|
18529
|
-
const mod = await import(url.pathToFileURL(absolute).href);
|
|
18530
|
-
return asConfig("default" in mod ? mod.default : mod);
|
|
18531
18915
|
}
|
|
18532
18916
|
function normalizeConfig(config) {
|
|
18533
18917
|
if (config.checks === void 0) return {};
|
|
18534
18918
|
if (typeof config.checks !== "object" || Array.isArray(config.checks)) {
|
|
18535
|
-
throw new
|
|
18919
|
+
throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "checks config must be an object.");
|
|
18536
18920
|
}
|
|
18537
18921
|
return config.checks;
|
|
18538
18922
|
}
|
|
@@ -18610,7 +18994,7 @@ function buildRules(config, options, presetSelect = []) {
|
|
|
18610
18994
|
}
|
|
18611
18995
|
throw new Error(`unsupported status "${value}"`);
|
|
18612
18996
|
});
|
|
18613
|
-
rules.push(createObservedOutcomeRule({ failOn: statuses }));
|
|
18997
|
+
rules.push(createObservedOutcomeRule({ failOn: statuses, requireAny: true }));
|
|
18614
18998
|
} catch (error) {
|
|
18615
18999
|
const message = error instanceof Error ? error.message : String(error);
|
|
18616
19000
|
diagnostics.push(
|
|
@@ -18682,7 +19066,7 @@ function exitCodeFor(result) {
|
|
|
18682
19066
|
return 3;
|
|
18683
19067
|
}
|
|
18684
19068
|
if (codes.some(
|
|
18685
|
-
(code) => code === "AI_CHECK_INVALID_ARGUMENTS" || code === "AI_CHECK_INVALID_CONFIG" || code === "AI_CHECK_CONFIG_LOAD_FAILED" || code === "AI_CHECK_RUN_SELECTION_REQUIRED"
|
|
19069
|
+
(code) => code === "AI_CHECK_INVALID_ARGUMENTS" || code === "AI_CHECK_INVALID_CONFIG" || code === "AI_CHECK_CONFIG_LOAD_FAILED" || code === "AI_CHECK_CONFIG_UNKNOWN_KEY" || code === "AI_CHECK_CONFIG_INVALID_VALUE" || code === "AI_CHECK_CONFIG_NO_EFFECTIVE_RULES" || code === "AI_CHECK_NO_RULES_EVALUATED" || code === "AI_CHECK_RUN_SELECTION_REQUIRED"
|
|
18686
19070
|
)) {
|
|
18687
19071
|
return 2;
|
|
18688
19072
|
}
|
|
@@ -18749,6 +19133,7 @@ function printHuman(result, options = {}) {
|
|
|
18749
19133
|
console.log(
|
|
18750
19134
|
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
18751
19135
|
);
|
|
19136
|
+
console.log(`Rules evaluated: ${result.summary.rulesEvaluated ?? result.ruleExecutions?.length ?? 0}`);
|
|
18752
19137
|
for (const diagnostic7 of result.diagnostics) {
|
|
18753
19138
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
18754
19139
|
}
|
|
@@ -18780,6 +19165,16 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18780
19165
|
const useSessionScope = Boolean(sessionId || groupId);
|
|
18781
19166
|
try {
|
|
18782
19167
|
let config = await loadConfig(options.config);
|
|
19168
|
+
if (options.config !== void 0 && !checkConfigHasEffect(config)) {
|
|
19169
|
+
result = errorResult2(
|
|
19170
|
+
"AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
|
|
19171
|
+
"Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
|
|
19172
|
+
);
|
|
19173
|
+
if (options.json) printJson(result);
|
|
19174
|
+
else printHuman(result, options);
|
|
19175
|
+
process.exitCode = exitCodeFor(result);
|
|
19176
|
+
return;
|
|
19177
|
+
}
|
|
18783
19178
|
let effectiveOptions = options;
|
|
18784
19179
|
const resolved = resolvePreset(options.preset, {
|
|
18785
19180
|
hasToolRules: hasToolRulesConfigured(config, options)
|
|
@@ -18899,12 +19294,13 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18899
19294
|
}
|
|
18900
19295
|
} catch (error) {
|
|
18901
19296
|
if (phase === "config") {
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
message
|
|
18907
|
-
|
|
19297
|
+
if (error instanceof CheckConfigError) {
|
|
19298
|
+
result = errorResult2(error.code, error.message);
|
|
19299
|
+
} else {
|
|
19300
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
19301
|
+
const code = message.startsWith("--") || message.includes("Unknown --preset") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
|
|
19302
|
+
result = errorResult2(code, message);
|
|
19303
|
+
}
|
|
18908
19304
|
} else {
|
|
18909
19305
|
result = readErrorResult(error);
|
|
18910
19306
|
}
|
|
@@ -19835,6 +20231,42 @@ function startViewerServer(options = {}) {
|
|
|
19835
20231
|
});
|
|
19836
20232
|
});
|
|
19837
20233
|
}
|
|
20234
|
+
function openInDefaultBrowser(target) {
|
|
20235
|
+
const platform = process.platform;
|
|
20236
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
20237
|
+
const args = platform === "win32" ? ["/c", "start", "", target] : [target];
|
|
20238
|
+
return new Promise((resolve) => {
|
|
20239
|
+
try {
|
|
20240
|
+
const child = child_process.spawn(command, args, {
|
|
20241
|
+
detached: true,
|
|
20242
|
+
stdio: "ignore",
|
|
20243
|
+
windowsHide: platform === "win32"
|
|
20244
|
+
});
|
|
20245
|
+
child.once("spawn", () => {
|
|
20246
|
+
try {
|
|
20247
|
+
child.unref();
|
|
20248
|
+
resolve({ ok: true });
|
|
20249
|
+
} catch (error) {
|
|
20250
|
+
resolve({
|
|
20251
|
+
ok: false,
|
|
20252
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
20253
|
+
});
|
|
20254
|
+
}
|
|
20255
|
+
});
|
|
20256
|
+
child.once("error", (error) => {
|
|
20257
|
+
resolve({
|
|
20258
|
+
ok: false,
|
|
20259
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
20260
|
+
});
|
|
20261
|
+
});
|
|
20262
|
+
} catch (error) {
|
|
20263
|
+
resolve({
|
|
20264
|
+
ok: false,
|
|
20265
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
20266
|
+
});
|
|
20267
|
+
}
|
|
20268
|
+
});
|
|
20269
|
+
}
|
|
19838
20270
|
|
|
19839
20271
|
// packages/cli/src/serve.ts
|
|
19840
20272
|
function parsePort(value) {
|
|
@@ -19864,9 +20296,11 @@ async function serveCommand(options = {}) {
|
|
|
19864
20296
|
if (options.open === true && host !== "127.0.0.1" && host !== "localhost") {
|
|
19865
20297
|
console.warn("Skipping browser open for non-local host binding.");
|
|
19866
20298
|
} else if (options.open === true) {
|
|
19867
|
-
const
|
|
19868
|
-
|
|
19869
|
-
|
|
20299
|
+
const opened = await openInDefaultBrowser(info.url);
|
|
20300
|
+
if (!opened.ok) {
|
|
20301
|
+
console.warn("Viewer started, but the browser could not be opened automatically.");
|
|
20302
|
+
console.warn(`Open manually: ${info.url}`);
|
|
20303
|
+
}
|
|
19870
20304
|
}
|
|
19871
20305
|
await new Promise(() => {
|
|
19872
20306
|
});
|
|
@@ -20025,9 +20459,11 @@ async function studioCommand(options = {}) {
|
|
|
20025
20459
|
if (options.open === true && info.host !== "127.0.0.1" && info.host !== "localhost") {
|
|
20026
20460
|
console.warn("Skipping browser open for non-local host binding.");
|
|
20027
20461
|
} else if (options.open === true) {
|
|
20028
|
-
const
|
|
20029
|
-
|
|
20030
|
-
|
|
20462
|
+
const opened = await openInDefaultBrowser(info.url);
|
|
20463
|
+
if (!opened.ok) {
|
|
20464
|
+
console.warn("Studio started, but the browser could not be opened automatically.");
|
|
20465
|
+
console.warn(`Open manually: ${info.url}`);
|
|
20466
|
+
}
|
|
20031
20467
|
}
|
|
20032
20468
|
await new Promise(() => {
|
|
20033
20469
|
});
|
|
@@ -20786,7 +21222,7 @@ function asStringArray3(value, label) {
|
|
|
20786
21222
|
}
|
|
20787
21223
|
return value;
|
|
20788
21224
|
}
|
|
20789
|
-
function
|
|
21225
|
+
function asConfig(value) {
|
|
20790
21226
|
if (value === void 0 || value === null) return {};
|
|
20791
21227
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
20792
21228
|
throw new Error("Config must export an object.");
|
|
@@ -20807,10 +21243,10 @@ async function loadConfig2(configPath) {
|
|
|
20807
21243
|
const absolute = path32__default.default.resolve(configPath);
|
|
20808
21244
|
if (extension === ".json") {
|
|
20809
21245
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
20810
|
-
return
|
|
21246
|
+
return asConfig(JSON.parse(raw));
|
|
20811
21247
|
}
|
|
20812
21248
|
const mod = await import(url.pathToFileURL(absolute).href);
|
|
20813
|
-
return
|
|
21249
|
+
return asConfig("default" in mod ? mod.default : mod);
|
|
20814
21250
|
}
|
|
20815
21251
|
function normalizeConfig2(config) {
|
|
20816
21252
|
if (config.eval === void 0) return {};
|
|
@@ -22325,33 +22761,6 @@ async function resolveHtmlPath(root) {
|
|
|
22325
22761
|
`No evidence.html found under ${root}. Pass a bundle directory or .html path.`
|
|
22326
22762
|
);
|
|
22327
22763
|
}
|
|
22328
|
-
function openLocalFile(filePath) {
|
|
22329
|
-
const fileUrl = url.pathToFileURL(filePath).href;
|
|
22330
|
-
const platform = process.platform;
|
|
22331
|
-
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
22332
|
-
const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
22333
|
-
return new Promise((resolve) => {
|
|
22334
|
-
try {
|
|
22335
|
-
const child = child_process.spawn(command, args, {
|
|
22336
|
-
detached: true,
|
|
22337
|
-
stdio: "ignore"
|
|
22338
|
-
});
|
|
22339
|
-
child.on("error", (error) => {
|
|
22340
|
-
resolve({
|
|
22341
|
-
ok: false,
|
|
22342
|
-
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
22343
|
-
});
|
|
22344
|
-
});
|
|
22345
|
-
child.unref();
|
|
22346
|
-
resolve({ ok: true, detail: fileUrl });
|
|
22347
|
-
} catch (error) {
|
|
22348
|
-
resolve({
|
|
22349
|
-
ok: false,
|
|
22350
|
-
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
22351
|
-
});
|
|
22352
|
-
}
|
|
22353
|
-
});
|
|
22354
|
-
}
|
|
22355
22764
|
async function bundleOpenCommand(targetPath, options = {}) {
|
|
22356
22765
|
const root = path32__default.default.resolve(targetPath.trim() || ".");
|
|
22357
22766
|
try {
|
|
@@ -22421,23 +22830,24 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22421
22830
|
await promises.readFile(path32__default.default.join(path32__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
22422
22831
|
} catch {
|
|
22423
22832
|
}
|
|
22424
|
-
const
|
|
22833
|
+
const fileUrl = url.pathToFileURL(htmlPath).href;
|
|
22834
|
+
const opened = await openInDefaultBrowser(fileUrl);
|
|
22425
22835
|
if (options.json) {
|
|
22426
22836
|
console.log(
|
|
22427
22837
|
writeJson6({
|
|
22428
22838
|
ok: opened.ok,
|
|
22429
22839
|
path: htmlPath,
|
|
22430
22840
|
opened: opened.ok,
|
|
22431
|
-
detail: opened.detail
|
|
22841
|
+
detail: opened.ok ? fileUrl : `${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`
|
|
22432
22842
|
}).trimEnd()
|
|
22433
22843
|
);
|
|
22434
22844
|
} else if (opened.ok) {
|
|
22435
22845
|
console.log(`Opened local Evidence: ${htmlPath}`);
|
|
22436
|
-
console.log(`URL: ${
|
|
22846
|
+
console.log(`URL: ${fileUrl}`);
|
|
22437
22847
|
} else {
|
|
22438
22848
|
console.error(`[AgentInspect] Could not open browser automatically.`);
|
|
22439
22849
|
console.error(`Open this file locally: ${htmlPath}`);
|
|
22440
|
-
console.error(opened.detail);
|
|
22850
|
+
console.error(`${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`);
|
|
22441
22851
|
}
|
|
22442
22852
|
if (!opened.ok) {
|
|
22443
22853
|
process.exitCode = 0;
|
|
@@ -24378,9 +24788,15 @@ function normalizeMetrics2(raw) {
|
|
|
24378
24788
|
const parsed = parseCohortMetricList(raw);
|
|
24379
24789
|
if (parsed.length === 0) return void 0;
|
|
24380
24790
|
const allowed = new Set(COHORT_METRIC_IDS);
|
|
24381
|
-
|
|
24382
|
-
|
|
24383
|
-
|
|
24791
|
+
const invalid = parsed.filter((metric) => !allowed.has(metric));
|
|
24792
|
+
if (invalid.length > 0) {
|
|
24793
|
+
const valueLabel = invalid.length === 1 ? "value" : "values";
|
|
24794
|
+
const invalidList = invalid.map((metric) => `"${metric}"`).join(", ");
|
|
24795
|
+
throw new Error(
|
|
24796
|
+
`Unsupported cohort --metric ${valueLabel}: ${invalidList}. Valid metrics: ${COHORT_METRIC_IDS.join(", ")}.`
|
|
24797
|
+
);
|
|
24798
|
+
}
|
|
24799
|
+
return parsed;
|
|
24384
24800
|
}
|
|
24385
24801
|
async function writeArtifacts(result, outputDir) {
|
|
24386
24802
|
await promises.mkdir(outputDir, { recursive: true });
|
|
@@ -24401,6 +24817,7 @@ async function writeArtifacts(result, outputDir) {
|
|
|
24401
24817
|
}
|
|
24402
24818
|
async function cohortCommand(options = {}) {
|
|
24403
24819
|
try {
|
|
24820
|
+
const metrics = normalizeMetrics2(options.metric);
|
|
24404
24821
|
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
24405
24822
|
const { runs } = await loadSessionRuns(traceDir);
|
|
24406
24823
|
const result = await analyzeCohort(runs, {
|
|
@@ -24409,7 +24826,7 @@ async function cohortCommand(options = {}) {
|
|
|
24409
24826
|
candidate: options.candidate,
|
|
24410
24827
|
cohortKey: options.cohortKey,
|
|
24411
24828
|
groupBy: options.groupBy,
|
|
24412
|
-
metrics
|
|
24829
|
+
metrics
|
|
24413
24830
|
});
|
|
24414
24831
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
24415
24832
|
let artifacts;
|