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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, diffRuns, manualTraceEventsToComparableRun } from './chunk-
|
|
2
|
+
import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, diffRuns, manualTraceEventsToComparableRun } from './chunk-GOHYSE7W.mjs';
|
|
3
3
|
import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
|
|
4
4
|
import path18 from 'path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -12,7 +12,7 @@ import { spawn } from 'child_process';
|
|
|
12
12
|
import { createRequire } from 'module';
|
|
13
13
|
|
|
14
14
|
// package.json
|
|
15
|
-
var version = "6.17.
|
|
15
|
+
var version = "6.17.5";
|
|
16
16
|
|
|
17
17
|
// packages/cli/src/trace-dir-scale.ts
|
|
18
18
|
var TRACE_COUNT_WARN = 1e3;
|
|
@@ -1540,6 +1540,11 @@ async function followFile(filePath, options, onLine, shouldStop) {
|
|
|
1540
1540
|
const msg = e instanceof Error ? e.message : String(e);
|
|
1541
1541
|
throw new Error(`Failed to stat file: ${filePath} (${msg})`);
|
|
1542
1542
|
}
|
|
1543
|
+
if (next.size < pos) {
|
|
1544
|
+
pos = 0;
|
|
1545
|
+
carry = "";
|
|
1546
|
+
lineNumber = 0;
|
|
1547
|
+
}
|
|
1543
1548
|
if (next.size > pos) {
|
|
1544
1549
|
const fh = await open(filePath, "r");
|
|
1545
1550
|
try {
|
|
@@ -3347,7 +3352,7 @@ async function newestTraceMtimeMs(traceDir) {
|
|
|
3347
3352
|
}
|
|
3348
3353
|
async function loadSessionRuns(traceDir) {
|
|
3349
3354
|
try {
|
|
3350
|
-
const mod = await import('./src-
|
|
3355
|
+
const mod = await import('./src-OYGG7QAZ.mjs');
|
|
3351
3356
|
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
3352
3357
|
const status = mod.indexStatus(dbPath);
|
|
3353
3358
|
if (!status.healthy) {
|
|
@@ -3820,8 +3825,11 @@ async function reportCommand(runId, options = {}) {
|
|
|
3820
3825
|
}
|
|
3821
3826
|
|
|
3822
3827
|
// packages/redact/src/sensitive-key.ts
|
|
3828
|
+
function keyHasExplicitSeparator(value) {
|
|
3829
|
+
return /[_\-.]/.test(value);
|
|
3830
|
+
}
|
|
3823
3831
|
function normalizeSensitiveKey(value) {
|
|
3824
|
-
return value.toLowerCase().replace(/[^a-z0-
|
|
3832
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
3825
3833
|
}
|
|
3826
3834
|
var NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
|
|
3827
3835
|
[
|
|
@@ -3851,6 +3859,7 @@ function isCredentialSensitiveKey(key, sensitiveKeys) {
|
|
|
3851
3859
|
const normalized = normalizeSensitiveKey(key);
|
|
3852
3860
|
if (!normalized) return false;
|
|
3853
3861
|
if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
|
|
3862
|
+
const allowPrefixCompound = keyHasExplicitSeparator(key);
|
|
3854
3863
|
for (const sensitive of sensitiveKeys) {
|
|
3855
3864
|
const s = normalizeSensitiveKey(sensitive);
|
|
3856
3865
|
if (!s) continue;
|
|
@@ -3859,7 +3868,8 @@ function isCredentialSensitiveKey(key, sensitiveKeys) {
|
|
|
3859
3868
|
continue;
|
|
3860
3869
|
}
|
|
3861
3870
|
if (normalized === s) return true;
|
|
3862
|
-
if (normalized.endsWith(`_${s}`)
|
|
3871
|
+
if (normalized.endsWith(`_${s}`)) return true;
|
|
3872
|
+
if (allowPrefixCompound && normalized.startsWith(`${s}_`)) return true;
|
|
3863
3873
|
}
|
|
3864
3874
|
return false;
|
|
3865
3875
|
}
|
|
@@ -5138,8 +5148,11 @@ function checkResultToEvidenceJson(result, runIds) {
|
|
|
5138
5148
|
status,
|
|
5139
5149
|
errors: result.summary.errors,
|
|
5140
5150
|
warnings: result.summary.warnings,
|
|
5141
|
-
findings: result.findings.length
|
|
5151
|
+
findings: result.findings.length,
|
|
5152
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0
|
|
5142
5153
|
})),
|
|
5154
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0,
|
|
5155
|
+
evaluatedRuleIds: (result.ruleExecutions ?? []).map((item) => item.ruleId),
|
|
5143
5156
|
findings: result.findings,
|
|
5144
5157
|
diagnostics: result.diagnostics
|
|
5145
5158
|
});
|
|
@@ -5764,9 +5777,11 @@ function mergeSafetyExtensions(result, read, options) {
|
|
|
5764
5777
|
passed,
|
|
5765
5778
|
failed,
|
|
5766
5779
|
warnings,
|
|
5767
|
-
errors: result.summary.errors
|
|
5780
|
+
errors: result.summary.errors,
|
|
5781
|
+
rulesEvaluated: result.summary.rulesEvaluated ?? 0
|
|
5768
5782
|
},
|
|
5769
|
-
findings
|
|
5783
|
+
findings,
|
|
5784
|
+
ruleExecutions: result.ruleExecutions ?? []
|
|
5770
5785
|
};
|
|
5771
5786
|
}
|
|
5772
5787
|
|
|
@@ -5886,10 +5901,12 @@ function errorResult(code, message, format = "unknown") {
|
|
|
5886
5901
|
passed: 0,
|
|
5887
5902
|
failed: 0,
|
|
5888
5903
|
warnings: 0,
|
|
5889
|
-
errors: 1
|
|
5904
|
+
errors: 1,
|
|
5905
|
+
rulesEvaluated: 0
|
|
5890
5906
|
},
|
|
5891
5907
|
findings: [],
|
|
5892
|
-
diagnostics
|
|
5908
|
+
diagnostics,
|
|
5909
|
+
ruleExecutions: []
|
|
5893
5910
|
};
|
|
5894
5911
|
}
|
|
5895
5912
|
function parseNumber(value, label) {
|
|
@@ -5907,36 +5924,329 @@ function asStringArray(value) {
|
|
|
5907
5924
|
}
|
|
5908
5925
|
return value;
|
|
5909
5926
|
}
|
|
5910
|
-
|
|
5927
|
+
var CHECKS_KEYS = /* @__PURE__ */ new Set(["select", "run", "tool", "llm", "structure", "safety"]);
|
|
5928
|
+
var RUN_KEYS = /* @__PURE__ */ new Set(["expected", "allowIncomplete", "maxDurationMs", "maxDepth"]);
|
|
5929
|
+
var TOOL_KEYS = /* @__PURE__ */ new Set(["required", "forbidden", "allowed", "minCount", "maxCount"]);
|
|
5930
|
+
var LLM_KEYS = /* @__PURE__ */ new Set([
|
|
5931
|
+
"allowedModels",
|
|
5932
|
+
"allowedProviders",
|
|
5933
|
+
"finishReasons",
|
|
5934
|
+
"maxCalls",
|
|
5935
|
+
"maxTotalTokens",
|
|
5936
|
+
"maxInputTokens",
|
|
5937
|
+
"maxOutputTokens",
|
|
5938
|
+
"maxCachedTokens"
|
|
5939
|
+
]);
|
|
5940
|
+
var STRUCTURE_KEYS = /* @__PURE__ */ new Set([
|
|
5941
|
+
"minConfidence",
|
|
5942
|
+
"requireParentBeforeChild",
|
|
5943
|
+
"requireTraceParentSpan",
|
|
5944
|
+
"orphan",
|
|
5945
|
+
"cycle",
|
|
5946
|
+
"maxChildren",
|
|
5947
|
+
"maxConcurrent"
|
|
5948
|
+
]);
|
|
5949
|
+
var SAFETY_KEYS = /* @__PURE__ */ new Set([
|
|
5950
|
+
"redaction",
|
|
5951
|
+
"rawContent",
|
|
5952
|
+
"secretPattern",
|
|
5953
|
+
"maxStringLength",
|
|
5954
|
+
"maxArrayLength",
|
|
5955
|
+
"maxObjectKeys",
|
|
5956
|
+
"maxSerializedBytes",
|
|
5957
|
+
"maxFindings"
|
|
5958
|
+
]);
|
|
5959
|
+
var RUN_EXPECTED = /* @__PURE__ */ new Set(["ok", "error", "running"]);
|
|
5960
|
+
var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["exact", "high", "medium", "low", "inferred"]);
|
|
5961
|
+
var CheckConfigError = class extends Error {
|
|
5962
|
+
code;
|
|
5963
|
+
constructor(code, message) {
|
|
5964
|
+
super(message);
|
|
5965
|
+
this.name = "CheckConfigError";
|
|
5966
|
+
this.code = code;
|
|
5967
|
+
}
|
|
5968
|
+
};
|
|
5969
|
+
function closestKey(unknown, known) {
|
|
5970
|
+
const lower = unknown.toLowerCase();
|
|
5971
|
+
let best;
|
|
5972
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
5973
|
+
for (const candidate of known) {
|
|
5974
|
+
if (candidate.toLowerCase() === lower) return candidate;
|
|
5975
|
+
let distance = Math.abs(candidate.length - unknown.length);
|
|
5976
|
+
const max = Math.max(candidate.length, unknown.length);
|
|
5977
|
+
for (let i = 0; i < Math.min(candidate.length, unknown.length); i += 1) {
|
|
5978
|
+
if (candidate[i].toLowerCase() !== unknown[i].toLowerCase()) distance += 1;
|
|
5979
|
+
}
|
|
5980
|
+
if (distance < bestDistance && distance <= Math.max(2, Math.floor(max / 3))) {
|
|
5981
|
+
bestDistance = distance;
|
|
5982
|
+
best = candidate;
|
|
5983
|
+
}
|
|
5984
|
+
}
|
|
5985
|
+
return best;
|
|
5986
|
+
}
|
|
5987
|
+
function rejectUnknownKeys(record, allowed, pathPrefix) {
|
|
5988
|
+
for (const key of Object.keys(record)) {
|
|
5989
|
+
if (allowed.has(key)) continue;
|
|
5990
|
+
const suggestion = closestKey(key, [...allowed]);
|
|
5991
|
+
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
5992
|
+
throw new CheckConfigError(
|
|
5993
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
5994
|
+
`Unknown check config key "${pathPrefix}.${key}".${hint}`
|
|
5995
|
+
);
|
|
5996
|
+
}
|
|
5997
|
+
}
|
|
5998
|
+
function requireObject(value, pathPrefix) {
|
|
5999
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
6000
|
+
throw new CheckConfigError(
|
|
6001
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
6002
|
+
`${pathPrefix} must be an object.`
|
|
6003
|
+
);
|
|
6004
|
+
}
|
|
6005
|
+
return value;
|
|
6006
|
+
}
|
|
6007
|
+
function requireStringArray(value, pathPrefix) {
|
|
6008
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.trim() === "")) {
|
|
6009
|
+
throw new CheckConfigError(
|
|
6010
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
6011
|
+
`${pathPrefix} must be an array of non-empty strings.`
|
|
6012
|
+
);
|
|
6013
|
+
}
|
|
6014
|
+
return value;
|
|
6015
|
+
}
|
|
6016
|
+
function requireNonNegativeNumber(value, pathPrefix) {
|
|
6017
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
6018
|
+
throw new CheckConfigError(
|
|
6019
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
6020
|
+
`${pathPrefix} must be a finite non-negative number.`
|
|
6021
|
+
);
|
|
6022
|
+
}
|
|
6023
|
+
return value;
|
|
6024
|
+
}
|
|
6025
|
+
function requireBoolean(value, pathPrefix) {
|
|
6026
|
+
if (typeof value !== "boolean") {
|
|
6027
|
+
throw new CheckConfigError(
|
|
6028
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
6029
|
+
`${pathPrefix} must be a boolean.`
|
|
6030
|
+
);
|
|
6031
|
+
}
|
|
6032
|
+
return value;
|
|
6033
|
+
}
|
|
6034
|
+
function parseRunSection(value) {
|
|
6035
|
+
const record = requireObject(value, "checks.run");
|
|
6036
|
+
rejectUnknownKeys(record, RUN_KEYS, "checks.run");
|
|
6037
|
+
const out = {};
|
|
6038
|
+
if (record.expected !== void 0) {
|
|
6039
|
+
if (typeof record.expected !== "string" || !RUN_EXPECTED.has(record.expected)) {
|
|
6040
|
+
throw new CheckConfigError(
|
|
6041
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
6042
|
+
`checks.run.expected must be one of: ok, error, running.`
|
|
6043
|
+
);
|
|
6044
|
+
}
|
|
6045
|
+
out.expected = record.expected;
|
|
6046
|
+
}
|
|
6047
|
+
if (record.allowIncomplete !== void 0) {
|
|
6048
|
+
out.allowIncomplete = requireBoolean(record.allowIncomplete, "checks.run.allowIncomplete");
|
|
6049
|
+
}
|
|
6050
|
+
if (record.maxDurationMs !== void 0) {
|
|
6051
|
+
out.maxDurationMs = requireNonNegativeNumber(record.maxDurationMs, "checks.run.maxDurationMs");
|
|
6052
|
+
}
|
|
6053
|
+
if (record.maxDepth !== void 0) {
|
|
6054
|
+
out.maxDepth = requireNonNegativeNumber(record.maxDepth, "checks.run.maxDepth");
|
|
6055
|
+
}
|
|
6056
|
+
return out;
|
|
6057
|
+
}
|
|
6058
|
+
function parseToolSection(value) {
|
|
6059
|
+
const record = requireObject(value, "checks.tool");
|
|
6060
|
+
rejectUnknownKeys(record, TOOL_KEYS, "checks.tool");
|
|
6061
|
+
const out = {};
|
|
6062
|
+
if (record.required !== void 0) out.required = requireStringArray(record.required, "checks.tool.required");
|
|
6063
|
+
if (record.forbidden !== void 0) out.forbidden = requireStringArray(record.forbidden, "checks.tool.forbidden");
|
|
6064
|
+
if (record.allowed !== void 0) out.allowed = requireStringArray(record.allowed, "checks.tool.allowed");
|
|
6065
|
+
if (record.minCount !== void 0) out.minCount = requireNonNegativeNumber(record.minCount, "checks.tool.minCount");
|
|
6066
|
+
if (record.maxCount !== void 0) out.maxCount = requireNonNegativeNumber(record.maxCount, "checks.tool.maxCount");
|
|
6067
|
+
return out;
|
|
6068
|
+
}
|
|
6069
|
+
function parseLlmSection(value) {
|
|
6070
|
+
const record = requireObject(value, "checks.llm");
|
|
6071
|
+
rejectUnknownKeys(record, LLM_KEYS, "checks.llm");
|
|
6072
|
+
const out = {};
|
|
6073
|
+
if (record.allowedModels !== void 0) {
|
|
6074
|
+
out.allowedModels = requireStringArray(record.allowedModels, "checks.llm.allowedModels");
|
|
6075
|
+
}
|
|
6076
|
+
if (record.allowedProviders !== void 0) {
|
|
6077
|
+
out.allowedProviders = requireStringArray(record.allowedProviders, "checks.llm.allowedProviders");
|
|
6078
|
+
}
|
|
6079
|
+
if (record.finishReasons !== void 0) {
|
|
6080
|
+
out.finishReasons = requireStringArray(record.finishReasons, "checks.llm.finishReasons");
|
|
6081
|
+
}
|
|
6082
|
+
if (record.maxCalls !== void 0) out.maxCalls = requireNonNegativeNumber(record.maxCalls, "checks.llm.maxCalls");
|
|
6083
|
+
if (record.maxTotalTokens !== void 0) {
|
|
6084
|
+
out.maxTotalTokens = requireNonNegativeNumber(record.maxTotalTokens, "checks.llm.maxTotalTokens");
|
|
6085
|
+
}
|
|
6086
|
+
if (record.maxInputTokens !== void 0) {
|
|
6087
|
+
out.maxInputTokens = requireNonNegativeNumber(record.maxInputTokens, "checks.llm.maxInputTokens");
|
|
6088
|
+
}
|
|
6089
|
+
if (record.maxOutputTokens !== void 0) {
|
|
6090
|
+
out.maxOutputTokens = requireNonNegativeNumber(record.maxOutputTokens, "checks.llm.maxOutputTokens");
|
|
6091
|
+
}
|
|
6092
|
+
if (record.maxCachedTokens !== void 0) {
|
|
6093
|
+
out.maxCachedTokens = requireNonNegativeNumber(record.maxCachedTokens, "checks.llm.maxCachedTokens");
|
|
6094
|
+
}
|
|
6095
|
+
return out;
|
|
6096
|
+
}
|
|
6097
|
+
function parseStructureSection(value) {
|
|
6098
|
+
const record = requireObject(value, "checks.structure");
|
|
6099
|
+
rejectUnknownKeys(record, STRUCTURE_KEYS, "checks.structure");
|
|
6100
|
+
const out = {};
|
|
6101
|
+
if (record.minConfidence !== void 0) {
|
|
6102
|
+
if (typeof record.minConfidence !== "string" || !CONFIDENCE_VALUES.has(record.minConfidence)) {
|
|
6103
|
+
throw new CheckConfigError(
|
|
6104
|
+
"AI_CHECK_CONFIG_INVALID_VALUE",
|
|
6105
|
+
`checks.structure.minConfidence must be one of: exact, high, medium, low, inferred.`
|
|
6106
|
+
);
|
|
6107
|
+
}
|
|
6108
|
+
out.minConfidence = record.minConfidence;
|
|
6109
|
+
}
|
|
6110
|
+
if (record.requireParentBeforeChild !== void 0) {
|
|
6111
|
+
out.requireParentBeforeChild = requireBoolean(
|
|
6112
|
+
record.requireParentBeforeChild,
|
|
6113
|
+
"checks.structure.requireParentBeforeChild"
|
|
6114
|
+
);
|
|
6115
|
+
}
|
|
6116
|
+
if (record.requireTraceParentSpan !== void 0) {
|
|
6117
|
+
out.requireTraceParentSpan = requireBoolean(
|
|
6118
|
+
record.requireTraceParentSpan,
|
|
6119
|
+
"checks.structure.requireTraceParentSpan"
|
|
6120
|
+
);
|
|
6121
|
+
}
|
|
6122
|
+
if (record.orphan !== void 0) out.orphan = requireBoolean(record.orphan, "checks.structure.orphan");
|
|
6123
|
+
if (record.cycle !== void 0) out.cycle = requireBoolean(record.cycle, "checks.structure.cycle");
|
|
6124
|
+
if (record.maxChildren !== void 0) {
|
|
6125
|
+
out.maxChildren = requireNonNegativeNumber(record.maxChildren, "checks.structure.maxChildren");
|
|
6126
|
+
}
|
|
6127
|
+
if (record.maxConcurrent !== void 0) {
|
|
6128
|
+
out.maxConcurrent = requireNonNegativeNumber(record.maxConcurrent, "checks.structure.maxConcurrent");
|
|
6129
|
+
}
|
|
6130
|
+
return out;
|
|
6131
|
+
}
|
|
6132
|
+
function parseSafetySection(value) {
|
|
6133
|
+
const record = requireObject(value, "checks.safety");
|
|
6134
|
+
rejectUnknownKeys(record, SAFETY_KEYS, "checks.safety");
|
|
6135
|
+
const out = {};
|
|
6136
|
+
if (record.redaction !== void 0) out.redaction = requireBoolean(record.redaction, "checks.safety.redaction");
|
|
6137
|
+
if (record.rawContent !== void 0) out.rawContent = requireBoolean(record.rawContent, "checks.safety.rawContent");
|
|
6138
|
+
if (record.secretPattern !== void 0) {
|
|
6139
|
+
out.secretPattern = requireBoolean(record.secretPattern, "checks.safety.secretPattern");
|
|
6140
|
+
}
|
|
6141
|
+
if (record.maxStringLength !== void 0) {
|
|
6142
|
+
out.maxStringLength = requireNonNegativeNumber(record.maxStringLength, "checks.safety.maxStringLength");
|
|
6143
|
+
}
|
|
6144
|
+
if (record.maxArrayLength !== void 0) {
|
|
6145
|
+
out.maxArrayLength = requireNonNegativeNumber(record.maxArrayLength, "checks.safety.maxArrayLength");
|
|
6146
|
+
}
|
|
6147
|
+
if (record.maxObjectKeys !== void 0) {
|
|
6148
|
+
out.maxObjectKeys = requireNonNegativeNumber(record.maxObjectKeys, "checks.safety.maxObjectKeys");
|
|
6149
|
+
}
|
|
6150
|
+
if (record.maxSerializedBytes !== void 0) {
|
|
6151
|
+
out.maxSerializedBytes = requireNonNegativeNumber(
|
|
6152
|
+
record.maxSerializedBytes,
|
|
6153
|
+
"checks.safety.maxSerializedBytes"
|
|
6154
|
+
);
|
|
6155
|
+
}
|
|
6156
|
+
if (record.maxFindings !== void 0) {
|
|
6157
|
+
out.maxFindings = requireNonNegativeNumber(record.maxFindings, "checks.safety.maxFindings");
|
|
6158
|
+
}
|
|
6159
|
+
return out;
|
|
6160
|
+
}
|
|
6161
|
+
function sectionHasEffect(section) {
|
|
6162
|
+
if (section === void 0) return false;
|
|
6163
|
+
return Object.keys(section).length > 0;
|
|
6164
|
+
}
|
|
6165
|
+
function checkConfigHasEffect(config) {
|
|
6166
|
+
const checks2 = config.checks;
|
|
6167
|
+
if (checks2 === void 0) return false;
|
|
6168
|
+
if ((checks2.select?.length ?? 0) > 0) return true;
|
|
6169
|
+
if (sectionHasEffect(checks2.run)) return true;
|
|
6170
|
+
if (sectionHasEffect(checks2.tool)) return true;
|
|
6171
|
+
if (sectionHasEffect(checks2.llm)) return true;
|
|
6172
|
+
if (sectionHasEffect(checks2.structure)) return true;
|
|
6173
|
+
if (sectionHasEffect(checks2.safety)) return true;
|
|
6174
|
+
return false;
|
|
6175
|
+
}
|
|
6176
|
+
function parseCheckConfig(value) {
|
|
5911
6177
|
if (value === void 0 || value === null) return {};
|
|
5912
6178
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
5913
|
-
throw new
|
|
6179
|
+
throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "Config must export an object.");
|
|
5914
6180
|
}
|
|
5915
|
-
|
|
6181
|
+
const root = value;
|
|
6182
|
+
if ("contract" in root) {
|
|
6183
|
+
throw new CheckConfigError(
|
|
6184
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
6185
|
+
'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`.'
|
|
6186
|
+
);
|
|
6187
|
+
}
|
|
6188
|
+
const rootKeys = Object.keys(root);
|
|
6189
|
+
for (const key of rootKeys) {
|
|
6190
|
+
if (key === "checks") continue;
|
|
6191
|
+
const suggestion = closestKey(key, ["checks"]);
|
|
6192
|
+
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
6193
|
+
throw new CheckConfigError(
|
|
6194
|
+
"AI_CHECK_CONFIG_UNKNOWN_KEY",
|
|
6195
|
+
`Unknown top-level check config key "${key}". Allowed: checks.${hint}`
|
|
6196
|
+
);
|
|
6197
|
+
}
|
|
6198
|
+
if (!("checks" in root)) return {};
|
|
6199
|
+
const checksRecord = requireObject(root.checks, "checks");
|
|
6200
|
+
rejectUnknownKeys(checksRecord, CHECKS_KEYS, "checks");
|
|
6201
|
+
const checks2 = {};
|
|
6202
|
+
if (checksRecord.select !== void 0) {
|
|
6203
|
+
checks2.select = requireStringArray(checksRecord.select, "checks.select");
|
|
6204
|
+
}
|
|
6205
|
+
if (checksRecord.run !== void 0) checks2.run = parseRunSection(checksRecord.run);
|
|
6206
|
+
if (checksRecord.tool !== void 0) checks2.tool = parseToolSection(checksRecord.tool);
|
|
6207
|
+
if (checksRecord.llm !== void 0) checks2.llm = parseLlmSection(checksRecord.llm);
|
|
6208
|
+
if (checksRecord.structure !== void 0) {
|
|
6209
|
+
checks2.structure = parseStructureSection(checksRecord.structure);
|
|
6210
|
+
}
|
|
6211
|
+
if (checksRecord.safety !== void 0) checks2.safety = parseSafetySection(checksRecord.safety);
|
|
6212
|
+
return { checks: checks2 };
|
|
5916
6213
|
}
|
|
5917
6214
|
async function loadConfig(configPath) {
|
|
5918
6215
|
if (configPath === void 0) return {};
|
|
5919
6216
|
const extension = path18.extname(configPath);
|
|
5920
6217
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
5921
|
-
throw new
|
|
6218
|
+
throw new CheckConfigError(
|
|
6219
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
5922
6220
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
5923
6221
|
);
|
|
5924
6222
|
}
|
|
5925
6223
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
5926
|
-
throw new
|
|
6224
|
+
throw new CheckConfigError(
|
|
6225
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
6226
|
+
"Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
|
|
6227
|
+
);
|
|
5927
6228
|
}
|
|
5928
6229
|
const absolute = path18.resolve(configPath);
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
6230
|
+
try {
|
|
6231
|
+
if (extension === ".json") {
|
|
6232
|
+
const raw = await readFile(absolute, "utf-8");
|
|
6233
|
+
return parseCheckConfig(JSON.parse(raw));
|
|
6234
|
+
}
|
|
6235
|
+
const mod = await import(pathToFileURL(absolute).href);
|
|
6236
|
+
return parseCheckConfig("default" in mod ? mod.default : mod);
|
|
6237
|
+
} catch (error) {
|
|
6238
|
+
if (error instanceof CheckConfigError) throw error;
|
|
6239
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6240
|
+
throw new CheckConfigError(
|
|
6241
|
+
"AI_CHECK_CONFIG_LOAD_FAILED",
|
|
6242
|
+
`Failed to load check config: ${message}`
|
|
6243
|
+
);
|
|
5932
6244
|
}
|
|
5933
|
-
const mod = await import(pathToFileURL(absolute).href);
|
|
5934
|
-
return asConfig("default" in mod ? mod.default : mod);
|
|
5935
6245
|
}
|
|
5936
6246
|
function normalizeConfig(config) {
|
|
5937
6247
|
if (config.checks === void 0) return {};
|
|
5938
6248
|
if (typeof config.checks !== "object" || Array.isArray(config.checks)) {
|
|
5939
|
-
throw new
|
|
6249
|
+
throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "checks config must be an object.");
|
|
5940
6250
|
}
|
|
5941
6251
|
return config.checks;
|
|
5942
6252
|
}
|
|
@@ -6014,7 +6324,7 @@ function buildRules(config, options, presetSelect = []) {
|
|
|
6014
6324
|
}
|
|
6015
6325
|
throw new Error(`unsupported status "${value}"`);
|
|
6016
6326
|
});
|
|
6017
|
-
rules.push(createObservedOutcomeRule({ failOn: statuses }));
|
|
6327
|
+
rules.push(createObservedOutcomeRule({ failOn: statuses, requireAny: true }));
|
|
6018
6328
|
} catch (error) {
|
|
6019
6329
|
const message = error instanceof Error ? error.message : String(error);
|
|
6020
6330
|
diagnostics.push(
|
|
@@ -6086,7 +6396,7 @@ function exitCodeFor(result) {
|
|
|
6086
6396
|
return 3;
|
|
6087
6397
|
}
|
|
6088
6398
|
if (codes.some(
|
|
6089
|
-
(code) => code === "AI_CHECK_INVALID_ARGUMENTS" || code === "AI_CHECK_INVALID_CONFIG" || code === "AI_CHECK_CONFIG_LOAD_FAILED" || code === "AI_CHECK_RUN_SELECTION_REQUIRED"
|
|
6399
|
+
(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"
|
|
6090
6400
|
)) {
|
|
6091
6401
|
return 2;
|
|
6092
6402
|
}
|
|
@@ -6153,6 +6463,7 @@ function printHuman(result, options = {}) {
|
|
|
6153
6463
|
console.log(
|
|
6154
6464
|
`Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
|
|
6155
6465
|
);
|
|
6466
|
+
console.log(`Rules evaluated: ${result.summary.rulesEvaluated ?? result.ruleExecutions?.length ?? 0}`);
|
|
6156
6467
|
for (const diagnostic3 of result.diagnostics) {
|
|
6157
6468
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
6158
6469
|
}
|
|
@@ -6184,6 +6495,16 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
6184
6495
|
const useSessionScope = Boolean(sessionId || groupId);
|
|
6185
6496
|
try {
|
|
6186
6497
|
let config = await loadConfig(options.config);
|
|
6498
|
+
if (options.config !== void 0 && !checkConfigHasEffect(config)) {
|
|
6499
|
+
result = errorResult(
|
|
6500
|
+
"AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
|
|
6501
|
+
"Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
|
|
6502
|
+
);
|
|
6503
|
+
if (options.json) printJson(result);
|
|
6504
|
+
else printHuman(result, options);
|
|
6505
|
+
process.exitCode = exitCodeFor(result);
|
|
6506
|
+
return;
|
|
6507
|
+
}
|
|
6187
6508
|
let effectiveOptions = options;
|
|
6188
6509
|
const resolved = resolvePreset(options.preset, {
|
|
6189
6510
|
hasToolRules: hasToolRulesConfigured(config, options)
|
|
@@ -6303,12 +6624,13 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
6303
6624
|
}
|
|
6304
6625
|
} catch (error) {
|
|
6305
6626
|
if (phase === "config") {
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
message
|
|
6311
|
-
|
|
6627
|
+
if (error instanceof CheckConfigError) {
|
|
6628
|
+
result = errorResult(error.code, error.message);
|
|
6629
|
+
} else {
|
|
6630
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6631
|
+
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";
|
|
6632
|
+
result = errorResult(code, message);
|
|
6633
|
+
}
|
|
6312
6634
|
} else {
|
|
6313
6635
|
result = readErrorResult(error);
|
|
6314
6636
|
}
|
|
@@ -7230,6 +7552,42 @@ function startViewerServer(options = {}) {
|
|
|
7230
7552
|
});
|
|
7231
7553
|
});
|
|
7232
7554
|
}
|
|
7555
|
+
function openInDefaultBrowser(target) {
|
|
7556
|
+
const platform = process.platform;
|
|
7557
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
7558
|
+
const args = platform === "win32" ? ["/c", "start", "", target] : [target];
|
|
7559
|
+
return new Promise((resolve) => {
|
|
7560
|
+
try {
|
|
7561
|
+
const child = spawn(command, args, {
|
|
7562
|
+
detached: true,
|
|
7563
|
+
stdio: "ignore",
|
|
7564
|
+
windowsHide: platform === "win32"
|
|
7565
|
+
});
|
|
7566
|
+
child.once("spawn", () => {
|
|
7567
|
+
try {
|
|
7568
|
+
child.unref();
|
|
7569
|
+
resolve({ ok: true });
|
|
7570
|
+
} catch (error) {
|
|
7571
|
+
resolve({
|
|
7572
|
+
ok: false,
|
|
7573
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
7574
|
+
});
|
|
7575
|
+
}
|
|
7576
|
+
});
|
|
7577
|
+
child.once("error", (error) => {
|
|
7578
|
+
resolve({
|
|
7579
|
+
ok: false,
|
|
7580
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
7581
|
+
});
|
|
7582
|
+
});
|
|
7583
|
+
} catch (error) {
|
|
7584
|
+
resolve({
|
|
7585
|
+
ok: false,
|
|
7586
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
7587
|
+
});
|
|
7588
|
+
}
|
|
7589
|
+
});
|
|
7590
|
+
}
|
|
7233
7591
|
|
|
7234
7592
|
// packages/cli/src/serve.ts
|
|
7235
7593
|
function parsePort(value) {
|
|
@@ -7259,9 +7617,11 @@ async function serveCommand(options = {}) {
|
|
|
7259
7617
|
if (options.open === true && host !== "127.0.0.1" && host !== "localhost") {
|
|
7260
7618
|
console.warn("Skipping browser open for non-local host binding.");
|
|
7261
7619
|
} else if (options.open === true) {
|
|
7262
|
-
const
|
|
7263
|
-
|
|
7264
|
-
|
|
7620
|
+
const opened = await openInDefaultBrowser(info.url);
|
|
7621
|
+
if (!opened.ok) {
|
|
7622
|
+
console.warn("Viewer started, but the browser could not be opened automatically.");
|
|
7623
|
+
console.warn(`Open manually: ${info.url}`);
|
|
7624
|
+
}
|
|
7265
7625
|
}
|
|
7266
7626
|
await new Promise(() => {
|
|
7267
7627
|
});
|
|
@@ -7420,9 +7780,11 @@ async function studioCommand(options = {}) {
|
|
|
7420
7780
|
if (options.open === true && info.host !== "127.0.0.1" && info.host !== "localhost") {
|
|
7421
7781
|
console.warn("Skipping browser open for non-local host binding.");
|
|
7422
7782
|
} else if (options.open === true) {
|
|
7423
|
-
const
|
|
7424
|
-
|
|
7425
|
-
|
|
7783
|
+
const opened = await openInDefaultBrowser(info.url);
|
|
7784
|
+
if (!opened.ok) {
|
|
7785
|
+
console.warn("Studio started, but the browser could not be opened automatically.");
|
|
7786
|
+
console.warn(`Open manually: ${info.url}`);
|
|
7787
|
+
}
|
|
7426
7788
|
}
|
|
7427
7789
|
await new Promise(() => {
|
|
7428
7790
|
});
|
|
@@ -8181,7 +8543,7 @@ function asStringArray2(value, label) {
|
|
|
8181
8543
|
}
|
|
8182
8544
|
return value;
|
|
8183
8545
|
}
|
|
8184
|
-
function
|
|
8546
|
+
function asConfig(value) {
|
|
8185
8547
|
if (value === void 0 || value === null) return {};
|
|
8186
8548
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
8187
8549
|
throw new Error("Config must export an object.");
|
|
@@ -8202,10 +8564,10 @@ async function loadConfig2(configPath) {
|
|
|
8202
8564
|
const absolute = path18.resolve(configPath);
|
|
8203
8565
|
if (extension === ".json") {
|
|
8204
8566
|
const raw = await readFile(absolute, "utf-8");
|
|
8205
|
-
return
|
|
8567
|
+
return asConfig(JSON.parse(raw));
|
|
8206
8568
|
}
|
|
8207
8569
|
const mod = await import(pathToFileURL(absolute).href);
|
|
8208
|
-
return
|
|
8570
|
+
return asConfig("default" in mod ? mod.default : mod);
|
|
8209
8571
|
}
|
|
8210
8572
|
function normalizeConfig2(config) {
|
|
8211
8573
|
if (config.eval === void 0) return {};
|
|
@@ -9710,33 +10072,6 @@ async function resolveHtmlPath(root) {
|
|
|
9710
10072
|
`No evidence.html found under ${root}. Pass a bundle directory or .html path.`
|
|
9711
10073
|
);
|
|
9712
10074
|
}
|
|
9713
|
-
function openLocalFile(filePath) {
|
|
9714
|
-
const fileUrl = pathToFileURL(filePath).href;
|
|
9715
|
-
const platform = process.platform;
|
|
9716
|
-
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
9717
|
-
const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
9718
|
-
return new Promise((resolve) => {
|
|
9719
|
-
try {
|
|
9720
|
-
const child = spawn(command, args, {
|
|
9721
|
-
detached: true,
|
|
9722
|
-
stdio: "ignore"
|
|
9723
|
-
});
|
|
9724
|
-
child.on("error", (error) => {
|
|
9725
|
-
resolve({
|
|
9726
|
-
ok: false,
|
|
9727
|
-
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
9728
|
-
});
|
|
9729
|
-
});
|
|
9730
|
-
child.unref();
|
|
9731
|
-
resolve({ ok: true, detail: fileUrl });
|
|
9732
|
-
} catch (error) {
|
|
9733
|
-
resolve({
|
|
9734
|
-
ok: false,
|
|
9735
|
-
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
9736
|
-
});
|
|
9737
|
-
}
|
|
9738
|
-
});
|
|
9739
|
-
}
|
|
9740
10075
|
async function bundleOpenCommand(targetPath, options = {}) {
|
|
9741
10076
|
const root = path18.resolve(targetPath.trim() || ".");
|
|
9742
10077
|
try {
|
|
@@ -9806,23 +10141,24 @@ async function bundleOpenCommand(targetPath, options = {}) {
|
|
|
9806
10141
|
await readFile(path18.join(path18.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
9807
10142
|
} catch {
|
|
9808
10143
|
}
|
|
9809
|
-
const
|
|
10144
|
+
const fileUrl = pathToFileURL(htmlPath).href;
|
|
10145
|
+
const opened = await openInDefaultBrowser(fileUrl);
|
|
9810
10146
|
if (options.json) {
|
|
9811
10147
|
console.log(
|
|
9812
10148
|
writeJson6({
|
|
9813
10149
|
ok: opened.ok,
|
|
9814
10150
|
path: htmlPath,
|
|
9815
10151
|
opened: opened.ok,
|
|
9816
|
-
detail: opened.detail
|
|
10152
|
+
detail: opened.ok ? fileUrl : `${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`
|
|
9817
10153
|
}).trimEnd()
|
|
9818
10154
|
);
|
|
9819
10155
|
} else if (opened.ok) {
|
|
9820
10156
|
console.log(`Opened local Evidence: ${htmlPath}`);
|
|
9821
|
-
console.log(`URL: ${
|
|
10157
|
+
console.log(`URL: ${fileUrl}`);
|
|
9822
10158
|
} else {
|
|
9823
10159
|
console.error(`[AgentInspect] Could not open browser automatically.`);
|
|
9824
10160
|
console.error(`Open this file locally: ${htmlPath}`);
|
|
9825
|
-
console.error(opened.detail);
|
|
10161
|
+
console.error(`${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`);
|
|
9826
10162
|
}
|
|
9827
10163
|
if (!opened.ok) {
|
|
9828
10164
|
process.exitCode = 0;
|
|
@@ -11255,7 +11591,7 @@ function isModuleNotFound4(e) {
|
|
|
11255
11591
|
}
|
|
11256
11592
|
async function loadIndexSqlite() {
|
|
11257
11593
|
try {
|
|
11258
|
-
return await import('./src-
|
|
11594
|
+
return await import('./src-OYGG7QAZ.mjs');
|
|
11259
11595
|
} catch (e) {
|
|
11260
11596
|
if (isModuleNotFound4(e)) {
|
|
11261
11597
|
console.error(
|
|
@@ -11752,9 +12088,15 @@ function normalizeMetrics(raw) {
|
|
|
11752
12088
|
const parsed = parseCohortMetricList(raw);
|
|
11753
12089
|
if (parsed.length === 0) return void 0;
|
|
11754
12090
|
const allowed = new Set(COHORT_METRIC_IDS);
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
12091
|
+
const invalid = parsed.filter((metric) => !allowed.has(metric));
|
|
12092
|
+
if (invalid.length > 0) {
|
|
12093
|
+
const valueLabel = invalid.length === 1 ? "value" : "values";
|
|
12094
|
+
const invalidList = invalid.map((metric) => `"${metric}"`).join(", ");
|
|
12095
|
+
throw new Error(
|
|
12096
|
+
`Unsupported cohort --metric ${valueLabel}: ${invalidList}. Valid metrics: ${COHORT_METRIC_IDS.join(", ")}.`
|
|
12097
|
+
);
|
|
12098
|
+
}
|
|
12099
|
+
return parsed;
|
|
11758
12100
|
}
|
|
11759
12101
|
async function writeArtifacts(result, outputDir) {
|
|
11760
12102
|
await mkdir(outputDir, { recursive: true });
|
|
@@ -11775,6 +12117,7 @@ async function writeArtifacts(result, outputDir) {
|
|
|
11775
12117
|
}
|
|
11776
12118
|
async function cohortCommand(options = {}) {
|
|
11777
12119
|
try {
|
|
12120
|
+
const metrics = normalizeMetrics(options.metric);
|
|
11778
12121
|
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
11779
12122
|
const { runs } = await loadSessionRuns(traceDir);
|
|
11780
12123
|
const result = await analyzeCohort(runs, {
|
|
@@ -11783,7 +12126,7 @@ async function cohortCommand(options = {}) {
|
|
|
11783
12126
|
candidate: options.candidate,
|
|
11784
12127
|
cohortKey: options.cohortKey,
|
|
11785
12128
|
groupBy: options.groupBy,
|
|
11786
|
-
metrics
|
|
12129
|
+
metrics
|
|
11787
12130
|
});
|
|
11788
12131
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
11789
12132
|
let artifacts;
|