agent-inspect 6.10.0 → 6.12.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/README.md +33 -15
- package/docs/ADOPTION.md +4 -0
- package/docs/CLI.md +11 -0
- package/docs/COMPARE.md +22 -0
- package/docs/DEMO-SCRIPT.md +12 -0
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-36IJ76LH.mjs → chunk-XTAA733P.mjs} +2 -2
- package/packages/cli/dist/{chunk-36IJ76LH.mjs.map → chunk-XTAA733P.mjs.map} +1 -1
- package/packages/cli/dist/index.cjs +376 -218
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +297 -148
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-YFN3Q3GP.mjs → src-G7PM24W2.mjs} +3 -3
- package/packages/cli/dist/{src-YFN3Q3GP.mjs.map → src-G7PM24W2.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +143 -0
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +40 -2
- package/packages/core/dist/advanced.d.ts +40 -2
- package/packages/core/dist/advanced.mjs +146 -4
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/{chunk-KDDU2R5P.mjs → chunk-LFWZEO2L.mjs} +2 -2
- package/packages/core/dist/{chunk-KDDU2R5P.mjs.map → chunk-LFWZEO2L.mjs.map} +1 -1
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
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, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, 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, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, 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-XTAA733P.mjs';
|
|
3
3
|
import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
|
|
4
|
-
import
|
|
4
|
+
import path16 from 'path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
6
6
|
import { Command, Option } from 'commander';
|
|
7
7
|
import { readFile, stat, mkdir, writeFile, unlink, appendFile, rm, access, open, readdir, constants } from 'fs/promises';
|
|
@@ -11,7 +11,7 @@ import { createServer } from 'http';
|
|
|
11
11
|
import { createRequire } from 'module';
|
|
12
12
|
|
|
13
13
|
// package.json
|
|
14
|
-
var version = "6.
|
|
14
|
+
var version = "6.12.0";
|
|
15
15
|
|
|
16
16
|
// packages/cli/src/trace-dir-scale.ts
|
|
17
17
|
var TRACE_COUNT_WARN = 1e3;
|
|
@@ -2971,9 +2971,9 @@ Trace directory: ${traceDir}`);
|
|
|
2971
2971
|
process.exitCode = 1;
|
|
2972
2972
|
}
|
|
2973
2973
|
const resolvedOutput = resolveOutputOption(options);
|
|
2974
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
2974
|
+
const outPath = resolvedOutput !== void 0 ? path16.resolve(resolvedOutput) : void 0;
|
|
2975
2975
|
if (outPath !== void 0) {
|
|
2976
|
-
await mkdir(
|
|
2976
|
+
await mkdir(path16.dirname(outPath), { recursive: true });
|
|
2977
2977
|
await writeFile(outPath, result.content, "utf-8");
|
|
2978
2978
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
2979
2979
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -3317,7 +3317,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
3317
3317
|
endedAt: row.endedAt ?? void 0,
|
|
3318
3318
|
durationMs: row.durationMs ?? void 0,
|
|
3319
3319
|
eventCount: 0,
|
|
3320
|
-
filePath:
|
|
3320
|
+
filePath: path16.join(traceDir, row.file),
|
|
3321
3321
|
fileSize: 0,
|
|
3322
3322
|
createdAt: new Date(row.mtimeMs)
|
|
3323
3323
|
};
|
|
@@ -3346,7 +3346,7 @@ async function newestTraceMtimeMs(traceDir) {
|
|
|
3346
3346
|
}
|
|
3347
3347
|
async function loadSessionRuns(traceDir) {
|
|
3348
3348
|
try {
|
|
3349
|
-
const mod = await import('./src-
|
|
3349
|
+
const mod = await import('./src-G7PM24W2.mjs');
|
|
3350
3350
|
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
3351
3351
|
const status = mod.indexStatus(dbPath);
|
|
3352
3352
|
if (!status.healthy) {
|
|
@@ -3795,9 +3795,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
3795
3795
|
...options.section ? { section: options.section } : {}
|
|
3796
3796
|
});
|
|
3797
3797
|
const resolvedOutput = resolveOutputOption(options);
|
|
3798
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
3798
|
+
const outPath = resolvedOutput !== void 0 ? path16.resolve(resolvedOutput) : void 0;
|
|
3799
3799
|
if (outPath !== void 0) {
|
|
3800
|
-
await mkdir(
|
|
3800
|
+
await mkdir(path16.dirname(outPath), { recursive: true });
|
|
3801
3801
|
await writeFile(outPath, result.content, "utf-8");
|
|
3802
3802
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
3803
3803
|
}
|
|
@@ -3923,8 +3923,8 @@ function passesLuhn(value) {
|
|
|
3923
3923
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3924
3924
|
var EPOCH_MS_RE = /^1[0-9]{12}$/;
|
|
3925
3925
|
var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
3926
|
-
function pathSuggestsNonCard(
|
|
3927
|
-
const normalized =
|
|
3926
|
+
function pathSuggestsNonCard(path27) {
|
|
3927
|
+
const normalized = path27.toLowerCase().replace(/[^a-z0-9._]/g, "");
|
|
3928
3928
|
return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
|
|
3929
3929
|
normalized
|
|
3930
3930
|
) || /(^|\.)ts(\.|$)/.test(normalized);
|
|
@@ -4111,17 +4111,17 @@ function applyRule(rule, value, replacement) {
|
|
|
4111
4111
|
}
|
|
4112
4112
|
return value;
|
|
4113
4113
|
}
|
|
4114
|
-
function childPath(
|
|
4114
|
+
function childPath(path27, key) {
|
|
4115
4115
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
4116
|
-
return
|
|
4116
|
+
return path27 ? `${path27}.${key}` : key;
|
|
4117
4117
|
}
|
|
4118
|
-
return `${
|
|
4118
|
+
return `${path27 || "$"}[${JSON.stringify(key)}]`;
|
|
4119
4119
|
}
|
|
4120
|
-
function indexPath(
|
|
4121
|
-
return `${
|
|
4120
|
+
function indexPath(path27, index) {
|
|
4121
|
+
return `${path27 || "$"}[${index}]`;
|
|
4122
4122
|
}
|
|
4123
|
-
function makeFinding(
|
|
4124
|
-
return preview === void 0 ? { path:
|
|
4123
|
+
function makeFinding(path27, detector, action, matchKind, severity = "warning", preview) {
|
|
4124
|
+
return preview === void 0 ? { path: path27, detector, action, severity, matchKind } : { path: path27, detector, action, severity, matchKind, preview };
|
|
4125
4125
|
}
|
|
4126
4126
|
function createRedactionProfile(profile = "local") {
|
|
4127
4127
|
switch (profile) {
|
|
@@ -4190,11 +4190,11 @@ var Redactor2 = class {
|
|
|
4190
4190
|
#recordFinding(state, finding) {
|
|
4191
4191
|
if (this.#collectFindings) state.findings.push(finding);
|
|
4192
4192
|
}
|
|
4193
|
-
#redactValue(value, key,
|
|
4193
|
+
#redactValue(value, key, path27, depth, state) {
|
|
4194
4194
|
if (depth > this.#maxDepth) {
|
|
4195
4195
|
this.#recordFinding(
|
|
4196
4196
|
state,
|
|
4197
|
-
makeFinding(
|
|
4197
|
+
makeFinding(path27, "structure.maxDepth", "truncate", "value", "warning")
|
|
4198
4198
|
);
|
|
4199
4199
|
return "[Truncated]";
|
|
4200
4200
|
}
|
|
@@ -4203,19 +4203,19 @@ var Redactor2 = class {
|
|
|
4203
4203
|
if (rule) {
|
|
4204
4204
|
this.#recordFinding(
|
|
4205
4205
|
state,
|
|
4206
|
-
makeFinding(
|
|
4206
|
+
makeFinding(path27, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
4207
4207
|
);
|
|
4208
4208
|
return applyRule(rule, value, this.#replacement);
|
|
4209
4209
|
}
|
|
4210
4210
|
}
|
|
4211
4211
|
for (const detector of this.#detectors) {
|
|
4212
|
-
const detections = detector.detect({ path:
|
|
4212
|
+
const detections = detector.detect({ path: path27, key, value });
|
|
4213
4213
|
for (const detection of detections) {
|
|
4214
4214
|
const action = detection.action ?? "replace";
|
|
4215
4215
|
this.#recordFinding(
|
|
4216
4216
|
state,
|
|
4217
4217
|
makeFinding(
|
|
4218
|
-
|
|
4218
|
+
path27,
|
|
4219
4219
|
detector.id,
|
|
4220
4220
|
action,
|
|
4221
4221
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -4233,7 +4233,7 @@ var Redactor2 = class {
|
|
|
4233
4233
|
const out = [];
|
|
4234
4234
|
state.seen.set(value, out);
|
|
4235
4235
|
value.forEach((item, index) => {
|
|
4236
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
4236
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path27, index), depth + 1, state);
|
|
4237
4237
|
});
|
|
4238
4238
|
return out;
|
|
4239
4239
|
}
|
|
@@ -4245,7 +4245,7 @@ var Redactor2 = class {
|
|
|
4245
4245
|
out[entryKey] = this.#redactValue(
|
|
4246
4246
|
entryValue,
|
|
4247
4247
|
entryKey,
|
|
4248
|
-
childPath(
|
|
4248
|
+
childPath(path27 === "$" ? "" : path27, entryKey),
|
|
4249
4249
|
depth + 1,
|
|
4250
4250
|
state
|
|
4251
4251
|
);
|
|
@@ -4706,14 +4706,14 @@ function uniqueSorted(values) {
|
|
|
4706
4706
|
return [...new Set(values)].sort();
|
|
4707
4707
|
}
|
|
4708
4708
|
function isWithinDirectory(child, parent) {
|
|
4709
|
-
const relative =
|
|
4710
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
4709
|
+
const relative = path16.relative(parent, child);
|
|
4710
|
+
return relative === "" || !relative.startsWith("..") && !path16.isAbsolute(relative);
|
|
4711
4711
|
}
|
|
4712
4712
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
4713
4713
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
4714
|
-
const inputAbs =
|
|
4715
|
-
const outputAbs =
|
|
4716
|
-
const inputDir =
|
|
4714
|
+
const inputAbs = path16.resolve(inputPath);
|
|
4715
|
+
const outputAbs = path16.resolve(output2.trim());
|
|
4716
|
+
const inputDir = path16.dirname(inputAbs);
|
|
4717
4717
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
4718
4718
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
4719
4719
|
}
|
|
@@ -4834,7 +4834,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
4834
4834
|
process.exitCode = 1;
|
|
4835
4835
|
return;
|
|
4836
4836
|
}
|
|
4837
|
-
const inputPath =
|
|
4837
|
+
const inputPath = path16.resolve(input3.trim());
|
|
4838
4838
|
const dryRun = options.dryRun === true;
|
|
4839
4839
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
4840
4840
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -4853,7 +4853,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
4853
4853
|
);
|
|
4854
4854
|
const result = await buildMigration(inputPath, outputPath);
|
|
4855
4855
|
if (!dryRun && outputPath !== void 0) {
|
|
4856
|
-
await mkdir(
|
|
4856
|
+
await mkdir(path16.dirname(outputPath), { recursive: true });
|
|
4857
4857
|
await writeFile(outputPath, result.content, "utf-8");
|
|
4858
4858
|
}
|
|
4859
4859
|
printSummary2(result, dryRun);
|
|
@@ -5183,23 +5183,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
5183
5183
|
}
|
|
5184
5184
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
5185
5185
|
}
|
|
5186
|
-
function validateSchemaField(value, field,
|
|
5186
|
+
function validateSchemaField(value, field, path27, evidence) {
|
|
5187
5187
|
const ruleId = "guardrail.structured-output";
|
|
5188
5188
|
if (field.type) {
|
|
5189
5189
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
5190
5190
|
if (actual !== field.type) {
|
|
5191
|
-
evidence.push({ ruleId, path:
|
|
5191
|
+
evidence.push({ ruleId, path: path27, preview: `expected ${field.type}, got ${actual}` });
|
|
5192
5192
|
return;
|
|
5193
5193
|
}
|
|
5194
5194
|
}
|
|
5195
5195
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
5196
|
-
evidence.push({ ruleId, path:
|
|
5196
|
+
evidence.push({ ruleId, path: path27, preview: "value not in enum" });
|
|
5197
5197
|
}
|
|
5198
5198
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
5199
5199
|
const record = value;
|
|
5200
5200
|
for (const key of field.required) {
|
|
5201
5201
|
if (!(key in record)) {
|
|
5202
|
-
evidence.push({ ruleId, path: `${
|
|
5202
|
+
evidence.push({ ruleId, path: `${path27}.${key}`, preview: "missing required key" });
|
|
5203
5203
|
}
|
|
5204
5204
|
}
|
|
5205
5205
|
}
|
|
@@ -5526,7 +5526,7 @@ function asConfig(value) {
|
|
|
5526
5526
|
}
|
|
5527
5527
|
async function loadConfig(configPath) {
|
|
5528
5528
|
if (configPath === void 0) return {};
|
|
5529
|
-
const extension =
|
|
5529
|
+
const extension = path16.extname(configPath);
|
|
5530
5530
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
5531
5531
|
throw new Error(
|
|
5532
5532
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -5535,7 +5535,7 @@ async function loadConfig(configPath) {
|
|
|
5535
5535
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
5536
5536
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
5537
5537
|
}
|
|
5538
|
-
const absolute =
|
|
5538
|
+
const absolute = path16.resolve(configPath);
|
|
5539
5539
|
if (extension === ".json") {
|
|
5540
5540
|
const raw = await readFile(absolute, "utf-8");
|
|
5541
5541
|
return asConfig(JSON.parse(raw));
|
|
@@ -5711,10 +5711,10 @@ function printHuman(result) {
|
|
|
5711
5711
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
5712
5712
|
}
|
|
5713
5713
|
for (const finding of result.findings) {
|
|
5714
|
-
const
|
|
5714
|
+
const path27 = finding.evidence[0]?.path;
|
|
5715
5715
|
const run = finding.evidence[0]?.runId;
|
|
5716
5716
|
const runPrefix = run ? `[${run}] ` : "";
|
|
5717
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
5717
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
|
|
5718
5718
|
}
|
|
5719
5719
|
}
|
|
5720
5720
|
function readErrorResult(error) {
|
|
@@ -5976,7 +5976,7 @@ async function loadSuiteViewerData(options) {
|
|
|
5976
5976
|
for (const suiteCase of result.cases) {
|
|
5977
5977
|
cases.push(await enrichCase(suiteCase, baselinePath));
|
|
5978
5978
|
}
|
|
5979
|
-
const artifactsDir =
|
|
5979
|
+
const artifactsDir = path16.join(path16.dirname(result.configPath), ".agent-inspect/suite-runs");
|
|
5980
5980
|
return {
|
|
5981
5981
|
suiteName: result.suiteName,
|
|
5982
5982
|
configPath: result.configPath,
|
|
@@ -6169,19 +6169,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
6169
6169
|
}
|
|
6170
6170
|
var INDEX_DIR_NAME = "index";
|
|
6171
6171
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
6172
|
-
const projectRoot =
|
|
6173
|
-
const workspaceDir =
|
|
6172
|
+
const projectRoot = path16.resolve(cwd);
|
|
6173
|
+
const workspaceDir = path16.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
6174
6174
|
return {
|
|
6175
6175
|
projectRoot,
|
|
6176
6176
|
workspaceDir,
|
|
6177
|
-
manifestPath:
|
|
6177
|
+
manifestPath: path16.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
6178
6178
|
};
|
|
6179
6179
|
}
|
|
6180
6180
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
6181
|
-
const base =
|
|
6182
|
-
const resolved =
|
|
6183
|
-
const rel =
|
|
6184
|
-
if (rel === "" || rel === "." || !rel.startsWith("..") && !
|
|
6181
|
+
const base = path16.resolve(workspaceDir);
|
|
6182
|
+
const resolved = path16.resolve(base, relative);
|
|
6183
|
+
const rel = path16.relative(base, resolved);
|
|
6184
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path16.isAbsolute(rel)) {
|
|
6185
6185
|
return resolved;
|
|
6186
6186
|
}
|
|
6187
6187
|
throw new Error(
|
|
@@ -6250,7 +6250,7 @@ async function createWorkspace(options = {}) {
|
|
|
6250
6250
|
created = false;
|
|
6251
6251
|
adopted = true;
|
|
6252
6252
|
} else {
|
|
6253
|
-
const project = options.project?.trim() ||
|
|
6253
|
+
const project = options.project?.trim() || path16.basename(location.projectRoot) || "workspace";
|
|
6254
6254
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
6255
6255
|
manifest = createDefaultWorkspaceManifest({
|
|
6256
6256
|
project,
|
|
@@ -6389,7 +6389,7 @@ async function doctorWorkspace(location) {
|
|
|
6389
6389
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
6390
6390
|
for (const file of await listJsonl(abs)) {
|
|
6391
6391
|
try {
|
|
6392
|
-
const s = await stat(
|
|
6392
|
+
const s = await stat(path16.join(abs, file));
|
|
6393
6393
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
6394
6394
|
} catch {
|
|
6395
6395
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -6437,7 +6437,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
6437
6437
|
const relPath = `${rel}/${entry}`;
|
|
6438
6438
|
removed.push(relPath);
|
|
6439
6439
|
if (!dryRun) {
|
|
6440
|
-
await rm(
|
|
6440
|
+
await rm(path16.join(abs, entry), { recursive: true, force: true });
|
|
6441
6441
|
}
|
|
6442
6442
|
}
|
|
6443
6443
|
}
|
|
@@ -6446,7 +6446,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
6446
6446
|
|
|
6447
6447
|
// packages/viewer/src/workspace-data.ts
|
|
6448
6448
|
async function loadWorkspaceViewerData(options) {
|
|
6449
|
-
const cwd =
|
|
6449
|
+
const cwd = path16.resolve(options.cwd ?? process.cwd());
|
|
6450
6450
|
const location = resolveWorkspaceLocation(cwd);
|
|
6451
6451
|
const manifestRead = await readWorkspaceManifestFile(location);
|
|
6452
6452
|
if (!manifestRead.ok || manifestRead.manifest === void 0) {
|
|
@@ -6459,7 +6459,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
6459
6459
|
const runs = [];
|
|
6460
6460
|
for (const rel of manifestRead.manifest.traceDirs) {
|
|
6461
6461
|
const traceDir = resolveTraceDir({
|
|
6462
|
-
dir:
|
|
6462
|
+
dir: path16.join(location.workspaceDir, rel)
|
|
6463
6463
|
});
|
|
6464
6464
|
const td = new TraceDirectory({ dir: traceDir });
|
|
6465
6465
|
const files = await td.list();
|
|
@@ -6473,7 +6473,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
6473
6473
|
runId: meta.runId,
|
|
6474
6474
|
...meta.name !== void 0 ? { name: meta.name } : {},
|
|
6475
6475
|
status: meta.status,
|
|
6476
|
-
file:
|
|
6476
|
+
file: path16.basename(meta.filePath)
|
|
6477
6477
|
});
|
|
6478
6478
|
}
|
|
6479
6479
|
}
|
|
@@ -6484,8 +6484,8 @@ async function loadWorkspaceViewerData(options) {
|
|
|
6484
6484
|
doctor,
|
|
6485
6485
|
runs,
|
|
6486
6486
|
bundleDirs: [
|
|
6487
|
-
|
|
6488
|
-
|
|
6487
|
+
path16.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
|
|
6488
|
+
path16.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
|
|
6489
6489
|
]
|
|
6490
6490
|
};
|
|
6491
6491
|
}
|
|
@@ -6548,7 +6548,7 @@ function createViewerServer(options = {}) {
|
|
|
6548
6548
|
ok: true,
|
|
6549
6549
|
readOnly: true,
|
|
6550
6550
|
mode,
|
|
6551
|
-
traceDir:
|
|
6551
|
+
traceDir: path16.resolve(traceDir)
|
|
6552
6552
|
});
|
|
6553
6553
|
}
|
|
6554
6554
|
if (pathname === "/api/suite" && mode === "suite") {
|
|
@@ -6577,7 +6577,7 @@ function createViewerServer(options = {}) {
|
|
|
6577
6577
|
runId: meta.runId,
|
|
6578
6578
|
name: meta.name,
|
|
6579
6579
|
status: meta.status,
|
|
6580
|
-
file:
|
|
6580
|
+
file: path16.basename(meta.filePath),
|
|
6581
6581
|
startedAt: meta.startedAt,
|
|
6582
6582
|
durationMs: meta.durationMs
|
|
6583
6583
|
}))
|
|
@@ -6694,7 +6694,7 @@ function startViewerServer(options = {}) {
|
|
|
6694
6694
|
resolve({
|
|
6695
6695
|
host,
|
|
6696
6696
|
port: resolvedPort,
|
|
6697
|
-
traceDir:
|
|
6697
|
+
traceDir: path16.resolve(traceDir),
|
|
6698
6698
|
url: `http://${host}:${resolvedPort}/${modeQuery}`,
|
|
6699
6699
|
mode
|
|
6700
6700
|
});
|
|
@@ -7065,10 +7065,10 @@ async function evalRun(input3, options = {}) {
|
|
|
7065
7065
|
diagnostics: []
|
|
7066
7066
|
};
|
|
7067
7067
|
}
|
|
7068
|
-
function evidenceForRun(run,
|
|
7069
|
-
return [{ runId: run.runId, ...
|
|
7068
|
+
function evidenceForRun(run, path27) {
|
|
7069
|
+
return [{ runId: run.runId, ...path27 !== void 0 ? { path: path27 } : {} }];
|
|
7070
7070
|
}
|
|
7071
|
-
function evidenceForEvent(event,
|
|
7071
|
+
function evidenceForEvent(event, path27) {
|
|
7072
7072
|
return [
|
|
7073
7073
|
{
|
|
7074
7074
|
runId: event.runId,
|
|
@@ -7076,7 +7076,7 @@ function evidenceForEvent(event, path26) {
|
|
|
7076
7076
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
7077
7077
|
kind: event.kind,
|
|
7078
7078
|
name: event.name,
|
|
7079
|
-
...
|
|
7079
|
+
...path27 !== void 0 ? { path: path27 } : {}
|
|
7080
7080
|
}
|
|
7081
7081
|
];
|
|
7082
7082
|
}
|
|
@@ -7234,9 +7234,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
7234
7234
|
function tokenize(text) {
|
|
7235
7235
|
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));
|
|
7236
7236
|
}
|
|
7237
|
-
function firstEvidence(fields, run,
|
|
7237
|
+
function firstEvidence(fields, run, path27) {
|
|
7238
7238
|
const first = fields[0];
|
|
7239
|
-
return first === void 0 ? evidenceForRun(run,
|
|
7239
|
+
return first === void 0 ? evidenceForRun(run, path27) : evidenceForEvent(first.node.event, first.path);
|
|
7240
7240
|
}
|
|
7241
7241
|
function collectSourceIds(nodes, keys) {
|
|
7242
7242
|
const wanted = keySet(keys);
|
|
@@ -7613,8 +7613,8 @@ function renderEvalMarkdown(result) {
|
|
|
7613
7613
|
if (result.findings.length > 0) {
|
|
7614
7614
|
lines.push("", "## Findings");
|
|
7615
7615
|
for (const finding of result.findings) {
|
|
7616
|
-
const
|
|
7617
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
7616
|
+
const path27 = finding.evidence[0]?.path;
|
|
7617
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
|
|
7618
7618
|
}
|
|
7619
7619
|
}
|
|
7620
7620
|
return `${lines.join("\n")}
|
|
@@ -7661,7 +7661,7 @@ function asConfig2(value) {
|
|
|
7661
7661
|
}
|
|
7662
7662
|
async function loadConfig2(configPath) {
|
|
7663
7663
|
if (configPath === void 0) return {};
|
|
7664
|
-
const extension =
|
|
7664
|
+
const extension = path16.extname(configPath);
|
|
7665
7665
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
7666
7666
|
throw new Error(
|
|
7667
7667
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -7670,7 +7670,7 @@ async function loadConfig2(configPath) {
|
|
|
7670
7670
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
7671
7671
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
7672
7672
|
}
|
|
7673
|
-
const absolute =
|
|
7673
|
+
const absolute = path16.resolve(configPath);
|
|
7674
7674
|
if (extension === ".json") {
|
|
7675
7675
|
const raw = await readFile(absolute, "utf-8");
|
|
7676
7676
|
return asConfig2(JSON.parse(raw));
|
|
@@ -7807,8 +7807,8 @@ function printHuman2(result) {
|
|
|
7807
7807
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
7808
7808
|
}
|
|
7809
7809
|
for (const finding of result.findings) {
|
|
7810
|
-
const
|
|
7811
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
7810
|
+
const path27 = finding.evidence[0]?.path;
|
|
7811
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
|
|
7812
7812
|
}
|
|
7813
7813
|
}
|
|
7814
7814
|
function readErrorResult2(error) {
|
|
@@ -8061,14 +8061,14 @@ function exitCodeFor3(result) {
|
|
|
8061
8061
|
return 2;
|
|
8062
8062
|
}
|
|
8063
8063
|
function explainFinding(finding, blocksBundle) {
|
|
8064
|
-
const
|
|
8064
|
+
const path27 = finding.evidence[0]?.path ?? "(unknown path)";
|
|
8065
8065
|
const category = finding.category ?? "structure";
|
|
8066
8066
|
const confidence = finding.confidence ?? "medium";
|
|
8067
8067
|
const detector = finding.detector ?? finding.ruleId;
|
|
8068
8068
|
const action = finding.action ?? "review";
|
|
8069
8069
|
const redactionHint = category === "credential" || category === "personal-data" || category === "raw-content" || action.includes("redact") ? "Usually removable by share/strict redaction before bundling." : "May require omitting the field, lowering limits, or an explicit local override.";
|
|
8070
8070
|
return [
|
|
8071
|
-
` Matched: detector=${detector}; path=${
|
|
8071
|
+
` Matched: detector=${detector}; path=${path27}; category=${category}`,
|
|
8072
8072
|
` Why: ${finding.message}`,
|
|
8073
8073
|
` Confidence: ${confidence}`,
|
|
8074
8074
|
` Redaction: ${redactionHint}`,
|
|
@@ -8110,9 +8110,9 @@ function printHuman3(result, explain = false) {
|
|
|
8110
8110
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
8111
8111
|
}
|
|
8112
8112
|
for (const finding of result.findings) {
|
|
8113
|
-
const
|
|
8113
|
+
const path27 = finding.evidence[0]?.path;
|
|
8114
8114
|
const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
|
|
8115
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
8115
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}${taxonomy}`);
|
|
8116
8116
|
if (explain) {
|
|
8117
8117
|
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
8118
8118
|
for (const line of explainFinding(finding, blocks)) {
|
|
@@ -8227,7 +8227,7 @@ function messageStartsWithDash(error) {
|
|
|
8227
8227
|
return message.startsWith("--");
|
|
8228
8228
|
}
|
|
8229
8229
|
function validateReporterArtifactPath(options) {
|
|
8230
|
-
const outputDir =
|
|
8230
|
+
const outputDir = path16.resolve(options.outputDir);
|
|
8231
8231
|
const diagnostics = [];
|
|
8232
8232
|
const rawPath = options.relativePath;
|
|
8233
8233
|
if (rawPath.length === 0) {
|
|
@@ -8247,7 +8247,7 @@ function validateReporterArtifactPath(options) {
|
|
|
8247
8247
|
});
|
|
8248
8248
|
return { ok: false, outputDir, diagnostics };
|
|
8249
8249
|
}
|
|
8250
|
-
if (
|
|
8250
|
+
if (path16.isAbsolute(rawPath) || path16.win32.isAbsolute(rawPath)) {
|
|
8251
8251
|
diagnostics.push({
|
|
8252
8252
|
code: "artifact_path_absolute",
|
|
8253
8253
|
severity: "error",
|
|
@@ -8256,7 +8256,7 @@ function validateReporterArtifactPath(options) {
|
|
|
8256
8256
|
});
|
|
8257
8257
|
return { ok: false, outputDir, diagnostics };
|
|
8258
8258
|
}
|
|
8259
|
-
const normalized =
|
|
8259
|
+
const normalized = path16.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
8260
8260
|
const segments = normalized.split("/");
|
|
8261
8261
|
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
8262
8262
|
diagnostics.push({
|
|
@@ -8267,9 +8267,9 @@ function validateReporterArtifactPath(options) {
|
|
|
8267
8267
|
});
|
|
8268
8268
|
return { ok: false, outputDir, diagnostics };
|
|
8269
8269
|
}
|
|
8270
|
-
const absolutePath =
|
|
8271
|
-
const relFromOutput =
|
|
8272
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") ||
|
|
8270
|
+
const absolutePath = path16.resolve(outputDir, normalized);
|
|
8271
|
+
const relFromOutput = path16.relative(outputDir, absolutePath);
|
|
8272
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path16.isAbsolute(relFromOutput)) {
|
|
8273
8273
|
diagnostics.push({
|
|
8274
8274
|
code: "artifact_path_escape",
|
|
8275
8275
|
severity: "error",
|
|
@@ -8295,7 +8295,7 @@ var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
|
8295
8295
|
function createEvidenceCiArtifacts(options) {
|
|
8296
8296
|
const profile = options.redactionProfile;
|
|
8297
8297
|
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
8298
|
-
const join = (name) => prefix === "" ? name :
|
|
8298
|
+
const join = (name) => prefix === "" ? name : path16.posix.join(prefix, name);
|
|
8299
8299
|
const formatFor = (name) => {
|
|
8300
8300
|
if (name.endsWith(".html")) return "html";
|
|
8301
8301
|
if (name.endsWith(".jsonl")) return "jsonl";
|
|
@@ -8384,8 +8384,8 @@ function renderCheckSection(result) {
|
|
|
8384
8384
|
`Diagnostics: ${result.diagnostics.length}`
|
|
8385
8385
|
];
|
|
8386
8386
|
for (const finding of result.findings.slice(0, 10)) {
|
|
8387
|
-
const
|
|
8388
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
8387
|
+
const path27 = finding.evidence[0]?.path ?? "(run)";
|
|
8388
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path27})`);
|
|
8389
8389
|
}
|
|
8390
8390
|
for (const diagnostic3 of result.diagnostics.slice(0, 10)) {
|
|
8391
8391
|
lines.push(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
@@ -8463,8 +8463,8 @@ function renderHtml(trace, check, diff) {
|
|
|
8463
8463
|
`;
|
|
8464
8464
|
}
|
|
8465
8465
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
8466
|
-
const outPath =
|
|
8467
|
-
await mkdir(
|
|
8466
|
+
const outPath = path16.join(outputDir, relativePath);
|
|
8467
|
+
await mkdir(path16.dirname(outPath), { recursive: true });
|
|
8468
8468
|
await writeFile(outPath, content, "utf-8");
|
|
8469
8469
|
files.push(relativePath);
|
|
8470
8470
|
}
|
|
@@ -8493,7 +8493,7 @@ function shouldWriteEvidence(options, status) {
|
|
|
8493
8493
|
return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
|
|
8494
8494
|
}
|
|
8495
8495
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
8496
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
8496
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path16.resolve(options.outputDir.trim()) : "";
|
|
8497
8497
|
if (outputDir === "") {
|
|
8498
8498
|
console.error("--output-dir is required.");
|
|
8499
8499
|
process.exitCode = 1;
|
|
@@ -8621,8 +8621,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
8621
8621
|
}
|
|
8622
8622
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
8623
8623
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
8624
|
-
await mkdir(
|
|
8625
|
-
await appendFile(
|
|
8624
|
+
await mkdir(path16.dirname(path16.resolve(summaryTarget)), { recursive: true });
|
|
8625
|
+
await appendFile(path16.resolve(summaryTarget), `
|
|
8626
8626
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
8627
8627
|
}
|
|
8628
8628
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -8641,10 +8641,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
8641
8641
|
findings: diff?.findings.length ?? 0,
|
|
8642
8642
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
8643
8643
|
},
|
|
8644
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
8644
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path16.resolve(summaryTarget) } : {},
|
|
8645
8645
|
note: NOTE
|
|
8646
8646
|
};
|
|
8647
|
-
await writeFile(
|
|
8647
|
+
await writeFile(path16.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
8648
8648
|
if (options.json === true) {
|
|
8649
8649
|
console.log(writeJson3(manifest).trimEnd());
|
|
8650
8650
|
} else {
|
|
@@ -8702,8 +8702,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
8702
8702
|
const location = resolveWorkspaceLocation(cwd);
|
|
8703
8703
|
const manifest = await readWorkspaceManifestFile(location);
|
|
8704
8704
|
if (manifest.ok && manifest.manifest) {
|
|
8705
|
-
const rel =
|
|
8706
|
-
if (!rel.startsWith("..") && !
|
|
8705
|
+
const rel = path16.relative(location.workspaceDir, normalized);
|
|
8706
|
+
if (!rel.startsWith("..") && !path16.isAbsolute(rel)) {
|
|
8707
8707
|
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
8708
8708
|
}
|
|
8709
8709
|
}
|
|
@@ -8719,7 +8719,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
8719
8719
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
8720
8720
|
const base2 = resolveInsideWorkspace(
|
|
8721
8721
|
location.workspaceDir,
|
|
8722
|
-
|
|
8722
|
+
path16.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
8723
8723
|
);
|
|
8724
8724
|
return format === "zip" ? `${base2}.zip` : base2;
|
|
8725
8725
|
}
|
|
@@ -9124,19 +9124,19 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
9124
9124
|
let sidecarDir = outputDir;
|
|
9125
9125
|
if (outputDir.toLowerCase().endsWith(".html")) {
|
|
9126
9126
|
htmlPath = outputDir;
|
|
9127
|
-
sidecarDir =
|
|
9127
|
+
sidecarDir = path16.dirname(outputDir);
|
|
9128
9128
|
} else {
|
|
9129
9129
|
await mkdir(outputDir, { recursive: true });
|
|
9130
|
-
htmlPath =
|
|
9130
|
+
htmlPath = path16.join(outputDir, EVIDENCE_HTML_FILENAME);
|
|
9131
9131
|
sidecarDir = outputDir;
|
|
9132
9132
|
}
|
|
9133
9133
|
await mkdir(sidecarDir, { recursive: true });
|
|
9134
9134
|
await writeFile(htmlPath, htmlContent, "utf-8");
|
|
9135
|
-
await writeFile(
|
|
9135
|
+
await writeFile(path16.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
9136
9136
|
outputPath = htmlPath;
|
|
9137
9137
|
} else if (format === "zip") {
|
|
9138
9138
|
const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
|
|
9139
|
-
const zipParent =
|
|
9139
|
+
const zipParent = path16.dirname(zipPath);
|
|
9140
9140
|
await mkdir(zipParent, { recursive: true });
|
|
9141
9141
|
const entries = [
|
|
9142
9142
|
...[...packaged.entries()].map(([relativePath, content]) => ({
|
|
@@ -9152,10 +9152,10 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
9152
9152
|
await mkdir(outputDir, { recursive: true });
|
|
9153
9153
|
for (const [relativePath, content] of packaged.entries()) {
|
|
9154
9154
|
const outPath = assertBundlePathContained(outputDir, relativePath);
|
|
9155
|
-
await mkdir(
|
|
9155
|
+
await mkdir(path16.dirname(outPath), { recursive: true });
|
|
9156
9156
|
await writeFile(outPath, content, "utf-8");
|
|
9157
9157
|
}
|
|
9158
|
-
await writeFile(
|
|
9158
|
+
await writeFile(path16.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
9159
9159
|
if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
|
|
9160
9160
|
files.push(EVIDENCE_MANIFEST_FILENAME);
|
|
9161
9161
|
}
|
|
@@ -9201,7 +9201,7 @@ function writeJson5(value) {
|
|
|
9201
9201
|
`;
|
|
9202
9202
|
}
|
|
9203
9203
|
async function bundleVerifyCommand(targetPath, options = {}) {
|
|
9204
|
-
const root =
|
|
9204
|
+
const root = path16.resolve(targetPath.trim() || ".");
|
|
9205
9205
|
const result = await verifyEvidenceDirectory(root, {
|
|
9206
9206
|
unexpectedFiles: options.unexpected ?? "fail"
|
|
9207
9207
|
});
|
|
@@ -9234,6 +9234,141 @@ async function bundleVerifyCommand(targetPath, options = {}) {
|
|
|
9234
9234
|
process.exitCode = 1;
|
|
9235
9235
|
}
|
|
9236
9236
|
}
|
|
9237
|
+
var CLIENTS = [
|
|
9238
|
+
"cursor",
|
|
9239
|
+
"claude-code",
|
|
9240
|
+
"codex",
|
|
9241
|
+
"gemini"
|
|
9242
|
+
];
|
|
9243
|
+
function isMcpConfigureClient(value) {
|
|
9244
|
+
return CLIENTS.includes(value);
|
|
9245
|
+
}
|
|
9246
|
+
function buildServerBlock(traceDir) {
|
|
9247
|
+
return {
|
|
9248
|
+
command: "npx",
|
|
9249
|
+
args: ["-y", "@agent-inspect/mcp-server", "--dir", traceDir],
|
|
9250
|
+
env: {
|
|
9251
|
+
AGENT_INSPECT_TRACE_DIR: traceDir,
|
|
9252
|
+
AGENT_INSPECT_MCP_REDACTION_PROFILE: "share"
|
|
9253
|
+
}
|
|
9254
|
+
};
|
|
9255
|
+
}
|
|
9256
|
+
function buildMcpClientConfig(client, traceDir) {
|
|
9257
|
+
const server = buildServerBlock(traceDir);
|
|
9258
|
+
switch (client) {
|
|
9259
|
+
case "cursor":
|
|
9260
|
+
return {
|
|
9261
|
+
mcpServers: {
|
|
9262
|
+
"agent-inspect": server
|
|
9263
|
+
}
|
|
9264
|
+
};
|
|
9265
|
+
case "claude-code":
|
|
9266
|
+
return {
|
|
9267
|
+
mcpServers: {
|
|
9268
|
+
"agent-inspect": server
|
|
9269
|
+
}
|
|
9270
|
+
};
|
|
9271
|
+
case "codex":
|
|
9272
|
+
return {
|
|
9273
|
+
mcp_servers: {
|
|
9274
|
+
"agent-inspect": {
|
|
9275
|
+
command: server.command,
|
|
9276
|
+
args: server.args,
|
|
9277
|
+
env: server.env
|
|
9278
|
+
}
|
|
9279
|
+
}
|
|
9280
|
+
};
|
|
9281
|
+
case "gemini":
|
|
9282
|
+
return {
|
|
9283
|
+
mcpServers: {
|
|
9284
|
+
"agent-inspect": server
|
|
9285
|
+
}
|
|
9286
|
+
};
|
|
9287
|
+
default: {
|
|
9288
|
+
const _exhaustive = client;
|
|
9289
|
+
return _exhaustive;
|
|
9290
|
+
}
|
|
9291
|
+
}
|
|
9292
|
+
}
|
|
9293
|
+
function resolveTargetPath(client, projectLocal) {
|
|
9294
|
+
if (projectLocal) {
|
|
9295
|
+
switch (client) {
|
|
9296
|
+
case "cursor":
|
|
9297
|
+
return path16.join(".cursor", "mcp.json");
|
|
9298
|
+
case "claude-code":
|
|
9299
|
+
return path16.join(".mcp.json");
|
|
9300
|
+
case "codex":
|
|
9301
|
+
return path16.join(".codex", "config.toml.json");
|
|
9302
|
+
case "gemini":
|
|
9303
|
+
return path16.join(".gemini", "settings.json");
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9306
|
+
switch (client) {
|
|
9307
|
+
case "cursor":
|
|
9308
|
+
return path16.join("~", ".cursor", "mcp.json");
|
|
9309
|
+
case "claude-code":
|
|
9310
|
+
return path16.join("~", ".claude.json");
|
|
9311
|
+
case "codex":
|
|
9312
|
+
return path16.join("~", ".codex", "config.toml");
|
|
9313
|
+
case "gemini":
|
|
9314
|
+
return path16.join("~", ".gemini", "settings.json");
|
|
9315
|
+
}
|
|
9316
|
+
}
|
|
9317
|
+
async function mcpConfigureCommand(options) {
|
|
9318
|
+
if (!isMcpConfigureClient(options.client)) {
|
|
9319
|
+
throw new Error(
|
|
9320
|
+
`Unsupported client "${String(options.client)}". Use: ${CLIENTS.join(", ")}`
|
|
9321
|
+
);
|
|
9322
|
+
}
|
|
9323
|
+
const traceDir = options.dir?.trim() || ".agent-inspect";
|
|
9324
|
+
const projectLocal = Boolean(options.projectLocal);
|
|
9325
|
+
const write = Boolean(options.write);
|
|
9326
|
+
const yes = Boolean(options.yes);
|
|
9327
|
+
const dryRun = !(write && yes && projectLocal);
|
|
9328
|
+
const config = buildMcpClientConfig(options.client, traceDir);
|
|
9329
|
+
const targetPath = resolveTargetPath(options.client, projectLocal);
|
|
9330
|
+
const notes = [
|
|
9331
|
+
"Read-only MCP server; no network upload; share redaction by default.",
|
|
9332
|
+
"Dry-run by default. Pass --project-local --write --yes to write a project file.",
|
|
9333
|
+
"User-level paths are never auto-written by this command.",
|
|
9334
|
+
"Remove the agent-inspect server block to uninstall."
|
|
9335
|
+
];
|
|
9336
|
+
let wrote = false;
|
|
9337
|
+
if (!dryRun && projectLocal) {
|
|
9338
|
+
const abs = path16.resolve(targetPath);
|
|
9339
|
+
await mkdir(path16.dirname(abs), { recursive: true });
|
|
9340
|
+
await writeFile(abs, `${JSON.stringify(config, null, 2)}
|
|
9341
|
+
`, "utf8");
|
|
9342
|
+
wrote = true;
|
|
9343
|
+
}
|
|
9344
|
+
const result = {
|
|
9345
|
+
client: options.client,
|
|
9346
|
+
dryRun,
|
|
9347
|
+
wrote,
|
|
9348
|
+
targetPath,
|
|
9349
|
+
config,
|
|
9350
|
+
notes
|
|
9351
|
+
};
|
|
9352
|
+
if (options.json) {
|
|
9353
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
9354
|
+
`);
|
|
9355
|
+
} else {
|
|
9356
|
+
process.stdout.write(
|
|
9357
|
+
[
|
|
9358
|
+
`Client: ${result.client}`,
|
|
9359
|
+
`Mode: ${result.dryRun ? "dry-run" : "write"}`,
|
|
9360
|
+
`Target: ${result.targetPath}`,
|
|
9361
|
+
`Wrote: ${result.wrote}`,
|
|
9362
|
+
"",
|
|
9363
|
+
JSON.stringify(result.config, null, 2),
|
|
9364
|
+
"",
|
|
9365
|
+
...result.notes.map((note) => `- ${note}`),
|
|
9366
|
+
""
|
|
9367
|
+
].join("\n")
|
|
9368
|
+
);
|
|
9369
|
+
}
|
|
9370
|
+
return result;
|
|
9371
|
+
}
|
|
9237
9372
|
var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
|
|
9238
9373
|
var MAX_TEXT = 180;
|
|
9239
9374
|
var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
|
|
@@ -9361,23 +9496,23 @@ function readManifestDocument(value) {
|
|
|
9361
9496
|
};
|
|
9362
9497
|
}
|
|
9363
9498
|
function cwdRelative(filePath) {
|
|
9364
|
-
const relative =
|
|
9365
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
9366
|
-
return
|
|
9499
|
+
const relative = path16.relative(process.cwd(), path16.resolve(filePath)).replace(/\\/g, "/");
|
|
9500
|
+
if (relative === "" || relative.startsWith("../") || path16.isAbsolute(relative)) {
|
|
9501
|
+
return path16.basename(filePath);
|
|
9367
9502
|
}
|
|
9368
9503
|
return relative;
|
|
9369
9504
|
}
|
|
9370
9505
|
async function readReporterManifest(filePath) {
|
|
9371
|
-
const absolute =
|
|
9506
|
+
const absolute = path16.resolve(filePath);
|
|
9372
9507
|
const raw = await readFile(absolute, "utf-8");
|
|
9373
9508
|
const document = readManifestDocument(JSON.parse(raw));
|
|
9374
9509
|
const manifest = document.manifest;
|
|
9375
9510
|
const results = manifest.results.map((result) => ({
|
|
9376
9511
|
testId: safeText(result.testId),
|
|
9377
9512
|
name: safeText(result.name),
|
|
9378
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
9513
|
+
...result.file === void 0 ? {} : { file: safeText(path16.basename(result.file)) },
|
|
9379
9514
|
status: result.status,
|
|
9380
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
9515
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path16.basename(result.tracePath)) },
|
|
9381
9516
|
artifacts: result.artifacts,
|
|
9382
9517
|
diagnostics: result.diagnostics
|
|
9383
9518
|
}));
|
|
@@ -9516,15 +9651,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
9516
9651
|
return;
|
|
9517
9652
|
}
|
|
9518
9653
|
const markdown = renderMarkdown2(result);
|
|
9519
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
9654
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path16.resolve(options.output.trim()) : void 0;
|
|
9520
9655
|
if (outputPath !== void 0) {
|
|
9521
|
-
await mkdir(
|
|
9656
|
+
await mkdir(path16.dirname(outputPath), { recursive: true });
|
|
9522
9657
|
await writeFile(outputPath, markdown, "utf-8");
|
|
9523
9658
|
}
|
|
9524
9659
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
9525
9660
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
9526
|
-
const summaryPath =
|
|
9527
|
-
await mkdir(
|
|
9661
|
+
const summaryPath = path16.resolve(summaryTarget);
|
|
9662
|
+
await mkdir(path16.dirname(summaryPath), { recursive: true });
|
|
9528
9663
|
await appendFile(summaryPath, `
|
|
9529
9664
|
${markdown}`, "utf-8");
|
|
9530
9665
|
}
|
|
@@ -9672,7 +9807,7 @@ jobs:
|
|
|
9672
9807
|
}
|
|
9673
9808
|
async function planInit(options = {}) {
|
|
9674
9809
|
const framework = normalizeFramework(options.framework);
|
|
9675
|
-
const cwd =
|
|
9810
|
+
const cwd = path16.resolve(options.cwd ?? process.cwd());
|
|
9676
9811
|
const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
|
|
9677
9812
|
const candidates = [
|
|
9678
9813
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
@@ -9687,7 +9822,7 @@ async function planInit(options = {}) {
|
|
|
9687
9822
|
}
|
|
9688
9823
|
const files = [];
|
|
9689
9824
|
for (const candidate of candidates) {
|
|
9690
|
-
const abs =
|
|
9825
|
+
const abs = path16.join(cwd, candidate.rel);
|
|
9691
9826
|
try {
|
|
9692
9827
|
await access(abs);
|
|
9693
9828
|
files.push({
|
|
@@ -9708,12 +9843,12 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
9708
9843
|
if (entry.action === "skip") {
|
|
9709
9844
|
continue;
|
|
9710
9845
|
}
|
|
9711
|
-
const abs =
|
|
9846
|
+
const abs = path16.join(cwd, entry.path);
|
|
9712
9847
|
if (options.dryRun) {
|
|
9713
9848
|
written.push(entry.path);
|
|
9714
9849
|
continue;
|
|
9715
9850
|
}
|
|
9716
|
-
await mkdir(
|
|
9851
|
+
await mkdir(path16.dirname(abs), { recursive: true });
|
|
9717
9852
|
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
|
|
9718
9853
|
await writeFile(abs, content, "utf-8");
|
|
9719
9854
|
written.push(entry.path);
|
|
@@ -9721,7 +9856,7 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
9721
9856
|
return written;
|
|
9722
9857
|
}
|
|
9723
9858
|
async function initCommand(options = {}) {
|
|
9724
|
-
const cwd =
|
|
9859
|
+
const cwd = path16.resolve(options.cwd ?? process.cwd());
|
|
9725
9860
|
try {
|
|
9726
9861
|
const plan = await planInit({ ...options, cwd });
|
|
9727
9862
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -9812,7 +9947,7 @@ function envCheck(name, optional = true) {
|
|
|
9812
9947
|
};
|
|
9813
9948
|
}
|
|
9814
9949
|
async function traceDirWritable(traceDir) {
|
|
9815
|
-
const resolved =
|
|
9950
|
+
const resolved = path16.resolve(traceDir);
|
|
9816
9951
|
try {
|
|
9817
9952
|
await mkdir(resolved, { recursive: true });
|
|
9818
9953
|
await access(resolved, constants.W_OK);
|
|
@@ -9833,10 +9968,10 @@ async function traceDirWritable(traceDir) {
|
|
|
9833
9968
|
}
|
|
9834
9969
|
}
|
|
9835
9970
|
function readPackageVersionNearEntry(entryPath, packageName) {
|
|
9836
|
-
let dir =
|
|
9837
|
-
const { root } =
|
|
9971
|
+
let dir = path16.dirname(path16.resolve(entryPath));
|
|
9972
|
+
const { root } = path16.parse(dir);
|
|
9838
9973
|
while (true) {
|
|
9839
|
-
const candidate =
|
|
9974
|
+
const candidate = path16.join(dir, "package.json");
|
|
9840
9975
|
if (existsSync(candidate)) {
|
|
9841
9976
|
try {
|
|
9842
9977
|
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
@@ -9847,14 +9982,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
|
|
|
9847
9982
|
}
|
|
9848
9983
|
}
|
|
9849
9984
|
if (dir === root) break;
|
|
9850
|
-
const parent =
|
|
9985
|
+
const parent = path16.dirname(dir);
|
|
9851
9986
|
if (parent === dir) break;
|
|
9852
9987
|
dir = parent;
|
|
9853
9988
|
}
|
|
9854
9989
|
return void 0;
|
|
9855
9990
|
}
|
|
9856
9991
|
function resolveInstalledPackage(cwd, name) {
|
|
9857
|
-
const require2 = createRequire(
|
|
9992
|
+
const require2 = createRequire(path16.join(cwd, "package.json"));
|
|
9858
9993
|
try {
|
|
9859
9994
|
const entry = require2.resolve(name);
|
|
9860
9995
|
let version2;
|
|
@@ -9952,7 +10087,7 @@ function versionMismatchCheck(cwd) {
|
|
|
9952
10087
|
};
|
|
9953
10088
|
}
|
|
9954
10089
|
async function runDoctorChecks(options = {}) {
|
|
9955
|
-
const cwd =
|
|
10090
|
+
const cwd = path16.resolve(options.cwd ?? process2.cwd());
|
|
9956
10091
|
const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
9957
10092
|
const checks2 = [
|
|
9958
10093
|
nodeVersionCheck(),
|
|
@@ -10192,7 +10327,7 @@ function parsePluginManifest(input3) {
|
|
|
10192
10327
|
};
|
|
10193
10328
|
}
|
|
10194
10329
|
async function readPluginManifestFile(packageDir) {
|
|
10195
|
-
const manifestPath =
|
|
10330
|
+
const manifestPath = path16.join(packageDir, PLUGIN_MANIFEST_FILENAME);
|
|
10196
10331
|
try {
|
|
10197
10332
|
const raw = await readFile(manifestPath, "utf8");
|
|
10198
10333
|
const parsed = parsePluginManifest(JSON.parse(raw));
|
|
@@ -10266,7 +10401,7 @@ function createTraceDirectoryIndexer() {
|
|
|
10266
10401
|
// packages/cli/src/plugins.ts
|
|
10267
10402
|
async function readPackageName(packageDir) {
|
|
10268
10403
|
try {
|
|
10269
|
-
const raw = await readFile(
|
|
10404
|
+
const raw = await readFile(path16.join(packageDir, "package.json"), "utf8");
|
|
10270
10405
|
const parsed = JSON.parse(raw);
|
|
10271
10406
|
return typeof parsed.name === "string" ? parsed.name : void 0;
|
|
10272
10407
|
} catch {
|
|
@@ -10274,7 +10409,7 @@ async function readPackageName(packageDir) {
|
|
|
10274
10409
|
}
|
|
10275
10410
|
}
|
|
10276
10411
|
async function discoverPlugins(cwd = process.cwd()) {
|
|
10277
|
-
const nodeModules =
|
|
10412
|
+
const nodeModules = path16.join(cwd, "node_modules");
|
|
10278
10413
|
const found = [];
|
|
10279
10414
|
let entries;
|
|
10280
10415
|
try {
|
|
@@ -10285,7 +10420,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
10285
10420
|
for (const entry of entries.sort()) {
|
|
10286
10421
|
if (entry.startsWith("@")) continue;
|
|
10287
10422
|
if (!isPluginPackageName(entry)) continue;
|
|
10288
|
-
const packageDir =
|
|
10423
|
+
const packageDir = path16.join(nodeModules, entry);
|
|
10289
10424
|
const manifestRead = await readPluginManifestFile(packageDir);
|
|
10290
10425
|
found.push({
|
|
10291
10426
|
packageName: entry,
|
|
@@ -10298,7 +10433,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
10298
10433
|
return found;
|
|
10299
10434
|
}
|
|
10300
10435
|
async function validatePluginPackage(packageRef, cwd = process.cwd()) {
|
|
10301
|
-
const packageDir =
|
|
10436
|
+
const packageDir = path16.isAbsolute(packageRef) ? packageRef : path16.join(cwd, "node_modules", packageRef);
|
|
10302
10437
|
const packageName = await readPackageName(packageDir) ?? packageRef;
|
|
10303
10438
|
const errors = [];
|
|
10304
10439
|
const warnings = [];
|
|
@@ -10374,7 +10509,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
|
|
|
10374
10509
|
}
|
|
10375
10510
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
10376
10511
|
function traceIndexPath(traceDir) {
|
|
10377
|
-
return
|
|
10512
|
+
return path16.join(traceDir, INDEX_FILENAME);
|
|
10378
10513
|
}
|
|
10379
10514
|
function parseMaxEntries(raw) {
|
|
10380
10515
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -10487,7 +10622,7 @@ function isModuleNotFound4(e) {
|
|
|
10487
10622
|
}
|
|
10488
10623
|
async function loadIndexSqlite() {
|
|
10489
10624
|
try {
|
|
10490
|
-
return await import('./src-
|
|
10625
|
+
return await import('./src-G7PM24W2.mjs');
|
|
10491
10626
|
} catch (e) {
|
|
10492
10627
|
if (isModuleNotFound4(e)) {
|
|
10493
10628
|
console.error(
|
|
@@ -10517,7 +10652,7 @@ async function newestTraceMtimeMs2(traceDir) {
|
|
|
10517
10652
|
for (const file of files) {
|
|
10518
10653
|
if (!file.endsWith(".jsonl")) continue;
|
|
10519
10654
|
try {
|
|
10520
|
-
const s = await stat(
|
|
10655
|
+
const s = await stat(path16.join(traceDir, file));
|
|
10521
10656
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
10522
10657
|
} catch {
|
|
10523
10658
|
}
|
|
@@ -10769,11 +10904,11 @@ function printJson5(value) {
|
|
|
10769
10904
|
console.log(JSON.stringify(value, null, 2));
|
|
10770
10905
|
}
|
|
10771
10906
|
function resolveCwd(options) {
|
|
10772
|
-
return
|
|
10907
|
+
return path16.resolve(options.cwd ?? process.cwd());
|
|
10773
10908
|
}
|
|
10774
10909
|
async function suiteInitCommand(options = {}) {
|
|
10775
10910
|
const cwd = resolveCwd(options);
|
|
10776
|
-
const configPath =
|
|
10911
|
+
const configPath = path16.join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
10777
10912
|
const template = options.template?.trim();
|
|
10778
10913
|
const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
|
|
10779
10914
|
if (options.dryRun) {
|
|
@@ -10892,13 +11027,13 @@ async function suiteListCommand(options = {}) {
|
|
|
10892
11027
|
}
|
|
10893
11028
|
async function writeSuiteArtifact(result, configOutputDir, options) {
|
|
10894
11029
|
const cwd = resolveCwd(options);
|
|
10895
|
-
const outputDir =
|
|
11030
|
+
const outputDir = path16.resolve(
|
|
10896
11031
|
cwd,
|
|
10897
11032
|
options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
|
|
10898
11033
|
);
|
|
10899
11034
|
await mkdir(outputDir, { recursive: true });
|
|
10900
11035
|
const stamp = result.startedAt.replace(/[:.]/g, "-");
|
|
10901
|
-
const filePath =
|
|
11036
|
+
const filePath = path16.join(outputDir, `${result.suiteName}-${stamp}.json`);
|
|
10902
11037
|
await writeFile(filePath, `${JSON.stringify(result, null, 2)}
|
|
10903
11038
|
`, "utf-8");
|
|
10904
11039
|
return filePath;
|
|
@@ -10956,7 +11091,7 @@ async function loadSuiteResultFromInput(options) {
|
|
|
10956
11091
|
if (options.input === void 0 || options.input.trim() === "") {
|
|
10957
11092
|
throw new Error("Pass --input <suite-run.json> from a prior suite run.");
|
|
10958
11093
|
}
|
|
10959
|
-
const inputPath =
|
|
11094
|
+
const inputPath = path16.resolve(cwd, options.input.trim());
|
|
10960
11095
|
const raw = await readFile(inputPath, "utf-8");
|
|
10961
11096
|
return JSON.parse(raw);
|
|
10962
11097
|
}
|
|
@@ -10990,9 +11125,9 @@ function normalizeMetrics(raw) {
|
|
|
10990
11125
|
}
|
|
10991
11126
|
async function writeArtifacts(result, outputDir) {
|
|
10992
11127
|
await mkdir(outputDir, { recursive: true });
|
|
10993
|
-
const jsonPath =
|
|
10994
|
-
const markdownPath =
|
|
10995
|
-
const htmlPath =
|
|
11128
|
+
const jsonPath = path16.join(outputDir, "cohort-results.json");
|
|
11129
|
+
const markdownPath = path16.join(outputDir, "cohort-summary.md");
|
|
11130
|
+
const htmlPath = path16.join(outputDir, "cohort-report.html");
|
|
10996
11131
|
await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
10997
11132
|
`, "utf-8");
|
|
10998
11133
|
await writeFile(
|
|
@@ -11020,7 +11155,7 @@ async function cohortCommand(options = {}) {
|
|
|
11020
11155
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
11021
11156
|
let artifacts;
|
|
11022
11157
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
11023
|
-
artifacts = await writeArtifacts(result,
|
|
11158
|
+
artifacts = await writeArtifacts(result, path16.resolve(options.output.trim()));
|
|
11024
11159
|
}
|
|
11025
11160
|
if (options.json || format === "json") {
|
|
11026
11161
|
console.log(
|
|
@@ -11090,11 +11225,11 @@ function parseDuration2(value) {
|
|
|
11090
11225
|
async function writeArtifacts2(result, outputDir) {
|
|
11091
11226
|
await mkdir(outputDir, { recursive: true });
|
|
11092
11227
|
const paths = {
|
|
11093
|
-
jsonPath:
|
|
11094
|
-
markdownPath:
|
|
11095
|
-
htmlPath:
|
|
11096
|
-
junitPath:
|
|
11097
|
-
githubPath:
|
|
11228
|
+
jsonPath: path16.join(outputDir, "gate-results.json"),
|
|
11229
|
+
markdownPath: path16.join(outputDir, "gate-summary.md"),
|
|
11230
|
+
htmlPath: path16.join(outputDir, "gate-report.html"),
|
|
11231
|
+
junitPath: path16.join(outputDir, "junit.xml"),
|
|
11232
|
+
githubPath: path16.join(outputDir, "github-step-summary.md")
|
|
11098
11233
|
};
|
|
11099
11234
|
await writeFile(
|
|
11100
11235
|
paths.jsonPath,
|
|
@@ -11162,7 +11297,7 @@ async function gateCommand(options = {}) {
|
|
|
11162
11297
|
const result = await runGate(runs, gateOptions);
|
|
11163
11298
|
let artifacts;
|
|
11164
11299
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
11165
|
-
artifacts = await writeArtifacts2(result,
|
|
11300
|
+
artifacts = await writeArtifacts2(result, path16.resolve(options.output.trim()));
|
|
11166
11301
|
}
|
|
11167
11302
|
if (options.json || format === "json") {
|
|
11168
11303
|
console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
|
|
@@ -11694,6 +11829,20 @@ function createCliProgram() {
|
|
|
11694
11829
|
).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) => {
|
|
11695
11830
|
runCommand(() => cohortCommand(opts));
|
|
11696
11831
|
});
|
|
11832
|
+
const mcpCmd = program.command("mcp").description("Configure local coding-agent MCP clients (read-only; dry-run by default)");
|
|
11833
|
+
mcpCmd.command("configure").description("Print or write MCP client config for Cursor/Claude/Codex/Gemini").requiredOption(
|
|
11834
|
+
"--client <name>",
|
|
11835
|
+
"cursor | claude-code | codex | gemini"
|
|
11836
|
+
).option("--dir <path>", "trace directory for the MCP server", ".agent-inspect").option("--project-local", "target a project-local config path").option("--write", "write config (requires --project-local --yes)").option("--yes", "confirm write").option("--json", "print deterministic JSON result").action((opts) => {
|
|
11837
|
+
runCommand(async () => {
|
|
11838
|
+
if (!isMcpConfigureClient(opts.client)) {
|
|
11839
|
+
throw new Error(
|
|
11840
|
+
`Unsupported --client "${opts.client}". Use: cursor, claude-code, codex, gemini`
|
|
11841
|
+
);
|
|
11842
|
+
}
|
|
11843
|
+
await mcpConfigureCommand({ ...opts, client: opts.client });
|
|
11844
|
+
});
|
|
11845
|
+
});
|
|
11697
11846
|
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(
|
|
11698
11847
|
"--require-observation <name>",
|
|
11699
11848
|
"required passed observation (repeatable or comma-separated)"
|
|
@@ -11710,9 +11859,9 @@ function isPrimaryModule() {
|
|
|
11710
11859
|
if (!entry) return false;
|
|
11711
11860
|
const selfPath = fileURLToPath(import.meta.url);
|
|
11712
11861
|
try {
|
|
11713
|
-
return realpathSync(
|
|
11862
|
+
return realpathSync(path16.resolve(entry)) === realpathSync(path16.resolve(selfPath));
|
|
11714
11863
|
} catch {
|
|
11715
|
-
return
|
|
11864
|
+
return path16.resolve(entry) === path16.resolve(selfPath);
|
|
11716
11865
|
}
|
|
11717
11866
|
}
|
|
11718
11867
|
if (isPrimaryModule()) {
|