agent-inspect 6.16.2 → 6.17.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 +6 -0
- package/README.md +1 -1
- package/docs/CI-ARTIFACTS.md +31 -0
- package/docs/CLI.md +24 -2
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +910 -320
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +832 -248
- package/packages/cli/dist/index.mjs.map +1 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, diffRuns, manualTraceEventsToComparableRun } from './chunk-LFSBMUCD.mjs';
|
|
3
3
|
import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
|
|
4
|
-
import
|
|
4
|
+
import path18 from 'path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
6
6
|
import { Command, Option } from 'commander';
|
|
7
|
-
import { readFile, stat, mkdir, writeFile, unlink, appendFile,
|
|
7
|
+
import { readFile, stat, mkdir, writeFile, unlink, appendFile, access, rm, open, readdir, constants } from 'fs/promises';
|
|
8
8
|
import process2, { stdin, stdout } from 'process';
|
|
9
9
|
import crypto, { createHash } from 'crypto';
|
|
10
10
|
import { createServer } from 'http';
|
|
11
|
+
import { spawn } from 'child_process';
|
|
11
12
|
import { createRequire } from 'module';
|
|
12
13
|
|
|
13
14
|
// package.json
|
|
14
|
-
var version = "6.
|
|
15
|
+
var version = "6.17.0";
|
|
15
16
|
|
|
16
17
|
// packages/cli/src/trace-dir-scale.ts
|
|
17
18
|
var TRACE_COUNT_WARN = 1e3;
|
|
@@ -2971,9 +2972,9 @@ Trace directory: ${traceDir}`);
|
|
|
2971
2972
|
process.exitCode = 1;
|
|
2972
2973
|
}
|
|
2973
2974
|
const resolvedOutput = resolveOutputOption(options);
|
|
2974
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
2975
|
+
const outPath = resolvedOutput !== void 0 ? path18.resolve(resolvedOutput) : void 0;
|
|
2975
2976
|
if (outPath !== void 0) {
|
|
2976
|
-
await mkdir(
|
|
2977
|
+
await mkdir(path18.dirname(outPath), { recursive: true });
|
|
2977
2978
|
await writeFile(outPath, result.content, "utf-8");
|
|
2978
2979
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
2979
2980
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -3317,7 +3318,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
3317
3318
|
endedAt: row.endedAt ?? void 0,
|
|
3318
3319
|
durationMs: row.durationMs ?? void 0,
|
|
3319
3320
|
eventCount: 0,
|
|
3320
|
-
filePath:
|
|
3321
|
+
filePath: path18.join(traceDir, row.file),
|
|
3321
3322
|
fileSize: 0,
|
|
3322
3323
|
createdAt: new Date(row.mtimeMs)
|
|
3323
3324
|
};
|
|
@@ -3795,9 +3796,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
3795
3796
|
...options.section ? { section: options.section } : {}
|
|
3796
3797
|
});
|
|
3797
3798
|
const resolvedOutput = resolveOutputOption(options);
|
|
3798
|
-
const outPath = resolvedOutput !== void 0 ?
|
|
3799
|
+
const outPath = resolvedOutput !== void 0 ? path18.resolve(resolvedOutput) : void 0;
|
|
3799
3800
|
if (outPath !== void 0) {
|
|
3800
|
-
await mkdir(
|
|
3801
|
+
await mkdir(path18.dirname(outPath), { recursive: true });
|
|
3801
3802
|
await writeFile(outPath, result.content, "utf-8");
|
|
3802
3803
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
3803
3804
|
}
|
|
@@ -3976,8 +3977,8 @@ function passesLuhn(value) {
|
|
|
3976
3977
|
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;
|
|
3977
3978
|
var EPOCH_MS_RE = /^1[0-9]{12}$/;
|
|
3978
3979
|
var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
3979
|
-
function pathSuggestsNonCard(
|
|
3980
|
-
const normalized =
|
|
3980
|
+
function pathSuggestsNonCard(path29) {
|
|
3981
|
+
const normalized = path29.toLowerCase().replace(/[^a-z0-9._]/g, "");
|
|
3981
3982
|
return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
|
|
3982
3983
|
normalized
|
|
3983
3984
|
) || /(^|\.)ts(\.|$)/.test(normalized);
|
|
@@ -4164,17 +4165,17 @@ function applyRule(rule, value, replacement) {
|
|
|
4164
4165
|
}
|
|
4165
4166
|
return value;
|
|
4166
4167
|
}
|
|
4167
|
-
function childPath(
|
|
4168
|
+
function childPath(path29, key) {
|
|
4168
4169
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
4169
|
-
return
|
|
4170
|
+
return path29 ? `${path29}.${key}` : key;
|
|
4170
4171
|
}
|
|
4171
|
-
return `${
|
|
4172
|
+
return `${path29 || "$"}[${JSON.stringify(key)}]`;
|
|
4172
4173
|
}
|
|
4173
|
-
function indexPath(
|
|
4174
|
-
return `${
|
|
4174
|
+
function indexPath(path29, index) {
|
|
4175
|
+
return `${path29 || "$"}[${index}]`;
|
|
4175
4176
|
}
|
|
4176
|
-
function makeFinding(
|
|
4177
|
-
return preview === void 0 ? { path:
|
|
4177
|
+
function makeFinding(path29, detector, action, matchKind, severity = "warning", preview) {
|
|
4178
|
+
return preview === void 0 ? { path: path29, detector, action, severity, matchKind } : { path: path29, detector, action, severity, matchKind, preview };
|
|
4178
4179
|
}
|
|
4179
4180
|
function createRedactionProfile(profile = "local") {
|
|
4180
4181
|
switch (profile) {
|
|
@@ -4243,11 +4244,11 @@ var Redactor2 = class {
|
|
|
4243
4244
|
#recordFinding(state, finding) {
|
|
4244
4245
|
if (this.#collectFindings) state.findings.push(finding);
|
|
4245
4246
|
}
|
|
4246
|
-
#redactValue(value, key,
|
|
4247
|
+
#redactValue(value, key, path29, depth, state) {
|
|
4247
4248
|
if (depth > this.#maxDepth) {
|
|
4248
4249
|
this.#recordFinding(
|
|
4249
4250
|
state,
|
|
4250
|
-
makeFinding(
|
|
4251
|
+
makeFinding(path29, "structure.maxDepth", "truncate", "value", "warning")
|
|
4251
4252
|
);
|
|
4252
4253
|
return "[Truncated]";
|
|
4253
4254
|
}
|
|
@@ -4256,19 +4257,19 @@ var Redactor2 = class {
|
|
|
4256
4257
|
if (rule) {
|
|
4257
4258
|
this.#recordFinding(
|
|
4258
4259
|
state,
|
|
4259
|
-
makeFinding(
|
|
4260
|
+
makeFinding(path29, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
4260
4261
|
);
|
|
4261
4262
|
return applyRule(rule, value, this.#replacement);
|
|
4262
4263
|
}
|
|
4263
4264
|
}
|
|
4264
4265
|
for (const detector of this.#detectors) {
|
|
4265
|
-
const detections = detector.detect({ path:
|
|
4266
|
+
const detections = detector.detect({ path: path29, key, value });
|
|
4266
4267
|
for (const detection of detections) {
|
|
4267
4268
|
const action = detection.action ?? "replace";
|
|
4268
4269
|
this.#recordFinding(
|
|
4269
4270
|
state,
|
|
4270
4271
|
makeFinding(
|
|
4271
|
-
|
|
4272
|
+
path29,
|
|
4272
4273
|
detector.id,
|
|
4273
4274
|
action,
|
|
4274
4275
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -4286,7 +4287,7 @@ var Redactor2 = class {
|
|
|
4286
4287
|
const out = [];
|
|
4287
4288
|
state.seen.set(value, out);
|
|
4288
4289
|
value.forEach((item, index) => {
|
|
4289
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
4290
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path29, index), depth + 1, state);
|
|
4290
4291
|
});
|
|
4291
4292
|
return out;
|
|
4292
4293
|
}
|
|
@@ -4298,7 +4299,7 @@ var Redactor2 = class {
|
|
|
4298
4299
|
out[entryKey] = this.#redactValue(
|
|
4299
4300
|
entryValue,
|
|
4300
4301
|
entryKey,
|
|
4301
|
-
childPath(
|
|
4302
|
+
childPath(path29 === "$" ? "" : path29, entryKey),
|
|
4302
4303
|
depth + 1,
|
|
4303
4304
|
state
|
|
4304
4305
|
);
|
|
@@ -4759,14 +4760,14 @@ function uniqueSorted(values) {
|
|
|
4759
4760
|
return [...new Set(values)].sort();
|
|
4760
4761
|
}
|
|
4761
4762
|
function isWithinDirectory(child, parent) {
|
|
4762
|
-
const relative =
|
|
4763
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
4763
|
+
const relative = path18.relative(parent, child);
|
|
4764
|
+
return relative === "" || !relative.startsWith("..") && !path18.isAbsolute(relative);
|
|
4764
4765
|
}
|
|
4765
4766
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
4766
4767
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
4767
|
-
const inputAbs =
|
|
4768
|
-
const outputAbs =
|
|
4769
|
-
const inputDir =
|
|
4768
|
+
const inputAbs = path18.resolve(inputPath);
|
|
4769
|
+
const outputAbs = path18.resolve(output2.trim());
|
|
4770
|
+
const inputDir = path18.dirname(inputAbs);
|
|
4770
4771
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
4771
4772
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
4772
4773
|
}
|
|
@@ -4887,7 +4888,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
4887
4888
|
process.exitCode = 1;
|
|
4888
4889
|
return;
|
|
4889
4890
|
}
|
|
4890
|
-
const inputPath =
|
|
4891
|
+
const inputPath = path18.resolve(input3.trim());
|
|
4891
4892
|
const dryRun = options.dryRun === true;
|
|
4892
4893
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
4893
4894
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -4906,7 +4907,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
4906
4907
|
);
|
|
4907
4908
|
const result = await buildMigration(inputPath, outputPath);
|
|
4908
4909
|
if (!dryRun && outputPath !== void 0) {
|
|
4909
|
-
await mkdir(
|
|
4910
|
+
await mkdir(path18.dirname(outputPath), { recursive: true });
|
|
4910
4911
|
await writeFile(outputPath, result.content, "utf-8");
|
|
4911
4912
|
}
|
|
4912
4913
|
printSummary2(result, dryRun);
|
|
@@ -4916,6 +4917,243 @@ async function migrateCommand(input3, options = {}) {
|
|
|
4916
4917
|
process.exitCode = 1;
|
|
4917
4918
|
}
|
|
4918
4919
|
}
|
|
4920
|
+
function validateReporterArtifactPath(options) {
|
|
4921
|
+
const outputDir = path18.resolve(options.outputDir);
|
|
4922
|
+
const diagnostics = [];
|
|
4923
|
+
const rawPath = options.relativePath;
|
|
4924
|
+
if (rawPath.length === 0) {
|
|
4925
|
+
diagnostics.push({
|
|
4926
|
+
code: "artifact_path_empty",
|
|
4927
|
+
severity: "error",
|
|
4928
|
+
message: "Reporter artifact path must not be empty."
|
|
4929
|
+
});
|
|
4930
|
+
return { ok: false, outputDir, diagnostics };
|
|
4931
|
+
}
|
|
4932
|
+
if (rawPath.includes("\0")) {
|
|
4933
|
+
diagnostics.push({
|
|
4934
|
+
code: "invalid_artifact_path",
|
|
4935
|
+
severity: "error",
|
|
4936
|
+
message: "Reporter artifact path must not contain null bytes.",
|
|
4937
|
+
target: rawPath
|
|
4938
|
+
});
|
|
4939
|
+
return { ok: false, outputDir, diagnostics };
|
|
4940
|
+
}
|
|
4941
|
+
if (path18.isAbsolute(rawPath) || path18.win32.isAbsolute(rawPath)) {
|
|
4942
|
+
diagnostics.push({
|
|
4943
|
+
code: "artifact_path_absolute",
|
|
4944
|
+
severity: "error",
|
|
4945
|
+
message: "Reporter artifact path must be relative.",
|
|
4946
|
+
target: rawPath
|
|
4947
|
+
});
|
|
4948
|
+
return { ok: false, outputDir, diagnostics };
|
|
4949
|
+
}
|
|
4950
|
+
const normalized = path18.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
4951
|
+
const segments = normalized.split("/");
|
|
4952
|
+
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
4953
|
+
diagnostics.push({
|
|
4954
|
+
code: "artifact_path_escape",
|
|
4955
|
+
severity: "error",
|
|
4956
|
+
message: "Reporter artifact path must stay under the output directory.",
|
|
4957
|
+
target: rawPath
|
|
4958
|
+
});
|
|
4959
|
+
return { ok: false, outputDir, diagnostics };
|
|
4960
|
+
}
|
|
4961
|
+
const absolutePath = path18.resolve(outputDir, normalized);
|
|
4962
|
+
const relFromOutput = path18.relative(outputDir, absolutePath);
|
|
4963
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path18.isAbsolute(relFromOutput)) {
|
|
4964
|
+
diagnostics.push({
|
|
4965
|
+
code: "artifact_path_escape",
|
|
4966
|
+
severity: "error",
|
|
4967
|
+
message: "Reporter artifact path resolved outside the output directory.",
|
|
4968
|
+
target: rawPath
|
|
4969
|
+
});
|
|
4970
|
+
return { ok: false, outputDir, diagnostics };
|
|
4971
|
+
}
|
|
4972
|
+
return {
|
|
4973
|
+
ok: true,
|
|
4974
|
+
outputDir,
|
|
4975
|
+
relativePath: normalized,
|
|
4976
|
+
absolutePath,
|
|
4977
|
+
diagnostics
|
|
4978
|
+
};
|
|
4979
|
+
}
|
|
4980
|
+
var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
4981
|
+
"evidence.html",
|
|
4982
|
+
"evidence.json",
|
|
4983
|
+
"check-results.json",
|
|
4984
|
+
"trace.jsonl"
|
|
4985
|
+
];
|
|
4986
|
+
function createEvidenceCiArtifacts(options) {
|
|
4987
|
+
const profile = options.redactionProfile ?? "share";
|
|
4988
|
+
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
4989
|
+
const join = (name) => prefix === "" ? name : path18.posix.join(prefix, name);
|
|
4990
|
+
const formatFor = (name) => {
|
|
4991
|
+
if (name.endsWith(".html")) return "html";
|
|
4992
|
+
if (name.endsWith(".jsonl")) return "jsonl";
|
|
4993
|
+
return "json";
|
|
4994
|
+
};
|
|
4995
|
+
return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
|
|
4996
|
+
kind: "evidence",
|
|
4997
|
+
path: join(name),
|
|
4998
|
+
format: formatFor(name),
|
|
4999
|
+
redactionProfile: profile,
|
|
5000
|
+
title: `Evidence v2 ${name}`
|
|
5001
|
+
}));
|
|
5002
|
+
}
|
|
5003
|
+
|
|
5004
|
+
// packages/cli/src/evidence-on.ts
|
|
5005
|
+
function shouldEmitEvidence(mode, failed) {
|
|
5006
|
+
if (mode === void 0 || mode === "never") return false;
|
|
5007
|
+
if (mode === "always") return true;
|
|
5008
|
+
return failed;
|
|
5009
|
+
}
|
|
5010
|
+
function parseEvidenceProfile(value) {
|
|
5011
|
+
const profile = (value ?? "share").trim().toLowerCase();
|
|
5012
|
+
if (profile === "local" || profile === "share" || profile === "strict") {
|
|
5013
|
+
return profile;
|
|
5014
|
+
}
|
|
5015
|
+
throw new Error(
|
|
5016
|
+
`Unsupported --evidence-profile "${value}". Use local, share, or strict.`
|
|
5017
|
+
);
|
|
5018
|
+
}
|
|
5019
|
+
function parseEvidenceFormat(value) {
|
|
5020
|
+
const format = (value ?? "directory").trim().toLowerCase();
|
|
5021
|
+
if (format === "directory" || format === "html" || format === "zip") {
|
|
5022
|
+
return format;
|
|
5023
|
+
}
|
|
5024
|
+
throw new Error(
|
|
5025
|
+
`Unsupported --evidence-format "${value}". Use directory, html, or zip.`
|
|
5026
|
+
);
|
|
5027
|
+
}
|
|
5028
|
+
function toAssessmentStatus(failed) {
|
|
5029
|
+
return failed ? "UNSAFE" : "SAFE";
|
|
5030
|
+
}
|
|
5031
|
+
function stableJson2(value) {
|
|
5032
|
+
return `${JSON.stringify(value, null, 2)}
|
|
5033
|
+
`;
|
|
5034
|
+
}
|
|
5035
|
+
async function writeLocalEvidence(input3) {
|
|
5036
|
+
const profile = input3.redactionProfile ?? "share";
|
|
5037
|
+
const format = input3.format ?? "directory";
|
|
5038
|
+
const baseDir = path18.resolve(input3.outputDir);
|
|
5039
|
+
await mkdir(
|
|
5040
|
+
format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path18.dirname(baseDir) : baseDir,
|
|
5041
|
+
{ recursive: true }
|
|
5042
|
+
);
|
|
5043
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
5044
|
+
if (input3.sourceContents instanceof Map) {
|
|
5045
|
+
for (const [runId, content] of input3.sourceContents) {
|
|
5046
|
+
sourceContents.set(runId, content);
|
|
5047
|
+
}
|
|
5048
|
+
} else if (input3.sourceContents !== void 0) {
|
|
5049
|
+
for (const [runId, content] of Object.entries(input3.sourceContents)) {
|
|
5050
|
+
sourceContents.set(runId, content);
|
|
5051
|
+
}
|
|
5052
|
+
}
|
|
5053
|
+
const traceDir = resolveTraceDir({ dir: input3.dir });
|
|
5054
|
+
let combined = "";
|
|
5055
|
+
for (const runId of input3.runIds) {
|
|
5056
|
+
let raw = sourceContents.get(runId) ?? "";
|
|
5057
|
+
if (raw === "") {
|
|
5058
|
+
try {
|
|
5059
|
+
raw = await readFile(getTraceFilePath(runId, traceDir), "utf-8");
|
|
5060
|
+
} catch {
|
|
5061
|
+
raw = "";
|
|
5062
|
+
}
|
|
5063
|
+
sourceContents.set(runId, raw);
|
|
5064
|
+
}
|
|
5065
|
+
const redacted = redactTraceContent(raw, profile);
|
|
5066
|
+
combined += redacted.content.endsWith("\n") ? redacted.content : `${redacted.content}
|
|
5067
|
+
`;
|
|
5068
|
+
}
|
|
5069
|
+
const assessmentStatus = toAssessmentStatus(input3.failed);
|
|
5070
|
+
const evidencePackage = buildEvidenceCiPackage({
|
|
5071
|
+
generatorVersion: version,
|
|
5072
|
+
runIds: input3.runIds,
|
|
5073
|
+
sourceContents,
|
|
5074
|
+
redactedTraceJsonl: combined,
|
|
5075
|
+
redactionProfile: profile,
|
|
5076
|
+
assessmentStatus,
|
|
5077
|
+
checkResultsJson: input3.checkResultsJson,
|
|
5078
|
+
...input3.summaryText !== void 0 ? { summaryText: input3.summaryText } : {}
|
|
5079
|
+
});
|
|
5080
|
+
const files = [
|
|
5081
|
+
["evidence.html", evidencePackage["evidence.html"]],
|
|
5082
|
+
["evidence.json", evidencePackage["evidence.json"]],
|
|
5083
|
+
["check-results.json", evidencePackage["check-results.json"]],
|
|
5084
|
+
["trace.jsonl", evidencePackage["trace.jsonl"]]
|
|
5085
|
+
];
|
|
5086
|
+
const expected = createEvidenceCiArtifacts({
|
|
5087
|
+
redactionProfile: profile
|
|
5088
|
+
}).map((a) => a.path);
|
|
5089
|
+
for (const name of expected) {
|
|
5090
|
+
if (!files.some(([fileName]) => fileName === name)) {
|
|
5091
|
+
throw new Error(`Evidence CI package missing expected file: ${name}`);
|
|
5092
|
+
}
|
|
5093
|
+
}
|
|
5094
|
+
if (format === "zip") {
|
|
5095
|
+
const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
|
|
5096
|
+
await mkdir(path18.dirname(zipPath), { recursive: true });
|
|
5097
|
+
const archive = buildZipArchive(
|
|
5098
|
+
files.map(([relativePath, content]) => ({
|
|
5099
|
+
path: relativePath,
|
|
5100
|
+
content
|
|
5101
|
+
}))
|
|
5102
|
+
);
|
|
5103
|
+
await writeFile(zipPath, archive);
|
|
5104
|
+
return zipPath;
|
|
5105
|
+
}
|
|
5106
|
+
if (format === "html") {
|
|
5107
|
+
let htmlPath = baseDir;
|
|
5108
|
+
let sidecarDir = baseDir;
|
|
5109
|
+
if (baseDir.toLowerCase().endsWith(".html")) {
|
|
5110
|
+
htmlPath = baseDir;
|
|
5111
|
+
sidecarDir = path18.dirname(baseDir);
|
|
5112
|
+
} else {
|
|
5113
|
+
await mkdir(baseDir, { recursive: true });
|
|
5114
|
+
htmlPath = path18.join(baseDir, "evidence.html");
|
|
5115
|
+
sidecarDir = baseDir;
|
|
5116
|
+
}
|
|
5117
|
+
await mkdir(sidecarDir, { recursive: true });
|
|
5118
|
+
await writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
|
|
5119
|
+
await writeFile(
|
|
5120
|
+
path18.join(sidecarDir, "evidence.json"),
|
|
5121
|
+
evidencePackage["evidence.json"],
|
|
5122
|
+
"utf-8"
|
|
5123
|
+
);
|
|
5124
|
+
return htmlPath;
|
|
5125
|
+
}
|
|
5126
|
+
await mkdir(baseDir, { recursive: true });
|
|
5127
|
+
for (const [name, content] of files) {
|
|
5128
|
+
await writeFile(path18.join(baseDir, name), content, "utf-8");
|
|
5129
|
+
}
|
|
5130
|
+
return baseDir;
|
|
5131
|
+
}
|
|
5132
|
+
function checkResultToEvidenceJson(result, runIds) {
|
|
5133
|
+
const status = result.status === "pass" ? "SAFE" : result.status === "fail" ? "UNSAFE" : "UNKNOWN";
|
|
5134
|
+
return stableJson2({
|
|
5135
|
+
aggregateStatus: status,
|
|
5136
|
+
runs: runIds.map((runId) => ({
|
|
5137
|
+
runId,
|
|
5138
|
+
status,
|
|
5139
|
+
errors: result.summary.errors,
|
|
5140
|
+
warnings: result.summary.warnings,
|
|
5141
|
+
findings: result.findings.length
|
|
5142
|
+
})),
|
|
5143
|
+
findings: result.findings,
|
|
5144
|
+
diagnostics: result.diagnostics
|
|
5145
|
+
});
|
|
5146
|
+
}
|
|
5147
|
+
function defaultEvidenceDir(label) {
|
|
5148
|
+
const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
|
|
5149
|
+
return path18.join(".agent-inspect", "evidence", safe);
|
|
5150
|
+
}
|
|
5151
|
+
function resolveEvidenceOutputDir(evidenceDir, label) {
|
|
5152
|
+
if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
|
|
5153
|
+
return path18.resolve(evidenceDir.trim());
|
|
5154
|
+
}
|
|
5155
|
+
return defaultEvidenceDir(label);
|
|
5156
|
+
}
|
|
4919
5157
|
var ALL_RULES = [
|
|
4920
5158
|
"circuit.same-tool-repetition",
|
|
4921
5159
|
"circuit.same-args-repetition",
|
|
@@ -5236,23 +5474,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
5236
5474
|
}
|
|
5237
5475
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
5238
5476
|
}
|
|
5239
|
-
function validateSchemaField(value, field,
|
|
5477
|
+
function validateSchemaField(value, field, path29, evidence) {
|
|
5240
5478
|
const ruleId = "guardrail.structured-output";
|
|
5241
5479
|
if (field.type) {
|
|
5242
5480
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
5243
5481
|
if (actual !== field.type) {
|
|
5244
|
-
evidence.push({ ruleId, path:
|
|
5482
|
+
evidence.push({ ruleId, path: path29, preview: `expected ${field.type}, got ${actual}` });
|
|
5245
5483
|
return;
|
|
5246
5484
|
}
|
|
5247
5485
|
}
|
|
5248
5486
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
5249
|
-
evidence.push({ ruleId, path:
|
|
5487
|
+
evidence.push({ ruleId, path: path29, preview: "value not in enum" });
|
|
5250
5488
|
}
|
|
5251
5489
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
5252
5490
|
const record = value;
|
|
5253
5491
|
for (const key of field.required) {
|
|
5254
5492
|
if (!(key in record)) {
|
|
5255
|
-
evidence.push({ ruleId, path: `${
|
|
5493
|
+
evidence.push({ ruleId, path: `${path29}.${key}`, preview: "missing required key" });
|
|
5256
5494
|
}
|
|
5257
5495
|
}
|
|
5258
5496
|
}
|
|
@@ -5533,6 +5771,54 @@ function mergeSafetyExtensions(result, read, options) {
|
|
|
5533
5771
|
}
|
|
5534
5772
|
|
|
5535
5773
|
// packages/cli/src/check.ts
|
|
5774
|
+
function resolvePreset(preset, context = {}) {
|
|
5775
|
+
if (preset === void 0 || preset.trim() === "") return void 0;
|
|
5776
|
+
const name = preset.trim().toLowerCase();
|
|
5777
|
+
if (name !== "trajectory" && name !== "safety" && name !== "comprehensive") {
|
|
5778
|
+
throw new Error(
|
|
5779
|
+
`Unknown --preset "${preset}". Use trajectory, safety, or comprehensive.`
|
|
5780
|
+
);
|
|
5781
|
+
}
|
|
5782
|
+
const trajectorySelect = [
|
|
5783
|
+
"run.status",
|
|
5784
|
+
"run.requireCompleted",
|
|
5785
|
+
"structure.orphan",
|
|
5786
|
+
"structure.cycle",
|
|
5787
|
+
"structure.relationship"
|
|
5788
|
+
];
|
|
5789
|
+
if (context.hasToolRules === true) {
|
|
5790
|
+
trajectorySelect.push("tool.usage");
|
|
5791
|
+
}
|
|
5792
|
+
const safetySelect = [
|
|
5793
|
+
"run.status",
|
|
5794
|
+
"safety.rawPrompt",
|
|
5795
|
+
"safety.secretPattern",
|
|
5796
|
+
"safety.redaction"
|
|
5797
|
+
];
|
|
5798
|
+
if (name === "trajectory") {
|
|
5799
|
+
return {
|
|
5800
|
+
requireCompleted: true,
|
|
5801
|
+
enableSafetyRedaction: false,
|
|
5802
|
+
enableStructureRelationshipDefaults: true,
|
|
5803
|
+
select: trajectorySelect
|
|
5804
|
+
};
|
|
5805
|
+
}
|
|
5806
|
+
if (name === "safety") {
|
|
5807
|
+
return {
|
|
5808
|
+
requireCompleted: false,
|
|
5809
|
+
enableSafetyRedaction: true,
|
|
5810
|
+
enableStructureRelationshipDefaults: false,
|
|
5811
|
+
select: safetySelect
|
|
5812
|
+
};
|
|
5813
|
+
}
|
|
5814
|
+
const select = [.../* @__PURE__ */ new Set([...trajectorySelect, ...safetySelect])];
|
|
5815
|
+
return {
|
|
5816
|
+
requireCompleted: true,
|
|
5817
|
+
enableSafetyRedaction: true,
|
|
5818
|
+
enableStructureRelationshipDefaults: true,
|
|
5819
|
+
select
|
|
5820
|
+
};
|
|
5821
|
+
}
|
|
5536
5822
|
var DEFAULT_SELECT = ["run.status"];
|
|
5537
5823
|
var CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
5538
5824
|
var TS_CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
|
|
@@ -5579,7 +5865,7 @@ function asConfig(value) {
|
|
|
5579
5865
|
}
|
|
5580
5866
|
async function loadConfig(configPath) {
|
|
5581
5867
|
if (configPath === void 0) return {};
|
|
5582
|
-
const extension =
|
|
5868
|
+
const extension = path18.extname(configPath);
|
|
5583
5869
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
5584
5870
|
throw new Error(
|
|
5585
5871
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -5588,7 +5874,7 @@ async function loadConfig(configPath) {
|
|
|
5588
5874
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
5589
5875
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
5590
5876
|
}
|
|
5591
|
-
const absolute =
|
|
5877
|
+
const absolute = path18.resolve(configPath);
|
|
5592
5878
|
if (extension === ".json") {
|
|
5593
5879
|
const raw = await readFile(absolute, "utf-8");
|
|
5594
5880
|
return asConfig(JSON.parse(raw));
|
|
@@ -5603,6 +5889,33 @@ function normalizeConfig(config) {
|
|
|
5603
5889
|
}
|
|
5604
5890
|
return config.checks;
|
|
5605
5891
|
}
|
|
5892
|
+
function hasToolRulesConfigured(config, options) {
|
|
5893
|
+
const tool = normalizeConfig(config).tool ?? {};
|
|
5894
|
+
return Boolean(
|
|
5895
|
+
(tool.required?.length ?? 0) > 0 || (tool.forbidden?.length ?? 0) > 0 || (tool.allowed?.length ?? 0) > 0 || tool.minCount !== void 0 || tool.maxCount !== void 0 || (options.requiredTool?.length ?? 0) > 0 || (options.forbiddenTool?.length ?? 0) > 0
|
|
5896
|
+
);
|
|
5897
|
+
}
|
|
5898
|
+
function applyResolvedPreset(config, options, resolved) {
|
|
5899
|
+
const checks2 = { ...normalizeConfig(config) };
|
|
5900
|
+
if (resolved.enableSafetyRedaction) {
|
|
5901
|
+
checks2.safety = { ...checks2.safety, redaction: true };
|
|
5902
|
+
}
|
|
5903
|
+
if (resolved.enableStructureRelationshipDefaults) {
|
|
5904
|
+
const structure = checks2.structure ?? {};
|
|
5905
|
+
const needed = structure.minConfidence === void 0 && structure.requireParentBeforeChild === void 0 && structure.requireTraceParentSpan === void 0;
|
|
5906
|
+
if (needed) {
|
|
5907
|
+
checks2.structure = { ...structure, requireParentBeforeChild: true };
|
|
5908
|
+
}
|
|
5909
|
+
}
|
|
5910
|
+
return {
|
|
5911
|
+
config: { checks: checks2 },
|
|
5912
|
+
options: {
|
|
5913
|
+
...options,
|
|
5914
|
+
...resolved.requireCompleted ? { requireCompleted: true } : {},
|
|
5915
|
+
rule: [...resolved.select, ...options.rule ?? []]
|
|
5916
|
+
}
|
|
5917
|
+
};
|
|
5918
|
+
}
|
|
5606
5919
|
function buildRules(config, options) {
|
|
5607
5920
|
const diagnostics = [];
|
|
5608
5921
|
const checks2 = normalizeConfig(config);
|
|
@@ -5746,7 +6059,42 @@ function stable2(value) {
|
|
|
5746
6059
|
function printJson(result) {
|
|
5747
6060
|
console.log(JSON.stringify(stable2(result), null, 2));
|
|
5748
6061
|
}
|
|
5749
|
-
function
|
|
6062
|
+
function isSafetyFinding(ruleId) {
|
|
6063
|
+
return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
|
|
6064
|
+
}
|
|
6065
|
+
function printPresetClassSummary(result, preset) {
|
|
6066
|
+
const name = preset?.trim().toLowerCase();
|
|
6067
|
+
if (name !== "trajectory" && name !== "safety" && name !== "comprehensive") {
|
|
6068
|
+
return;
|
|
6069
|
+
}
|
|
6070
|
+
const hasSafetyFindings = result.findings.some(
|
|
6071
|
+
(finding) => isSafetyFinding(finding.ruleId)
|
|
6072
|
+
);
|
|
6073
|
+
const hasTrajectoryFindings = result.findings.some(
|
|
6074
|
+
(finding) => !isSafetyFinding(finding.ruleId)
|
|
6075
|
+
);
|
|
6076
|
+
if (name === "trajectory") {
|
|
6077
|
+
console.log(
|
|
6078
|
+
`Trajectory: ${result.status === "pass" && !hasTrajectoryFindings ? "PASS" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
6079
|
+
);
|
|
6080
|
+
console.log("Share safety: not evaluated");
|
|
6081
|
+
console.log("Run verify-safe before sharing.");
|
|
6082
|
+
return;
|
|
6083
|
+
}
|
|
6084
|
+
if (name === "safety") {
|
|
6085
|
+
console.log(
|
|
6086
|
+
`Share safety: ${result.status === "pass" && !hasSafetyFindings ? "PASS" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
6087
|
+
);
|
|
6088
|
+
return;
|
|
6089
|
+
}
|
|
6090
|
+
console.log(
|
|
6091
|
+
`Trajectory: ${hasTrajectoryFindings || result.status === "error" ? "FAIL" : "PASS"}`
|
|
6092
|
+
);
|
|
6093
|
+
console.log(
|
|
6094
|
+
`Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
|
|
6095
|
+
);
|
|
6096
|
+
}
|
|
6097
|
+
function printHuman(result, options = {}) {
|
|
5750
6098
|
const scoped = result;
|
|
5751
6099
|
if (scoped.scopeLabel) {
|
|
5752
6100
|
console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
|
|
@@ -5755,6 +6103,7 @@ function printHuman(result) {
|
|
|
5755
6103
|
}
|
|
5756
6104
|
}
|
|
5757
6105
|
console.log(`Check status: ${result.status}`);
|
|
6106
|
+
printPresetClassSummary(result, options.preset);
|
|
5758
6107
|
console.log(`Format: ${result.format}`);
|
|
5759
6108
|
if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
|
|
5760
6109
|
console.log(
|
|
@@ -5764,10 +6113,10 @@ function printHuman(result) {
|
|
|
5764
6113
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
5765
6114
|
}
|
|
5766
6115
|
for (const finding of result.findings) {
|
|
5767
|
-
const
|
|
6116
|
+
const path29 = finding.evidence[0]?.path;
|
|
5768
6117
|
const run = finding.evidence[0]?.runId;
|
|
5769
6118
|
const runPrefix = run ? `[${run}] ` : "";
|
|
5770
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
6119
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}`);
|
|
5771
6120
|
}
|
|
5772
6121
|
}
|
|
5773
6122
|
function readErrorResult(error) {
|
|
@@ -5783,12 +6132,24 @@ function readErrorResult(error) {
|
|
|
5783
6132
|
async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
5784
6133
|
let result;
|
|
5785
6134
|
let phase = "config";
|
|
6135
|
+
let evidenceRead;
|
|
6136
|
+
let evidenceRunIds = [];
|
|
6137
|
+
let evidenceSourceContents;
|
|
5786
6138
|
const sessionId = options.session?.trim();
|
|
5787
6139
|
const groupId = options.group?.trim();
|
|
5788
6140
|
const useSessionScope = Boolean(sessionId || groupId);
|
|
5789
6141
|
try {
|
|
5790
|
-
|
|
5791
|
-
|
|
6142
|
+
let config = await loadConfig(options.config);
|
|
6143
|
+
let effectiveOptions = options;
|
|
6144
|
+
const resolved = resolvePreset(options.preset, {
|
|
6145
|
+
hasToolRules: hasToolRulesConfigured(config, options)
|
|
6146
|
+
});
|
|
6147
|
+
if (resolved !== void 0) {
|
|
6148
|
+
const applied = applyResolvedPreset(config, options, resolved);
|
|
6149
|
+
config = applied.config;
|
|
6150
|
+
effectiveOptions = applied.options;
|
|
6151
|
+
}
|
|
6152
|
+
const built = buildRules(config, effectiveOptions);
|
|
5792
6153
|
if (built.diagnostics.some((item) => item.severity === "error")) {
|
|
5793
6154
|
result = errorResult("AI_CHECK_INVALID_CONFIG", "Invalid check configuration.");
|
|
5794
6155
|
result.diagnostics = [...built.diagnostics];
|
|
@@ -5809,6 +6170,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
5809
6170
|
correlateByGroupId: options.correlateGroup === true
|
|
5810
6171
|
});
|
|
5811
6172
|
const perRun = [];
|
|
6173
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
5812
6174
|
for (const meta of scoped.metas) {
|
|
5813
6175
|
const read = await openTrace(
|
|
5814
6176
|
{ type: "file", path: meta.filePath },
|
|
@@ -5816,6 +6178,15 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
5816
6178
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
5817
6179
|
}
|
|
5818
6180
|
);
|
|
6181
|
+
try {
|
|
6182
|
+
sourceContents.set(meta.runId, await readFile(meta.filePath, "utf-8"));
|
|
6183
|
+
} catch {
|
|
6184
|
+
sourceContents.set(
|
|
6185
|
+
meta.runId,
|
|
6186
|
+
`${read.events.map((event) => JSON.stringify(event)).join("\n")}
|
|
6187
|
+
`
|
|
6188
|
+
);
|
|
6189
|
+
}
|
|
5819
6190
|
perRun.push(
|
|
5820
6191
|
mergeSafetyExtensions(
|
|
5821
6192
|
runTraceChecks(
|
|
@@ -5834,6 +6205,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
5834
6205
|
)
|
|
5835
6206
|
);
|
|
5836
6207
|
}
|
|
6208
|
+
evidenceRunIds = scoped.runIds;
|
|
6209
|
+
evidenceSourceContents = sourceContents;
|
|
5837
6210
|
result = aggregateSessionCheckResults(perRun, {
|
|
5838
6211
|
scopeKind: scoped.scopeKind,
|
|
5839
6212
|
scopeLabel: scoped.scopeLabel,
|
|
@@ -5848,6 +6221,26 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
5848
6221
|
const read = await openTrace(input3, {
|
|
5849
6222
|
...options.format !== void 0 ? { format: options.format } : {}
|
|
5850
6223
|
});
|
|
6224
|
+
evidenceRead = read;
|
|
6225
|
+
evidenceRunIds = options.run !== void 0 ? [options.run] : read.runs.length === 1 ? [read.runs[0].runId] : read.runs.map((run) => run.runId);
|
|
6226
|
+
if (input3.type === "file") {
|
|
6227
|
+
try {
|
|
6228
|
+
const raw = await readFile(input3.path, "utf-8");
|
|
6229
|
+
evidenceSourceContents = new Map(
|
|
6230
|
+
evidenceRunIds.map((runId) => [runId, raw])
|
|
6231
|
+
);
|
|
6232
|
+
} catch {
|
|
6233
|
+
evidenceSourceContents = void 0;
|
|
6234
|
+
}
|
|
6235
|
+
} else {
|
|
6236
|
+
evidenceSourceContents = new Map(
|
|
6237
|
+
evidenceRunIds.map((runId) => [
|
|
6238
|
+
runId,
|
|
6239
|
+
`${read.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
|
|
6240
|
+
`
|
|
6241
|
+
])
|
|
6242
|
+
);
|
|
6243
|
+
}
|
|
5851
6244
|
result = mergeSafetyExtensions(
|
|
5852
6245
|
runTraceChecks(
|
|
5853
6246
|
{ read },
|
|
@@ -5867,7 +6260,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
5867
6260
|
} catch (error) {
|
|
5868
6261
|
if (phase === "config") {
|
|
5869
6262
|
const message = error instanceof Error ? error.message : String(error);
|
|
5870
|
-
const code = message.startsWith("--") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
|
|
6263
|
+
const code = message.startsWith("--") || message.includes("Unknown --preset") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
|
|
5871
6264
|
result = errorResult(
|
|
5872
6265
|
code,
|
|
5873
6266
|
message
|
|
@@ -5877,8 +6270,47 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
|
|
|
5877
6270
|
}
|
|
5878
6271
|
}
|
|
5879
6272
|
process.exitCode = exitCodeFor(result);
|
|
6273
|
+
const failed = result.status !== "pass";
|
|
6274
|
+
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
6275
|
+
try {
|
|
6276
|
+
const runIds = evidenceRunIds.length > 0 ? evidenceRunIds : result.runId !== void 0 ? [result.runId] : ["check"];
|
|
6277
|
+
if (evidenceSourceContents === void 0 && evidenceRead !== void 0) {
|
|
6278
|
+
evidenceSourceContents = new Map(
|
|
6279
|
+
runIds.map((runId) => [
|
|
6280
|
+
runId,
|
|
6281
|
+
`${evidenceRead.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
|
|
6282
|
+
`
|
|
6283
|
+
])
|
|
6284
|
+
);
|
|
6285
|
+
}
|
|
6286
|
+
let redactionProfile = parseEvidenceProfile(options.evidenceProfile);
|
|
6287
|
+
let evidenceFormat = parseEvidenceFormat(options.evidenceFormat);
|
|
6288
|
+
const outputDir = resolveEvidenceOutputDir(
|
|
6289
|
+
options.evidenceDir,
|
|
6290
|
+
runIds[0] ?? "check"
|
|
6291
|
+
);
|
|
6292
|
+
const written = await writeLocalEvidence({
|
|
6293
|
+
outputDir,
|
|
6294
|
+
runIds,
|
|
6295
|
+
...evidenceSourceContents !== void 0 ? { sourceContents: evidenceSourceContents } : {},
|
|
6296
|
+
...options.dir !== void 0 ? { dir: options.dir } : {},
|
|
6297
|
+
failed,
|
|
6298
|
+
checkResultsJson: checkResultToEvidenceJson(result, runIds),
|
|
6299
|
+
summaryText: `Check status: ${result.status}`,
|
|
6300
|
+
redactionProfile,
|
|
6301
|
+
format: evidenceFormat
|
|
6302
|
+
});
|
|
6303
|
+
if (!options.json) {
|
|
6304
|
+
console.log(`Evidence: ${written}`);
|
|
6305
|
+
}
|
|
6306
|
+
} catch (error) {
|
|
6307
|
+
console.error(
|
|
6308
|
+
`[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
|
|
6309
|
+
);
|
|
6310
|
+
}
|
|
6311
|
+
}
|
|
5880
6312
|
if (options.json) printJson(result);
|
|
5881
|
-
else printHuman(result);
|
|
6313
|
+
else printHuman(result, options);
|
|
5882
6314
|
}
|
|
5883
6315
|
|
|
5884
6316
|
// packages/viewer/src/html.ts
|
|
@@ -6029,7 +6461,7 @@ async function loadSuiteViewerData(options) {
|
|
|
6029
6461
|
for (const suiteCase of result.cases) {
|
|
6030
6462
|
cases.push(await enrichCase(suiteCase, baselinePath));
|
|
6031
6463
|
}
|
|
6032
|
-
const artifactsDir =
|
|
6464
|
+
const artifactsDir = path18.join(path18.dirname(result.configPath), ".agent-inspect/suite-runs");
|
|
6033
6465
|
return {
|
|
6034
6466
|
suiteName: result.suiteName,
|
|
6035
6467
|
configPath: result.configPath,
|
|
@@ -6222,19 +6654,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
6222
6654
|
}
|
|
6223
6655
|
var INDEX_DIR_NAME = "index";
|
|
6224
6656
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
6225
|
-
const projectRoot =
|
|
6226
|
-
const workspaceDir =
|
|
6657
|
+
const projectRoot = path18.resolve(cwd);
|
|
6658
|
+
const workspaceDir = path18.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
6227
6659
|
return {
|
|
6228
6660
|
projectRoot,
|
|
6229
6661
|
workspaceDir,
|
|
6230
|
-
manifestPath:
|
|
6662
|
+
manifestPath: path18.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
6231
6663
|
};
|
|
6232
6664
|
}
|
|
6233
6665
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
6234
|
-
const base =
|
|
6235
|
-
const resolved =
|
|
6236
|
-
const rel =
|
|
6237
|
-
if (rel === "" || rel === "." || !rel.startsWith("..") && !
|
|
6666
|
+
const base = path18.resolve(workspaceDir);
|
|
6667
|
+
const resolved = path18.resolve(base, relative);
|
|
6668
|
+
const rel = path18.relative(base, resolved);
|
|
6669
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path18.isAbsolute(rel)) {
|
|
6238
6670
|
return resolved;
|
|
6239
6671
|
}
|
|
6240
6672
|
throw new Error(
|
|
@@ -6303,7 +6735,7 @@ async function createWorkspace(options = {}) {
|
|
|
6303
6735
|
created = false;
|
|
6304
6736
|
adopted = true;
|
|
6305
6737
|
} else {
|
|
6306
|
-
const project = options.project?.trim() ||
|
|
6738
|
+
const project = options.project?.trim() || path18.basename(location.projectRoot) || "workspace";
|
|
6307
6739
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
6308
6740
|
manifest = createDefaultWorkspaceManifest({
|
|
6309
6741
|
project,
|
|
@@ -6442,7 +6874,7 @@ async function doctorWorkspace(location) {
|
|
|
6442
6874
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
6443
6875
|
for (const file of await listJsonl(abs)) {
|
|
6444
6876
|
try {
|
|
6445
|
-
const s = await stat(
|
|
6877
|
+
const s = await stat(path18.join(abs, file));
|
|
6446
6878
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
6447
6879
|
} catch {
|
|
6448
6880
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -6490,7 +6922,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
6490
6922
|
const relPath = `${rel}/${entry}`;
|
|
6491
6923
|
removed.push(relPath);
|
|
6492
6924
|
if (!dryRun) {
|
|
6493
|
-
await rm(
|
|
6925
|
+
await rm(path18.join(abs, entry), { recursive: true, force: true });
|
|
6494
6926
|
}
|
|
6495
6927
|
}
|
|
6496
6928
|
}
|
|
@@ -6499,7 +6931,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
6499
6931
|
|
|
6500
6932
|
// packages/viewer/src/workspace-data.ts
|
|
6501
6933
|
async function loadWorkspaceViewerData(options) {
|
|
6502
|
-
const cwd =
|
|
6934
|
+
const cwd = path18.resolve(options.cwd ?? process.cwd());
|
|
6503
6935
|
const location = resolveWorkspaceLocation(cwd);
|
|
6504
6936
|
const manifestRead = await readWorkspaceManifestFile(location);
|
|
6505
6937
|
if (!manifestRead.ok || manifestRead.manifest === void 0) {
|
|
@@ -6512,7 +6944,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
6512
6944
|
const runs = [];
|
|
6513
6945
|
for (const rel of manifestRead.manifest.traceDirs) {
|
|
6514
6946
|
const traceDir = resolveTraceDir({
|
|
6515
|
-
dir:
|
|
6947
|
+
dir: path18.join(location.workspaceDir, rel)
|
|
6516
6948
|
});
|
|
6517
6949
|
const td = new TraceDirectory({ dir: traceDir });
|
|
6518
6950
|
const files = await td.list();
|
|
@@ -6526,7 +6958,7 @@ async function loadWorkspaceViewerData(options) {
|
|
|
6526
6958
|
runId: meta.runId,
|
|
6527
6959
|
...meta.name !== void 0 ? { name: meta.name } : {},
|
|
6528
6960
|
status: meta.status,
|
|
6529
|
-
file:
|
|
6961
|
+
file: path18.basename(meta.filePath)
|
|
6530
6962
|
});
|
|
6531
6963
|
}
|
|
6532
6964
|
}
|
|
@@ -6537,8 +6969,8 @@ async function loadWorkspaceViewerData(options) {
|
|
|
6537
6969
|
doctor,
|
|
6538
6970
|
runs,
|
|
6539
6971
|
bundleDirs: [
|
|
6540
|
-
|
|
6541
|
-
|
|
6972
|
+
path18.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
|
|
6973
|
+
path18.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
|
|
6542
6974
|
]
|
|
6543
6975
|
};
|
|
6544
6976
|
}
|
|
@@ -6601,7 +7033,7 @@ function createViewerServer(options = {}) {
|
|
|
6601
7033
|
ok: true,
|
|
6602
7034
|
readOnly: true,
|
|
6603
7035
|
mode,
|
|
6604
|
-
traceDir:
|
|
7036
|
+
traceDir: path18.resolve(traceDir)
|
|
6605
7037
|
});
|
|
6606
7038
|
}
|
|
6607
7039
|
if (pathname === "/api/suite" && mode === "suite") {
|
|
@@ -6630,7 +7062,7 @@ function createViewerServer(options = {}) {
|
|
|
6630
7062
|
runId: meta.runId,
|
|
6631
7063
|
name: meta.name,
|
|
6632
7064
|
status: meta.status,
|
|
6633
|
-
file:
|
|
7065
|
+
file: path18.basename(meta.filePath),
|
|
6634
7066
|
startedAt: meta.startedAt,
|
|
6635
7067
|
durationMs: meta.durationMs
|
|
6636
7068
|
}))
|
|
@@ -6747,7 +7179,7 @@ function startViewerServer(options = {}) {
|
|
|
6747
7179
|
resolve({
|
|
6748
7180
|
host,
|
|
6749
7181
|
port: resolvedPort,
|
|
6750
|
-
traceDir:
|
|
7182
|
+
traceDir: path18.resolve(traceDir),
|
|
6751
7183
|
url: `http://${host}:${resolvedPort}/${modeQuery}`,
|
|
6752
7184
|
mode
|
|
6753
7185
|
});
|
|
@@ -7118,10 +7550,10 @@ async function evalRun(input3, options = {}) {
|
|
|
7118
7550
|
diagnostics: []
|
|
7119
7551
|
};
|
|
7120
7552
|
}
|
|
7121
|
-
function evidenceForRun(run,
|
|
7122
|
-
return [{ runId: run.runId, ...
|
|
7553
|
+
function evidenceForRun(run, path29) {
|
|
7554
|
+
return [{ runId: run.runId, ...path29 !== void 0 ? { path: path29 } : {} }];
|
|
7123
7555
|
}
|
|
7124
|
-
function evidenceForEvent(event,
|
|
7556
|
+
function evidenceForEvent(event, path29) {
|
|
7125
7557
|
return [
|
|
7126
7558
|
{
|
|
7127
7559
|
runId: event.runId,
|
|
@@ -7129,7 +7561,7 @@ function evidenceForEvent(event, path27) {
|
|
|
7129
7561
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
7130
7562
|
kind: event.kind,
|
|
7131
7563
|
name: event.name,
|
|
7132
|
-
...
|
|
7564
|
+
...path29 !== void 0 ? { path: path29 } : {}
|
|
7133
7565
|
}
|
|
7134
7566
|
];
|
|
7135
7567
|
}
|
|
@@ -7287,9 +7719,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
7287
7719
|
function tokenize(text) {
|
|
7288
7720
|
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));
|
|
7289
7721
|
}
|
|
7290
|
-
function firstEvidence(fields, run,
|
|
7722
|
+
function firstEvidence(fields, run, path29) {
|
|
7291
7723
|
const first = fields[0];
|
|
7292
|
-
return first === void 0 ? evidenceForRun(run,
|
|
7724
|
+
return first === void 0 ? evidenceForRun(run, path29) : evidenceForEvent(first.node.event, first.path);
|
|
7293
7725
|
}
|
|
7294
7726
|
function collectSourceIds(nodes, keys) {
|
|
7295
7727
|
const wanted = keySet(keys);
|
|
@@ -7666,8 +8098,8 @@ function renderEvalMarkdown(result) {
|
|
|
7666
8098
|
if (result.findings.length > 0) {
|
|
7667
8099
|
lines.push("", "## Findings");
|
|
7668
8100
|
for (const finding of result.findings) {
|
|
7669
|
-
const
|
|
7670
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
8101
|
+
const path29 = finding.evidence[0]?.path;
|
|
8102
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}`);
|
|
7671
8103
|
}
|
|
7672
8104
|
}
|
|
7673
8105
|
return `${lines.join("\n")}
|
|
@@ -7714,7 +8146,7 @@ function asConfig2(value) {
|
|
|
7714
8146
|
}
|
|
7715
8147
|
async function loadConfig2(configPath) {
|
|
7716
8148
|
if (configPath === void 0) return {};
|
|
7717
|
-
const extension =
|
|
8149
|
+
const extension = path18.extname(configPath);
|
|
7718
8150
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
7719
8151
|
throw new Error(
|
|
7720
8152
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -7723,7 +8155,7 @@ async function loadConfig2(configPath) {
|
|
|
7723
8155
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
7724
8156
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
7725
8157
|
}
|
|
7726
|
-
const absolute =
|
|
8158
|
+
const absolute = path18.resolve(configPath);
|
|
7727
8159
|
if (extension === ".json") {
|
|
7728
8160
|
const raw = await readFile(absolute, "utf-8");
|
|
7729
8161
|
return asConfig2(JSON.parse(raw));
|
|
@@ -7860,8 +8292,8 @@ function printHuman2(result) {
|
|
|
7860
8292
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
7861
8293
|
}
|
|
7862
8294
|
for (const finding of result.findings) {
|
|
7863
|
-
const
|
|
7864
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
8295
|
+
const path29 = finding.evidence[0]?.path;
|
|
8296
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}`);
|
|
7865
8297
|
}
|
|
7866
8298
|
}
|
|
7867
8299
|
function readErrorResult2(error) {
|
|
@@ -8114,14 +8546,14 @@ function exitCodeFor3(result) {
|
|
|
8114
8546
|
return 2;
|
|
8115
8547
|
}
|
|
8116
8548
|
function explainFinding(finding, blocksBundle) {
|
|
8117
|
-
const
|
|
8549
|
+
const path29 = finding.evidence[0]?.path ?? "(unknown path)";
|
|
8118
8550
|
const category = finding.category ?? "structure";
|
|
8119
8551
|
const confidence = finding.confidence ?? "medium";
|
|
8120
8552
|
const detector = finding.detector ?? finding.ruleId;
|
|
8121
8553
|
const action = finding.action ?? "review";
|
|
8122
8554
|
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.";
|
|
8123
8555
|
return [
|
|
8124
|
-
` Matched: detector=${detector}; path=${
|
|
8556
|
+
` Matched: detector=${detector}; path=${path29}; category=${category}`,
|
|
8125
8557
|
` Why: ${finding.message}`,
|
|
8126
8558
|
` Confidence: ${confidence}`,
|
|
8127
8559
|
` Redaction: ${redactionHint}`,
|
|
@@ -8163,9 +8595,9 @@ function printHuman3(result, explain = false) {
|
|
|
8163
8595
|
console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
8164
8596
|
}
|
|
8165
8597
|
for (const finding of result.findings) {
|
|
8166
|
-
const
|
|
8598
|
+
const path29 = finding.evidence[0]?.path;
|
|
8167
8599
|
const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
|
|
8168
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
8600
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}${taxonomy}`);
|
|
8169
8601
|
if (explain) {
|
|
8170
8602
|
const blocks = finding.severity === "error" || finding.status === "fail";
|
|
8171
8603
|
for (const line of explainFinding(finding, blocks)) {
|
|
@@ -8279,91 +8711,6 @@ function messageStartsWithDash(error) {
|
|
|
8279
8711
|
const message = error instanceof Error ? error.message : String(error);
|
|
8280
8712
|
return message.startsWith("--");
|
|
8281
8713
|
}
|
|
8282
|
-
function validateReporterArtifactPath(options) {
|
|
8283
|
-
const outputDir = path16.resolve(options.outputDir);
|
|
8284
|
-
const diagnostics = [];
|
|
8285
|
-
const rawPath = options.relativePath;
|
|
8286
|
-
if (rawPath.length === 0) {
|
|
8287
|
-
diagnostics.push({
|
|
8288
|
-
code: "artifact_path_empty",
|
|
8289
|
-
severity: "error",
|
|
8290
|
-
message: "Reporter artifact path must not be empty."
|
|
8291
|
-
});
|
|
8292
|
-
return { ok: false, outputDir, diagnostics };
|
|
8293
|
-
}
|
|
8294
|
-
if (rawPath.includes("\0")) {
|
|
8295
|
-
diagnostics.push({
|
|
8296
|
-
code: "invalid_artifact_path",
|
|
8297
|
-
severity: "error",
|
|
8298
|
-
message: "Reporter artifact path must not contain null bytes.",
|
|
8299
|
-
target: rawPath
|
|
8300
|
-
});
|
|
8301
|
-
return { ok: false, outputDir, diagnostics };
|
|
8302
|
-
}
|
|
8303
|
-
if (path16.isAbsolute(rawPath) || path16.win32.isAbsolute(rawPath)) {
|
|
8304
|
-
diagnostics.push({
|
|
8305
|
-
code: "artifact_path_absolute",
|
|
8306
|
-
severity: "error",
|
|
8307
|
-
message: "Reporter artifact path must be relative.",
|
|
8308
|
-
target: rawPath
|
|
8309
|
-
});
|
|
8310
|
-
return { ok: false, outputDir, diagnostics };
|
|
8311
|
-
}
|
|
8312
|
-
const normalized = path16.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
8313
|
-
const segments = normalized.split("/");
|
|
8314
|
-
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
8315
|
-
diagnostics.push({
|
|
8316
|
-
code: "artifact_path_escape",
|
|
8317
|
-
severity: "error",
|
|
8318
|
-
message: "Reporter artifact path must stay under the output directory.",
|
|
8319
|
-
target: rawPath
|
|
8320
|
-
});
|
|
8321
|
-
return { ok: false, outputDir, diagnostics };
|
|
8322
|
-
}
|
|
8323
|
-
const absolutePath = path16.resolve(outputDir, normalized);
|
|
8324
|
-
const relFromOutput = path16.relative(outputDir, absolutePath);
|
|
8325
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path16.isAbsolute(relFromOutput)) {
|
|
8326
|
-
diagnostics.push({
|
|
8327
|
-
code: "artifact_path_escape",
|
|
8328
|
-
severity: "error",
|
|
8329
|
-
message: "Reporter artifact path resolved outside the output directory.",
|
|
8330
|
-
target: rawPath
|
|
8331
|
-
});
|
|
8332
|
-
return { ok: false, outputDir, diagnostics };
|
|
8333
|
-
}
|
|
8334
|
-
return {
|
|
8335
|
-
ok: true,
|
|
8336
|
-
outputDir,
|
|
8337
|
-
relativePath: normalized,
|
|
8338
|
-
absolutePath,
|
|
8339
|
-
diagnostics
|
|
8340
|
-
};
|
|
8341
|
-
}
|
|
8342
|
-
var EVIDENCE_CI_ARTIFACT_FILES = [
|
|
8343
|
-
"evidence.html",
|
|
8344
|
-
"evidence.json",
|
|
8345
|
-
"check-results.json",
|
|
8346
|
-
"trace.jsonl"
|
|
8347
|
-
];
|
|
8348
|
-
function createEvidenceCiArtifacts(options) {
|
|
8349
|
-
const profile = options.redactionProfile;
|
|
8350
|
-
const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
|
|
8351
|
-
const join = (name) => prefix === "" ? name : path16.posix.join(prefix, name);
|
|
8352
|
-
const formatFor = (name) => {
|
|
8353
|
-
if (name.endsWith(".html")) return "html";
|
|
8354
|
-
if (name.endsWith(".jsonl")) return "jsonl";
|
|
8355
|
-
return "json";
|
|
8356
|
-
};
|
|
8357
|
-
return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
|
|
8358
|
-
kind: "evidence",
|
|
8359
|
-
path: join(name),
|
|
8360
|
-
format: formatFor(name),
|
|
8361
|
-
redactionProfile: profile,
|
|
8362
|
-
title: `Evidence v2 ${name}`
|
|
8363
|
-
}));
|
|
8364
|
-
}
|
|
8365
|
-
|
|
8366
|
-
// packages/cli/src/artifacts.ts
|
|
8367
8714
|
var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
|
|
8368
8715
|
var SAFETY_RULES = [
|
|
8369
8716
|
createSafetyRawContentRule(),
|
|
@@ -8437,8 +8784,8 @@ function renderCheckSection(result) {
|
|
|
8437
8784
|
`Diagnostics: ${result.diagnostics.length}`
|
|
8438
8785
|
];
|
|
8439
8786
|
for (const finding of result.findings.slice(0, 10)) {
|
|
8440
|
-
const
|
|
8441
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
8787
|
+
const path29 = finding.evidence[0]?.path ?? "(run)";
|
|
8788
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path29})`);
|
|
8442
8789
|
}
|
|
8443
8790
|
for (const diagnostic3 of result.diagnostics.slice(0, 10)) {
|
|
8444
8791
|
lines.push(`- ${diagnostic3.code}: ${diagnostic3.message}`);
|
|
@@ -8516,8 +8863,8 @@ function renderHtml(trace, check, diff) {
|
|
|
8516
8863
|
`;
|
|
8517
8864
|
}
|
|
8518
8865
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
8519
|
-
const outPath =
|
|
8520
|
-
await mkdir(
|
|
8866
|
+
const outPath = path18.join(outputDir, relativePath);
|
|
8867
|
+
await mkdir(path18.dirname(outPath), { recursive: true });
|
|
8521
8868
|
await writeFile(outPath, content, "utf-8");
|
|
8522
8869
|
files.push(relativePath);
|
|
8523
8870
|
}
|
|
@@ -8546,7 +8893,7 @@ function shouldWriteEvidence(options, status) {
|
|
|
8546
8893
|
return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
|
|
8547
8894
|
}
|
|
8548
8895
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
8549
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
8896
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path18.resolve(options.outputDir.trim()) : "";
|
|
8550
8897
|
if (outputDir === "") {
|
|
8551
8898
|
console.error("--output-dir is required.");
|
|
8552
8899
|
process.exitCode = 1;
|
|
@@ -8686,8 +9033,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
8686
9033
|
}
|
|
8687
9034
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
8688
9035
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
8689
|
-
await mkdir(
|
|
8690
|
-
await appendFile(
|
|
9036
|
+
await mkdir(path18.dirname(path18.resolve(summaryTarget)), { recursive: true });
|
|
9037
|
+
await appendFile(path18.resolve(summaryTarget), `
|
|
8691
9038
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
8692
9039
|
}
|
|
8693
9040
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -8706,10 +9053,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
8706
9053
|
findings: diff?.findings.length ?? 0,
|
|
8707
9054
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
8708
9055
|
},
|
|
8709
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
9056
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path18.resolve(summaryTarget) } : {},
|
|
8710
9057
|
note: NOTE
|
|
8711
9058
|
};
|
|
8712
|
-
await writeFile(
|
|
9059
|
+
await writeFile(path18.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
8713
9060
|
if (options.json === true) {
|
|
8714
9061
|
console.log(writeJson3(manifest).trimEnd());
|
|
8715
9062
|
} else {
|
|
@@ -8767,8 +9114,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
8767
9114
|
const location = resolveWorkspaceLocation(cwd);
|
|
8768
9115
|
const manifest = await readWorkspaceManifestFile(location);
|
|
8769
9116
|
if (manifest.ok && manifest.manifest) {
|
|
8770
|
-
const rel =
|
|
8771
|
-
if (!rel.startsWith("..") && !
|
|
9117
|
+
const rel = path18.relative(location.workspaceDir, normalized);
|
|
9118
|
+
if (!rel.startsWith("..") && !path18.isAbsolute(rel)) {
|
|
8772
9119
|
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
8773
9120
|
}
|
|
8774
9121
|
}
|
|
@@ -8784,7 +9131,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
|
|
|
8784
9131
|
const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
|
|
8785
9132
|
const base2 = resolveInsideWorkspace(
|
|
8786
9133
|
location.workspaceDir,
|
|
8787
|
-
|
|
9134
|
+
path18.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
8788
9135
|
);
|
|
8789
9136
|
return format === "zip" ? `${base2}.zip` : base2;
|
|
8790
9137
|
}
|
|
@@ -9189,19 +9536,19 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
9189
9536
|
let sidecarDir = outputDir;
|
|
9190
9537
|
if (outputDir.toLowerCase().endsWith(".html")) {
|
|
9191
9538
|
htmlPath = outputDir;
|
|
9192
|
-
sidecarDir =
|
|
9539
|
+
sidecarDir = path18.dirname(outputDir);
|
|
9193
9540
|
} else {
|
|
9194
9541
|
await mkdir(outputDir, { recursive: true });
|
|
9195
|
-
htmlPath =
|
|
9542
|
+
htmlPath = path18.join(outputDir, EVIDENCE_HTML_FILENAME);
|
|
9196
9543
|
sidecarDir = outputDir;
|
|
9197
9544
|
}
|
|
9198
9545
|
await mkdir(sidecarDir, { recursive: true });
|
|
9199
9546
|
await writeFile(htmlPath, htmlContent, "utf-8");
|
|
9200
|
-
await writeFile(
|
|
9547
|
+
await writeFile(path18.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
9201
9548
|
outputPath = htmlPath;
|
|
9202
9549
|
} else if (format === "zip") {
|
|
9203
9550
|
const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
|
|
9204
|
-
const zipParent =
|
|
9551
|
+
const zipParent = path18.dirname(zipPath);
|
|
9205
9552
|
await mkdir(zipParent, { recursive: true });
|
|
9206
9553
|
const entries = [
|
|
9207
9554
|
...[...packaged.entries()].map(([relativePath, content]) => ({
|
|
@@ -9217,10 +9564,10 @@ async function bundleCommand(runIdArg, options = {}) {
|
|
|
9217
9564
|
await mkdir(outputDir, { recursive: true });
|
|
9218
9565
|
for (const [relativePath, content] of packaged.entries()) {
|
|
9219
9566
|
const outPath = assertBundlePathContained(outputDir, relativePath);
|
|
9220
|
-
await mkdir(
|
|
9567
|
+
await mkdir(path18.dirname(outPath), { recursive: true });
|
|
9221
9568
|
await writeFile(outPath, content, "utf-8");
|
|
9222
9569
|
}
|
|
9223
|
-
await writeFile(
|
|
9570
|
+
await writeFile(path18.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
|
|
9224
9571
|
if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
|
|
9225
9572
|
files.push(EVIDENCE_MANIFEST_FILENAME);
|
|
9226
9573
|
}
|
|
@@ -9266,7 +9613,7 @@ function writeJson5(value) {
|
|
|
9266
9613
|
`;
|
|
9267
9614
|
}
|
|
9268
9615
|
async function bundleVerifyCommand(targetPath, options = {}) {
|
|
9269
|
-
const root =
|
|
9616
|
+
const root = path18.resolve(targetPath.trim() || ".");
|
|
9270
9617
|
const result = await verifyEvidenceDirectory(root, {
|
|
9271
9618
|
unexpectedFiles: options.unexpected ?? "fail"
|
|
9272
9619
|
});
|
|
@@ -9299,6 +9646,144 @@ async function bundleVerifyCommand(targetPath, options = {}) {
|
|
|
9299
9646
|
process.exitCode = 1;
|
|
9300
9647
|
}
|
|
9301
9648
|
}
|
|
9649
|
+
function writeJson6(value) {
|
|
9650
|
+
return `${JSON.stringify(value, null, 2)}
|
|
9651
|
+
`;
|
|
9652
|
+
}
|
|
9653
|
+
async function resolveHtmlPath(root) {
|
|
9654
|
+
const candidates = [
|
|
9655
|
+
path18.join(root, "evidence.html"),
|
|
9656
|
+
root.toLowerCase().endsWith(".html") ? root : ""
|
|
9657
|
+
].filter(Boolean);
|
|
9658
|
+
for (const candidate of candidates) {
|
|
9659
|
+
try {
|
|
9660
|
+
const info = await stat(candidate);
|
|
9661
|
+
if (info.isFile()) return candidate;
|
|
9662
|
+
} catch {
|
|
9663
|
+
}
|
|
9664
|
+
}
|
|
9665
|
+
throw new Error(
|
|
9666
|
+
`No evidence.html found under ${root}. Pass a bundle directory or .html path.`
|
|
9667
|
+
);
|
|
9668
|
+
}
|
|
9669
|
+
function openLocalFile(filePath) {
|
|
9670
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
9671
|
+
const platform = process.platform;
|
|
9672
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
9673
|
+
const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
9674
|
+
return new Promise((resolve) => {
|
|
9675
|
+
try {
|
|
9676
|
+
const child = spawn(command, args, {
|
|
9677
|
+
detached: true,
|
|
9678
|
+
stdio: "ignore"
|
|
9679
|
+
});
|
|
9680
|
+
child.on("error", (error) => {
|
|
9681
|
+
resolve({
|
|
9682
|
+
ok: false,
|
|
9683
|
+
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
9684
|
+
});
|
|
9685
|
+
});
|
|
9686
|
+
child.unref();
|
|
9687
|
+
resolve({ ok: true, detail: fileUrl });
|
|
9688
|
+
} catch (error) {
|
|
9689
|
+
resolve({
|
|
9690
|
+
ok: false,
|
|
9691
|
+
detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
|
|
9692
|
+
});
|
|
9693
|
+
}
|
|
9694
|
+
});
|
|
9695
|
+
}
|
|
9696
|
+
async function bundleOpenCommand(targetPath, options = {}) {
|
|
9697
|
+
const root = path18.resolve(targetPath.trim() || ".");
|
|
9698
|
+
try {
|
|
9699
|
+
await access(root);
|
|
9700
|
+
} catch {
|
|
9701
|
+
const message = `Evidence path not found: ${root}`;
|
|
9702
|
+
if (options.json) {
|
|
9703
|
+
console.log(writeJson6({ ok: false, error: message }).trimEnd());
|
|
9704
|
+
} else {
|
|
9705
|
+
console.error(`[AgentInspect] ${message}`);
|
|
9706
|
+
}
|
|
9707
|
+
process.exitCode = 1;
|
|
9708
|
+
return;
|
|
9709
|
+
}
|
|
9710
|
+
let verifyRoot = root;
|
|
9711
|
+
try {
|
|
9712
|
+
const info = await stat(root);
|
|
9713
|
+
if (info.isFile() && root.toLowerCase().endsWith(".html")) {
|
|
9714
|
+
verifyRoot = path18.dirname(root);
|
|
9715
|
+
}
|
|
9716
|
+
} catch {
|
|
9717
|
+
}
|
|
9718
|
+
if (options.skipVerify !== true) {
|
|
9719
|
+
const result = await verifyEvidenceDirectory(verifyRoot, {
|
|
9720
|
+
unexpectedFiles: "fail"
|
|
9721
|
+
});
|
|
9722
|
+
if (!result.ok) {
|
|
9723
|
+
if (options.json) {
|
|
9724
|
+
console.log(
|
|
9725
|
+
writeJson6({
|
|
9726
|
+
ok: false,
|
|
9727
|
+
error: "Evidence verify failed",
|
|
9728
|
+
root: result.root,
|
|
9729
|
+
issues: result.issues
|
|
9730
|
+
}).trimEnd()
|
|
9731
|
+
);
|
|
9732
|
+
} else {
|
|
9733
|
+
console.error(`Evidence verify: fail (${result.issues.length} issue(s))`);
|
|
9734
|
+
for (const issue of result.issues) {
|
|
9735
|
+
console.error(`- [${issue.severity}] ${issue.code}: ${issue.message}`);
|
|
9736
|
+
}
|
|
9737
|
+
console.error("Fix integrity issues or pass --skip-verify (not recommended).");
|
|
9738
|
+
}
|
|
9739
|
+
process.exitCode = 1;
|
|
9740
|
+
return;
|
|
9741
|
+
}
|
|
9742
|
+
}
|
|
9743
|
+
let htmlPath;
|
|
9744
|
+
try {
|
|
9745
|
+
htmlPath = await resolveHtmlPath(
|
|
9746
|
+
root.toLowerCase().endsWith(".html") ? path18.dirname(root) : root
|
|
9747
|
+
);
|
|
9748
|
+
if (root.toLowerCase().endsWith(".html")) {
|
|
9749
|
+
htmlPath = root;
|
|
9750
|
+
}
|
|
9751
|
+
} catch (error) {
|
|
9752
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9753
|
+
if (options.json) {
|
|
9754
|
+
console.log(writeJson6({ ok: false, error: message }).trimEnd());
|
|
9755
|
+
} else {
|
|
9756
|
+
console.error(`[AgentInspect] ${message}`);
|
|
9757
|
+
}
|
|
9758
|
+
process.exitCode = 1;
|
|
9759
|
+
return;
|
|
9760
|
+
}
|
|
9761
|
+
try {
|
|
9762
|
+
await readFile(path18.join(path18.dirname(htmlPath), "evidence.json"), "utf-8");
|
|
9763
|
+
} catch {
|
|
9764
|
+
}
|
|
9765
|
+
const opened = await openLocalFile(htmlPath);
|
|
9766
|
+
if (options.json) {
|
|
9767
|
+
console.log(
|
|
9768
|
+
writeJson6({
|
|
9769
|
+
ok: opened.ok,
|
|
9770
|
+
path: htmlPath,
|
|
9771
|
+
opened: opened.ok,
|
|
9772
|
+
detail: opened.detail
|
|
9773
|
+
}).trimEnd()
|
|
9774
|
+
);
|
|
9775
|
+
} else if (opened.ok) {
|
|
9776
|
+
console.log(`Opened local Evidence: ${htmlPath}`);
|
|
9777
|
+
console.log(`URL: ${opened.detail}`);
|
|
9778
|
+
} else {
|
|
9779
|
+
console.error(`[AgentInspect] Could not open browser automatically.`);
|
|
9780
|
+
console.error(`Open this file locally: ${htmlPath}`);
|
|
9781
|
+
console.error(opened.detail);
|
|
9782
|
+
}
|
|
9783
|
+
if (!opened.ok) {
|
|
9784
|
+
process.exitCode = 0;
|
|
9785
|
+
}
|
|
9786
|
+
}
|
|
9302
9787
|
var CLIENTS = [
|
|
9303
9788
|
"cursor",
|
|
9304
9789
|
"claude-code",
|
|
@@ -9359,24 +9844,24 @@ function resolveTargetPath(client, projectLocal) {
|
|
|
9359
9844
|
if (projectLocal) {
|
|
9360
9845
|
switch (client) {
|
|
9361
9846
|
case "cursor":
|
|
9362
|
-
return
|
|
9847
|
+
return path18.join(".cursor", "mcp.json");
|
|
9363
9848
|
case "claude-code":
|
|
9364
|
-
return
|
|
9849
|
+
return path18.join(".mcp.json");
|
|
9365
9850
|
case "codex":
|
|
9366
|
-
return
|
|
9851
|
+
return path18.join(".codex", "config.toml.json");
|
|
9367
9852
|
case "gemini":
|
|
9368
|
-
return
|
|
9853
|
+
return path18.join(".gemini", "settings.json");
|
|
9369
9854
|
}
|
|
9370
9855
|
}
|
|
9371
9856
|
switch (client) {
|
|
9372
9857
|
case "cursor":
|
|
9373
|
-
return
|
|
9858
|
+
return path18.join("~", ".cursor", "mcp.json");
|
|
9374
9859
|
case "claude-code":
|
|
9375
|
-
return
|
|
9860
|
+
return path18.join("~", ".claude.json");
|
|
9376
9861
|
case "codex":
|
|
9377
|
-
return
|
|
9862
|
+
return path18.join("~", ".codex", "config.toml");
|
|
9378
9863
|
case "gemini":
|
|
9379
|
-
return
|
|
9864
|
+
return path18.join("~", ".gemini", "settings.json");
|
|
9380
9865
|
}
|
|
9381
9866
|
}
|
|
9382
9867
|
async function mcpConfigureCommand(options) {
|
|
@@ -9400,8 +9885,8 @@ async function mcpConfigureCommand(options) {
|
|
|
9400
9885
|
];
|
|
9401
9886
|
let wrote = false;
|
|
9402
9887
|
if (!dryRun && projectLocal) {
|
|
9403
|
-
const abs =
|
|
9404
|
-
await mkdir(
|
|
9888
|
+
const abs = path18.resolve(targetPath);
|
|
9889
|
+
await mkdir(path18.dirname(abs), { recursive: true });
|
|
9405
9890
|
await writeFile(abs, `${JSON.stringify(config, null, 2)}
|
|
9406
9891
|
`, "utf8");
|
|
9407
9892
|
wrote = true;
|
|
@@ -9449,7 +9934,7 @@ function stable7(value) {
|
|
|
9449
9934
|
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable7(record[key])])
|
|
9450
9935
|
);
|
|
9451
9936
|
}
|
|
9452
|
-
function
|
|
9937
|
+
function writeJson7(value) {
|
|
9453
9938
|
return `${JSON.stringify(stable7(value), null, 2)}
|
|
9454
9939
|
`;
|
|
9455
9940
|
}
|
|
@@ -9561,23 +10046,23 @@ function readManifestDocument(value) {
|
|
|
9561
10046
|
};
|
|
9562
10047
|
}
|
|
9563
10048
|
function cwdRelative(filePath) {
|
|
9564
|
-
const relative =
|
|
9565
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
9566
|
-
return
|
|
10049
|
+
const relative = path18.relative(process.cwd(), path18.resolve(filePath)).replace(/\\/g, "/");
|
|
10050
|
+
if (relative === "" || relative.startsWith("../") || path18.isAbsolute(relative)) {
|
|
10051
|
+
return path18.basename(filePath);
|
|
9567
10052
|
}
|
|
9568
10053
|
return relative;
|
|
9569
10054
|
}
|
|
9570
10055
|
async function readReporterManifest(filePath) {
|
|
9571
|
-
const absolute =
|
|
10056
|
+
const absolute = path18.resolve(filePath);
|
|
9572
10057
|
const raw = await readFile(absolute, "utf-8");
|
|
9573
10058
|
const document = readManifestDocument(JSON.parse(raw));
|
|
9574
10059
|
const manifest = document.manifest;
|
|
9575
10060
|
const results = manifest.results.map((result) => ({
|
|
9576
10061
|
testId: safeText(result.testId),
|
|
9577
10062
|
name: safeText(result.name),
|
|
9578
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
10063
|
+
...result.file === void 0 ? {} : { file: safeText(path18.basename(result.file)) },
|
|
9579
10064
|
status: result.status,
|
|
9580
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
10065
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path18.basename(result.tracePath)) },
|
|
9581
10066
|
artifacts: result.artifacts,
|
|
9582
10067
|
diagnostics: result.diagnostics
|
|
9583
10068
|
}));
|
|
@@ -9716,20 +10201,20 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
9716
10201
|
return;
|
|
9717
10202
|
}
|
|
9718
10203
|
const markdown = renderMarkdown2(result);
|
|
9719
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
10204
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path18.resolve(options.output.trim()) : void 0;
|
|
9720
10205
|
if (outputPath !== void 0) {
|
|
9721
|
-
await mkdir(
|
|
10206
|
+
await mkdir(path18.dirname(outputPath), { recursive: true });
|
|
9722
10207
|
await writeFile(outputPath, markdown, "utf-8");
|
|
9723
10208
|
}
|
|
9724
10209
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
9725
10210
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
9726
|
-
const summaryPath =
|
|
9727
|
-
await mkdir(
|
|
10211
|
+
const summaryPath = path18.resolve(summaryTarget);
|
|
10212
|
+
await mkdir(path18.dirname(summaryPath), { recursive: true });
|
|
9728
10213
|
await appendFile(summaryPath, `
|
|
9729
10214
|
${markdown}`, "utf-8");
|
|
9730
10215
|
}
|
|
9731
10216
|
if (options.json === true) {
|
|
9732
|
-
console.log(
|
|
10217
|
+
console.log(writeJson7(result).trimEnd());
|
|
9733
10218
|
} else if (outputPath !== void 0) {
|
|
9734
10219
|
console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
|
|
9735
10220
|
console.log(`Status: ${result.status}`);
|
|
@@ -9867,7 +10352,7 @@ console.log("Trace written to .agent-inspect/");
|
|
|
9867
10352
|
`;
|
|
9868
10353
|
}
|
|
9869
10354
|
}
|
|
9870
|
-
function githubWorkflowTemplate() {
|
|
10355
|
+
function githubWorkflowTemplate(demoPath) {
|
|
9871
10356
|
return `name: AgentInspect artifacts
|
|
9872
10357
|
|
|
9873
10358
|
on:
|
|
@@ -9884,19 +10369,32 @@ jobs:
|
|
|
9884
10369
|
with:
|
|
9885
10370
|
node-version: "22"
|
|
9886
10371
|
- run: npm ci
|
|
9887
|
-
-
|
|
9888
|
-
|
|
10372
|
+
- name: Run deterministic agent fixture
|
|
10373
|
+
run: node ${demoPath}
|
|
10374
|
+
- name: Trajectory check with Evidence on failure
|
|
10375
|
+
run: >
|
|
10376
|
+
npx --yes agent-inspect check --dir .agent-inspect
|
|
10377
|
+
--preset trajectory
|
|
10378
|
+
--evidence-on fail
|
|
10379
|
+
--evidence-profile share
|
|
10380
|
+
--evidence-format directory
|
|
10381
|
+
- name: Verify share safety
|
|
10382
|
+
if: always()
|
|
10383
|
+
run: npx --yes agent-inspect verify-safe . --dir .agent-inspect
|
|
10384
|
+
- name: Upload AgentInspect traces and Evidence
|
|
9889
10385
|
if: always()
|
|
9890
10386
|
uses: actions/upload-artifact@v4
|
|
9891
10387
|
with:
|
|
9892
10388
|
name: agent-inspect-traces
|
|
9893
|
-
path:
|
|
10389
|
+
path: |
|
|
10390
|
+
.agent-inspect/**/*.jsonl
|
|
10391
|
+
.agent-inspect/evidence/**
|
|
9894
10392
|
if-no-files-found: ignore
|
|
9895
10393
|
`;
|
|
9896
10394
|
}
|
|
9897
10395
|
async function planInit(options = {}) {
|
|
9898
10396
|
const framework = normalizeFramework(options.framework);
|
|
9899
|
-
const cwd =
|
|
10397
|
+
const cwd = path18.resolve(options.cwd ?? process.cwd());
|
|
9900
10398
|
const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
|
|
9901
10399
|
const candidates = [
|
|
9902
10400
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
@@ -9906,12 +10404,12 @@ async function planInit(options = {}) {
|
|
|
9906
10404
|
if (options.ci === "github") {
|
|
9907
10405
|
candidates.push({
|
|
9908
10406
|
rel: ".github/workflows/agent-inspect-artifacts.yml",
|
|
9909
|
-
content: githubWorkflowTemplate()
|
|
10407
|
+
content: githubWorkflowTemplate(demoPath)
|
|
9910
10408
|
});
|
|
9911
10409
|
}
|
|
9912
10410
|
const files = [];
|
|
9913
10411
|
for (const candidate of candidates) {
|
|
9914
|
-
const abs =
|
|
10412
|
+
const abs = path18.join(cwd, candidate.rel);
|
|
9915
10413
|
try {
|
|
9916
10414
|
await access(abs);
|
|
9917
10415
|
files.push({
|
|
@@ -9932,20 +10430,21 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
9932
10430
|
if (entry.action === "skip") {
|
|
9933
10431
|
continue;
|
|
9934
10432
|
}
|
|
9935
|
-
const abs =
|
|
10433
|
+
const abs = path18.join(cwd, entry.path);
|
|
9936
10434
|
if (options.dryRun) {
|
|
9937
10435
|
written.push(entry.path);
|
|
9938
10436
|
continue;
|
|
9939
10437
|
}
|
|
9940
|
-
await mkdir(
|
|
9941
|
-
const
|
|
10438
|
+
await mkdir(path18.dirname(abs), { recursive: true });
|
|
10439
|
+
const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
|
|
10440
|
+
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
|
|
9942
10441
|
await writeFile(abs, content, "utf-8");
|
|
9943
10442
|
written.push(entry.path);
|
|
9944
10443
|
}
|
|
9945
10444
|
return written;
|
|
9946
10445
|
}
|
|
9947
10446
|
async function initCommand(options = {}) {
|
|
9948
|
-
const cwd =
|
|
10447
|
+
const cwd = path18.resolve(options.cwd ?? process.cwd());
|
|
9949
10448
|
try {
|
|
9950
10449
|
const plan = await planInit({ ...options, cwd });
|
|
9951
10450
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -10037,7 +10536,7 @@ function envCheck(name, optional = true) {
|
|
|
10037
10536
|
};
|
|
10038
10537
|
}
|
|
10039
10538
|
async function traceDirWritable(traceDir) {
|
|
10040
|
-
const resolved =
|
|
10539
|
+
const resolved = path18.resolve(traceDir);
|
|
10041
10540
|
try {
|
|
10042
10541
|
await mkdir(resolved, { recursive: true });
|
|
10043
10542
|
await access(resolved, constants.W_OK);
|
|
@@ -10058,10 +10557,10 @@ async function traceDirWritable(traceDir) {
|
|
|
10058
10557
|
}
|
|
10059
10558
|
}
|
|
10060
10559
|
function readPackageVersionNearEntry(entryPath, packageName) {
|
|
10061
|
-
let dir =
|
|
10062
|
-
const { root } =
|
|
10560
|
+
let dir = path18.dirname(path18.resolve(entryPath));
|
|
10561
|
+
const { root } = path18.parse(dir);
|
|
10063
10562
|
while (true) {
|
|
10064
|
-
const candidate =
|
|
10563
|
+
const candidate = path18.join(dir, "package.json");
|
|
10065
10564
|
if (existsSync(candidate)) {
|
|
10066
10565
|
try {
|
|
10067
10566
|
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
@@ -10072,14 +10571,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
|
|
|
10072
10571
|
}
|
|
10073
10572
|
}
|
|
10074
10573
|
if (dir === root) break;
|
|
10075
|
-
const parent =
|
|
10574
|
+
const parent = path18.dirname(dir);
|
|
10076
10575
|
if (parent === dir) break;
|
|
10077
10576
|
dir = parent;
|
|
10078
10577
|
}
|
|
10079
10578
|
return void 0;
|
|
10080
10579
|
}
|
|
10081
10580
|
function resolveInstalledPackage(cwd, name) {
|
|
10082
|
-
const require2 = createRequire(
|
|
10581
|
+
const require2 = createRequire(path18.join(cwd, "package.json"));
|
|
10083
10582
|
try {
|
|
10084
10583
|
const entry = require2.resolve(name);
|
|
10085
10584
|
let version2;
|
|
@@ -10177,7 +10676,7 @@ function versionMismatchCheck(cwd) {
|
|
|
10177
10676
|
};
|
|
10178
10677
|
}
|
|
10179
10678
|
async function runDoctorChecks(options = {}) {
|
|
10180
|
-
const cwd =
|
|
10679
|
+
const cwd = path18.resolve(options.cwd ?? process2.cwd());
|
|
10181
10680
|
const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
10182
10681
|
const checks2 = [
|
|
10183
10682
|
nodeVersionCheck(),
|
|
@@ -10417,7 +10916,7 @@ function parsePluginManifest(input3) {
|
|
|
10417
10916
|
};
|
|
10418
10917
|
}
|
|
10419
10918
|
async function readPluginManifestFile(packageDir) {
|
|
10420
|
-
const manifestPath =
|
|
10919
|
+
const manifestPath = path18.join(packageDir, PLUGIN_MANIFEST_FILENAME);
|
|
10421
10920
|
try {
|
|
10422
10921
|
const raw = await readFile(manifestPath, "utf8");
|
|
10423
10922
|
const parsed = parsePluginManifest(JSON.parse(raw));
|
|
@@ -10491,7 +10990,7 @@ function createTraceDirectoryIndexer() {
|
|
|
10491
10990
|
// packages/cli/src/plugins.ts
|
|
10492
10991
|
async function readPackageName(packageDir) {
|
|
10493
10992
|
try {
|
|
10494
|
-
const raw = await readFile(
|
|
10993
|
+
const raw = await readFile(path18.join(packageDir, "package.json"), "utf8");
|
|
10495
10994
|
const parsed = JSON.parse(raw);
|
|
10496
10995
|
return typeof parsed.name === "string" ? parsed.name : void 0;
|
|
10497
10996
|
} catch {
|
|
@@ -10499,7 +10998,7 @@ async function readPackageName(packageDir) {
|
|
|
10499
10998
|
}
|
|
10500
10999
|
}
|
|
10501
11000
|
async function discoverPlugins(cwd = process.cwd()) {
|
|
10502
|
-
const nodeModules =
|
|
11001
|
+
const nodeModules = path18.join(cwd, "node_modules");
|
|
10503
11002
|
const found = [];
|
|
10504
11003
|
let entries;
|
|
10505
11004
|
try {
|
|
@@ -10510,7 +11009,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
10510
11009
|
for (const entry of entries.sort()) {
|
|
10511
11010
|
if (entry.startsWith("@")) continue;
|
|
10512
11011
|
if (!isPluginPackageName(entry)) continue;
|
|
10513
|
-
const packageDir =
|
|
11012
|
+
const packageDir = path18.join(nodeModules, entry);
|
|
10514
11013
|
const manifestRead = await readPluginManifestFile(packageDir);
|
|
10515
11014
|
found.push({
|
|
10516
11015
|
packageName: entry,
|
|
@@ -10523,7 +11022,7 @@ async function discoverPlugins(cwd = process.cwd()) {
|
|
|
10523
11022
|
return found;
|
|
10524
11023
|
}
|
|
10525
11024
|
async function validatePluginPackage(packageRef, cwd = process.cwd()) {
|
|
10526
|
-
const packageDir =
|
|
11025
|
+
const packageDir = path18.isAbsolute(packageRef) ? packageRef : path18.join(cwd, "node_modules", packageRef);
|
|
10527
11026
|
const packageName = await readPackageName(packageDir) ?? packageRef;
|
|
10528
11027
|
const errors = [];
|
|
10529
11028
|
const warnings = [];
|
|
@@ -10599,7 +11098,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
|
|
|
10599
11098
|
}
|
|
10600
11099
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
10601
11100
|
function traceIndexPath(traceDir) {
|
|
10602
|
-
return
|
|
11101
|
+
return path18.join(traceDir, INDEX_FILENAME);
|
|
10603
11102
|
}
|
|
10604
11103
|
function parseMaxEntries(raw) {
|
|
10605
11104
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -10742,7 +11241,7 @@ async function newestTraceMtimeMs2(traceDir) {
|
|
|
10742
11241
|
for (const file of files) {
|
|
10743
11242
|
if (!file.endsWith(".jsonl")) continue;
|
|
10744
11243
|
try {
|
|
10745
|
-
const s = await stat(
|
|
11244
|
+
const s = await stat(path18.join(traceDir, file));
|
|
10746
11245
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
10747
11246
|
} catch {
|
|
10748
11247
|
}
|
|
@@ -10994,11 +11493,11 @@ function printJson5(value) {
|
|
|
10994
11493
|
console.log(JSON.stringify(value, null, 2));
|
|
10995
11494
|
}
|
|
10996
11495
|
function resolveCwd(options) {
|
|
10997
|
-
return
|
|
11496
|
+
return path18.resolve(options.cwd ?? process.cwd());
|
|
10998
11497
|
}
|
|
10999
11498
|
async function suiteInitCommand(options = {}) {
|
|
11000
11499
|
const cwd = resolveCwd(options);
|
|
11001
|
-
const configPath =
|
|
11500
|
+
const configPath = path18.join(cwd, DEFAULT_CONFIG_FILENAME);
|
|
11002
11501
|
const template = options.template?.trim();
|
|
11003
11502
|
const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
|
|
11004
11503
|
if (options.dryRun) {
|
|
@@ -11117,13 +11616,13 @@ async function suiteListCommand(options = {}) {
|
|
|
11117
11616
|
}
|
|
11118
11617
|
async function writeSuiteArtifact(result, configOutputDir, options) {
|
|
11119
11618
|
const cwd = resolveCwd(options);
|
|
11120
|
-
const outputDir =
|
|
11619
|
+
const outputDir = path18.resolve(
|
|
11121
11620
|
cwd,
|
|
11122
11621
|
options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
|
|
11123
11622
|
);
|
|
11124
11623
|
await mkdir(outputDir, { recursive: true });
|
|
11125
11624
|
const stamp = result.startedAt.replace(/[:.]/g, "-");
|
|
11126
|
-
const filePath =
|
|
11625
|
+
const filePath = path18.join(outputDir, `${result.suiteName}-${stamp}.json`);
|
|
11127
11626
|
await writeFile(filePath, `${JSON.stringify(result, null, 2)}
|
|
11128
11627
|
`, "utf-8");
|
|
11129
11628
|
return filePath;
|
|
@@ -11181,7 +11680,7 @@ async function loadSuiteResultFromInput(options) {
|
|
|
11181
11680
|
if (options.input === void 0 || options.input.trim() === "") {
|
|
11182
11681
|
throw new Error("Pass --input <suite-run.json> from a prior suite run.");
|
|
11183
11682
|
}
|
|
11184
|
-
const inputPath =
|
|
11683
|
+
const inputPath = path18.resolve(cwd, options.input.trim());
|
|
11185
11684
|
const raw = await readFile(inputPath, "utf-8");
|
|
11186
11685
|
return JSON.parse(raw);
|
|
11187
11686
|
}
|
|
@@ -11215,9 +11714,9 @@ function normalizeMetrics(raw) {
|
|
|
11215
11714
|
}
|
|
11216
11715
|
async function writeArtifacts(result, outputDir) {
|
|
11217
11716
|
await mkdir(outputDir, { recursive: true });
|
|
11218
|
-
const jsonPath =
|
|
11219
|
-
const markdownPath =
|
|
11220
|
-
const htmlPath =
|
|
11717
|
+
const jsonPath = path18.join(outputDir, "cohort-results.json");
|
|
11718
|
+
const markdownPath = path18.join(outputDir, "cohort-summary.md");
|
|
11719
|
+
const htmlPath = path18.join(outputDir, "cohort-report.html");
|
|
11221
11720
|
await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
|
|
11222
11721
|
`, "utf-8");
|
|
11223
11722
|
await writeFile(
|
|
@@ -11245,7 +11744,7 @@ async function cohortCommand(options = {}) {
|
|
|
11245
11744
|
const format = options.format ?? (options.json ? "json" : "markdown");
|
|
11246
11745
|
let artifacts;
|
|
11247
11746
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
11248
|
-
artifacts = await writeArtifacts(result,
|
|
11747
|
+
artifacts = await writeArtifacts(result, path18.resolve(options.output.trim()));
|
|
11249
11748
|
}
|
|
11250
11749
|
if (options.json || format === "json") {
|
|
11251
11750
|
console.log(
|
|
@@ -11315,11 +11814,11 @@ function parseDuration2(value) {
|
|
|
11315
11814
|
async function writeArtifacts2(result, outputDir) {
|
|
11316
11815
|
await mkdir(outputDir, { recursive: true });
|
|
11317
11816
|
const paths = {
|
|
11318
|
-
jsonPath:
|
|
11319
|
-
markdownPath:
|
|
11320
|
-
htmlPath:
|
|
11321
|
-
junitPath:
|
|
11322
|
-
githubPath:
|
|
11817
|
+
jsonPath: path18.join(outputDir, "gate-results.json"),
|
|
11818
|
+
markdownPath: path18.join(outputDir, "gate-summary.md"),
|
|
11819
|
+
htmlPath: path18.join(outputDir, "gate-report.html"),
|
|
11820
|
+
junitPath: path18.join(outputDir, "junit.xml"),
|
|
11821
|
+
githubPath: path18.join(outputDir, "github-step-summary.md")
|
|
11323
11822
|
};
|
|
11324
11823
|
await writeFile(
|
|
11325
11824
|
paths.jsonPath,
|
|
@@ -11387,7 +11886,57 @@ async function gateCommand(options = {}) {
|
|
|
11387
11886
|
const result = await runGate(runs, gateOptions);
|
|
11388
11887
|
let artifacts;
|
|
11389
11888
|
if (options.output !== void 0 && options.output.trim() !== "") {
|
|
11390
|
-
artifacts = await writeArtifacts2(result,
|
|
11889
|
+
artifacts = await writeArtifacts2(result, path18.resolve(options.output.trim()));
|
|
11890
|
+
}
|
|
11891
|
+
const failed = !result.ok;
|
|
11892
|
+
if (shouldEmitEvidence(options.evidenceOn, failed)) {
|
|
11893
|
+
try {
|
|
11894
|
+
const runIds = runs.length > 0 ? runs.map((run) => run.runId) : result.suiteResult?.cases.map((item) => item.runId).filter((id) => typeof id === "string" && id.length > 0) ?? ["gate"];
|
|
11895
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
11896
|
+
for (const run of runs) {
|
|
11897
|
+
if (run.filePath) {
|
|
11898
|
+
try {
|
|
11899
|
+
sourceContents.set(run.runId, await readFile(run.filePath, "utf-8"));
|
|
11900
|
+
} catch {
|
|
11901
|
+
sourceContents.set(run.runId, "");
|
|
11902
|
+
}
|
|
11903
|
+
}
|
|
11904
|
+
}
|
|
11905
|
+
const label = runIds[0] ?? "gate";
|
|
11906
|
+
const outputDir = resolveEvidenceOutputDir(
|
|
11907
|
+
options.evidenceDir,
|
|
11908
|
+
`gate-${label}`
|
|
11909
|
+
);
|
|
11910
|
+
const written = await writeLocalEvidence({
|
|
11911
|
+
outputDir,
|
|
11912
|
+
runIds: runIds.length > 0 ? runIds : ["gate"],
|
|
11913
|
+
sourceContents,
|
|
11914
|
+
...gateOptions.traceDir !== void 0 ? { dir: gateOptions.traceDir } : {},
|
|
11915
|
+
failed,
|
|
11916
|
+
checkResultsJson: `${JSON.stringify(
|
|
11917
|
+
{
|
|
11918
|
+
aggregateStatus: failed ? "UNSAFE" : "SAFE",
|
|
11919
|
+
gate: result
|
|
11920
|
+
},
|
|
11921
|
+
null,
|
|
11922
|
+
2
|
|
11923
|
+
)}
|
|
11924
|
+
`,
|
|
11925
|
+
summaryText: renderGateReport(result, { format: "markdown" }),
|
|
11926
|
+
redactionProfile: parseEvidenceProfile(options.evidenceProfile),
|
|
11927
|
+
format: parseEvidenceFormat(options.evidenceFormat)
|
|
11928
|
+
});
|
|
11929
|
+
if (!options.json && format !== "json") {
|
|
11930
|
+
console.log(`Evidence: ${written}`);
|
|
11931
|
+
}
|
|
11932
|
+
if (artifacts !== void 0) {
|
|
11933
|
+
artifacts = { ...artifacts, evidence: written };
|
|
11934
|
+
}
|
|
11935
|
+
} catch (error) {
|
|
11936
|
+
console.error(
|
|
11937
|
+
`[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
|
|
11938
|
+
);
|
|
11939
|
+
}
|
|
11391
11940
|
}
|
|
11392
11941
|
if (options.json || format === "json") {
|
|
11393
11942
|
console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
|
|
@@ -11564,6 +12113,23 @@ function createCliProgram() {
|
|
|
11564
12113
|
"--circuit <rule>",
|
|
11565
12114
|
"run optional circuit rules (repeatable): same-tool-repetition, max-retries, ...",
|
|
11566
12115
|
(value, previous = []) => [...previous, value]
|
|
12116
|
+
).addOption(
|
|
12117
|
+
new Option("--preset <name>", "additive check preset").choices(["trajectory", "safety", "comprehensive"])
|
|
12118
|
+
).addOption(
|
|
12119
|
+
new Option(
|
|
12120
|
+
"--evidence-on <mode>",
|
|
12121
|
+
"write local Evidence v2 (fail=on failure, always, never; no upload)"
|
|
12122
|
+
).choices(["fail", "always", "never"])
|
|
12123
|
+
).option("--evidence-dir <path>", "local Evidence output directory or base path").addOption(
|
|
12124
|
+
new Option(
|
|
12125
|
+
"--evidence-profile <profile>",
|
|
12126
|
+
"Evidence redaction profile (default share)"
|
|
12127
|
+
).choices(["local", "share", "strict"])
|
|
12128
|
+
).addOption(
|
|
12129
|
+
new Option(
|
|
12130
|
+
"--evidence-format <format>",
|
|
12131
|
+
"Evidence output format (default directory)"
|
|
12132
|
+
).choices(["directory", "html", "zip"])
|
|
11567
12133
|
).action((target, opts) => {
|
|
11568
12134
|
runCommand(() => checkCommand(target, opts));
|
|
11569
12135
|
});
|
|
@@ -11662,6 +12228,9 @@ function createCliProgram() {
|
|
|
11662
12228
|
).option("--json", "print deterministic JSON verify result").action((targetPath, opts) => {
|
|
11663
12229
|
runCommand(() => bundleVerifyCommand(targetPath, opts));
|
|
11664
12230
|
});
|
|
12231
|
+
bundleCmd.command("open").description("Verify then open local Evidence HTML in the platform browser (no network)").argument("<path>", "evidence/bundle directory or evidence.html path").option("--skip-verify", "skip integrity verify before open (not recommended)").option("--json", "print deterministic JSON open result").action((targetPath, opts) => {
|
|
12232
|
+
runCommand(() => bundleOpenCommand(targetPath, opts));
|
|
12233
|
+
});
|
|
11665
12234
|
program.command("ci-summary").description("Summarize local reporter artifact manifests for CI").argument("<manifest...>", "reporter artifact manifest JSON files").option("-o, --output <path>", "write Markdown summary to a local file").option("--github-summary <path>", "append Markdown summary to this local file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON summary").action((manifest, opts) => {
|
|
11666
12235
|
runCommand(() => ciSummaryCommand(manifest, opts));
|
|
11667
12236
|
});
|
|
@@ -11941,7 +12510,22 @@ function createCliProgram() {
|
|
|
11941
12510
|
).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
|
|
11942
12511
|
"-o, --output <dir>",
|
|
11943
12512
|
"write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
|
|
11944
|
-
).option("--json", "print deterministic JSON result").
|
|
12513
|
+
).option("--json", "print deterministic JSON result").addOption(
|
|
12514
|
+
new Option(
|
|
12515
|
+
"--evidence-on <mode>",
|
|
12516
|
+
"write local Evidence v2 (fail=on failure, always, never; no upload)"
|
|
12517
|
+
).choices(["fail", "always", "never"])
|
|
12518
|
+
).option("--evidence-dir <path>", "local Evidence output directory or base path").addOption(
|
|
12519
|
+
new Option(
|
|
12520
|
+
"--evidence-profile <profile>",
|
|
12521
|
+
"Evidence redaction profile (default share)"
|
|
12522
|
+
).choices(["local", "share", "strict"])
|
|
12523
|
+
).addOption(
|
|
12524
|
+
new Option(
|
|
12525
|
+
"--evidence-format <format>",
|
|
12526
|
+
"Evidence output format (default directory)"
|
|
12527
|
+
).choices(["directory", "html", "zip"])
|
|
12528
|
+
).action((opts) => {
|
|
11945
12529
|
runCommand(() => gateCommand(opts));
|
|
11946
12530
|
});
|
|
11947
12531
|
return program;
|
|
@@ -11951,9 +12535,9 @@ function isPrimaryModule() {
|
|
|
11951
12535
|
if (!entry) return false;
|
|
11952
12536
|
const selfPath = fileURLToPath(import.meta.url);
|
|
11953
12537
|
try {
|
|
11954
|
-
return realpathSync(
|
|
12538
|
+
return realpathSync(path18.resolve(entry)) === realpathSync(path18.resolve(selfPath));
|
|
11955
12539
|
} catch {
|
|
11956
|
-
return
|
|
12540
|
+
return path18.resolve(entry) === path18.resolve(selfPath);
|
|
11957
12541
|
}
|
|
11958
12542
|
}
|
|
11959
12543
|
if (isPrimaryModule()) {
|