agent-inspect 5.0.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/docs/CLI.md +65 -0
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-TB45H3QT.mjs → chunk-SJ5R2XBE.mjs} +1043 -31
- package/packages/cli/dist/chunk-SJ5R2XBE.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +1543 -312
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +276 -164
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-ZRFSYML6.mjs → src-PK22BBMH.mjs} +3 -3
- package/packages/cli/dist/{src-ZRFSYML6.mjs.map → src-PK22BBMH.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +944 -12
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +134 -1
- package/packages/core/dist/advanced.d.ts +134 -1
- package/packages/core/dist/advanced.mjs +921 -8
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/cli/dist/chunk-TB45H3QT.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, enrichSessionRunRecord, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, openTrace, TraceReadError, filterMetasBySessionScope, runTraceChecks, aggregateSessionCheckResults, createBaselineRegressionRule, resolveBundleRunIds, aggregateBundleSafeStatus, bundleFailsOnSafety, buildPlaceholderArtifact, buildBundleMetadata, buildBundleSummaryMarkdown, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, TreeBuilder, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, normalizeBundleOutputPath, defaultBundleOutputPath, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, truncateStringForProfile } from './chunk-
|
|
2
|
+
import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, enrichSessionRunRecord, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, openTrace, TraceReadError, filterMetasBySessionScope, runTraceChecks, aggregateSessionCheckResults, createBaselineRegressionRule, resolveBundleRunIds, aggregateBundleSafeStatus, bundleFailsOnSafety, buildPlaceholderArtifact, buildBundleMetadata, buildBundleSummaryMarkdown, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, normalizeBundleOutputPath, defaultBundleOutputPath, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, escapeMarkdown, escapeHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, flattenTree, safeString, compactAttributes, stableJson, truncateStringForProfile } from './chunk-SJ5R2XBE.mjs';
|
|
3
3
|
import { realpathSync, constants as constants$1 } from 'fs';
|
|
4
4
|
import path12 from 'path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -11,7 +11,7 @@ import { createServer } from 'http';
|
|
|
11
11
|
import { createRequire } from 'module';
|
|
12
12
|
|
|
13
13
|
// package.json
|
|
14
|
-
var version = "5.
|
|
14
|
+
var version = "5.2.0";
|
|
15
15
|
|
|
16
16
|
// packages/cli/src/trace-dir-scale.ts
|
|
17
17
|
var TRACE_COUNT_WARN = 1e3;
|
|
@@ -923,7 +923,7 @@ function matchMapping(eventName, mappings) {
|
|
|
923
923
|
function isFiniteNumber(v) {
|
|
924
924
|
return typeof v === "number" && Number.isFinite(v);
|
|
925
925
|
}
|
|
926
|
-
function
|
|
926
|
+
function safeString2(v) {
|
|
927
927
|
if (typeof v !== "string") return void 0;
|
|
928
928
|
const t = v.trim();
|
|
929
929
|
return t === "" ? void 0 : t;
|
|
@@ -973,7 +973,7 @@ var EventNormalizer = class {
|
|
|
973
973
|
let runId;
|
|
974
974
|
for (const k of cfg.runIdKeys) {
|
|
975
975
|
const v = raw[k];
|
|
976
|
-
const s =
|
|
976
|
+
const s = safeString2(v);
|
|
977
977
|
if (s) {
|
|
978
978
|
runId = s;
|
|
979
979
|
break;
|
|
@@ -989,7 +989,7 @@ var EventNormalizer = class {
|
|
|
989
989
|
}
|
|
990
990
|
};
|
|
991
991
|
}
|
|
992
|
-
const eventName =
|
|
992
|
+
const eventName = safeString2(raw[cfg.eventKey]);
|
|
993
993
|
if (!eventName) {
|
|
994
994
|
return {
|
|
995
995
|
warning: {
|
|
@@ -1007,7 +1007,7 @@ var EventNormalizer = class {
|
|
|
1007
1007
|
const timestamp = parsedTs ?? Date.now();
|
|
1008
1008
|
const timestampMissing = parsedTs === void 0;
|
|
1009
1009
|
const parentIdKey = cfg.parentIdKey;
|
|
1010
|
-
const parentId = parentIdKey ?
|
|
1010
|
+
const parentId = parentIdKey ? safeString2(raw[parentIdKey]) : void 0;
|
|
1011
1011
|
let durationMs2;
|
|
1012
1012
|
const durationKey = cfg.durationKey;
|
|
1013
1013
|
if (durationKey) {
|
|
@@ -1018,7 +1018,7 @@ var EventNormalizer = class {
|
|
|
1018
1018
|
}
|
|
1019
1019
|
let status;
|
|
1020
1020
|
const statusKey = cfg.statusKey;
|
|
1021
|
-
const statusRaw = statusKey ?
|
|
1021
|
+
const statusRaw = statusKey ? safeString2(raw[statusKey]) : void 0;
|
|
1022
1022
|
if (statusRaw === "running" || statusRaw === "ok" || statusRaw === "error") {
|
|
1023
1023
|
status = statusRaw;
|
|
1024
1024
|
} else if (mapping?.status) {
|
|
@@ -1950,114 +1950,6 @@ function redactRunTreeForExport(tree, options) {
|
|
|
1950
1950
|
return clone;
|
|
1951
1951
|
}
|
|
1952
1952
|
|
|
1953
|
-
// packages/core/src/exporters/helpers.ts
|
|
1954
|
-
var REDACT_SUBSTRINGS = [
|
|
1955
|
-
"authorization",
|
|
1956
|
-
"cookie",
|
|
1957
|
-
"token",
|
|
1958
|
-
"apikey",
|
|
1959
|
-
"password",
|
|
1960
|
-
"secret",
|
|
1961
|
-
"email"
|
|
1962
|
-
];
|
|
1963
|
-
function shouldRedactKey(key) {
|
|
1964
|
-
const k = key.toLowerCase();
|
|
1965
|
-
for (const s of REDACT_SUBSTRINGS) {
|
|
1966
|
-
if (k.includes(s)) return true;
|
|
1967
|
-
}
|
|
1968
|
-
return false;
|
|
1969
|
-
}
|
|
1970
|
-
function safeString2(value, maxLength) {
|
|
1971
|
-
if (value === null || value === void 0) return "";
|
|
1972
|
-
let s;
|
|
1973
|
-
if (typeof value === "string") s = value;
|
|
1974
|
-
else if (typeof value === "number" || typeof value === "boolean") s = String(value);
|
|
1975
|
-
else s = stableJson(value, false);
|
|
1976
|
-
if (maxLength !== void 0 && maxLength >= 0 && s.length > maxLength) {
|
|
1977
|
-
return `${s.slice(0, maxLength)}\u2026`;
|
|
1978
|
-
}
|
|
1979
|
-
return s;
|
|
1980
|
-
}
|
|
1981
|
-
function escapeMarkdown(value) {
|
|
1982
|
-
return value.replace(/\|/g, "\\|").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, " ");
|
|
1983
|
-
}
|
|
1984
|
-
function escapeHtml(value) {
|
|
1985
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1986
|
-
}
|
|
1987
|
-
function sortKeysDeep(input3) {
|
|
1988
|
-
if (input3 === null || typeof input3 !== "object") return input3;
|
|
1989
|
-
if (Array.isArray(input3)) return input3.map(sortKeysDeep);
|
|
1990
|
-
const o = input3;
|
|
1991
|
-
const out = {};
|
|
1992
|
-
for (const k of Object.keys(o).sort()) {
|
|
1993
|
-
out[k] = sortKeysDeep(o[k]);
|
|
1994
|
-
}
|
|
1995
|
-
return out;
|
|
1996
|
-
}
|
|
1997
|
-
function stableJson(value, pretty) {
|
|
1998
|
-
const sorted = sortKeysDeep(value);
|
|
1999
|
-
return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
|
|
2000
|
-
}
|
|
2001
|
-
function compactAttributes(attrs, options) {
|
|
2002
|
-
if (attrs === void 0) return {};
|
|
2003
|
-
const maxLen = options?.maxLength ?? 500;
|
|
2004
|
-
const redacted = options?.redacted ?? true;
|
|
2005
|
-
const out = {};
|
|
2006
|
-
for (const key of Object.keys(attrs).sort()) {
|
|
2007
|
-
if (redacted && shouldRedactKey(key)) {
|
|
2008
|
-
out[key] = "[REDACTED]";
|
|
2009
|
-
continue;
|
|
2010
|
-
}
|
|
2011
|
-
const v = attrs[key];
|
|
2012
|
-
out[key] = compactValue(v, maxLen, redacted);
|
|
2013
|
-
}
|
|
2014
|
-
return out;
|
|
2015
|
-
}
|
|
2016
|
-
function compactValue(value, maxLen, redacted) {
|
|
2017
|
-
if (value === null || typeof value !== "object") {
|
|
2018
|
-
return typeof value === "string" ? safeString2(value, maxLen) : value;
|
|
2019
|
-
}
|
|
2020
|
-
if (Array.isArray(value)) {
|
|
2021
|
-
const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen, redacted));
|
|
2022
|
-
if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
|
|
2023
|
-
return arr;
|
|
2024
|
-
}
|
|
2025
|
-
const o = value;
|
|
2026
|
-
const inner = {};
|
|
2027
|
-
for (const k of Object.keys(o)) {
|
|
2028
|
-
if (redacted && shouldRedactKey(k)) inner[k] = "[REDACTED]";
|
|
2029
|
-
else inner[k] = compactValue(o[k], maxLen, redacted);
|
|
2030
|
-
}
|
|
2031
|
-
return inner;
|
|
2032
|
-
}
|
|
2033
|
-
function flattenTree(tree) {
|
|
2034
|
-
const out = [];
|
|
2035
|
-
function walk(nodes) {
|
|
2036
|
-
for (const n of nodes) {
|
|
2037
|
-
out.push(n);
|
|
2038
|
-
if (n.children.length > 0) walk(n.children);
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2041
|
-
walk(tree.children);
|
|
2042
|
-
return out;
|
|
2043
|
-
}
|
|
2044
|
-
function zeroKinds() {
|
|
2045
|
-
return {
|
|
2046
|
-
RUN: 0,
|
|
2047
|
-
AGENT: 0,
|
|
2048
|
-
LLM: 0,
|
|
2049
|
-
TOOL: 0,
|
|
2050
|
-
CHAIN: 0,
|
|
2051
|
-
RETRIEVER: 0,
|
|
2052
|
-
DECISION: 0,
|
|
2053
|
-
RESULT: 0,
|
|
2054
|
-
ERROR: 0,
|
|
2055
|
-
LOGIC: 0,
|
|
2056
|
-
LOG: 0,
|
|
2057
|
-
OUTCOME: 0
|
|
2058
|
-
};
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
1953
|
// packages/core/src/exporters/html-exporter.ts
|
|
2062
1954
|
function renderTreeHtml(nodes, ulClass = "tree") {
|
|
2063
1955
|
if (nodes.length === 0) return "";
|
|
@@ -2131,7 +2023,7 @@ function exportHtml(tree, options) {
|
|
|
2131
2023
|
if (includeErrors && errors.length > 0) {
|
|
2132
2024
|
errorsHtml += "<h2>Errors</h2><ul>";
|
|
2133
2025
|
for (const n of errors) {
|
|
2134
|
-
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ?
|
|
2026
|
+
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
|
|
2135
2027
|
n.event.attributes.error.message,
|
|
2136
2028
|
maxLen
|
|
2137
2029
|
) : "";
|
|
@@ -2280,7 +2172,7 @@ function exportMarkdown(tree, options) {
|
|
|
2280
2172
|
lines.push("## Errors");
|
|
2281
2173
|
lines.push("");
|
|
2282
2174
|
for (const n of errors) {
|
|
2283
|
-
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ?
|
|
2175
|
+
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
|
|
2284
2176
|
n.event.attributes.error.message,
|
|
2285
2177
|
maxLen
|
|
2286
2178
|
) : "";
|
|
@@ -3237,13 +3129,13 @@ function pairSteps(left, right) {
|
|
|
3237
3129
|
return pairs;
|
|
3238
3130
|
}
|
|
3239
3131
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
3240
|
-
const
|
|
3132
|
+
const path21 = buildPath(segments);
|
|
3241
3133
|
if (L.name !== R.name) {
|
|
3242
3134
|
out.push({
|
|
3243
3135
|
kind: "structure",
|
|
3244
3136
|
severity: "warning",
|
|
3245
3137
|
message: "Step name differs",
|
|
3246
|
-
path:
|
|
3138
|
+
path: path21,
|
|
3247
3139
|
left: L.name,
|
|
3248
3140
|
right: R.name
|
|
3249
3141
|
});
|
|
@@ -3253,7 +3145,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
3253
3145
|
kind: "step-type",
|
|
3254
3146
|
severity: "warning",
|
|
3255
3147
|
message: "Step type differs",
|
|
3256
|
-
path:
|
|
3148
|
+
path: path21,
|
|
3257
3149
|
left: L.type,
|
|
3258
3150
|
right: R.type
|
|
3259
3151
|
});
|
|
@@ -3263,7 +3155,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
3263
3155
|
kind: "step-status",
|
|
3264
3156
|
severity: "warning",
|
|
3265
3157
|
message: "Step status differs",
|
|
3266
|
-
path:
|
|
3158
|
+
path: path21,
|
|
3267
3159
|
left: L.status,
|
|
3268
3160
|
right: R.status
|
|
3269
3161
|
});
|
|
@@ -3275,7 +3167,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
3275
3167
|
kind: "error",
|
|
3276
3168
|
severity: "error",
|
|
3277
3169
|
message: "Step error message differs",
|
|
3278
|
-
path:
|
|
3170
|
+
path: path21,
|
|
3279
3171
|
left: le || void 0,
|
|
3280
3172
|
right: re || void 0
|
|
3281
3173
|
});
|
|
@@ -3293,7 +3185,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
3293
3185
|
kind: "duration",
|
|
3294
3186
|
severity: "info",
|
|
3295
3187
|
message: "Step duration differs",
|
|
3296
|
-
path:
|
|
3188
|
+
path: path21,
|
|
3297
3189
|
left: ld,
|
|
3298
3190
|
right: rd
|
|
3299
3191
|
});
|
|
@@ -3306,7 +3198,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
3306
3198
|
kind: "metadata",
|
|
3307
3199
|
severity: "info",
|
|
3308
3200
|
message: "Step metadata differs",
|
|
3309
|
-
path:
|
|
3201
|
+
path: path21,
|
|
3310
3202
|
left: L.metadata,
|
|
3311
3203
|
right: R.metadata
|
|
3312
3204
|
});
|
|
@@ -3318,7 +3210,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
3318
3210
|
kind: "output",
|
|
3319
3211
|
severity: "info",
|
|
3320
3212
|
message: "Output preview differs",
|
|
3321
|
-
path:
|
|
3213
|
+
path: path21,
|
|
3322
3214
|
left: L.outputPreview,
|
|
3323
3215
|
right: R.outputPreview
|
|
3324
3216
|
});
|
|
@@ -3478,11 +3370,11 @@ function diffRuns(left, right, options) {
|
|
|
3478
3370
|
}
|
|
3479
3371
|
|
|
3480
3372
|
// packages/core/src/diff/renderer.ts
|
|
3481
|
-
function formatPath(
|
|
3482
|
-
if (
|
|
3373
|
+
function formatPath(path21) {
|
|
3374
|
+
if (path21 === void 0 || path21.path.length === 0) {
|
|
3483
3375
|
return "(run)";
|
|
3484
3376
|
}
|
|
3485
|
-
return
|
|
3377
|
+
return path21.path.map((s) => s.name).join(" > ");
|
|
3486
3378
|
}
|
|
3487
3379
|
function formatValue(v, verbose) {
|
|
3488
3380
|
if (v === void 0) return "(undefined)";
|
|
@@ -3890,7 +3782,7 @@ async function newestTraceMtimeMs(traceDir) {
|
|
|
3890
3782
|
}
|
|
3891
3783
|
async function loadSessionRuns(traceDir) {
|
|
3892
3784
|
try {
|
|
3893
|
-
const mod = await import('./src-
|
|
3785
|
+
const mod = await import('./src-PK22BBMH.mjs');
|
|
3894
3786
|
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
3895
3787
|
const status = mod.indexStatus(dbPath);
|
|
3896
3788
|
if (!status.healthy) {
|
|
@@ -4587,17 +4479,17 @@ function applyRule(rule, value, replacement) {
|
|
|
4587
4479
|
}
|
|
4588
4480
|
return value;
|
|
4589
4481
|
}
|
|
4590
|
-
function childPath(
|
|
4482
|
+
function childPath(path21, key) {
|
|
4591
4483
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
4592
|
-
return
|
|
4484
|
+
return path21 ? `${path21}.${key}` : key;
|
|
4593
4485
|
}
|
|
4594
|
-
return `${
|
|
4486
|
+
return `${path21 || "$"}[${JSON.stringify(key)}]`;
|
|
4595
4487
|
}
|
|
4596
|
-
function indexPath(
|
|
4597
|
-
return `${
|
|
4488
|
+
function indexPath(path21, index) {
|
|
4489
|
+
return `${path21 || "$"}[${index}]`;
|
|
4598
4490
|
}
|
|
4599
|
-
function makeFinding(
|
|
4600
|
-
return preview === void 0 ? { path:
|
|
4491
|
+
function makeFinding(path21, detector, action, matchKind, severity = "warning", preview) {
|
|
4492
|
+
return preview === void 0 ? { path: path21, detector, action, severity, matchKind } : { path: path21, detector, action, severity, matchKind, preview };
|
|
4601
4493
|
}
|
|
4602
4494
|
function createRedactionProfile(profile = "local") {
|
|
4603
4495
|
switch (profile) {
|
|
@@ -4666,11 +4558,11 @@ var Redactor2 = class {
|
|
|
4666
4558
|
#recordFinding(state, finding) {
|
|
4667
4559
|
if (this.#collectFindings) state.findings.push(finding);
|
|
4668
4560
|
}
|
|
4669
|
-
#redactValue(value, key,
|
|
4561
|
+
#redactValue(value, key, path21, depth, state) {
|
|
4670
4562
|
if (depth > this.#maxDepth) {
|
|
4671
4563
|
this.#recordFinding(
|
|
4672
4564
|
state,
|
|
4673
|
-
makeFinding(
|
|
4565
|
+
makeFinding(path21, "structure.maxDepth", "truncate", "value", "warning")
|
|
4674
4566
|
);
|
|
4675
4567
|
return "[Truncated]";
|
|
4676
4568
|
}
|
|
@@ -4679,19 +4571,19 @@ var Redactor2 = class {
|
|
|
4679
4571
|
if (rule) {
|
|
4680
4572
|
this.#recordFinding(
|
|
4681
4573
|
state,
|
|
4682
|
-
makeFinding(
|
|
4574
|
+
makeFinding(path21, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
4683
4575
|
);
|
|
4684
4576
|
return applyRule(rule, value, this.#replacement);
|
|
4685
4577
|
}
|
|
4686
4578
|
}
|
|
4687
4579
|
for (const detector of this.#detectors) {
|
|
4688
|
-
const detections = detector.detect({ path:
|
|
4580
|
+
const detections = detector.detect({ path: path21, key, value });
|
|
4689
4581
|
for (const detection of detections) {
|
|
4690
4582
|
const action = detection.action ?? "replace";
|
|
4691
4583
|
this.#recordFinding(
|
|
4692
4584
|
state,
|
|
4693
4585
|
makeFinding(
|
|
4694
|
-
|
|
4586
|
+
path21,
|
|
4695
4587
|
detector.id,
|
|
4696
4588
|
action,
|
|
4697
4589
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -4709,7 +4601,7 @@ var Redactor2 = class {
|
|
|
4709
4601
|
const out = [];
|
|
4710
4602
|
state.seen.set(value, out);
|
|
4711
4603
|
value.forEach((item, index) => {
|
|
4712
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
4604
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path21, index), depth + 1, state);
|
|
4713
4605
|
});
|
|
4714
4606
|
return out;
|
|
4715
4607
|
}
|
|
@@ -4721,7 +4613,7 @@ var Redactor2 = class {
|
|
|
4721
4613
|
out[entryKey] = this.#redactValue(
|
|
4722
4614
|
entryValue,
|
|
4723
4615
|
entryKey,
|
|
4724
|
-
childPath(
|
|
4616
|
+
childPath(path21 === "$" ? "" : path21, entryKey),
|
|
4725
4617
|
depth + 1,
|
|
4726
4618
|
state
|
|
4727
4619
|
);
|
|
@@ -5648,23 +5540,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
5648
5540
|
}
|
|
5649
5541
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
5650
5542
|
}
|
|
5651
|
-
function validateSchemaField(value, field,
|
|
5543
|
+
function validateSchemaField(value, field, path21, evidence) {
|
|
5652
5544
|
const ruleId = "guardrail.structured-output";
|
|
5653
5545
|
if (field.type) {
|
|
5654
5546
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
5655
5547
|
if (actual !== field.type) {
|
|
5656
|
-
evidence.push({ ruleId, path:
|
|
5548
|
+
evidence.push({ ruleId, path: path21, preview: `expected ${field.type}, got ${actual}` });
|
|
5657
5549
|
return;
|
|
5658
5550
|
}
|
|
5659
5551
|
}
|
|
5660
5552
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
5661
|
-
evidence.push({ ruleId, path:
|
|
5553
|
+
evidence.push({ ruleId, path: path21, preview: "value not in enum" });
|
|
5662
5554
|
}
|
|
5663
5555
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
5664
5556
|
const record = value;
|
|
5665
5557
|
for (const key of field.required) {
|
|
5666
5558
|
if (!(key in record)) {
|
|
5667
|
-
evidence.push({ ruleId, path: `${
|
|
5559
|
+
evidence.push({ ruleId, path: `${path21}.${key}`, preview: "missing required key" });
|
|
5668
5560
|
}
|
|
5669
5561
|
}
|
|
5670
5562
|
}
|
|
@@ -6165,10 +6057,10 @@ function printHuman(result) {
|
|
|
6165
6057
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
6166
6058
|
}
|
|
6167
6059
|
for (const finding of result.findings) {
|
|
6168
|
-
const
|
|
6060
|
+
const path21 = finding.evidence[0]?.path;
|
|
6169
6061
|
const run = finding.evidence[0]?.runId;
|
|
6170
6062
|
const runPrefix = run ? `[${run}] ` : "";
|
|
6171
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
6063
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
|
|
6172
6064
|
}
|
|
6173
6065
|
}
|
|
6174
6066
|
function readErrorResult(error) {
|
|
@@ -6706,10 +6598,10 @@ async function evalRun(input3, options = {}) {
|
|
|
6706
6598
|
diagnostics: []
|
|
6707
6599
|
};
|
|
6708
6600
|
}
|
|
6709
|
-
function evidenceForRun(run,
|
|
6710
|
-
return [{ runId: run.runId, ...
|
|
6601
|
+
function evidenceForRun(run, path21) {
|
|
6602
|
+
return [{ runId: run.runId, ...path21 !== void 0 ? { path: path21 } : {} }];
|
|
6711
6603
|
}
|
|
6712
|
-
function evidenceForEvent(event,
|
|
6604
|
+
function evidenceForEvent(event, path21) {
|
|
6713
6605
|
return [
|
|
6714
6606
|
{
|
|
6715
6607
|
runId: event.runId,
|
|
@@ -6717,7 +6609,7 @@ function evidenceForEvent(event, path19) {
|
|
|
6717
6609
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
6718
6610
|
kind: event.kind,
|
|
6719
6611
|
name: event.name,
|
|
6720
|
-
...
|
|
6612
|
+
...path21 !== void 0 ? { path: path21 } : {}
|
|
6721
6613
|
}
|
|
6722
6614
|
];
|
|
6723
6615
|
}
|
|
@@ -6875,9 +6767,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
6875
6767
|
function tokenize(text) {
|
|
6876
6768
|
return [...text.toLowerCase().matchAll(/[a-z0-9][a-z0-9'-]{2,}/g)].map((match) => match[0].replace(/^['-]+|['-]+$/g, "")).filter((token) => token.length > 2 && !STOP_WORDS.has(token));
|
|
6877
6769
|
}
|
|
6878
|
-
function firstEvidence(fields, run,
|
|
6770
|
+
function firstEvidence(fields, run, path21) {
|
|
6879
6771
|
const first = fields[0];
|
|
6880
|
-
return first === void 0 ? evidenceForRun(run,
|
|
6772
|
+
return first === void 0 ? evidenceForRun(run, path21) : evidenceForEvent(first.node.event, first.path);
|
|
6881
6773
|
}
|
|
6882
6774
|
function collectSourceIds(nodes, keys) {
|
|
6883
6775
|
const wanted = keySet(keys);
|
|
@@ -7254,8 +7146,8 @@ function renderEvalMarkdown(result) {
|
|
|
7254
7146
|
if (result.findings.length > 0) {
|
|
7255
7147
|
lines.push("", "## Findings");
|
|
7256
7148
|
for (const finding of result.findings) {
|
|
7257
|
-
const
|
|
7258
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
7149
|
+
const path21 = finding.evidence[0]?.path;
|
|
7150
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
|
|
7259
7151
|
}
|
|
7260
7152
|
}
|
|
7261
7153
|
return `${lines.join("\n")}
|
|
@@ -7448,8 +7340,8 @@ function printHuman2(result) {
|
|
|
7448
7340
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
7449
7341
|
}
|
|
7450
7342
|
for (const finding of result.findings) {
|
|
7451
|
-
const
|
|
7452
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
7343
|
+
const path21 = finding.evidence[0]?.path;
|
|
7344
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
|
|
7453
7345
|
}
|
|
7454
7346
|
}
|
|
7455
7347
|
function readErrorResult2(error) {
|
|
@@ -7687,8 +7579,8 @@ function printHuman3(result) {
|
|
|
7687
7579
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
7688
7580
|
}
|
|
7689
7581
|
for (const finding of result.findings) {
|
|
7690
|
-
const
|
|
7691
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
7582
|
+
const path21 = finding.evidence[0]?.path;
|
|
7583
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
|
|
7692
7584
|
}
|
|
7693
7585
|
console.log(`Note: ${result.note}`);
|
|
7694
7586
|
}
|
|
@@ -7839,8 +7731,8 @@ function renderCheckSection(result) {
|
|
|
7839
7731
|
`Diagnostics: ${result.diagnostics.length}`
|
|
7840
7732
|
];
|
|
7841
7733
|
for (const finding of result.findings.slice(0, 10)) {
|
|
7842
|
-
const
|
|
7843
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
7734
|
+
const path21 = finding.evidence[0]?.path ?? "(run)";
|
|
7735
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path21})`);
|
|
7844
7736
|
}
|
|
7845
7737
|
for (const diagnostic3 of result.diagnostics.slice(0, 10)) {
|
|
7846
7738
|
lines.push(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
@@ -9794,7 +9686,7 @@ function isModuleNotFound3(e) {
|
|
|
9794
9686
|
}
|
|
9795
9687
|
async function loadIndexSqlite() {
|
|
9796
9688
|
try {
|
|
9797
|
-
return await import('./src-
|
|
9689
|
+
return await import('./src-PK22BBMH.mjs');
|
|
9798
9690
|
} catch (e) {
|
|
9799
9691
|
if (isModuleNotFound3(e)) {
|
|
9800
9692
|
console.error(
|
|
@@ -10278,6 +10170,211 @@ async function suiteReportCommand(options = {}) {
|
|
|
10278
10170
|
process.exitCode = 1;
|
|
10279
10171
|
}
|
|
10280
10172
|
}
|
|
10173
|
+
function normalizeMetrics(raw) {
|
|
10174
|
+
const parsed = parseCohortMetricList(raw);
|
|
10175
|
+
if (parsed.length === 0) return void 0;
|
|
10176
|
+
const allowed = new Set(COHORT_METRIC_IDS);
|
|
10177
|
+
return parsed.filter(
|
|
10178
|
+
(item) => allowed.has(item)
|
|
10179
|
+
);
|
|
10180
|
+
}
|
|
10181
|
+
async function writeArtifacts(result, outputDir) {
|
|
10182
|
+
await mkdir(outputDir, { recursive: true });
|
|
10183
|
+
const jsonPath = path12.join(outputDir, "cohort-results.json");
|
|
10184
|
+
const markdownPath = path12.join(outputDir, "cohort-summary.md");
|
|
10185
|
+
const htmlPath = path12.join(outputDir, "cohort-report.html");
|
|
10186
|
+
await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
10187
|
+
`, "utf-8");
|
|
10188
|
+
await writeFile(
|
|
10189
|
+
markdownPath,
|
|
10190
|
+
`${renderCohortReport(result, { format: "markdown" })}
|
|
10191
|
+
`,
|
|
10192
|
+
"utf-8"
|
|
10193
|
+
);
|
|
10194
|
+
await writeFile(htmlPath, `${renderCohortReport(result, { format: "html" })}
|
|
10195
|
+
`, "utf-8");
|
|
10196
|
+
return { jsonPath, markdownPath, htmlPath };
|
|
10197
|
+
}
|
|
10198
|
+
async function cohortCommand(options = {}) {
|
|
10199
|
+
try {
|
|
10200
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
10201
|
+
const { runs } = await loadSessionRuns(traceDir);
|
|
10202
|
+
const result = await analyzeCohort(runs, {
|
|
10203
|
+
traceDir,
|
|
10204
|
+
baseline: options.baseline,
|
|
10205
|
+
candidate: options.candidate,
|
|
10206
|
+
cohortKey: options.cohortKey,
|
|
10207
|
+
groupBy: options.groupBy,
|
|
10208
|
+
metrics: normalizeMetrics(options.metric)
|
|
10209
|
+
});
|
|
10210
|
+
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
10211
|
+
let artifacts;
|
|
10212
|
+
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
10213
|
+
artifacts = await writeArtifacts(result, path12.resolve(options.output.trim()));
|
|
10214
|
+
}
|
|
10215
|
+
if (options.json || format === "json") {
|
|
10216
|
+
console.log(
|
|
10217
|
+
JSON.stringify(
|
|
10218
|
+
{
|
|
10219
|
+
...result,
|
|
10220
|
+
artifacts: artifacts ?? null
|
|
10221
|
+
},
|
|
10222
|
+
null,
|
|
10223
|
+
2
|
|
10224
|
+
)
|
|
10225
|
+
);
|
|
10226
|
+
} else if (format === "html") {
|
|
10227
|
+
console.log(renderCohortReport(result, { format: "html" }));
|
|
10228
|
+
if (artifacts !== void 0) {
|
|
10229
|
+
console.error(`Artifacts written to ${options.output}`);
|
|
10230
|
+
}
|
|
10231
|
+
} else {
|
|
10232
|
+
console.log(renderCohortReport(result, { format: "markdown" }));
|
|
10233
|
+
if (artifacts !== void 0) {
|
|
10234
|
+
console.log("");
|
|
10235
|
+
console.log(`Artifacts:`);
|
|
10236
|
+
console.log(`- ${artifacts.jsonPath}`);
|
|
10237
|
+
console.log(`- ${artifacts.markdownPath}`);
|
|
10238
|
+
console.log(`- ${artifacts.htmlPath}`);
|
|
10239
|
+
}
|
|
10240
|
+
}
|
|
10241
|
+
if (!result.ok) process.exitCode = 1;
|
|
10242
|
+
} catch (error) {
|
|
10243
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10244
|
+
if (options.json) {
|
|
10245
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
10246
|
+
} else {
|
|
10247
|
+
console.error(`[AgentInspect] cohort failed: ${message}`);
|
|
10248
|
+
}
|
|
10249
|
+
process.exitCode = 1;
|
|
10250
|
+
}
|
|
10251
|
+
}
|
|
10252
|
+
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set(["markdown", "json", "html", "junit", "github"]);
|
|
10253
|
+
function collectList(value) {
|
|
10254
|
+
if (value === void 0) return [];
|
|
10255
|
+
const items = Array.isArray(value) ? value : [value];
|
|
10256
|
+
return items.flatMap((item) => parseGateList(item));
|
|
10257
|
+
}
|
|
10258
|
+
function parseRate(value) {
|
|
10259
|
+
if (value === void 0 || value.trim() === "") return void 0;
|
|
10260
|
+
const parsed = Number(value);
|
|
10261
|
+
if (!Number.isFinite(parsed)) {
|
|
10262
|
+
throw new Error(`Invalid --max-error-rate: ${value}`);
|
|
10263
|
+
}
|
|
10264
|
+
return parsed;
|
|
10265
|
+
}
|
|
10266
|
+
function parseDuration2(value) {
|
|
10267
|
+
if (value === void 0 || value.trim() === "") return void 0;
|
|
10268
|
+
const parsed = Number(value);
|
|
10269
|
+
if (!Number.isFinite(parsed)) {
|
|
10270
|
+
throw new Error(`Invalid --max-p95-duration: ${value}`);
|
|
10271
|
+
}
|
|
10272
|
+
return parsed;
|
|
10273
|
+
}
|
|
10274
|
+
async function writeArtifacts2(result, outputDir) {
|
|
10275
|
+
await mkdir(outputDir, { recursive: true });
|
|
10276
|
+
const paths = {
|
|
10277
|
+
jsonPath: path12.join(outputDir, "gate-results.json"),
|
|
10278
|
+
markdownPath: path12.join(outputDir, "gate-summary.md"),
|
|
10279
|
+
htmlPath: path12.join(outputDir, "gate-report.html"),
|
|
10280
|
+
junitPath: path12.join(outputDir, "junit.xml"),
|
|
10281
|
+
githubPath: path12.join(outputDir, "github-step-summary.md")
|
|
10282
|
+
};
|
|
10283
|
+
await writeFile(
|
|
10284
|
+
paths.jsonPath,
|
|
10285
|
+
`${renderGateReport(result, { format: "json" })}
|
|
10286
|
+
`,
|
|
10287
|
+
"utf-8"
|
|
10288
|
+
);
|
|
10289
|
+
await writeFile(
|
|
10290
|
+
paths.markdownPath,
|
|
10291
|
+
`${renderGateReport(result, { format: "markdown" })}
|
|
10292
|
+
`,
|
|
10293
|
+
"utf-8"
|
|
10294
|
+
);
|
|
10295
|
+
await writeFile(
|
|
10296
|
+
paths.htmlPath,
|
|
10297
|
+
`${renderGateReport(result, { format: "html" })}
|
|
10298
|
+
`,
|
|
10299
|
+
"utf-8"
|
|
10300
|
+
);
|
|
10301
|
+
await writeFile(
|
|
10302
|
+
paths.junitPath,
|
|
10303
|
+
`${renderGateReport(result, { format: "junit" })}
|
|
10304
|
+
`,
|
|
10305
|
+
"utf-8"
|
|
10306
|
+
);
|
|
10307
|
+
await writeFile(
|
|
10308
|
+
paths.githubPath,
|
|
10309
|
+
`${renderGateReport(result, { format: "github" })}
|
|
10310
|
+
`,
|
|
10311
|
+
"utf-8"
|
|
10312
|
+
);
|
|
10313
|
+
return paths;
|
|
10314
|
+
}
|
|
10315
|
+
async function gateCommand(options = {}) {
|
|
10316
|
+
try {
|
|
10317
|
+
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
10318
|
+
if (!SUPPORTED_FORMATS.has(format)) {
|
|
10319
|
+
if (options.json) {
|
|
10320
|
+
console.log(
|
|
10321
|
+
JSON.stringify({ ok: false, exitCode: 4, error: `Unsupported format: ${format}` }, null, 2)
|
|
10322
|
+
);
|
|
10323
|
+
} else {
|
|
10324
|
+
console.error(`[AgentInspect] Unsupported format: ${format}`);
|
|
10325
|
+
}
|
|
10326
|
+
process.exitCode = 4;
|
|
10327
|
+
return;
|
|
10328
|
+
}
|
|
10329
|
+
const gateOptions = {
|
|
10330
|
+
...options.dir !== void 0 ? { traceDir: resolveTraceDir({ dir: options.dir }) } : {},
|
|
10331
|
+
...options.suite !== void 0 ? { suitePath: options.suite } : {},
|
|
10332
|
+
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
10333
|
+
...parseRate(options.maxErrorRate) !== void 0 ? { maxErrorRate: parseRate(options.maxErrorRate) } : {},
|
|
10334
|
+
...parseDuration2(options.maxP95Duration) !== void 0 ? { maxP95DurationMs: parseDuration2(options.maxP95Duration) } : {},
|
|
10335
|
+
forbidTools: collectList(options.forbidTool),
|
|
10336
|
+
requireObservations: collectList(options.requireObservation)
|
|
10337
|
+
};
|
|
10338
|
+
let runs = [];
|
|
10339
|
+
const needsRuns = gateHasThresholds(gateOptions) || gateOptions.traceDir !== void 0 && gateOptions.suitePath === void 0;
|
|
10340
|
+
if (needsRuns) {
|
|
10341
|
+
const traceDir = gateOptions.traceDir ?? resolveTraceDir({ dir: options.dir });
|
|
10342
|
+
const loaded = await loadSessionRuns(traceDir);
|
|
10343
|
+
runs = loaded.runs;
|
|
10344
|
+
gateOptions.traceDir = traceDir;
|
|
10345
|
+
}
|
|
10346
|
+
const result = await runGate(runs, gateOptions);
|
|
10347
|
+
let artifacts;
|
|
10348
|
+
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
10349
|
+
artifacts = await writeArtifacts2(result, path12.resolve(options.output.trim()));
|
|
10350
|
+
}
|
|
10351
|
+
if (options.json || format === "json") {
|
|
10352
|
+
console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
|
|
10353
|
+
} else if (format === "html") {
|
|
10354
|
+
console.log(renderGateReport(result, { format: "html" }));
|
|
10355
|
+
} else if (format === "junit") {
|
|
10356
|
+
console.log(renderGateReport(result, { format: "junit" }));
|
|
10357
|
+
} else if (format === "github") {
|
|
10358
|
+
console.log(renderGateReport(result, { format: "github" }));
|
|
10359
|
+
} else {
|
|
10360
|
+
console.log(renderGateReport(result, { format: "markdown" }));
|
|
10361
|
+
if (artifacts !== void 0) {
|
|
10362
|
+
console.log("");
|
|
10363
|
+
console.log("Artifacts:");
|
|
10364
|
+
for (const value of Object.values(artifacts)) console.log(`- ${value}`);
|
|
10365
|
+
}
|
|
10366
|
+
}
|
|
10367
|
+
process.exitCode = result.exitCode;
|
|
10368
|
+
} catch (error) {
|
|
10369
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10370
|
+
if (options.json) {
|
|
10371
|
+
console.log(JSON.stringify({ ok: false, exitCode: 2, error: message }, null, 2));
|
|
10372
|
+
} else {
|
|
10373
|
+
console.error(`[AgentInspect] gate failed: ${message}`);
|
|
10374
|
+
}
|
|
10375
|
+
process.exitCode = 2;
|
|
10376
|
+
}
|
|
10377
|
+
}
|
|
10281
10378
|
|
|
10282
10379
|
// packages/cli/src/index.ts
|
|
10283
10380
|
function runCommand(action) {
|
|
@@ -10712,6 +10809,21 @@ function createCliProgram() {
|
|
|
10712
10809
|
suiteCmd.command("report").description("Render a report from a prior suite run artifact").option("--input <path>", "suite run JSON artifact").option("--format <format>", "markdown or json", "markdown").option("--json", "print JSON wrapper").action((opts) => {
|
|
10713
10810
|
runCommand(() => suiteReportCommand(opts));
|
|
10714
10811
|
});
|
|
10812
|
+
program.command("cohort").description("Compare baseline/candidate trace cohorts for regressions (v5.1+)").option("--dir <path>", "trace directory").option("--baseline <label>", "baseline cohort label (metadata key)").option("--candidate <label>", "candidate cohort label (metadata key)").option("--cohort-key <key>", "metadata key for cohort labels", "cohort").option("--group-by <spec>", "model | session | group | metadata.<key>", "model").option(
|
|
10813
|
+
"--metric <list>",
|
|
10814
|
+
"comma-separated metrics (errorRate,duration,toolChoice,...)"
|
|
10815
|
+
).option("--format <format>", "markdown, json, or html", "markdown").option("-o, --output <dir>", "write cohort-results.json, cohort-summary.md, cohort-report.html").option("--json", "print deterministic JSON result").action((opts) => {
|
|
10816
|
+
runCommand(() => cohortCommand(opts));
|
|
10817
|
+
});
|
|
10818
|
+
program.command("gate").description("Run deterministic CI quality gates over traces or suites (v5.2+)").option("--dir <path>", "trace directory for threshold checks").option("--suite <path>", "suite config path").option("--max-error-rate <percent>", "maximum allowed error rate percentage").option("--max-p95-duration <ms>", "maximum allowed p95 run duration in ms").option("--forbid-tool <name>", "forbidden tool name (repeatable or comma-separated)").option(
|
|
10819
|
+
"--require-observation <name>",
|
|
10820
|
+
"required passed observation (repeatable or comma-separated)"
|
|
10821
|
+
).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
|
|
10822
|
+
"-o, --output <dir>",
|
|
10823
|
+
"write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
|
|
10824
|
+
).option("--json", "print deterministic JSON result").action((opts) => {
|
|
10825
|
+
runCommand(() => gateCommand(opts));
|
|
10826
|
+
});
|
|
10715
10827
|
return program;
|
|
10716
10828
|
}
|
|
10717
10829
|
function isPrimaryModule() {
|