agent-inspect 6.17.4 → 6.17.6
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/ADAPTERS.md +3 -3
- package/docs/API.md +13 -7
- package/docs/CLI.md +2 -0
- package/docs/LIMITATIONS.md +1 -0
- package/docs/TRACE-CONTRACTS.md +90 -0
- package/package.json +8 -5
- package/packages/cli/dist/{chunk-YX6RFLV5.mjs → chunk-GOHYSE7W.mjs} +86 -17
- package/packages/cli/dist/chunk-GOHYSE7W.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +522 -81
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +441 -69
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-X6SLMBNH.mjs → src-OYGG7QAZ.mjs} +3 -3
- package/packages/cli/dist/{src-X6SLMBNH.mjs.map → src-OYGG7QAZ.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +85 -16
- 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 +119 -26
- 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-HN377P23.mjs → chunk-DIZPIPY2.mjs} +121 -28
- 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-YX6RFLV5.mjs.map +0 -1
- package/packages/core/dist/chunk-HN377P23.mjs.map +0 -1
|
@@ -13,8 +13,9 @@ var readline = require('readline');
|
|
|
13
13
|
var url = require('url');
|
|
14
14
|
var module$1 = require('module');
|
|
15
15
|
var commander = require('commander');
|
|
16
|
-
var http = require('http');
|
|
17
16
|
var child_process = require('child_process');
|
|
17
|
+
var util = require('util');
|
|
18
|
+
var http = require('http');
|
|
18
19
|
|
|
19
20
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
20
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -3565,14 +3566,15 @@ var init_cohort = __esm({
|
|
|
3565
3566
|
|
|
3566
3567
|
// packages/core/src/sessions/checks.ts
|
|
3567
3568
|
function emptySummary() {
|
|
3568
|
-
return { passed: 0, failed: 0, warnings: 0, errors: 0 };
|
|
3569
|
+
return { passed: 0, failed: 0, warnings: 0, errors: 0, rulesEvaluated: 0 };
|
|
3569
3570
|
}
|
|
3570
3571
|
function mergeSummary(target, source) {
|
|
3571
3572
|
return {
|
|
3572
3573
|
passed: target.passed + source.passed,
|
|
3573
3574
|
failed: target.failed + source.failed,
|
|
3574
3575
|
warnings: target.warnings + source.warnings,
|
|
3575
|
-
errors: target.errors + source.errors
|
|
3576
|
+
errors: target.errors + source.errors,
|
|
3577
|
+
rulesEvaluated: target.rulesEvaluated + source.rulesEvaluated
|
|
3576
3578
|
};
|
|
3577
3579
|
}
|
|
3578
3580
|
function sessionDiagnostic(code, message) {
|
|
@@ -3596,6 +3598,7 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3596
3598
|
`${scope.scopeKind} not found: ${scope.scopeLabel}`
|
|
3597
3599
|
)
|
|
3598
3600
|
],
|
|
3601
|
+
ruleExecutions: [],
|
|
3599
3602
|
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
3600
3603
|
};
|
|
3601
3604
|
}
|
|
@@ -3616,17 +3619,20 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3616
3619
|
`No readable traces in ${scope.scopeKind}: ${scope.scopeLabel}`
|
|
3617
3620
|
)
|
|
3618
3621
|
],
|
|
3622
|
+
ruleExecutions: [],
|
|
3619
3623
|
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
3620
3624
|
};
|
|
3621
3625
|
}
|
|
3622
3626
|
let summary = emptySummary();
|
|
3623
3627
|
const findings = [];
|
|
3624
3628
|
const diagnostics = [];
|
|
3629
|
+
const ruleExecutions = [];
|
|
3625
3630
|
const runResults = [];
|
|
3626
3631
|
for (const result of perRun) {
|
|
3627
3632
|
summary = mergeSummary(summary, result.summary);
|
|
3628
3633
|
findings.push(...result.findings);
|
|
3629
3634
|
diagnostics.push(...result.diagnostics);
|
|
3635
|
+
ruleExecutions.push(...result.ruleExecutions ?? []);
|
|
3630
3636
|
if (result.runId) {
|
|
3631
3637
|
runResults.push({ runId: result.runId, status: result.status });
|
|
3632
3638
|
}
|
|
@@ -3639,6 +3645,11 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3639
3645
|
if (runCmp !== 0) return runCmp;
|
|
3640
3646
|
return a.ruleId.localeCompare(b.ruleId);
|
|
3641
3647
|
});
|
|
3648
|
+
ruleExecutions.sort((a, b) => {
|
|
3649
|
+
const runCmp = (a.runId ?? "").localeCompare(b.runId ?? "");
|
|
3650
|
+
if (runCmp !== 0) return runCmp;
|
|
3651
|
+
return a.ruleId.localeCompare(b.ruleId);
|
|
3652
|
+
});
|
|
3642
3653
|
const hasErrors = diagnostics.some((item) => item.severity === "error");
|
|
3643
3654
|
const status = hasErrors ? "error" : summary.failed > 0 ? "fail" : "pass";
|
|
3644
3655
|
return {
|
|
@@ -3652,6 +3663,7 @@ function aggregateSessionCheckResults(perRun, scope) {
|
|
|
3652
3663
|
summary,
|
|
3653
3664
|
findings,
|
|
3654
3665
|
diagnostics,
|
|
3666
|
+
ruleExecutions,
|
|
3655
3667
|
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
3656
3668
|
};
|
|
3657
3669
|
}
|
|
@@ -6857,10 +6869,11 @@ function emptySummary2() {
|
|
|
6857
6869
|
passed: 0,
|
|
6858
6870
|
failed: 0,
|
|
6859
6871
|
warnings: 0,
|
|
6860
|
-
errors: 0
|
|
6872
|
+
errors: 0,
|
|
6873
|
+
rulesEvaluated: 0
|
|
6861
6874
|
};
|
|
6862
6875
|
}
|
|
6863
|
-
function errorResult(input3, diagnostics, selectedRun) {
|
|
6876
|
+
function errorResult(input3, diagnostics, selectedRun, ruleExecutions = []) {
|
|
6864
6877
|
return {
|
|
6865
6878
|
ok: false,
|
|
6866
6879
|
status: "error",
|
|
@@ -6868,10 +6881,12 @@ function errorResult(input3, diagnostics, selectedRun) {
|
|
|
6868
6881
|
...selectedRun ? { runId: selectedRun.runId } : {},
|
|
6869
6882
|
summary: {
|
|
6870
6883
|
...emptySummary2(),
|
|
6871
|
-
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
6884
|
+
errors: diagnostics.filter((item) => item.severity === "error").length,
|
|
6885
|
+
rulesEvaluated: ruleExecutions.length
|
|
6872
6886
|
},
|
|
6873
6887
|
findings: [],
|
|
6874
|
-
diagnostics: [...diagnostics]
|
|
6888
|
+
diagnostics: [...diagnostics],
|
|
6889
|
+
ruleExecutions: [...ruleExecutions]
|
|
6875
6890
|
};
|
|
6876
6891
|
}
|
|
6877
6892
|
function flattenNodes(nodes) {
|
|
@@ -7027,7 +7042,7 @@ function normalizeFinding(rule, finding) {
|
|
|
7027
7042
|
...finding.action !== void 0 ? { action: finding.action } : {}
|
|
7028
7043
|
};
|
|
7029
7044
|
}
|
|
7030
|
-
function summarize(findings, diagnostics) {
|
|
7045
|
+
function summarize(findings, diagnostics, rulesEvaluated) {
|
|
7031
7046
|
return {
|
|
7032
7047
|
passed: findings.filter((finding) => finding.status === "pass").length,
|
|
7033
7048
|
failed: findings.filter(
|
|
@@ -7036,9 +7051,21 @@ function summarize(findings, diagnostics) {
|
|
|
7036
7051
|
warnings: findings.filter(
|
|
7037
7052
|
(finding) => finding.status === "warning" || finding.severity === "warning"
|
|
7038
7053
|
).length,
|
|
7039
|
-
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
7054
|
+
errors: diagnostics.filter((item) => item.severity === "error").length,
|
|
7055
|
+
rulesEvaluated
|
|
7040
7056
|
};
|
|
7041
7057
|
}
|
|
7058
|
+
function classifyRuleExecution(findings, threw) {
|
|
7059
|
+
if (findings.some((finding) => finding.status === "fail" && finding.severity === "error")) {
|
|
7060
|
+
return "fail";
|
|
7061
|
+
}
|
|
7062
|
+
if (findings.some(
|
|
7063
|
+
(finding) => finding.status === "warning" || finding.severity === "warning"
|
|
7064
|
+
)) {
|
|
7065
|
+
return "warning";
|
|
7066
|
+
}
|
|
7067
|
+
return "pass";
|
|
7068
|
+
}
|
|
7042
7069
|
function stringAttr(event, keys) {
|
|
7043
7070
|
for (const key of keys) {
|
|
7044
7071
|
const value = event.attributes?.[key];
|
|
@@ -7135,6 +7162,9 @@ function finishedEvents(context, kind) {
|
|
|
7135
7162
|
(event) => (kind === void 0 || event.kind === kind) && event.status !== "running"
|
|
7136
7163
|
);
|
|
7137
7164
|
}
|
|
7165
|
+
function toolInvocationEvents(context) {
|
|
7166
|
+
return semanticEvents(context).filter((event) => event.kind === "TOOL");
|
|
7167
|
+
}
|
|
7138
7168
|
function isRecord8(value) {
|
|
7139
7169
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7140
7170
|
}
|
|
@@ -7535,7 +7565,7 @@ function createToolUsageRule(options) {
|
|
|
7535
7565
|
category: "tool",
|
|
7536
7566
|
defaultSeverity: "error",
|
|
7537
7567
|
evaluate(context) {
|
|
7538
|
-
const tools =
|
|
7568
|
+
const tools = toolInvocationEvents(context);
|
|
7539
7569
|
const names = tools.map(toolName);
|
|
7540
7570
|
const nameSet = new Set(names);
|
|
7541
7571
|
const findings = [];
|
|
@@ -8185,12 +8215,24 @@ function createBaselineRegressionRule(options) {
|
|
|
8185
8215
|
}
|
|
8186
8216
|
function createObservedOutcomeRule(options = {}) {
|
|
8187
8217
|
const failOn = options.failOn ?? ["failed"];
|
|
8218
|
+
const requireAny = options.requireAny === true;
|
|
8188
8219
|
return {
|
|
8189
8220
|
id: "outcome.status",
|
|
8190
8221
|
category: "run",
|
|
8191
8222
|
defaultSeverity: "error",
|
|
8192
8223
|
evaluate(context) {
|
|
8193
8224
|
const outcomes = extractOutcomesFromPersistedEvents(context.events);
|
|
8225
|
+
if (requireAny && outcomes.length === 0) {
|
|
8226
|
+
return [
|
|
8227
|
+
failFinding(
|
|
8228
|
+
"outcome.status",
|
|
8229
|
+
"Expected at least one observed outcome.",
|
|
8230
|
+
runEvidence(context.selectedRun),
|
|
8231
|
+
{ requireAny: true, expected: "at least one observed outcome" },
|
|
8232
|
+
{ code: "outcome.missing", actual: 0 }
|
|
8233
|
+
)
|
|
8234
|
+
];
|
|
8235
|
+
}
|
|
8194
8236
|
const matching = outcomesMatchingStatus(outcomes, failOn);
|
|
8195
8237
|
if (matching.length === 0) return [];
|
|
8196
8238
|
return [
|
|
@@ -8226,6 +8268,18 @@ function runTraceChecks(input3, options = {}) {
|
|
|
8226
8268
|
if (rules.diagnostics.length > 0) {
|
|
8227
8269
|
return errorResult(input3, rules.diagnostics, selected.run);
|
|
8228
8270
|
}
|
|
8271
|
+
if (rules.rules.length === 0) {
|
|
8272
|
+
return errorResult(
|
|
8273
|
+
input3,
|
|
8274
|
+
[
|
|
8275
|
+
diagnostic3(
|
|
8276
|
+
"AI_CHECK_NO_RULES_EVALUATED",
|
|
8277
|
+
"No trace check rules were evaluated. Configure at least one rule, contract, or CLI check option."
|
|
8278
|
+
)
|
|
8279
|
+
],
|
|
8280
|
+
selected.run
|
|
8281
|
+
);
|
|
8282
|
+
}
|
|
8229
8283
|
const facts = buildFacts2(input3, selected.run);
|
|
8230
8284
|
const context = {
|
|
8231
8285
|
...facts,
|
|
@@ -8234,22 +8288,38 @@ function runTraceChecks(input3, options = {}) {
|
|
|
8234
8288
|
};
|
|
8235
8289
|
const diagnostics = [];
|
|
8236
8290
|
const findings = [];
|
|
8291
|
+
const ruleExecutions = [];
|
|
8237
8292
|
for (const rule of rules.rules) {
|
|
8238
8293
|
try {
|
|
8239
|
-
|
|
8294
|
+
const ruleFindings = rule.evaluate(context).map((finding) => normalizeFinding(rule, finding));
|
|
8295
|
+
findings.push(...ruleFindings);
|
|
8296
|
+
ruleExecutions.push({
|
|
8297
|
+
ruleId: rule.id,
|
|
8298
|
+
category: rule.category,
|
|
8299
|
+
status: classifyRuleExecution(ruleFindings, false),
|
|
8300
|
+
findingCount: ruleFindings.length,
|
|
8301
|
+
...selected.run ? { runId: selected.run.runId } : {}
|
|
8302
|
+
});
|
|
8240
8303
|
} catch (error) {
|
|
8241
8304
|
const message = error instanceof Error ? error.message : String(error);
|
|
8242
8305
|
diagnostics.push(
|
|
8243
8306
|
diagnostic3("AI_CHECK_INTERNAL_ERROR", `Rule ${rule.id} failed: ${message}`, rule.id)
|
|
8244
8307
|
);
|
|
8308
|
+
ruleExecutions.push({
|
|
8309
|
+
ruleId: rule.id,
|
|
8310
|
+
category: rule.category,
|
|
8311
|
+
status: "error",
|
|
8312
|
+
findingCount: 0,
|
|
8313
|
+
...selected.run ? { runId: selected.run.runId } : {}
|
|
8314
|
+
});
|
|
8245
8315
|
}
|
|
8246
8316
|
}
|
|
8247
8317
|
if (diagnostics.length > 0) {
|
|
8248
|
-
return errorResult(input3, diagnostics, selected.run);
|
|
8318
|
+
return errorResult(input3, diagnostics, selected.run, ruleExecutions);
|
|
8249
8319
|
}
|
|
8250
8320
|
const eventById = new Map(input3.read.events.map((event) => [event.eventId, event]));
|
|
8251
8321
|
const sortedFindings = findings.sort(compareFindings(eventById));
|
|
8252
|
-
const summary = summarize(sortedFindings, diagnostics);
|
|
8322
|
+
const summary = summarize(sortedFindings, diagnostics, ruleExecutions.length);
|
|
8253
8323
|
const status = summary.failed > 0 ? "fail" : "pass";
|
|
8254
8324
|
return {
|
|
8255
8325
|
ok: status === "pass",
|
|
@@ -8258,7 +8328,8 @@ function runTraceChecks(input3, options = {}) {
|
|
|
8258
8328
|
...selected.run ? { runId: selected.run.runId } : {},
|
|
8259
8329
|
summary,
|
|
8260
8330
|
findings: sortedFindings,
|
|
8261
|
-
diagnostics
|
|
8331
|
+
diagnostics,
|
|
8332
|
+
ruleExecutions
|
|
8262
8333
|
};
|
|
8263
8334
|
}
|
|
8264
8335
|
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;
|
|
@@ -10707,8 +10778,7 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
10707
10778
|
status: "pass",
|
|
10708
10779
|
format: read.format,
|
|
10709
10780
|
findings: [],
|
|
10710
|
-
diagnostics: []
|
|
10711
|
-
};
|
|
10781
|
+
diagnostics: []};
|
|
10712
10782
|
const observationResult = validateExpectedObservations(suiteCase, read);
|
|
10713
10783
|
const diagnostics = [
|
|
10714
10784
|
...checkResult.diagnostics.map(
|
|
@@ -12511,7 +12581,7 @@ var init_src = __esm({
|
|
|
12511
12581
|
});
|
|
12512
12582
|
|
|
12513
12583
|
// package.json
|
|
12514
|
-
var version = "6.17.
|
|
12584
|
+
var version = "6.17.6";
|
|
12515
12585
|
|
|
12516
12586
|
// packages/cli/src/list.ts
|
|
12517
12587
|
init_advanced();
|
|
@@ -14080,6 +14150,11 @@ async function followFile(filePath, options, onLine, shouldStop) {
|
|
|
14080
14150
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14081
14151
|
throw new Error(`Failed to stat file: ${filePath} (${msg})`);
|
|
14082
14152
|
}
|
|
14153
|
+
if (next.size < pos) {
|
|
14154
|
+
pos = 0;
|
|
14155
|
+
carry = "";
|
|
14156
|
+
lineNumber = 0;
|
|
14157
|
+
}
|
|
14083
14158
|
if (next.size > pos) {
|
|
14084
14159
|
const fh = await promises.open(filePath, "r");
|
|
14085
14160
|
try {
|
|
@@ -17744,8 +17819,11 @@ function checkResultToEvidenceJson(result, runIds) {
|
|
|
17744
17819
|
status,
|
|
17745
17820
|
errors: result.summary.errors,
|
|
17746
17821
|
warnings: result.summary.warnings,
|
|
17747
|
-
findings: result.findings.length
|
|
17822
|
+
findings: result.findings.length,
|
|
17823
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0
|
|
17748
17824
|
})),
|
|
17825
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0,
|
|
17826
|
+
evaluatedRuleIds: (result.ruleExecutions ?? []).map((item) => item.ruleId),
|
|
17749
17827
|
findings: result.findings,
|
|
17750
17828
|
diagnostics: result.diagnostics
|
|
17751
17829
|
});
|
|
@@ -18370,13 +18448,16 @@ function mergeSafetyExtensions(result, read, options) {
|
|
|
18370
18448
|
passed,
|
|
18371
18449
|
failed,
|
|
18372
18450
|
warnings,
|
|
18373
|
-
errors: result.summary.errors
|
|
18451
|
+
errors: result.summary.errors,
|
|
18452
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0
|
|
18374
18453
|
},
|
|
18375
|
-
findings
|
|
18454
|
+
findings,
|
|
18455
|
+
ruleExecutions: result.ruleExecutions ?? []
|
|
18376
18456
|
};
|
|
18377
18457
|
}
|
|
18378
18458
|
|
|
18379
18459
|
// packages/cli/src/check.ts
|
|
18460
|
+
var execFileAsync = util.promisify(child_process.execFile);
|
|
18380
18461
|
var DEFAULT_SELECT = ["run.status"];
|
|
18381
18462
|
function uniqueSelectIds(ids) {
|
|
18382
18463
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -18492,10 +18573,12 @@ function errorResult2(code, message, format = "unknown") {
|
|
|
18492
18573
|
passed: 0,
|
|
18493
18574
|
failed: 0,
|
|
18494
18575
|
warnings: 0,
|
|
18495
|
-
errors: 1
|
|
18576
|
+
errors: 1,
|
|
18577
|
+
rulesEvaluated: 0
|
|
18496
18578
|
},
|
|
18497
18579
|
findings: [],
|
|
18498
|
-
diagnostics
|
|
18580
|
+
diagnostics,
|
|
18581
|
+
ruleExecutions: []
|
|
18499
18582
|
};
|
|
18500
18583
|
}
|
|
18501
18584
|
function parseNumber(value, label) {
|
|
@@ -18513,36 +18596,368 @@ function asStringArray2(value) {
|
|
|
18513
18596
|
}
|
|
18514
18597
|
return value;
|
|
18515
18598
|
}
|
|
18516
|
-
|
|
18599
|
+
var CHECKS_KEYS = /* @__PURE__ */ new Set(["select", "run", "tool", "llm", "structure", "safety"]);
|
|
18600
|
+
var RUN_KEYS = /* @__PURE__ */ new Set(["expected", "allowIncomplete", "maxDurationMs", "maxDepth"]);
|
|
18601
|
+
var TOOL_KEYS = /* @__PURE__ */ new Set(["required", "forbidden", "allowed", "minCount", "maxCount"]);
|
|
18602
|
+
var LLM_KEYS = /* @__PURE__ */ new Set([
|
|
18603
|
+
"allowedModels",
|
|
18604
|
+
"allowedProviders",
|
|
18605
|
+
"finishReasons",
|
|
18606
|
+
"maxCalls",
|
|
18607
|
+
"maxTotalTokens",
|
|
18608
|
+
"maxInputTokens",
|
|
18609
|
+
"maxOutputTokens",
|
|
18610
|
+
"maxCachedTokens"
|
|
18611
|
+
]);
|
|
18612
|
+
var STRUCTURE_KEYS = /* @__PURE__ */ new Set([
|
|
18613
|
+
"minConfidence",
|
|
18614
|
+
"requireParentBeforeChild",
|
|
18615
|
+
"requireTraceParentSpan",
|
|
18616
|
+
"orphan",
|
|
18617
|
+
"cycle",
|
|
18618
|
+
"maxChildren",
|
|
18619
|
+
"maxConcurrent"
|
|
18620
|
+
]);
|
|
18621
|
+
var SAFETY_KEYS = /* @__PURE__ */ new Set([
|
|
18622
|
+
"redaction",
|
|
18623
|
+
"rawContent",
|
|
18624
|
+
"secretPattern",
|
|
18625
|
+
"maxStringLength",
|
|
18626
|
+
"maxArrayLength",
|
|
18627
|
+
"maxObjectKeys",
|
|
18628
|
+
"maxSerializedBytes",
|
|
18629
|
+
"maxFindings"
|
|
18630
|
+
]);
|
|
18631
|
+
var RUN_EXPECTED = /* @__PURE__ */ new Set(["ok", "error", "running"]);
|
|
18632
|
+
var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["exact", "high", "medium", "low", "inferred"]);
|
|
18633
|
+
var CheckConfigError = class extends Error {
|
|
18634
|
+
code;
|
|
18635
|
+
constructor(code, message) {
|
|
18636
|
+
super(message);
|
|
18637
|
+
this.name = "CheckConfigError";
|
|
18638
|
+
this.code = code;
|
|
18639
|
+
}
|
|
18640
|
+
};
|
|
18641
|
+
function closestKey(unknown, known) {
|
|
18642
|
+
const lower = unknown.toLowerCase();
|
|
18643
|
+
let best;
|
|
18644
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
18645
|
+
for (const candidate of known) {
|
|
18646
|
+
if (candidate.toLowerCase() === lower) return candidate;
|
|
18647
|
+
let distance = Math.abs(candidate.length - unknown.length);
|
|
18648
|
+
const max = Math.max(candidate.length, unknown.length);
|
|
18649
|
+
for (let i = 0; i < Math.min(candidate.length, unknown.length); i += 1) {
|
|
18650
|
+
if (candidate[i].toLowerCase() !== unknown[i].toLowerCase()) distance += 1;
|
|
18651
|
+
}
|
|
18652
|
+
if (distance < bestDistance && distance <= Math.max(2, Math.floor(max / 3))) {
|
|
18653
|
+
bestDistance = distance;
|
|
18654
|
+
best = candidate;
|
|
18655
|
+
}
|
|
18656
|
+
}
|
|
18657
|
+
return best;
|
|
18658
|
+
}
|
|
18659
|
+
function rejectUnknownKeys(record, allowed, pathPrefix) {
|
|
18660
|
+
for (const key of Object.keys(record)) {
|
|
18661
|
+
if (allowed.has(key)) continue;
|
|
18662
|
+
const suggestion = closestKey(key, [...allowed]);
|
|
18663
|
+
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
18664
|
+
throw new CheckConfigError(
|
|
18665
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
18666
|
+
`Unknown check config key "${pathPrefix}.${key}".${hint}`
|
|
18667
|
+
);
|
|
18668
|
+
}
|
|
18669
|
+
}
|
|
18670
|
+
function requireObject(value, pathPrefix) {
|
|
18671
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
18672
|
+
throw new CheckConfigError(
|
|
18673
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18674
|
+
`${pathPrefix} must be an object.`
|
|
18675
|
+
);
|
|
18676
|
+
}
|
|
18677
|
+
return value;
|
|
18678
|
+
}
|
|
18679
|
+
function requireStringArray(value, pathPrefix) {
|
|
18680
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.trim() === "")) {
|
|
18681
|
+
throw new CheckConfigError(
|
|
18682
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18683
|
+
`${pathPrefix} must be an array of non-empty strings.`
|
|
18684
|
+
);
|
|
18685
|
+
}
|
|
18686
|
+
return value;
|
|
18687
|
+
}
|
|
18688
|
+
function requireNonNegativeNumber(value, pathPrefix) {
|
|
18689
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
18690
|
+
throw new CheckConfigError(
|
|
18691
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18692
|
+
`${pathPrefix} must be a finite non-negative number.`
|
|
18693
|
+
);
|
|
18694
|
+
}
|
|
18695
|
+
return value;
|
|
18696
|
+
}
|
|
18697
|
+
function requireBoolean(value, pathPrefix) {
|
|
18698
|
+
if (typeof value !== "boolean") {
|
|
18699
|
+
throw new CheckConfigError(
|
|
18700
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18701
|
+
`${pathPrefix} must be a boolean.`
|
|
18702
|
+
);
|
|
18703
|
+
}
|
|
18704
|
+
return value;
|
|
18705
|
+
}
|
|
18706
|
+
function parseRunSection(value) {
|
|
18707
|
+
const record = requireObject(value, "checks.run");
|
|
18708
|
+
rejectUnknownKeys(record, RUN_KEYS, "checks.run");
|
|
18709
|
+
const out = {};
|
|
18710
|
+
if (record.expected !== void 0) {
|
|
18711
|
+
if (typeof record.expected !== "string" || !RUN_EXPECTED.has(record.expected)) {
|
|
18712
|
+
throw new CheckConfigError(
|
|
18713
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18714
|
+
`checks.run.expected must be one of: ok, error, running.`
|
|
18715
|
+
);
|
|
18716
|
+
}
|
|
18717
|
+
out.expected = record.expected;
|
|
18718
|
+
}
|
|
18719
|
+
if (record.allowIncomplete !== void 0) {
|
|
18720
|
+
out.allowIncomplete = requireBoolean(record.allowIncomplete, "checks.run.allowIncomplete");
|
|
18721
|
+
}
|
|
18722
|
+
if (record.maxDurationMs !== void 0) {
|
|
18723
|
+
out.maxDurationMs = requireNonNegativeNumber(record.maxDurationMs, "checks.run.maxDurationMs");
|
|
18724
|
+
}
|
|
18725
|
+
if (record.maxDepth !== void 0) {
|
|
18726
|
+
out.maxDepth = requireNonNegativeNumber(record.maxDepth, "checks.run.maxDepth");
|
|
18727
|
+
}
|
|
18728
|
+
return out;
|
|
18729
|
+
}
|
|
18730
|
+
function parseToolSection(value) {
|
|
18731
|
+
const record = requireObject(value, "checks.tool");
|
|
18732
|
+
rejectUnknownKeys(record, TOOL_KEYS, "checks.tool");
|
|
18733
|
+
const out = {};
|
|
18734
|
+
if (record.required !== void 0) out.required = requireStringArray(record.required, "checks.tool.required");
|
|
18735
|
+
if (record.forbidden !== void 0) out.forbidden = requireStringArray(record.forbidden, "checks.tool.forbidden");
|
|
18736
|
+
if (record.allowed !== void 0) out.allowed = requireStringArray(record.allowed, "checks.tool.allowed");
|
|
18737
|
+
if (record.minCount !== void 0) out.minCount = requireNonNegativeNumber(record.minCount, "checks.tool.minCount");
|
|
18738
|
+
if (record.maxCount !== void 0) out.maxCount = requireNonNegativeNumber(record.maxCount, "checks.tool.maxCount");
|
|
18739
|
+
return out;
|
|
18740
|
+
}
|
|
18741
|
+
function parseLlmSection(value) {
|
|
18742
|
+
const record = requireObject(value, "checks.llm");
|
|
18743
|
+
rejectUnknownKeys(record, LLM_KEYS, "checks.llm");
|
|
18744
|
+
const out = {};
|
|
18745
|
+
if (record.allowedModels !== void 0) {
|
|
18746
|
+
out.allowedModels = requireStringArray(record.allowedModels, "checks.llm.allowedModels");
|
|
18747
|
+
}
|
|
18748
|
+
if (record.allowedProviders !== void 0) {
|
|
18749
|
+
out.allowedProviders = requireStringArray(record.allowedProviders, "checks.llm.allowedProviders");
|
|
18750
|
+
}
|
|
18751
|
+
if (record.finishReasons !== void 0) {
|
|
18752
|
+
out.finishReasons = requireStringArray(record.finishReasons, "checks.llm.finishReasons");
|
|
18753
|
+
}
|
|
18754
|
+
if (record.maxCalls !== void 0) out.maxCalls = requireNonNegativeNumber(record.maxCalls, "checks.llm.maxCalls");
|
|
18755
|
+
if (record.maxTotalTokens !== void 0) {
|
|
18756
|
+
out.maxTotalTokens = requireNonNegativeNumber(record.maxTotalTokens, "checks.llm.maxTotalTokens");
|
|
18757
|
+
}
|
|
18758
|
+
if (record.maxInputTokens !== void 0) {
|
|
18759
|
+
out.maxInputTokens = requireNonNegativeNumber(record.maxInputTokens, "checks.llm.maxInputTokens");
|
|
18760
|
+
}
|
|
18761
|
+
if (record.maxOutputTokens !== void 0) {
|
|
18762
|
+
out.maxOutputTokens = requireNonNegativeNumber(record.maxOutputTokens, "checks.llm.maxOutputTokens");
|
|
18763
|
+
}
|
|
18764
|
+
if (record.maxCachedTokens !== void 0) {
|
|
18765
|
+
out.maxCachedTokens = requireNonNegativeNumber(record.maxCachedTokens, "checks.llm.maxCachedTokens");
|
|
18766
|
+
}
|
|
18767
|
+
return out;
|
|
18768
|
+
}
|
|
18769
|
+
function parseStructureSection(value) {
|
|
18770
|
+
const record = requireObject(value, "checks.structure");
|
|
18771
|
+
rejectUnknownKeys(record, STRUCTURE_KEYS, "checks.structure");
|
|
18772
|
+
const out = {};
|
|
18773
|
+
if (record.minConfidence !== void 0) {
|
|
18774
|
+
if (typeof record.minConfidence !== "string" || !CONFIDENCE_VALUES.has(record.minConfidence)) {
|
|
18775
|
+
throw new CheckConfigError(
|
|
18776
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
18777
|
+
`checks.structure.minConfidence must be one of: exact, high, medium, low, inferred.`
|
|
18778
|
+
);
|
|
18779
|
+
}
|
|
18780
|
+
out.minConfidence = record.minConfidence;
|
|
18781
|
+
}
|
|
18782
|
+
if (record.requireParentBeforeChild !== void 0) {
|
|
18783
|
+
out.requireParentBeforeChild = requireBoolean(
|
|
18784
|
+
record.requireParentBeforeChild,
|
|
18785
|
+
"checks.structure.requireParentBeforeChild"
|
|
18786
|
+
);
|
|
18787
|
+
}
|
|
18788
|
+
if (record.requireTraceParentSpan !== void 0) {
|
|
18789
|
+
out.requireTraceParentSpan = requireBoolean(
|
|
18790
|
+
record.requireTraceParentSpan,
|
|
18791
|
+
"checks.structure.requireTraceParentSpan"
|
|
18792
|
+
);
|
|
18793
|
+
}
|
|
18794
|
+
if (record.orphan !== void 0) out.orphan = requireBoolean(record.orphan, "checks.structure.orphan");
|
|
18795
|
+
if (record.cycle !== void 0) out.cycle = requireBoolean(record.cycle, "checks.structure.cycle");
|
|
18796
|
+
if (record.maxChildren !== void 0) {
|
|
18797
|
+
out.maxChildren = requireNonNegativeNumber(record.maxChildren, "checks.structure.maxChildren");
|
|
18798
|
+
}
|
|
18799
|
+
if (record.maxConcurrent !== void 0) {
|
|
18800
|
+
out.maxConcurrent = requireNonNegativeNumber(record.maxConcurrent, "checks.structure.maxConcurrent");
|
|
18801
|
+
}
|
|
18802
|
+
return out;
|
|
18803
|
+
}
|
|
18804
|
+
function parseSafetySection(value) {
|
|
18805
|
+
const record = requireObject(value, "checks.safety");
|
|
18806
|
+
rejectUnknownKeys(record, SAFETY_KEYS, "checks.safety");
|
|
18807
|
+
const out = {};
|
|
18808
|
+
if (record.redaction !== void 0) out.redaction = requireBoolean(record.redaction, "checks.safety.redaction");
|
|
18809
|
+
if (record.rawContent !== void 0) out.rawContent = requireBoolean(record.rawContent, "checks.safety.rawContent");
|
|
18810
|
+
if (record.secretPattern !== void 0) {
|
|
18811
|
+
out.secretPattern = requireBoolean(record.secretPattern, "checks.safety.secretPattern");
|
|
18812
|
+
}
|
|
18813
|
+
if (record.maxStringLength !== void 0) {
|
|
18814
|
+
out.maxStringLength = requireNonNegativeNumber(record.maxStringLength, "checks.safety.maxStringLength");
|
|
18815
|
+
}
|
|
18816
|
+
if (record.maxArrayLength !== void 0) {
|
|
18817
|
+
out.maxArrayLength = requireNonNegativeNumber(record.maxArrayLength, "checks.safety.maxArrayLength");
|
|
18818
|
+
}
|
|
18819
|
+
if (record.maxObjectKeys !== void 0) {
|
|
18820
|
+
out.maxObjectKeys = requireNonNegativeNumber(record.maxObjectKeys, "checks.safety.maxObjectKeys");
|
|
18821
|
+
}
|
|
18822
|
+
if (record.maxSerializedBytes !== void 0) {
|
|
18823
|
+
out.maxSerializedBytes = requireNonNegativeNumber(
|
|
18824
|
+
record.maxSerializedBytes,
|
|
18825
|
+
"checks.safety.maxSerializedBytes"
|
|
18826
|
+
);
|
|
18827
|
+
}
|
|
18828
|
+
if (record.maxFindings !== void 0) {
|
|
18829
|
+
out.maxFindings = requireNonNegativeNumber(record.maxFindings, "checks.safety.maxFindings");
|
|
18830
|
+
}
|
|
18831
|
+
return out;
|
|
18832
|
+
}
|
|
18833
|
+
function sectionHasEffect(section) {
|
|
18834
|
+
if (section === void 0) return false;
|
|
18835
|
+
return Object.keys(section).length > 0;
|
|
18836
|
+
}
|
|
18837
|
+
function checkConfigHasEffect(config) {
|
|
18838
|
+
const checks2 = config.checks;
|
|
18839
|
+
if (checks2 === void 0) return false;
|
|
18840
|
+
if ((checks2.select?.length ?? 0) > 0) return true;
|
|
18841
|
+
if (sectionHasEffect(checks2.run)) return true;
|
|
18842
|
+
if (sectionHasEffect(checks2.tool)) return true;
|
|
18843
|
+
if (sectionHasEffect(checks2.llm)) return true;
|
|
18844
|
+
if (sectionHasEffect(checks2.structure)) return true;
|
|
18845
|
+
if (sectionHasEffect(checks2.safety)) return true;
|
|
18846
|
+
return false;
|
|
18847
|
+
}
|
|
18848
|
+
function parseCheckConfig(value) {
|
|
18517
18849
|
if (value === void 0 || value === null) return {};
|
|
18518
18850
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
18519
|
-
throw new
|
|
18851
|
+
throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "Config must export an object.");
|
|
18520
18852
|
}
|
|
18521
|
-
|
|
18853
|
+
const root = value;
|
|
18854
|
+
if ("contract" in root) {
|
|
18855
|
+
throw new CheckConfigError(
|
|
18856
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
18857
|
+
'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`.'
|
|
18858
|
+
);
|
|
18859
|
+
}
|
|
18860
|
+
const rootKeys = Object.keys(root);
|
|
18861
|
+
for (const key of rootKeys) {
|
|
18862
|
+
if (key === "checks") continue;
|
|
18863
|
+
const suggestion = closestKey(key, ["checks"]);
|
|
18864
|
+
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
18865
|
+
throw new CheckConfigError(
|
|
18866
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
18867
|
+
`Unknown top-level check config key "${key}". Allowed: checks.${hint}`
|
|
18868
|
+
);
|
|
18869
|
+
}
|
|
18870
|
+
if (!("checks" in root)) return {};
|
|
18871
|
+
const checksRecord = requireObject(root.checks, "checks");
|
|
18872
|
+
rejectUnknownKeys(checksRecord, CHECKS_KEYS, "checks");
|
|
18873
|
+
const checks2 = {};
|
|
18874
|
+
if (checksRecord.select !== void 0) {
|
|
18875
|
+
checks2.select = requireStringArray(checksRecord.select, "checks.select");
|
|
18876
|
+
}
|
|
18877
|
+
if (checksRecord.run !== void 0) checks2.run = parseRunSection(checksRecord.run);
|
|
18878
|
+
if (checksRecord.tool !== void 0) checks2.tool = parseToolSection(checksRecord.tool);
|
|
18879
|
+
if (checksRecord.llm !== void 0) checks2.llm = parseLlmSection(checksRecord.llm);
|
|
18880
|
+
if (checksRecord.structure !== void 0) {
|
|
18881
|
+
checks2.structure = parseStructureSection(checksRecord.structure);
|
|
18882
|
+
}
|
|
18883
|
+
if (checksRecord.safety !== void 0) checks2.safety = parseSafetySection(checksRecord.safety);
|
|
18884
|
+
return { checks: checks2 };
|
|
18522
18885
|
}
|
|
18523
18886
|
async function loadConfig(configPath) {
|
|
18524
18887
|
if (configPath === void 0) return {};
|
|
18525
18888
|
const extension = path32__default.default.extname(configPath);
|
|
18526
18889
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
18527
|
-
throw new
|
|
18890
|
+
throw new CheckConfigError(
|
|
18891
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
18528
18892
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
18529
18893
|
);
|
|
18530
18894
|
}
|
|
18531
18895
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
18532
|
-
throw new
|
|
18896
|
+
throw new CheckConfigError(
|
|
18897
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
18898
|
+
"Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
|
|
18899
|
+
);
|
|
18533
18900
|
}
|
|
18534
18901
|
const absolute = path32__default.default.resolve(configPath);
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
|
|
18902
|
+
try {
|
|
18903
|
+
if (extension === ".json") {
|
|
18904
|
+
const raw = await promises.readFile(absolute, "utf-8");
|
|
18905
|
+
return parseCheckConfig(JSON.parse(raw));
|
|
18906
|
+
}
|
|
18907
|
+
return parseCheckConfig(await importJsCheckConfig(absolute));
|
|
18908
|
+
} catch (error) {
|
|
18909
|
+
if (error instanceof CheckConfigError) throw error;
|
|
18910
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18911
|
+
throw new CheckConfigError(
|
|
18912
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
18913
|
+
`Failed to load check config: ${message}`
|
|
18914
|
+
);
|
|
18915
|
+
}
|
|
18916
|
+
}
|
|
18917
|
+
async function importJsCheckConfig(absolute) {
|
|
18918
|
+
const href = url.pathToFileURL(absolute).href;
|
|
18919
|
+
if (!process.env.VITEST) {
|
|
18920
|
+
const mod = await import(
|
|
18921
|
+
/* @vite-ignore */
|
|
18922
|
+
href
|
|
18923
|
+
);
|
|
18924
|
+
return "default" in mod ? mod.default : mod;
|
|
18925
|
+
}
|
|
18926
|
+
const script = `
|
|
18927
|
+
const mod = await import(${JSON.stringify(href)});
|
|
18928
|
+
const value = "default" in mod ? mod.default : mod;
|
|
18929
|
+
process.stdout.write(JSON.stringify({ ok: true, value }));
|
|
18930
|
+
`;
|
|
18931
|
+
const env2 = { ...process.env };
|
|
18932
|
+
delete env2.NODE_OPTIONS;
|
|
18933
|
+
delete env2.VITEST;
|
|
18934
|
+
delete env2.VITEST_WORKER_ID;
|
|
18935
|
+
const { stdout, stderr } = await execFileAsync(
|
|
18936
|
+
process.execPath,
|
|
18937
|
+
["--input-type=module", "--eval", script],
|
|
18938
|
+
{
|
|
18939
|
+
encoding: "utf8",
|
|
18940
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
18941
|
+
env: env2
|
|
18942
|
+
}
|
|
18943
|
+
);
|
|
18944
|
+
try {
|
|
18945
|
+
const parsed = JSON.parse(stdout);
|
|
18946
|
+
if (parsed.ok !== true) {
|
|
18947
|
+
throw new Error(stderr.trim() || "Check config module did not return a value");
|
|
18948
|
+
}
|
|
18949
|
+
return parsed.value;
|
|
18950
|
+
} catch (error) {
|
|
18951
|
+
if (stderr.trim()) {
|
|
18952
|
+
throw new Error(stderr.trim());
|
|
18953
|
+
}
|
|
18954
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
18538
18955
|
}
|
|
18539
|
-
const mod = await import(url.pathToFileURL(absolute).href);
|
|
18540
|
-
return asConfig("default" in mod ? mod.default : mod);
|
|
18541
18956
|
}
|
|
18542
18957
|
function normalizeConfig(config) {
|
|
18543
18958
|
if (config.checks === void 0) return {};
|
|
18544
18959
|
if (typeof config.checks !== "object" || Array.isArray(config.checks)) {
|
|
18545
|
-
throw new
|
|
18960
|
+
throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "checks config must be an object.");
|
|
18546
18961
|
}
|
|
18547
18962
|
return config.checks;
|
|
18548
18963
|
}
|
|
@@ -18620,7 +19035,7 @@ function buildRules(config, options, presetSelect = []) {
|
|
|
18620
19035
|
}
|
|
18621
19036
|
throw new Error(`unsupported status "${value}"`);
|
|
18622
19037
|
});
|
|
18623
|
-
rules.push(createObservedOutcomeRule({ failOn: statuses }));
|
|
19038
|
+
rules.push(createObservedOutcomeRule({ failOn: statuses, requireAny: true }));
|
|
18624
19039
|
} catch (error) {
|
|
18625
19040
|
const message = error instanceof Error ? error.message : String(error);
|
|
18626
19041
|
diagnostics.push(
|
|
@@ -18692,7 +19107,7 @@ function exitCodeFor(result) {
|
|
|
18692
19107
|
return 3;
|
|
18693
19108
|
}
|
|
18694
19109
|
if (codes.some(
|
|
18695
|
-
(code) => code === "AI_CHECK_INVALID_ARGUMENTS" || code === "AI_CHECK_INVALID_CONFIG" || code === "AI_CHECK_CONFIG_LOAD_FAILED" || code === "AI_CHECK_RUN_SELECTION_REQUIRED"
|
|
19110
|
+
(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"
|
|
18696
19111
|
)) {
|
|
18697
19112
|
return 2;
|
|
18698
19113
|
}
|
|
@@ -18759,6 +19174,7 @@ function printHuman(result, options = {}) {
|
|
|
18759
19174
|
console.log(
|
|
18760
19175
|
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
18761
19176
|
);
|
|
19177
|
+
console.log(`Rules evaluated: ${result.summary.rulesEvaluated ?? result.ruleExecutions?.length ?? 0}`);
|
|
18762
19178
|
for (const diagnostic7 of result.diagnostics) {
|
|
18763
19179
|
console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
|
|
18764
19180
|
}
|
|
@@ -18790,6 +19206,16 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18790
19206
|
const useSessionScope = Boolean(sessionId || groupId);
|
|
18791
19207
|
try {
|
|
18792
19208
|
let config = await loadConfig(options.config);
|
|
19209
|
+
if (options.config !== void 0 && !checkConfigHasEffect(config)) {
|
|
19210
|
+
result = errorResult2(
|
|
19211
|
+
"AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
|
|
19212
|
+
"Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
|
|
19213
|
+
);
|
|
19214
|
+
if (options.json) printJson(result);
|
|
19215
|
+
else printHuman(result, options);
|
|
19216
|
+
process.exitCode = exitCodeFor(result);
|
|
19217
|
+
return;
|
|
19218
|
+
}
|
|
18793
19219
|
let effectiveOptions = options;
|
|
18794
19220
|
const resolved = resolvePreset(options.preset, {
|
|
18795
19221
|
hasToolRules: hasToolRulesConfigured(config, options)
|
|
@@ -18909,12 +19335,13 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
18909
19335
|
}
|
|
18910
19336
|
} catch (error) {
|
|
18911
19337
|
if (phase === "config") {
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
message
|
|
18917
|
-
|
|
19338
|
+
if (error instanceof CheckConfigError) {
|
|
19339
|
+
result = errorResult2(error.code, error.message);
|
|
19340
|
+
} else {
|
|
19341
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
19342
|
+
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";
|
|
19343
|
+
result = errorResult2(code, message);
|
|
19344
|
+
}
|
|
18918
19345
|
} else {
|
|
18919
19346
|
result = readErrorResult(error);
|
|
18920
19347
|
}
|
|
@@ -19845,6 +20272,42 @@ function startViewerServer(options = {}) {
|
|
|
19845
20272
|
});
|
|
19846
20273
|
});
|
|
19847
20274
|
}
|
|
20275
|
+
function openInDefaultBrowser(target) {
|
|
20276
|
+
const platform = process.platform;
|
|
20277
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
20278
|
+
const args = platform === "win32" ? ["/c", "start", "", target] : [target];
|
|
20279
|
+
return new Promise((resolve) => {
|
|
20280
|
+
try {
|
|
20281
|
+
const child = child_process.spawn(command, args, {
|
|
20282
|
+
detached: true,
|
|
20283
|
+
stdio: "ignore",
|
|
20284
|
+
windowsHide: platform === "win32"
|
|
20285
|
+
});
|
|
20286
|
+
child.once("spawn", () => {
|
|
20287
|
+
try {
|
|
20288
|
+
child.unref();
|
|
20289
|
+
resolve({ ok: true });
|
|
20290
|
+
} catch (error) {
|
|
20291
|
+
resolve({
|
|
20292
|
+
ok: false,
|
|
20293
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
20294
|
+
});
|
|
20295
|
+
}
|
|
20296
|
+
});
|
|
20297
|
+
child.once("error", (error) => {
|
|
20298
|
+
resolve({
|
|
20299
|
+
ok: false,
|
|
20300
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
20301
|
+
});
|
|
20302
|
+
});
|
|
20303
|
+
} catch (error) {
|
|
20304
|
+
resolve({
|
|
20305
|
+
ok: false,
|
|
20306
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
20307
|
+
});
|
|
20308
|
+
}
|
|
20309
|
+
});
|
|
20310
|
+
}
|
|
19848
20311
|
|
|
19849
20312
|
// packages/cli/src/serve.ts
|
|
19850
20313
|
function parsePort(value) {
|
|
@@ -19874,9 +20337,11 @@ async function serveCommand(options = {}) {
|
|
|
19874
20337
|
if (options.open === true && host !== "127.0.0.1" && host !== "localhost") {
|
|
19875
20338
|
console.warn("Skipping browser open for non-local host binding.");
|
|
19876
20339
|
} else if (options.open === true) {
|
|
19877
|
-
const
|
|
19878
|
-
|
|
19879
|
-
|
|
20340
|
+
const opened = await openInDefaultBrowser(info.url);
|
|
20341
|
+
if (!opened.ok) {
|
|
20342
|
+
console.warn("Viewer started, but the browser could not be opened automatically.");
|
|
20343
|
+
console.warn(`Open manually: ${info.url}`);
|
|
20344
|
+
}
|
|
19880
20345
|
}
|
|
19881
20346
|
await new Promise(() => {
|
|
19882
20347
|
});
|
|
@@ -20035,9 +20500,11 @@ async function studioCommand(options = {}) {
|
|
|
20035
20500
|
if (options.open === true && info.host !== "127.0.0.1" && info.host !== "localhost") {
|
|
20036
20501
|
console.warn("Skipping browser open for non-local host binding.");
|
|
20037
20502
|
} else if (options.open === true) {
|
|
20038
|
-
const
|
|
20039
|
-
|
|
20040
|
-
|
|
20503
|
+
const opened = await openInDefaultBrowser(info.url);
|
|
20504
|
+
if (!opened.ok) {
|
|
20505
|
+
console.warn("Studio started, but the browser could not be opened automatically.");
|
|
20506
|
+
console.warn(`Open manually: ${info.url}`);
|
|
20507
|
+
}
|
|
20041
20508
|
}
|
|
20042
20509
|
await new Promise(() => {
|
|
20043
20510
|
});
|
|
@@ -20796,7 +21263,7 @@ function asStringArray3(value, label) {
|
|
|
20796
21263
|
}
|
|
20797
21264
|
return value;
|
|
20798
21265
|
}
|
|
20799
|
-
function
|
|
21266
|
+
function asConfig(value) {
|
|
20800
21267
|
if (value === void 0 || value === null) return {};
|
|
20801
21268
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
20802
21269
|
throw new Error("Config must export an object.");
|
|
@@ -20817,10 +21284,10 @@ async function loadConfig2(configPath) {
|
|
|
20817
21284
|
const absolute = path32__default.default.resolve(configPath);
|
|
20818
21285
|
if (extension === ".json") {
|
|
20819
21286
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
20820
|
-
return
|
|
21287
|
+
return asConfig(JSON.parse(raw));
|
|
20821
21288
|
}
|
|
20822
21289
|
const mod = await import(url.pathToFileURL(absolute).href);
|
|
20823
|
-
return
|
|
21290
|
+
return asConfig("default" in mod ? mod.default : mod);
|
|
20824
21291
|
}
|
|
20825
21292
|
function normalizeConfig2(config) {
|
|
20826
21293
|
if (config.eval === void 0) return {};
|
|
@@ -22335,33 +22802,6 @@ async function resolveHtmlPath(root) {
|
|
|
22335
22802
|
`No evidence.html found under ${root}. Pass a bundle directory or .html path.`
|
|
22336
22803
|
);
|
|
22337
22804
|
}
|
|
22338
|
-
function openLocalFile(filePath) {
|
|
22339
|
-
const fileUrl = url.pathToFileURL(filePath).href;
|
|
22340
|
-
const platform = process.platform;
|
|
22341
|
-
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
22342
|
-
const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
22343
|
-
return new Promise((resolve) => {
|
|
22344
|
-
try {
|
|
22345
|
-
const child = child_process.spawn(command, args, {
|
|
22346
|
-
detached: true,
|
|
22347
|
-
stdio: "ignore"
|
|
22348
|
-
});
|
|
22349
|
-
child.on("error", (error) => {
|
|
22350
|
-
resolve({
|
|
22351
|
-
ok: false,
|
|
22352
|
-
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
22353
|
-
});
|
|
22354
|
-
});
|
|
22355
|
-
child.unref();
|
|
22356
|
-
resolve({ ok: true, detail: fileUrl });
|
|
22357
|
-
} catch (error) {
|
|
22358
|
-
resolve({
|
|
22359
|
-
ok: false,
|
|
22360
|
-
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
22361
|
-
});
|
|
22362
|
-
}
|
|
22363
|
-
});
|
|
22364
|
-
}
|
|
22365
22805
|
async function bundleOpenCommand(targetPath, options = {}) {
|
|
22366
22806
|
const root = path32__default.default.resolve(targetPath.trim() || ".");
|
|
22367
22807
|
try {
|
|
@@ -22431,23 +22871,24 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
22431
22871
|
await promises.readFile(path32__default.default.join(path32__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
22432
22872
|
} catch {
|
|
22433
22873
|
}
|
|
22434
|
-
const
|
|
22874
|
+
const fileUrl = url.pathToFileURL(htmlPath).href;
|
|
22875
|
+
const opened = await openInDefaultBrowser(fileUrl);
|
|
22435
22876
|
if (options.json) {
|
|
22436
22877
|
console.log(
|
|
22437
22878
|
writeJson6({
|
|
22438
22879
|
ok: opened.ok,
|
|
22439
22880
|
path: htmlPath,
|
|
22440
22881
|
opened: opened.ok,
|
|
22441
|
-
detail: opened.detail
|
|
22882
|
+
detail: opened.ok ? fileUrl : `${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`
|
|
22442
22883
|
}).trimEnd()
|
|
22443
22884
|
);
|
|
22444
22885
|
} else if (opened.ok) {
|
|
22445
22886
|
console.log(`Opened local Evidence: ${htmlPath}`);
|
|
22446
|
-
console.log(`URL: ${
|
|
22887
|
+
console.log(`URL: ${fileUrl}`);
|
|
22447
22888
|
} else {
|
|
22448
22889
|
console.error(`[AgentInspect] Could not open browser automatically.`);
|
|
22449
22890
|
console.error(`Open this file locally: ${htmlPath}`);
|
|
22450
|
-
console.error(opened.detail);
|
|
22891
|
+
console.error(`${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`);
|
|
22451
22892
|
}
|
|
22452
22893
|
if (!opened.ok) {
|
|
22453
22894
|
process.exitCode = 0;
|