agent-inspect 4.2.0 → 4.3.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/docs/CLI.md +33 -0
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-5VSPJEZ7.mjs → chunk-BS5LSKZ3.mjs} +190 -6
- package/packages/cli/dist/chunk-BS5LSKZ3.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +2122 -1533
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +1863 -1496
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-VQT7QLGV.mjs → src-YFMPWEIS.mjs} +3 -3
- package/packages/cli/dist/{src-VQT7QLGV.mjs.map → src-YFMPWEIS.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +196 -3
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +93 -1
- package/packages/core/dist/advanced.d.ts +93 -1
- package/packages/core/dist/advanced.mjs +189 -4
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/cli/dist/chunk-5VSPJEZ7.mjs.map +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
var crypto = require('crypto');
|
|
5
5
|
var promises = require('fs/promises');
|
|
6
6
|
var os = require('os');
|
|
7
|
-
var
|
|
7
|
+
var path19 = require('path');
|
|
8
8
|
var async_hooks = require('async_hooks');
|
|
9
9
|
var process3 = require('process');
|
|
10
10
|
var tty = require('tty');
|
|
@@ -20,7 +20,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
20
20
|
|
|
21
21
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
22
22
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
23
|
-
var
|
|
23
|
+
var path19__default = /*#__PURE__*/_interopDefault(path19);
|
|
24
24
|
var process3__default = /*#__PURE__*/_interopDefault(process3);
|
|
25
25
|
var tty__default = /*#__PURE__*/_interopDefault(tty);
|
|
26
26
|
|
|
@@ -859,7 +859,7 @@ function getDefaultTraceDir() {
|
|
|
859
859
|
if (typeof home !== "string" || home.trim() === "") {
|
|
860
860
|
return FALLBACK_TRACE_DIR;
|
|
861
861
|
}
|
|
862
|
-
return
|
|
862
|
+
return path19__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
863
863
|
} catch {
|
|
864
864
|
return FALLBACK_TRACE_DIR;
|
|
865
865
|
}
|
|
@@ -867,11 +867,11 @@ function getDefaultTraceDir() {
|
|
|
867
867
|
function getTraceFilePath(runId, traceDir) {
|
|
868
868
|
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
869
869
|
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
870
|
-
safeId =
|
|
870
|
+
safeId = path19__default.default.basename(safeId);
|
|
871
871
|
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
872
872
|
safeId = "run_unknown";
|
|
873
873
|
}
|
|
874
|
-
return
|
|
874
|
+
return path19__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
875
875
|
}
|
|
876
876
|
function formatError(error) {
|
|
877
877
|
if (error instanceof Error) {
|
|
@@ -928,7 +928,7 @@ var init_utils = __esm({
|
|
|
928
928
|
init_duration();
|
|
929
929
|
DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
930
930
|
RUNS_DIR_NAME = "runs";
|
|
931
|
-
FALLBACK_TRACE_DIR =
|
|
931
|
+
FALLBACK_TRACE_DIR = path19__default.default.join(
|
|
932
932
|
os__default.default.tmpdir(),
|
|
933
933
|
"agent-inspect",
|
|
934
934
|
RUNS_DIR_NAME
|
|
@@ -1723,7 +1723,7 @@ var init_trace_directory = __esm({
|
|
|
1723
1723
|
this.#dir = resolveTraceDir(options);
|
|
1724
1724
|
}
|
|
1725
1725
|
getPath(filename) {
|
|
1726
|
-
return filename ?
|
|
1726
|
+
return filename ? path19__default.default.join(this.#dir, filename) : this.#dir;
|
|
1727
1727
|
}
|
|
1728
1728
|
async list() {
|
|
1729
1729
|
try {
|
|
@@ -1752,7 +1752,7 @@ function parseIsoToMs2(value) {
|
|
|
1752
1752
|
}
|
|
1753
1753
|
async function extractMetadata(filePath, _quickScan) {
|
|
1754
1754
|
const stats = await promises.stat(filePath);
|
|
1755
|
-
let runIdFromFile =
|
|
1755
|
+
let runIdFromFile = path19__default.default.basename(filePath);
|
|
1756
1756
|
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1757
1757
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1758
1758
|
}
|
|
@@ -3562,12 +3562,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3562
3562
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3563
3563
|
);
|
|
3564
3564
|
const ordered = [...runs].sort(compareRuns);
|
|
3565
|
-
const
|
|
3565
|
+
const path25 = [];
|
|
3566
3566
|
const visited = /* @__PURE__ */ new Set();
|
|
3567
3567
|
const pushRun = (run, confidence, source) => {
|
|
3568
3568
|
if (visited.has(run.runId)) return;
|
|
3569
3569
|
visited.add(run.runId);
|
|
3570
|
-
|
|
3570
|
+
path25.push({
|
|
3571
3571
|
runId: run.runId,
|
|
3572
3572
|
name: run.name,
|
|
3573
3573
|
startedAt: run.startedAt,
|
|
@@ -3592,7 +3592,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3592
3592
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3593
3593
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3594
3594
|
}
|
|
3595
|
-
return
|
|
3595
|
+
return path25;
|
|
3596
3596
|
}
|
|
3597
3597
|
function metaRunIdMatches(run, token, runById) {
|
|
3598
3598
|
const meta2 = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -3732,6 +3732,224 @@ var init_trace_verification = __esm({
|
|
|
3732
3732
|
}
|
|
3733
3733
|
});
|
|
3734
3734
|
|
|
3735
|
+
// packages/core/src/bundle/resolve.ts
|
|
3736
|
+
function parseSinceCutoff(since) {
|
|
3737
|
+
const trimmed = since.trim();
|
|
3738
|
+
if (trimmed === "") {
|
|
3739
|
+
throw new Error("--since requires a non-empty duration (e.g. 24h, 7d).");
|
|
3740
|
+
}
|
|
3741
|
+
return Date.now() - parseDuration(trimmed);
|
|
3742
|
+
}
|
|
3743
|
+
function runActivityMs(run) {
|
|
3744
|
+
if (run.startedAt !== void 0 && Number.isFinite(run.startedAt)) return run.startedAt;
|
|
3745
|
+
if (run.endedAt !== void 0 && Number.isFinite(run.endedAt)) return run.endedAt;
|
|
3746
|
+
return void 0;
|
|
3747
|
+
}
|
|
3748
|
+
function runsInSinceWindow(runs, since) {
|
|
3749
|
+
const cutoff = parseSinceCutoff(since);
|
|
3750
|
+
const ids = [];
|
|
3751
|
+
for (const run of runs) {
|
|
3752
|
+
const activity = runActivityMs(run);
|
|
3753
|
+
if (activity !== void 0 && activity >= cutoff) {
|
|
3754
|
+
ids.push(run.runId);
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
return ids.sort((a, b) => a.localeCompare(b));
|
|
3758
|
+
}
|
|
3759
|
+
function findSession(index, sessionId) {
|
|
3760
|
+
return index.sessions.find((session) => session.sessionId === sessionId);
|
|
3761
|
+
}
|
|
3762
|
+
function resolveBundleRunIds(index, runs, options) {
|
|
3763
|
+
const runId = options.runId?.trim();
|
|
3764
|
+
const sessionId = options.sessionId?.trim();
|
|
3765
|
+
const since = options.since?.trim();
|
|
3766
|
+
const modes = [runId ? 1 : 0, sessionId ? 1 : 0, since ? 1 : 0].reduce((a, b) => a + b, 0);
|
|
3767
|
+
if (modes === 0) {
|
|
3768
|
+
throw new Error(
|
|
3769
|
+
"bundle requires a run id, --session <sessionId>, or --since <duration>."
|
|
3770
|
+
);
|
|
3771
|
+
}
|
|
3772
|
+
if (modes > 1) {
|
|
3773
|
+
throw new Error(
|
|
3774
|
+
"bundle accepts only one target: a run id, --session, or --since (not combined)."
|
|
3775
|
+
);
|
|
3776
|
+
}
|
|
3777
|
+
if (runId) {
|
|
3778
|
+
const known = runs.some((run) => run.runId === runId);
|
|
3779
|
+
if (!known) {
|
|
3780
|
+
throw new Error(`Run "${runId}" was not found in the trace directory.`);
|
|
3781
|
+
}
|
|
3782
|
+
return { runIds: [runId] };
|
|
3783
|
+
}
|
|
3784
|
+
if (sessionId) {
|
|
3785
|
+
const session = findSession(index, sessionId);
|
|
3786
|
+
if (!session) {
|
|
3787
|
+
throw new Error(`Session "${sessionId}" was not found.`);
|
|
3788
|
+
}
|
|
3789
|
+
if (session.runIds.length === 0) {
|
|
3790
|
+
throw new Error(`Session "${sessionId}" has no runs to bundle.`);
|
|
3791
|
+
}
|
|
3792
|
+
return {
|
|
3793
|
+
runIds: [...session.runIds].sort((a, b) => a.localeCompare(b)),
|
|
3794
|
+
sessionId
|
|
3795
|
+
};
|
|
3796
|
+
}
|
|
3797
|
+
const runIds = runsInSinceWindow(runs, since);
|
|
3798
|
+
if (runIds.length === 0) {
|
|
3799
|
+
throw new Error(`No runs matched --since ${since}.`);
|
|
3800
|
+
}
|
|
3801
|
+
return { runIds, since };
|
|
3802
|
+
}
|
|
3803
|
+
var init_resolve = __esm({
|
|
3804
|
+
"packages/core/src/bundle/resolve.ts"() {
|
|
3805
|
+
init_duration();
|
|
3806
|
+
}
|
|
3807
|
+
});
|
|
3808
|
+
|
|
3809
|
+
// packages/core/src/bundle/safety-status.ts
|
|
3810
|
+
function aggregateBundleSafeStatus(statuses) {
|
|
3811
|
+
if (statuses.length === 0) return "UNKNOWN";
|
|
3812
|
+
if (statuses.some((status) => status === "UNSAFE")) return "UNSAFE";
|
|
3813
|
+
if (statuses.some((status) => status === "UNKNOWN")) return "UNKNOWN";
|
|
3814
|
+
if (statuses.some((status) => status === "SAFE WITH WARNINGS")) return "SAFE WITH WARNINGS";
|
|
3815
|
+
return "SAFE";
|
|
3816
|
+
}
|
|
3817
|
+
function toMetadataSafeStatus(status) {
|
|
3818
|
+
if (status === "SAFE WITH WARNINGS") return "SAFE_WITH_WARNINGS";
|
|
3819
|
+
return status;
|
|
3820
|
+
}
|
|
3821
|
+
function bundleFailsOnSafety(status, allowUnsafe) {
|
|
3822
|
+
if (allowUnsafe) return false;
|
|
3823
|
+
return status === "UNSAFE" || status === "UNKNOWN";
|
|
3824
|
+
}
|
|
3825
|
+
var init_safety_status = __esm({
|
|
3826
|
+
"packages/core/src/bundle/safety-status.ts"() {
|
|
3827
|
+
}
|
|
3828
|
+
});
|
|
3829
|
+
|
|
3830
|
+
// packages/core/src/bundle/manifest.ts
|
|
3831
|
+
function buildBundleMetadata(parts) {
|
|
3832
|
+
const aggregate = aggregateBundleSafeStatus(
|
|
3833
|
+
parts.checks.runs.map((run) => run.status)
|
|
3834
|
+
);
|
|
3835
|
+
return {
|
|
3836
|
+
createdAt: parts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3837
|
+
agentInspectVersion: parts.agentInspectVersion,
|
|
3838
|
+
redactionProfile: parts.profile,
|
|
3839
|
+
sourceTraceCount: parts.resolve.runIds.length,
|
|
3840
|
+
runIds: [...parts.resolve.runIds],
|
|
3841
|
+
safeStatus: toMetadataSafeStatus(aggregate),
|
|
3842
|
+
files: [...parts.files].sort((a, b) => a.localeCompare(b)),
|
|
3843
|
+
note: BUNDLE_NOTE,
|
|
3844
|
+
...parts.resolve.sessionId !== void 0 ? { sessionId: parts.resolve.sessionId } : {},
|
|
3845
|
+
...parts.resolve.since !== void 0 ? { since: parts.resolve.since } : {}
|
|
3846
|
+
};
|
|
3847
|
+
}
|
|
3848
|
+
function buildPlaceholderArtifact() {
|
|
3849
|
+
return {
|
|
3850
|
+
status: "not_requested",
|
|
3851
|
+
note: PLACEHOLDER_NOTE
|
|
3852
|
+
};
|
|
3853
|
+
}
|
|
3854
|
+
var BUNDLE_NOTE, PLACEHOLDER_NOTE;
|
|
3855
|
+
var init_manifest = __esm({
|
|
3856
|
+
"packages/core/src/bundle/manifest.ts"() {
|
|
3857
|
+
init_safety_status();
|
|
3858
|
+
BUNDLE_NOTE = "Generated locally by AgentInspect. Bundles are derived copies for review \u2014 not compliance or security certification. Review before sharing.";
|
|
3859
|
+
PLACEHOLDER_NOTE = "No eval or performance artifacts were requested for this bundle.";
|
|
3860
|
+
}
|
|
3861
|
+
});
|
|
3862
|
+
|
|
3863
|
+
// packages/core/src/bundle/summary.ts
|
|
3864
|
+
function markdownTable(rows) {
|
|
3865
|
+
const lines = ["| Field | Value |", "| --- | --- |"];
|
|
3866
|
+
for (const [key, value] of rows) {
|
|
3867
|
+
lines.push(`| ${key} | ${value ?? "unknown"} |`);
|
|
3868
|
+
}
|
|
3869
|
+
return lines.join("\n");
|
|
3870
|
+
}
|
|
3871
|
+
function buildBundleSummaryMarkdown(parts) {
|
|
3872
|
+
const { metadata, checks: checks2, redaction } = parts;
|
|
3873
|
+
const lines = [
|
|
3874
|
+
"# AgentInspect trace bundle",
|
|
3875
|
+
"",
|
|
3876
|
+
metadata.note,
|
|
3877
|
+
"",
|
|
3878
|
+
"## Overview",
|
|
3879
|
+
"",
|
|
3880
|
+
markdownTable([
|
|
3881
|
+
["Created", metadata.createdAt],
|
|
3882
|
+
["AgentInspect", metadata.agentInspectVersion],
|
|
3883
|
+
["Redaction profile", metadata.redactionProfile],
|
|
3884
|
+
["Safe status", metadata.safeStatus],
|
|
3885
|
+
["Source traces", metadata.sourceTraceCount],
|
|
3886
|
+
["Runs", metadata.runIds.join(", ")],
|
|
3887
|
+
...metadata.sessionId ? [["Session", metadata.sessionId]] : [],
|
|
3888
|
+
...metadata.since ? [["Since", metadata.since]] : []
|
|
3889
|
+
]),
|
|
3890
|
+
"",
|
|
3891
|
+
"## Safety checks",
|
|
3892
|
+
"",
|
|
3893
|
+
`Aggregate: **${checks2.aggregateStatus}**`,
|
|
3894
|
+
""
|
|
3895
|
+
];
|
|
3896
|
+
for (const run of checks2.runs) {
|
|
3897
|
+
lines.push(
|
|
3898
|
+
`- \`${run.runId}\`: ${run.status} (${run.findings} finding(s), ${run.errors} error(s), ${run.warnings} warning(s))`
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3901
|
+
lines.push("", "## Redaction", "", `Total findings: ${redaction.totalFindings}`, "");
|
|
3902
|
+
for (const run of redaction.runs) {
|
|
3903
|
+
const detectors = run.detectors.length > 0 ? run.detectors.join(", ") : "none";
|
|
3904
|
+
lines.push(`- \`${run.runId}\`: ${run.findings} finding(s); detectors: ${detectors}`);
|
|
3905
|
+
}
|
|
3906
|
+
lines.push(
|
|
3907
|
+
"",
|
|
3908
|
+
"## Files",
|
|
3909
|
+
"",
|
|
3910
|
+
...metadata.files.map((file) => `- \`${file}\``),
|
|
3911
|
+
"",
|
|
3912
|
+
"_Review every generated artifact before sharing outside your team._",
|
|
3913
|
+
""
|
|
3914
|
+
);
|
|
3915
|
+
return lines.join("\n");
|
|
3916
|
+
}
|
|
3917
|
+
var init_summary = __esm({
|
|
3918
|
+
"packages/core/src/bundle/summary.ts"() {
|
|
3919
|
+
}
|
|
3920
|
+
});
|
|
3921
|
+
function normalizeBundleOutputPath(out) {
|
|
3922
|
+
const trimmed = out.trim();
|
|
3923
|
+
if (trimmed === "") {
|
|
3924
|
+
throw new Error("--out requires a non-empty path.");
|
|
3925
|
+
}
|
|
3926
|
+
const resolved = path19__default.default.resolve(trimmed);
|
|
3927
|
+
if (resolved.toLowerCase().endsWith(".zip")) {
|
|
3928
|
+
return resolved.slice(0, -4);
|
|
3929
|
+
}
|
|
3930
|
+
return resolved;
|
|
3931
|
+
}
|
|
3932
|
+
function defaultBundleOutputPath(runIds) {
|
|
3933
|
+
const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
|
|
3934
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3935
|
+
return path19__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
3936
|
+
}
|
|
3937
|
+
var init_paths = __esm({
|
|
3938
|
+
"packages/core/src/bundle/paths.ts"() {
|
|
3939
|
+
}
|
|
3940
|
+
});
|
|
3941
|
+
|
|
3942
|
+
// packages/core/src/bundle/index.ts
|
|
3943
|
+
var init_bundle = __esm({
|
|
3944
|
+
"packages/core/src/bundle/index.ts"() {
|
|
3945
|
+
init_resolve();
|
|
3946
|
+
init_manifest();
|
|
3947
|
+
init_summary();
|
|
3948
|
+
init_safety_status();
|
|
3949
|
+
init_paths();
|
|
3950
|
+
}
|
|
3951
|
+
});
|
|
3952
|
+
|
|
3735
3953
|
// packages/core/src/inspect-run.ts
|
|
3736
3954
|
var init_inspect_run = __esm({
|
|
3737
3955
|
"packages/core/src/inspect-run.ts"() {
|
|
@@ -3775,6 +3993,7 @@ var init_advanced = __esm({
|
|
|
3775
3993
|
init_sessions();
|
|
3776
3994
|
init_trace_verification();
|
|
3777
3995
|
init_duration();
|
|
3996
|
+
init_bundle();
|
|
3778
3997
|
init_maybe_inspect_run();
|
|
3779
3998
|
}
|
|
3780
3999
|
});
|
|
@@ -3839,19 +4058,19 @@ var require_file_uri_to_path = __commonJS({
|
|
|
3839
4058
|
var rest = decodeURI(uri.substring(7));
|
|
3840
4059
|
var firstSlash = rest.indexOf("/");
|
|
3841
4060
|
var host = rest.substring(0, firstSlash);
|
|
3842
|
-
var
|
|
4061
|
+
var path25 = rest.substring(firstSlash + 1);
|
|
3843
4062
|
if ("localhost" == host) host = "";
|
|
3844
4063
|
if (host) {
|
|
3845
4064
|
host = sep + sep + host;
|
|
3846
4065
|
}
|
|
3847
|
-
|
|
4066
|
+
path25 = path25.replace(/^(.+)\|/, "$1:");
|
|
3848
4067
|
if (sep == "\\") {
|
|
3849
|
-
|
|
4068
|
+
path25 = path25.replace(/\//g, "\\");
|
|
3850
4069
|
}
|
|
3851
|
-
if (/^.+\:/.test(
|
|
3852
|
-
|
|
4070
|
+
if (/^.+\:/.test(path25)) ; else {
|
|
4071
|
+
path25 = sep + path25;
|
|
3853
4072
|
}
|
|
3854
|
-
return host +
|
|
4073
|
+
return host + path25;
|
|
3855
4074
|
}
|
|
3856
4075
|
}
|
|
3857
4076
|
});
|
|
@@ -3860,18 +4079,18 @@ var require_file_uri_to_path = __commonJS({
|
|
|
3860
4079
|
var require_bindings = __commonJS({
|
|
3861
4080
|
"node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js"(exports$1, module) {
|
|
3862
4081
|
var fs = __require("fs");
|
|
3863
|
-
var
|
|
4082
|
+
var path25 = __require("path");
|
|
3864
4083
|
var fileURLToPath2 = require_file_uri_to_path();
|
|
3865
|
-
var join =
|
|
3866
|
-
var dirname =
|
|
3867
|
-
var exists = fs.accessSync && function(
|
|
4084
|
+
var join = path25.join;
|
|
4085
|
+
var dirname = path25.dirname;
|
|
4086
|
+
var exists = fs.accessSync && function(path26) {
|
|
3868
4087
|
try {
|
|
3869
|
-
fs.accessSync(
|
|
4088
|
+
fs.accessSync(path26);
|
|
3870
4089
|
} catch (e) {
|
|
3871
4090
|
return false;
|
|
3872
4091
|
}
|
|
3873
4092
|
return true;
|
|
3874
|
-
} || fs.existsSync ||
|
|
4093
|
+
} || fs.existsSync || path25.existsSync;
|
|
3875
4094
|
var defaults = {
|
|
3876
4095
|
arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
|
|
3877
4096
|
compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
|
|
@@ -3916,7 +4135,7 @@ var require_bindings = __commonJS({
|
|
|
3916
4135
|
if (!opts.module_root) {
|
|
3917
4136
|
opts.module_root = exports$1.getRoot(exports$1.getFileName());
|
|
3918
4137
|
}
|
|
3919
|
-
if (
|
|
4138
|
+
if (path25.extname(opts.bindings) != ".node") {
|
|
3920
4139
|
opts.bindings += ".node";
|
|
3921
4140
|
}
|
|
3922
4141
|
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
@@ -4151,7 +4370,7 @@ var require_pragma = __commonJS({
|
|
|
4151
4370
|
var require_backup = __commonJS({
|
|
4152
4371
|
"node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/backup.js"(exports$1, module) {
|
|
4153
4372
|
var fs = __require("fs");
|
|
4154
|
-
var
|
|
4373
|
+
var path25 = __require("path");
|
|
4155
4374
|
var { promisify } = __require("util");
|
|
4156
4375
|
var { cppdb } = require_util();
|
|
4157
4376
|
var fsAccess = promisify(fs.access);
|
|
@@ -4167,7 +4386,7 @@ var require_backup = __commonJS({
|
|
|
4167
4386
|
if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
|
|
4168
4387
|
if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
|
|
4169
4388
|
if (handler != null && typeof handler !== "function") throw new TypeError('Expected the "progress" option to be a function');
|
|
4170
|
-
await fsAccess(
|
|
4389
|
+
await fsAccess(path25.dirname(filename)).catch(() => {
|
|
4171
4390
|
throw new TypeError("Cannot save backup because the directory does not exist");
|
|
4172
4391
|
});
|
|
4173
4392
|
const isNewFile = await fsAccess(filename).then(() => false, () => true);
|
|
@@ -4467,7 +4686,7 @@ var require_inspect = __commonJS({
|
|
|
4467
4686
|
var require_database = __commonJS({
|
|
4468
4687
|
"node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/database.js"(exports$1, module) {
|
|
4469
4688
|
var fs = __require("fs");
|
|
4470
|
-
var
|
|
4689
|
+
var path25 = __require("path");
|
|
4471
4690
|
var util = require_util();
|
|
4472
4691
|
var SqliteError = require_sqlite_error();
|
|
4473
4692
|
var DEFAULT_ADDON;
|
|
@@ -4503,7 +4722,7 @@ var require_database = __commonJS({
|
|
|
4503
4722
|
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
|
|
4504
4723
|
} else if (typeof nativeBinding === "string") {
|
|
4505
4724
|
const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
4506
|
-
addon = requireFunc(
|
|
4725
|
+
addon = requireFunc(path25.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
|
|
4507
4726
|
} else {
|
|
4508
4727
|
addon = nativeBinding;
|
|
4509
4728
|
}
|
|
@@ -4511,7 +4730,7 @@ var require_database = __commonJS({
|
|
|
4511
4730
|
addon.setErrorConstructor(SqliteError);
|
|
4512
4731
|
addon.isInitialized = true;
|
|
4513
4732
|
}
|
|
4514
|
-
if (!anonymous && !fs.existsSync(
|
|
4733
|
+
if (!anonymous && !fs.existsSync(path25.dirname(filename))) {
|
|
4515
4734
|
throw new TypeError("Cannot open database because the directory does not exist");
|
|
4516
4735
|
}
|
|
4517
4736
|
Object.defineProperties(this, {
|
|
@@ -4638,8 +4857,8 @@ GROUP BY session_id;
|
|
|
4638
4857
|
}
|
|
4639
4858
|
});
|
|
4640
4859
|
function resolveIndexDbPath(traceDir, dbPath) {
|
|
4641
|
-
if (dbPath && dbPath.trim() !== "") return
|
|
4642
|
-
return
|
|
4860
|
+
if (dbPath && dbPath.trim() !== "") return path19__default.default.resolve(dbPath);
|
|
4861
|
+
return path19__default.default.join(path19__default.default.resolve(traceDir), INDEX_DB_FILENAME);
|
|
4643
4862
|
}
|
|
4644
4863
|
function str(value) {
|
|
4645
4864
|
return typeof value === "string" && value !== "" ? value : null;
|
|
@@ -4731,7 +4950,7 @@ async function buildIndex(options = {}) {
|
|
|
4731
4950
|
warnings.push(`index.unreadable: ${file}`);
|
|
4732
4951
|
}
|
|
4733
4952
|
}
|
|
4734
|
-
await promises.mkdir(
|
|
4953
|
+
await promises.mkdir(path19__default.default.dirname(dbPath), { recursive: true });
|
|
4735
4954
|
await promises.rm(dbPath, { force: true });
|
|
4736
4955
|
const db = new import_better_sqlite3.default(dbPath);
|
|
4737
4956
|
let runCount = 0;
|
|
@@ -4969,7 +5188,7 @@ var init_src = __esm({
|
|
|
4969
5188
|
});
|
|
4970
5189
|
|
|
4971
5190
|
// package.json
|
|
4972
|
-
var version = "4.
|
|
5191
|
+
var version = "4.3.0";
|
|
4973
5192
|
|
|
4974
5193
|
// packages/cli/src/list.ts
|
|
4975
5194
|
init_advanced();
|
|
@@ -5878,7 +6097,7 @@ function findReaderByFormat(format, readers) {
|
|
|
5878
6097
|
}
|
|
5879
6098
|
async function jsonlFilesInDirectory(dirPath) {
|
|
5880
6099
|
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
5881
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
6100
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path19__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
5882
6101
|
}
|
|
5883
6102
|
async function resolveInput(input3) {
|
|
5884
6103
|
const cached = resolvedInputCache.get(input3);
|
|
@@ -9355,7 +9574,8 @@ function exportOpenInference(tree, options) {
|
|
|
9355
9574
|
];
|
|
9356
9575
|
const traceId = hexFrom(`trace:${tree.runId}`, 16);
|
|
9357
9576
|
const includeAttributes = options?.includeAttributes ?? false;
|
|
9358
|
-
const maxLen = options?.maxAttributeLength;
|
|
9577
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
9578
|
+
const pretty = options?.pretty ?? true;
|
|
9359
9579
|
const spans = [];
|
|
9360
9580
|
for (const n of flattenTree(tree)) {
|
|
9361
9581
|
const ev = n.event;
|
|
@@ -9429,7 +9649,7 @@ function exportOpenInference(tree, options) {
|
|
|
9429
9649
|
};
|
|
9430
9650
|
return {
|
|
9431
9651
|
format: "openinference",
|
|
9432
|
-
content: JSON.stringify(payload, null, 2 ),
|
|
9652
|
+
content: JSON.stringify(payload, null, pretty ? 2 : void 0),
|
|
9433
9653
|
contentType: "application/json",
|
|
9434
9654
|
fileExtension: ".openinference.json",
|
|
9435
9655
|
warnings
|
|
@@ -9463,7 +9683,8 @@ function exportOtlpJson(tree, options) {
|
|
|
9463
9683
|
];
|
|
9464
9684
|
const traceId = hexFrom2(`trace:${tree.runId}`, 16);
|
|
9465
9685
|
const includeAttributes = options?.includeAttributes ?? false;
|
|
9466
|
-
const maxLen = options?.maxAttributeLength;
|
|
9686
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
9687
|
+
const pretty = options?.pretty ?? true;
|
|
9467
9688
|
const flat = flattenTree(tree);
|
|
9468
9689
|
const spans = [];
|
|
9469
9690
|
for (const n of flat) {
|
|
@@ -9559,7 +9780,7 @@ function exportOtlpJson(tree, options) {
|
|
|
9559
9780
|
};
|
|
9560
9781
|
return {
|
|
9561
9782
|
format: "otlp-json",
|
|
9562
|
-
content: JSON.stringify(payload, null, 2 ),
|
|
9783
|
+
content: JSON.stringify(payload, null, pretty ? 2 : void 0),
|
|
9563
9784
|
contentType: "application/json",
|
|
9564
9785
|
fileExtension: ".otlp.json",
|
|
9565
9786
|
warnings
|
|
@@ -9782,9 +10003,9 @@ function mergeExportDefaults(options) {
|
|
|
9782
10003
|
includeMetadata: options.includeMetadata ?? true,
|
|
9783
10004
|
includeAttributes: options.includeAttributes ?? false,
|
|
9784
10005
|
includeErrors: options.includeErrors ?? true,
|
|
9785
|
-
pretty: options.pretty,
|
|
9786
|
-
redacted: options.redacted,
|
|
9787
|
-
maxAttributeLength: options.maxAttributeLength,
|
|
10006
|
+
pretty: options.pretty ?? true,
|
|
10007
|
+
redacted: options.redacted ?? true,
|
|
10008
|
+
maxAttributeLength: options.maxAttributeLength ?? 500,
|
|
9788
10009
|
redactionProfile: options.redactionProfile ?? "local"
|
|
9789
10010
|
};
|
|
9790
10011
|
}
|
|
@@ -10020,9 +10241,9 @@ Trace directory: ${traceDir}`);
|
|
|
10020
10241
|
if (validation !== void 0 && !validation.ok) {
|
|
10021
10242
|
process.exitCode = 1;
|
|
10022
10243
|
}
|
|
10023
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
10244
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path19__default.default.resolve(options.output.trim()) : void 0;
|
|
10024
10245
|
if (outPath !== void 0) {
|
|
10025
|
-
await promises.mkdir(
|
|
10246
|
+
await promises.mkdir(path19__default.default.dirname(outPath), { recursive: true });
|
|
10026
10247
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
10027
10248
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
10028
10249
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -10202,13 +10423,13 @@ function pairSteps(left, right) {
|
|
|
10202
10423
|
return pairs;
|
|
10203
10424
|
}
|
|
10204
10425
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
10205
|
-
const
|
|
10426
|
+
const path25 = buildPath(segments);
|
|
10206
10427
|
if (L.name !== R.name) {
|
|
10207
10428
|
out.push({
|
|
10208
10429
|
kind: "structure",
|
|
10209
10430
|
severity: "warning",
|
|
10210
10431
|
message: "Step name differs",
|
|
10211
|
-
path:
|
|
10432
|
+
path: path25,
|
|
10212
10433
|
left: L.name,
|
|
10213
10434
|
right: R.name
|
|
10214
10435
|
});
|
|
@@ -10218,7 +10439,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
10218
10439
|
kind: "step-type",
|
|
10219
10440
|
severity: "warning",
|
|
10220
10441
|
message: "Step type differs",
|
|
10221
|
-
path:
|
|
10442
|
+
path: path25,
|
|
10222
10443
|
left: L.type,
|
|
10223
10444
|
right: R.type
|
|
10224
10445
|
});
|
|
@@ -10228,7 +10449,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
10228
10449
|
kind: "step-status",
|
|
10229
10450
|
severity: "warning",
|
|
10230
10451
|
message: "Step status differs",
|
|
10231
|
-
path:
|
|
10452
|
+
path: path25,
|
|
10232
10453
|
left: L.status,
|
|
10233
10454
|
right: R.status
|
|
10234
10455
|
});
|
|
@@ -10240,7 +10461,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
10240
10461
|
kind: "error",
|
|
10241
10462
|
severity: "error",
|
|
10242
10463
|
message: "Step error message differs",
|
|
10243
|
-
path:
|
|
10464
|
+
path: path25,
|
|
10244
10465
|
left: le || void 0,
|
|
10245
10466
|
right: re || void 0
|
|
10246
10467
|
});
|
|
@@ -10258,7 +10479,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
10258
10479
|
kind: "duration",
|
|
10259
10480
|
severity: "info",
|
|
10260
10481
|
message: "Step duration differs",
|
|
10261
|
-
path:
|
|
10482
|
+
path: path25,
|
|
10262
10483
|
left: ld,
|
|
10263
10484
|
right: rd
|
|
10264
10485
|
});
|
|
@@ -10271,7 +10492,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
10271
10492
|
kind: "metadata",
|
|
10272
10493
|
severity: "info",
|
|
10273
10494
|
message: "Step metadata differs",
|
|
10274
|
-
path:
|
|
10495
|
+
path: path25,
|
|
10275
10496
|
left: L.metadata,
|
|
10276
10497
|
right: R.metadata
|
|
10277
10498
|
});
|
|
@@ -10283,7 +10504,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
10283
10504
|
kind: "output",
|
|
10284
10505
|
severity: "info",
|
|
10285
10506
|
message: "Output preview differs",
|
|
10286
|
-
path:
|
|
10507
|
+
path: path25,
|
|
10287
10508
|
left: L.outputPreview,
|
|
10288
10509
|
right: R.outputPreview
|
|
10289
10510
|
});
|
|
@@ -10444,11 +10665,11 @@ function diffRuns(left, right, options) {
|
|
|
10444
10665
|
|
|
10445
10666
|
// packages/core/src/diff/renderer.ts
|
|
10446
10667
|
init_source();
|
|
10447
|
-
function formatPath(
|
|
10448
|
-
if (
|
|
10668
|
+
function formatPath(path25) {
|
|
10669
|
+
if (path25 === void 0 || path25.path.length === 0) {
|
|
10449
10670
|
return "(run)";
|
|
10450
10671
|
}
|
|
10451
|
-
return
|
|
10672
|
+
return path25.path.map((s) => s.name).join(" > ");
|
|
10452
10673
|
}
|
|
10453
10674
|
function formatValue(v, verbose) {
|
|
10454
10675
|
if (v === void 0) return "(undefined)";
|
|
@@ -10835,7 +11056,7 @@ function indexedToMetadata(row, traceDir) {
|
|
|
10835
11056
|
endedAt: row.endedAt ?? void 0,
|
|
10836
11057
|
durationMs: row.durationMs ?? void 0,
|
|
10837
11058
|
eventCount: 0,
|
|
10838
|
-
filePath:
|
|
11059
|
+
filePath: path19__default.default.join(traceDir, row.file),
|
|
10839
11060
|
fileSize: 0,
|
|
10840
11061
|
createdAt: new Date(row.mtimeMs)
|
|
10841
11062
|
};
|
|
@@ -10899,7 +11120,7 @@ async function loadSessionIndex(traceDir, options = {}) {
|
|
|
10899
11120
|
staleThresholdMs
|
|
10900
11121
|
});
|
|
10901
11122
|
}
|
|
10902
|
-
function
|
|
11123
|
+
function findSession2(index, sessionId) {
|
|
10903
11124
|
return index.sessions.find((session) => session.sessionId === sessionId);
|
|
10904
11125
|
}
|
|
10905
11126
|
function latestSession(index) {
|
|
@@ -10908,12 +11129,12 @@ function latestSession(index) {
|
|
|
10908
11129
|
(a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity)
|
|
10909
11130
|
)[0];
|
|
10910
11131
|
}
|
|
10911
|
-
function
|
|
11132
|
+
function parseSinceCutoff2(since) {
|
|
10912
11133
|
if (!since || since.trim() === "") return void 0;
|
|
10913
11134
|
return Date.now() - parseDuration(since.trim());
|
|
10914
11135
|
}
|
|
10915
11136
|
function sessionsInSinceWindow(index, since) {
|
|
10916
|
-
const cutoff =
|
|
11137
|
+
const cutoff = parseSinceCutoff2(since);
|
|
10917
11138
|
if (cutoff === void 0) return index.sessions;
|
|
10918
11139
|
return index.sessions.filter(
|
|
10919
11140
|
(session) => Date.parse(session.lastActivity) >= cutoff
|
|
@@ -11168,7 +11389,7 @@ async function sessionCommand(sessionId, options = {}) {
|
|
|
11168
11389
|
try {
|
|
11169
11390
|
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
11170
11391
|
const index = await loadSessionIndex(traceDir);
|
|
11171
|
-
const session =
|
|
11392
|
+
const session = findSession2(index, id);
|
|
11172
11393
|
if (!session) {
|
|
11173
11394
|
console.log(`Session not found: ${id}`);
|
|
11174
11395
|
console.log(`Trace directory: ${traceDir}`);
|
|
@@ -11315,9 +11536,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
11315
11536
|
redactionProfile,
|
|
11316
11537
|
correlation: !options.noCorrelation
|
|
11317
11538
|
});
|
|
11318
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
11539
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path19__default.default.resolve(options.output.trim()) : void 0;
|
|
11319
11540
|
if (outPath !== void 0) {
|
|
11320
|
-
await promises.mkdir(
|
|
11541
|
+
await promises.mkdir(path19__default.default.dirname(outPath), { recursive: true });
|
|
11321
11542
|
await promises.writeFile(outPath, result.content, "utf-8");
|
|
11322
11543
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
11323
11544
|
}
|
|
@@ -11567,17 +11788,17 @@ function applyRule(rule, value, replacement) {
|
|
|
11567
11788
|
}
|
|
11568
11789
|
return value;
|
|
11569
11790
|
}
|
|
11570
|
-
function childPath(
|
|
11791
|
+
function childPath(path25, key) {
|
|
11571
11792
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
11572
|
-
return
|
|
11793
|
+
return path25 ? `${path25}.${key}` : key;
|
|
11573
11794
|
}
|
|
11574
|
-
return `${
|
|
11795
|
+
return `${path25 || "$"}[${JSON.stringify(key)}]`;
|
|
11575
11796
|
}
|
|
11576
|
-
function indexPath(
|
|
11577
|
-
return `${
|
|
11797
|
+
function indexPath(path25, index) {
|
|
11798
|
+
return `${path25 || "$"}[${index}]`;
|
|
11578
11799
|
}
|
|
11579
|
-
function makeFinding(
|
|
11580
|
-
return preview === void 0 ? { path:
|
|
11800
|
+
function makeFinding(path25, detector, action, matchKind, severity = "warning", preview) {
|
|
11801
|
+
return preview === void 0 ? { path: path25, detector, action, severity, matchKind } : { path: path25, detector, action, severity, matchKind, preview };
|
|
11581
11802
|
}
|
|
11582
11803
|
function createRedactionProfile(profile = "local") {
|
|
11583
11804
|
switch (profile) {
|
|
@@ -11646,11 +11867,11 @@ var Redactor2 = class {
|
|
|
11646
11867
|
#recordFinding(state, finding) {
|
|
11647
11868
|
if (this.#collectFindings) state.findings.push(finding);
|
|
11648
11869
|
}
|
|
11649
|
-
#redactValue(value, key,
|
|
11870
|
+
#redactValue(value, key, path25, depth, state) {
|
|
11650
11871
|
if (depth > this.#maxDepth) {
|
|
11651
11872
|
this.#recordFinding(
|
|
11652
11873
|
state,
|
|
11653
|
-
makeFinding(
|
|
11874
|
+
makeFinding(path25, "structure.maxDepth", "truncate", "value", "warning")
|
|
11654
11875
|
);
|
|
11655
11876
|
return "[Truncated]";
|
|
11656
11877
|
}
|
|
@@ -11659,19 +11880,19 @@ var Redactor2 = class {
|
|
|
11659
11880
|
if (rule) {
|
|
11660
11881
|
this.#recordFinding(
|
|
11661
11882
|
state,
|
|
11662
|
-
makeFinding(
|
|
11883
|
+
makeFinding(path25, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
11663
11884
|
);
|
|
11664
11885
|
return applyRule(rule, value, this.#replacement);
|
|
11665
11886
|
}
|
|
11666
11887
|
}
|
|
11667
11888
|
for (const detector of this.#detectors) {
|
|
11668
|
-
const detections = detector.detect({ path:
|
|
11889
|
+
const detections = detector.detect({ path: path25, key, value });
|
|
11669
11890
|
for (const detection of detections) {
|
|
11670
11891
|
const action = detection.action ?? "replace";
|
|
11671
11892
|
this.#recordFinding(
|
|
11672
11893
|
state,
|
|
11673
11894
|
makeFinding(
|
|
11674
|
-
|
|
11895
|
+
path25,
|
|
11675
11896
|
detector.id,
|
|
11676
11897
|
action,
|
|
11677
11898
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -11689,7 +11910,7 @@ var Redactor2 = class {
|
|
|
11689
11910
|
const out = [];
|
|
11690
11911
|
state.seen.set(value, out);
|
|
11691
11912
|
value.forEach((item, index) => {
|
|
11692
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
11913
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path25, index), depth + 1, state);
|
|
11693
11914
|
});
|
|
11694
11915
|
return out;
|
|
11695
11916
|
}
|
|
@@ -11701,7 +11922,7 @@ var Redactor2 = class {
|
|
|
11701
11922
|
out[entryKey] = this.#redactValue(
|
|
11702
11923
|
entryValue,
|
|
11703
11924
|
entryKey,
|
|
11704
|
-
childPath(
|
|
11925
|
+
childPath(path25 === "$" ? "" : path25, entryKey),
|
|
11705
11926
|
depth + 1,
|
|
11706
11927
|
state
|
|
11707
11928
|
);
|
|
@@ -11830,6 +12051,9 @@ function redactDocument(content, profile) {
|
|
|
11830
12051
|
return redactJsonlText(content, profile);
|
|
11831
12052
|
}
|
|
11832
12053
|
}
|
|
12054
|
+
function redactTraceContent(content, profile) {
|
|
12055
|
+
return redactDocument(content, profile);
|
|
12056
|
+
}
|
|
11833
12057
|
async function redactCommand(target, options = {}, stdin = process.stdin) {
|
|
11834
12058
|
const profile = parseRedactionProfile3(options.profile);
|
|
11835
12059
|
const source = await contentFromTarget(target, options, stdin);
|
|
@@ -12158,14 +12382,14 @@ function uniqueSorted(values) {
|
|
|
12158
12382
|
return [...new Set(values)].sort();
|
|
12159
12383
|
}
|
|
12160
12384
|
function isWithinDirectory(child, parent) {
|
|
12161
|
-
const relative =
|
|
12162
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
12385
|
+
const relative = path19__default.default.relative(parent, child);
|
|
12386
|
+
return relative === "" || !relative.startsWith("..") && !path19__default.default.isAbsolute(relative);
|
|
12163
12387
|
}
|
|
12164
12388
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
12165
12389
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
12166
|
-
const inputAbs =
|
|
12167
|
-
const outputAbs =
|
|
12168
|
-
const inputDir =
|
|
12390
|
+
const inputAbs = path19__default.default.resolve(inputPath);
|
|
12391
|
+
const outputAbs = path19__default.default.resolve(output2.trim());
|
|
12392
|
+
const inputDir = path19__default.default.dirname(inputAbs);
|
|
12169
12393
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
12170
12394
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
12171
12395
|
}
|
|
@@ -12286,7 +12510,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
12286
12510
|
process.exitCode = 1;
|
|
12287
12511
|
return;
|
|
12288
12512
|
}
|
|
12289
|
-
const inputPath =
|
|
12513
|
+
const inputPath = path19__default.default.resolve(input3.trim());
|
|
12290
12514
|
const dryRun = options.dryRun === true;
|
|
12291
12515
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
12292
12516
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -12305,7 +12529,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
12305
12529
|
);
|
|
12306
12530
|
const result = await buildMigration(inputPath, outputPath);
|
|
12307
12531
|
if (!dryRun && outputPath !== void 0) {
|
|
12308
|
-
await promises.mkdir(
|
|
12532
|
+
await promises.mkdir(path19__default.default.dirname(outputPath), { recursive: true });
|
|
12309
12533
|
await promises.writeFile(outputPath, result.content, "utf-8");
|
|
12310
12534
|
}
|
|
12311
12535
|
printSummary2(result, dryRun);
|
|
@@ -12584,7 +12808,7 @@ function stripPrefix(name, prefixes) {
|
|
|
12584
12808
|
}
|
|
12585
12809
|
return name;
|
|
12586
12810
|
}
|
|
12587
|
-
function eventEvidence(event,
|
|
12811
|
+
function eventEvidence(event, path25) {
|
|
12588
12812
|
return {
|
|
12589
12813
|
runId: event.runId,
|
|
12590
12814
|
eventId: event.eventId,
|
|
@@ -12594,7 +12818,7 @@ function eventEvidence(event, path23) {
|
|
|
12594
12818
|
kind: event.kind,
|
|
12595
12819
|
name: event.name,
|
|
12596
12820
|
status: event.status,
|
|
12597
|
-
...
|
|
12821
|
+
...path25 ? { path: path25 } : {}
|
|
12598
12822
|
};
|
|
12599
12823
|
}
|
|
12600
12824
|
function runEvidence(run) {
|
|
@@ -12657,9 +12881,9 @@ function eventEndMs(event) {
|
|
|
12657
12881
|
function normalizedKey(value) {
|
|
12658
12882
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
12659
12883
|
}
|
|
12660
|
-
function lastPathSegment(
|
|
12661
|
-
const parts =
|
|
12662
|
-
return parts[parts.length - 1] ??
|
|
12884
|
+
function lastPathSegment(path25) {
|
|
12885
|
+
const parts = path25.split(".");
|
|
12886
|
+
return parts[parts.length - 1] ?? path25;
|
|
12663
12887
|
}
|
|
12664
12888
|
function valueType(value) {
|
|
12665
12889
|
if (Array.isArray(value)) return "array";
|
|
@@ -12673,12 +12897,12 @@ function serializedByteLength(value) {
|
|
|
12673
12897
|
return void 0;
|
|
12674
12898
|
}
|
|
12675
12899
|
}
|
|
12676
|
-
function pushValueEntries(entries, event, value,
|
|
12677
|
-
entries.push({ event, path:
|
|
12900
|
+
function pushValueEntries(entries, event, value, path25, key, depth = 0) {
|
|
12901
|
+
entries.push({ event, path: path25, key, value });
|
|
12678
12902
|
if (depth >= 8) return;
|
|
12679
12903
|
if (Array.isArray(value)) {
|
|
12680
12904
|
for (const [index, item] of value.entries()) {
|
|
12681
|
-
pushValueEntries(entries, event, item, `${
|
|
12905
|
+
pushValueEntries(entries, event, item, `${path25}.${index}`, String(index), depth + 1);
|
|
12682
12906
|
}
|
|
12683
12907
|
return;
|
|
12684
12908
|
}
|
|
@@ -12688,7 +12912,7 @@ function pushValueEntries(entries, event, value, path23, key, depth = 0) {
|
|
|
12688
12912
|
entries,
|
|
12689
12913
|
event,
|
|
12690
12914
|
value[nestedKey],
|
|
12691
|
-
`${
|
|
12915
|
+
`${path25}.${nestedKey}`,
|
|
12692
12916
|
nestedKey,
|
|
12693
12917
|
depth + 1
|
|
12694
12918
|
);
|
|
@@ -12769,9 +12993,9 @@ function eventDurationMs(event) {
|
|
|
12769
12993
|
}
|
|
12770
12994
|
function treeShape(nodes) {
|
|
12771
12995
|
const lines = [];
|
|
12772
|
-
const visit = (node,
|
|
12773
|
-
lines.push(`${
|
|
12774
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
12996
|
+
const visit = (node, path25) => {
|
|
12997
|
+
lines.push(`${path25}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
12998
|
+
node.children.forEach((child, index) => visit(child, `${path25}.${index}`));
|
|
12775
12999
|
};
|
|
12776
13000
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
12777
13001
|
return lines;
|
|
@@ -12820,9 +13044,9 @@ function retrievalShape(context) {
|
|
|
12820
13044
|
function guardrailShape(context) {
|
|
12821
13045
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
12822
13046
|
}
|
|
12823
|
-
function firstEvidenceForKind(context, kind,
|
|
13047
|
+
function firstEvidenceForKind(context, kind, path25) {
|
|
12824
13048
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
12825
|
-
return event ? [eventEvidence(event,
|
|
13049
|
+
return event ? [eventEvidence(event, path25)] : runEvidence(context.selectedRun);
|
|
12826
13050
|
}
|
|
12827
13051
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
12828
13052
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -13172,13 +13396,13 @@ function createStructureCycleRule() {
|
|
|
13172
13396
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
13173
13397
|
const findings = [];
|
|
13174
13398
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
13175
|
-
const
|
|
13399
|
+
const path25 = [];
|
|
13176
13400
|
const seenAt = /* @__PURE__ */ new Map();
|
|
13177
13401
|
let current = event;
|
|
13178
13402
|
while (current) {
|
|
13179
13403
|
const existing = seenAt.get(current.eventId);
|
|
13180
13404
|
if (existing !== void 0) {
|
|
13181
|
-
const cycle =
|
|
13405
|
+
const cycle = path25.slice(existing);
|
|
13182
13406
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
13183
13407
|
if (!seenCycles.has(key)) {
|
|
13184
13408
|
seenCycles.add(key);
|
|
@@ -13194,8 +13418,8 @@ function createStructureCycleRule() {
|
|
|
13194
13418
|
}
|
|
13195
13419
|
break;
|
|
13196
13420
|
}
|
|
13197
|
-
seenAt.set(current.eventId,
|
|
13198
|
-
|
|
13421
|
+
seenAt.set(current.eventId, path25.length);
|
|
13422
|
+
path25.push(current);
|
|
13199
13423
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
13200
13424
|
}
|
|
13201
13425
|
}
|
|
@@ -13992,23 +14216,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
13992
14216
|
}
|
|
13993
14217
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
13994
14218
|
}
|
|
13995
|
-
function validateSchemaField(value, field,
|
|
14219
|
+
function validateSchemaField(value, field, path25, evidence) {
|
|
13996
14220
|
const ruleId = "guardrail.structured-output";
|
|
13997
14221
|
if (field.type) {
|
|
13998
14222
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
13999
14223
|
if (actual !== field.type) {
|
|
14000
|
-
evidence.push({ ruleId, path:
|
|
14224
|
+
evidence.push({ ruleId, path: path25, preview: `expected ${field.type}, got ${actual}` });
|
|
14001
14225
|
return;
|
|
14002
14226
|
}
|
|
14003
14227
|
}
|
|
14004
14228
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
14005
|
-
evidence.push({ ruleId, path:
|
|
14229
|
+
evidence.push({ ruleId, path: path25, preview: "value not in enum" });
|
|
14006
14230
|
}
|
|
14007
14231
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
14008
14232
|
const record = value;
|
|
14009
14233
|
for (const key of field.required) {
|
|
14010
14234
|
if (!(key in record)) {
|
|
14011
|
-
evidence.push({ ruleId, path: `${
|
|
14235
|
+
evidence.push({ ruleId, path: `${path25}.${key}`, preview: "missing required key" });
|
|
14012
14236
|
}
|
|
14013
14237
|
}
|
|
14014
14238
|
}
|
|
@@ -14335,7 +14559,7 @@ function asConfig(value) {
|
|
|
14335
14559
|
}
|
|
14336
14560
|
async function loadConfig(configPath) {
|
|
14337
14561
|
if (configPath === void 0) return {};
|
|
14338
|
-
const extension =
|
|
14562
|
+
const extension = path19__default.default.extname(configPath);
|
|
14339
14563
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
14340
14564
|
throw new Error(
|
|
14341
14565
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -14344,7 +14568,7 @@ async function loadConfig(configPath) {
|
|
|
14344
14568
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
14345
14569
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
14346
14570
|
}
|
|
14347
|
-
const absolute =
|
|
14571
|
+
const absolute = path19__default.default.resolve(configPath);
|
|
14348
14572
|
if (extension === ".json") {
|
|
14349
14573
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
14350
14574
|
return asConfig(JSON.parse(raw));
|
|
@@ -14493,10 +14717,10 @@ function printHuman(result) {
|
|
|
14493
14717
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
14494
14718
|
}
|
|
14495
14719
|
for (const finding of result.findings) {
|
|
14496
|
-
const
|
|
14720
|
+
const path25 = finding.evidence[0]?.path;
|
|
14497
14721
|
const run = finding.evidence[0]?.runId;
|
|
14498
14722
|
const runPrefix = run ? `[${run}] ` : "";
|
|
14499
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
14723
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
|
|
14500
14724
|
}
|
|
14501
14725
|
}
|
|
14502
14726
|
function readErrorResult(error) {
|
|
@@ -14699,7 +14923,7 @@ function createViewerServer(options = {}) {
|
|
|
14699
14923
|
return sendJson(res, 200, {
|
|
14700
14924
|
ok: true,
|
|
14701
14925
|
readOnly: true,
|
|
14702
|
-
traceDir:
|
|
14926
|
+
traceDir: path19__default.default.resolve(traceDir)
|
|
14703
14927
|
});
|
|
14704
14928
|
}
|
|
14705
14929
|
const td = new TraceDirectory({ dir: traceDir });
|
|
@@ -14717,7 +14941,7 @@ function createViewerServer(options = {}) {
|
|
|
14717
14941
|
runId: meta2.runId,
|
|
14718
14942
|
name: meta2.name,
|
|
14719
14943
|
status: meta2.status,
|
|
14720
|
-
file:
|
|
14944
|
+
file: path19__default.default.basename(meta2.filePath),
|
|
14721
14945
|
startedAt: meta2.startedAt,
|
|
14722
14946
|
durationMs: meta2.durationMs
|
|
14723
14947
|
}))
|
|
@@ -14832,7 +15056,7 @@ function startViewerServer(options = {}) {
|
|
|
14832
15056
|
resolve({
|
|
14833
15057
|
host,
|
|
14834
15058
|
port: resolvedPort,
|
|
14835
|
-
traceDir:
|
|
15059
|
+
traceDir: path19__default.default.resolve(traceDir),
|
|
14836
15060
|
url: `http://${host}:${resolvedPort}`
|
|
14837
15061
|
});
|
|
14838
15062
|
});
|
|
@@ -15037,10 +15261,10 @@ async function evalRun(input3, options = {}) {
|
|
|
15037
15261
|
diagnostics: []
|
|
15038
15262
|
};
|
|
15039
15263
|
}
|
|
15040
|
-
function evidenceForRun(run,
|
|
15041
|
-
return [{ runId: run.runId, ...
|
|
15264
|
+
function evidenceForRun(run, path25) {
|
|
15265
|
+
return [{ runId: run.runId, ...path25 !== void 0 ? { path: path25 } : {} }];
|
|
15042
15266
|
}
|
|
15043
|
-
function evidenceForEvent(event,
|
|
15267
|
+
function evidenceForEvent(event, path25) {
|
|
15044
15268
|
return [
|
|
15045
15269
|
{
|
|
15046
15270
|
runId: event.runId,
|
|
@@ -15048,7 +15272,7 @@ function evidenceForEvent(event, path23) {
|
|
|
15048
15272
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
15049
15273
|
kind: event.kind,
|
|
15050
15274
|
name: event.name,
|
|
15051
|
-
...
|
|
15275
|
+
...path25 !== void 0 ? { path: path25 } : {}
|
|
15052
15276
|
}
|
|
15053
15277
|
];
|
|
15054
15278
|
}
|
|
@@ -15206,9 +15430,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
15206
15430
|
function tokenize(text) {
|
|
15207
15431
|
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));
|
|
15208
15432
|
}
|
|
15209
|
-
function firstEvidence(fields, run,
|
|
15433
|
+
function firstEvidence(fields, run, path25) {
|
|
15210
15434
|
const first = fields[0];
|
|
15211
|
-
return first === void 0 ? evidenceForRun(run,
|
|
15435
|
+
return first === void 0 ? evidenceForRun(run, path25) : evidenceForEvent(first.node.event, first.path);
|
|
15212
15436
|
}
|
|
15213
15437
|
function collectSourceIds(nodes, keys) {
|
|
15214
15438
|
const wanted = keySet(keys);
|
|
@@ -15585,8 +15809,8 @@ function renderEvalMarkdown(result) {
|
|
|
15585
15809
|
if (result.findings.length > 0) {
|
|
15586
15810
|
lines.push("", "## Findings");
|
|
15587
15811
|
for (const finding of result.findings) {
|
|
15588
|
-
const
|
|
15589
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
15812
|
+
const path25 = finding.evidence[0]?.path;
|
|
15813
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
|
|
15590
15814
|
}
|
|
15591
15815
|
}
|
|
15592
15816
|
return `${lines.join("\n")}
|
|
@@ -15633,7 +15857,7 @@ function asConfig2(value) {
|
|
|
15633
15857
|
}
|
|
15634
15858
|
async function loadConfig2(configPath) {
|
|
15635
15859
|
if (configPath === void 0) return {};
|
|
15636
|
-
const extension =
|
|
15860
|
+
const extension = path19__default.default.extname(configPath);
|
|
15637
15861
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
15638
15862
|
throw new Error(
|
|
15639
15863
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -15642,7 +15866,7 @@ async function loadConfig2(configPath) {
|
|
|
15642
15866
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
15643
15867
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
15644
15868
|
}
|
|
15645
|
-
const absolute =
|
|
15869
|
+
const absolute = path19__default.default.resolve(configPath);
|
|
15646
15870
|
if (extension === ".json") {
|
|
15647
15871
|
const raw = await promises.readFile(absolute, "utf-8");
|
|
15648
15872
|
return asConfig2(JSON.parse(raw));
|
|
@@ -15779,8 +16003,8 @@ function printHuman2(result) {
|
|
|
15779
16003
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
15780
16004
|
}
|
|
15781
16005
|
for (const finding of result.findings) {
|
|
15782
|
-
const
|
|
15783
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
16006
|
+
const path25 = finding.evidence[0]?.path;
|
|
16007
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
|
|
15784
16008
|
}
|
|
15785
16009
|
}
|
|
15786
16010
|
function readErrorResult2(error) {
|
|
@@ -16018,8 +16242,8 @@ function printHuman3(result) {
|
|
|
16018
16242
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
16019
16243
|
}
|
|
16020
16244
|
for (const finding of result.findings) {
|
|
16021
|
-
const
|
|
16022
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
16245
|
+
const path25 = finding.evidence[0]?.path;
|
|
16246
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
|
|
16023
16247
|
}
|
|
16024
16248
|
console.log(`Note: ${result.note}`);
|
|
16025
16249
|
}
|
|
@@ -16065,6 +16289,38 @@ function scanCommand(target, options = {}, stdin = process.stdin) {
|
|
|
16065
16289
|
function verifySafeCommand(target, options = {}, stdin = process.stdin) {
|
|
16066
16290
|
return safetyCommand("verify-safe", target, options, stdin);
|
|
16067
16291
|
}
|
|
16292
|
+
function assessOpenedTrace(read, options = {}) {
|
|
16293
|
+
try {
|
|
16294
|
+
const rules = buildSafetyRules(options);
|
|
16295
|
+
const checkResult = runTraceChecks(
|
|
16296
|
+
{ read },
|
|
16297
|
+
{
|
|
16298
|
+
rules,
|
|
16299
|
+
...options.runId !== void 0 ? { runId: options.runId } : {},
|
|
16300
|
+
...options.run !== void 0 ? { runId: options.run } : {}
|
|
16301
|
+
}
|
|
16302
|
+
);
|
|
16303
|
+
const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId) : [];
|
|
16304
|
+
return resultFromParts({
|
|
16305
|
+
command: "verify-safe",
|
|
16306
|
+
format: checkResult.format,
|
|
16307
|
+
runId: checkResult.runId,
|
|
16308
|
+
findings: [...checkResult.findings, ...detectorFindings],
|
|
16309
|
+
diagnostics: [
|
|
16310
|
+
...checkResult.diagnostics.map(diagnosticFromCheck),
|
|
16311
|
+
...warningDiagnostics(read.warnings, read.unsupportedFields)
|
|
16312
|
+
],
|
|
16313
|
+
warnings: read.warnings,
|
|
16314
|
+
unsupportedFields: read.unsupportedFields
|
|
16315
|
+
});
|
|
16316
|
+
} catch (error) {
|
|
16317
|
+
return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult3("verify-safe", error);
|
|
16318
|
+
}
|
|
16319
|
+
}
|
|
16320
|
+
function messageStartsWithDash(error) {
|
|
16321
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16322
|
+
return message.startsWith("--");
|
|
16323
|
+
}
|
|
16068
16324
|
var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
|
|
16069
16325
|
var SAFETY_RULES = [
|
|
16070
16326
|
createSafetyRawContentRule(),
|
|
@@ -16092,7 +16348,7 @@ function writeJson3(value) {
|
|
|
16092
16348
|
function escapeHtml2(value) {
|
|
16093
16349
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
16094
16350
|
}
|
|
16095
|
-
function
|
|
16351
|
+
function markdownTable2(rows) {
|
|
16096
16352
|
const lines = ["| Field | Value |", "| --- | --- |"];
|
|
16097
16353
|
for (const [key, value] of rows) {
|
|
16098
16354
|
lines.push(`| ${key} | ${value ?? "unknown"} |`);
|
|
@@ -16138,8 +16394,8 @@ function renderCheckSection(result) {
|
|
|
16138
16394
|
`Diagnostics: ${result.diagnostics.length}`
|
|
16139
16395
|
];
|
|
16140
16396
|
for (const finding of result.findings.slice(0, 10)) {
|
|
16141
|
-
const
|
|
16142
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
16397
|
+
const path25 = finding.evidence[0]?.path ?? "(run)";
|
|
16398
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path25})`);
|
|
16143
16399
|
}
|
|
16144
16400
|
for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
|
|
16145
16401
|
lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
@@ -16154,7 +16410,7 @@ function renderMarkdown(trace, check, diff) {
|
|
|
16154
16410
|
"",
|
|
16155
16411
|
"## Trace",
|
|
16156
16412
|
"",
|
|
16157
|
-
|
|
16413
|
+
markdownTable2([
|
|
16158
16414
|
["Format", trace.format],
|
|
16159
16415
|
["Run", trace.runId],
|
|
16160
16416
|
["Run status", trace.runStatus],
|
|
@@ -16217,8 +16473,8 @@ function renderHtml(trace, check, diff) {
|
|
|
16217
16473
|
`;
|
|
16218
16474
|
}
|
|
16219
16475
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
16220
|
-
const outPath =
|
|
16221
|
-
await promises.mkdir(
|
|
16476
|
+
const outPath = path19__default.default.join(outputDir, relativePath);
|
|
16477
|
+
await promises.mkdir(path19__default.default.dirname(outPath), { recursive: true });
|
|
16222
16478
|
await promises.writeFile(outPath, content, "utf-8");
|
|
16223
16479
|
files.push(relativePath);
|
|
16224
16480
|
}
|
|
@@ -16234,7 +16490,7 @@ function manifestStatus(check, diff) {
|
|
|
16234
16490
|
return "ok";
|
|
16235
16491
|
}
|
|
16236
16492
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
16237
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
16493
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path19__default.default.resolve(options.outputDir.trim()) : "";
|
|
16238
16494
|
if (outputDir === "") {
|
|
16239
16495
|
console.error("--output-dir is required.");
|
|
16240
16496
|
process.exitCode = 1;
|
|
@@ -16300,8 +16556,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
16300
16556
|
await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
|
|
16301
16557
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
16302
16558
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
16303
|
-
await promises.mkdir(
|
|
16304
|
-
await promises.appendFile(
|
|
16559
|
+
await promises.mkdir(path19__default.default.dirname(path19__default.default.resolve(summaryTarget)), { recursive: true });
|
|
16560
|
+
await promises.appendFile(path19__default.default.resolve(summaryTarget), `
|
|
16305
16561
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
16306
16562
|
}
|
|
16307
16563
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -16320,10 +16576,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
16320
16576
|
findings: diff?.findings.length ?? 0,
|
|
16321
16577
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
16322
16578
|
},
|
|
16323
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
16579
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path19__default.default.resolve(summaryTarget) } : {},
|
|
16324
16580
|
note: NOTE
|
|
16325
16581
|
};
|
|
16326
|
-
await promises.writeFile(
|
|
16582
|
+
await promises.writeFile(path19__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
16327
16583
|
if (options.json === true) {
|
|
16328
16584
|
console.log(writeJson3(manifest).trimEnd());
|
|
16329
16585
|
} else {
|
|
@@ -16334,1573 +16590,1901 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
16334
16590
|
}
|
|
16335
16591
|
}
|
|
16336
16592
|
}
|
|
16337
|
-
|
|
16338
|
-
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
16370
|
-
diagnostics.push({
|
|
16371
|
-
code: "artifact_path_escape",
|
|
16372
|
-
severity: "error",
|
|
16373
|
-
message: "Reporter artifact path must stay under the output directory.",
|
|
16374
|
-
target: rawPath
|
|
16375
|
-
});
|
|
16376
|
-
return { ok: false, outputDir, diagnostics };
|
|
16377
|
-
}
|
|
16378
|
-
const absolutePath = path16__default.default.resolve(outputDir, normalized);
|
|
16379
|
-
const relFromOutput = path16__default.default.relative(outputDir, absolutePath);
|
|
16380
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path16__default.default.isAbsolute(relFromOutput)) {
|
|
16381
|
-
diagnostics.push({
|
|
16382
|
-
code: "artifact_path_escape",
|
|
16383
|
-
severity: "error",
|
|
16384
|
-
message: "Reporter artifact path resolved outside the output directory.",
|
|
16385
|
-
target: rawPath
|
|
16386
|
-
});
|
|
16387
|
-
return { ok: false, outputDir, diagnostics };
|
|
16388
|
-
}
|
|
16593
|
+
|
|
16594
|
+
// packages/cli/src/bundle.ts
|
|
16595
|
+
init_advanced();
|
|
16596
|
+
|
|
16597
|
+
// packages/core/src/workspace/types.ts
|
|
16598
|
+
var WORKSPACE_SCHEMA_VERSION = "1.0";
|
|
16599
|
+
var WORKSPACE_DIR_NAME = ".agent-inspect";
|
|
16600
|
+
var WORKSPACE_MANIFEST_FILENAME = "workspace.json";
|
|
16601
|
+
|
|
16602
|
+
// packages/core/src/workspace/manifest.ts
|
|
16603
|
+
var DEFAULT_WORKSPACE_LAYOUT = {
|
|
16604
|
+
traceDirs: ["runs"],
|
|
16605
|
+
reportsDir: "reports",
|
|
16606
|
+
artifactsDir: "artifacts",
|
|
16607
|
+
bundlesDir: "bundles",
|
|
16608
|
+
notesDir: "notes"
|
|
16609
|
+
};
|
|
16610
|
+
var DEFAULT_REDACTION_PROFILE = "share";
|
|
16611
|
+
var REDACTION_PROFILES = [
|
|
16612
|
+
"local",
|
|
16613
|
+
"share",
|
|
16614
|
+
"strict"
|
|
16615
|
+
];
|
|
16616
|
+
var INDEX_TYPES = ["none", "sqlite", "custom"];
|
|
16617
|
+
var MAX_WORKSPACE_MANIFEST_BYTES = 64 * 1024;
|
|
16618
|
+
function createDefaultWorkspaceManifest(options) {
|
|
16619
|
+
const project = typeof options.project === "string" ? options.project.trim() : "";
|
|
16620
|
+
const index = {
|
|
16621
|
+
enabled: options.index?.enabled ?? false,
|
|
16622
|
+
type: options.index?.type ?? "none",
|
|
16623
|
+
...options.index?.path !== void 0 ? { path: options.index.path } : {}
|
|
16624
|
+
};
|
|
16389
16625
|
return {
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16626
|
+
schemaVersion: WORKSPACE_SCHEMA_VERSION,
|
|
16627
|
+
project,
|
|
16628
|
+
createdAt: options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
16629
|
+
traceDirs: options.traceDirs ? [...options.traceDirs] : [...DEFAULT_WORKSPACE_LAYOUT.traceDirs],
|
|
16630
|
+
reportsDir: options.reportsDir ?? DEFAULT_WORKSPACE_LAYOUT.reportsDir,
|
|
16631
|
+
artifactsDir: options.artifactsDir ?? DEFAULT_WORKSPACE_LAYOUT.artifactsDir,
|
|
16632
|
+
bundlesDir: options.bundlesDir ?? DEFAULT_WORKSPACE_LAYOUT.bundlesDir,
|
|
16633
|
+
notesDir: options.notesDir ?? DEFAULT_WORKSPACE_LAYOUT.notesDir,
|
|
16634
|
+
redactionProfile: options.redactionProfile ?? DEFAULT_REDACTION_PROFILE,
|
|
16635
|
+
index
|
|
16395
16636
|
};
|
|
16396
16637
|
}
|
|
16397
|
-
|
|
16398
|
-
// packages/cli/src/ci-summary.ts
|
|
16399
|
-
var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
|
|
16400
|
-
var MAX_TEXT = 180;
|
|
16401
|
-
var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
|
|
16402
|
-
var STATUSES = /* @__PURE__ */ new Set(["passed", "failed", "skipped", "todo"]);
|
|
16403
|
-
var ARTIFACT_KINDS = /* @__PURE__ */ new Set(["trace", "report", "eval", "redaction", "summary"]);
|
|
16404
|
-
var ARTIFACT_FORMATS = /* @__PURE__ */ new Set(["json", "jsonl", "md", "html"]);
|
|
16405
|
-
var REDACTION_PROFILES = /* @__PURE__ */ new Set(["local", "share", "strict"]);
|
|
16406
|
-
function stable6(value) {
|
|
16407
|
-
if (Array.isArray(value)) return value.map(stable6);
|
|
16408
|
-
if (value === null || typeof value !== "object") return value;
|
|
16409
|
-
const record = value;
|
|
16410
|
-
return Object.fromEntries(
|
|
16411
|
-
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable6(record[key])])
|
|
16412
|
-
);
|
|
16413
|
-
}
|
|
16414
|
-
function writeJson4(value) {
|
|
16415
|
-
return `${JSON.stringify(stable6(value), null, 2)}
|
|
16416
|
-
`;
|
|
16417
|
-
}
|
|
16418
|
-
function isObject(value) {
|
|
16638
|
+
function isPlainObject(value) {
|
|
16419
16639
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16420
16640
|
}
|
|
16421
|
-
function
|
|
16422
|
-
if (typeof
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16641
|
+
function isSafeRelativeWorkspacePath(p) {
|
|
16642
|
+
if (typeof p !== "string") return false;
|
|
16643
|
+
const trimmed = p.trim();
|
|
16644
|
+
if (trimmed === "") return false;
|
|
16645
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("\\")) return false;
|
|
16646
|
+
if (/^[a-zA-Z]:/.test(trimmed)) return false;
|
|
16647
|
+
const segments = trimmed.split(/[/\\]+/);
|
|
16648
|
+
return !segments.some((seg) => seg === "..");
|
|
16426
16649
|
}
|
|
16427
|
-
function
|
|
16428
|
-
|
|
16429
|
-
}
|
|
16430
|
-
|
|
16431
|
-
const framework = readString(value, "manifest.framework");
|
|
16432
|
-
if (!FRAMEWORKS.has(framework)) {
|
|
16433
|
-
throw new Error(`Unsupported reporter framework: ${framework}.`);
|
|
16650
|
+
function validateDirField(value, field, errors) {
|
|
16651
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
16652
|
+
errors.push(`${field} must be a non-empty string`);
|
|
16653
|
+
return;
|
|
16434
16654
|
}
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
if (!STATUSES.has(status)) {
|
|
16440
|
-
throw new Error(`Unsupported reporter test status: ${status}.`);
|
|
16655
|
+
if (!isSafeRelativeWorkspacePath(value)) {
|
|
16656
|
+
errors.push(
|
|
16657
|
+
`${field} must be a relative path inside the workspace (no absolute paths or ".." traversal)`
|
|
16658
|
+
);
|
|
16441
16659
|
}
|
|
16442
|
-
return status;
|
|
16443
16660
|
}
|
|
16444
|
-
function
|
|
16445
|
-
if (!
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
const redactionProfile = readString(
|
|
16449
|
-
value.redactionProfile,
|
|
16450
|
-
`manifest.artifacts[${index}].redactionProfile`
|
|
16451
|
-
);
|
|
16452
|
-
if (!ARTIFACT_KINDS.has(kind)) throw new Error(`Unsupported artifact kind: ${kind}.`);
|
|
16453
|
-
if (!ARTIFACT_FORMATS.has(format)) throw new Error(`Unsupported artifact format: ${format}.`);
|
|
16454
|
-
if (!REDACTION_PROFILES.has(redactionProfile)) {
|
|
16455
|
-
throw new Error(`Unsupported artifact redaction profile: ${redactionProfile}.`);
|
|
16661
|
+
function validateIndex(value, errors) {
|
|
16662
|
+
if (!isPlainObject(value)) {
|
|
16663
|
+
errors.push("index must be an object");
|
|
16664
|
+
return void 0;
|
|
16456
16665
|
}
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
outputDir: process.cwd(),
|
|
16460
|
-
relativePath: artifactPath
|
|
16461
|
-
});
|
|
16462
|
-
if (!pathCheck.ok || pathCheck.relativePath === void 0) {
|
|
16463
|
-
throw new Error(`Unsafe reporter artifact path: ${artifactPath}.`);
|
|
16666
|
+
if (typeof value.enabled !== "boolean") {
|
|
16667
|
+
errors.push("index.enabled must be a boolean");
|
|
16464
16668
|
}
|
|
16669
|
+
if (!INDEX_TYPES.includes(value.type)) {
|
|
16670
|
+
errors.push(`index.type must be one of: ${INDEX_TYPES.join(", ")}`);
|
|
16671
|
+
}
|
|
16672
|
+
if (value.path !== void 0 && !isSafeRelativeWorkspacePath(value.path)) {
|
|
16673
|
+
errors.push(
|
|
16674
|
+
'index.path must be a relative path inside the workspace (no absolute paths or ".." traversal)'
|
|
16675
|
+
);
|
|
16676
|
+
}
|
|
16677
|
+
if (errors.length > 0) return void 0;
|
|
16465
16678
|
return {
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
redactionProfile
|
|
16470
|
-
};
|
|
16471
|
-
}
|
|
16472
|
-
function readArtifacts(value, label) {
|
|
16473
|
-
if (value === void 0) return [];
|
|
16474
|
-
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
16475
|
-
return value.map((item, index) => readArtifact(item, index));
|
|
16476
|
-
}
|
|
16477
|
-
function readDiagnosticsCount(value, label) {
|
|
16478
|
-
if (value === void 0) return 0;
|
|
16479
|
-
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
16480
|
-
return value.length;
|
|
16481
|
-
}
|
|
16482
|
-
function readResult(value, index) {
|
|
16483
|
-
if (!isObject(value)) throw new Error(`manifest.results[${index}] must be an object.`);
|
|
16484
|
-
const file = readOptionalString(value.file);
|
|
16485
|
-
const tracePath = readOptionalString(value.tracePath);
|
|
16486
|
-
return {
|
|
16487
|
-
testId: readString(value.testId, `manifest.results[${index}].testId`),
|
|
16488
|
-
name: readString(value.name, `manifest.results[${index}].name`),
|
|
16489
|
-
...file === void 0 ? {} : { file },
|
|
16490
|
-
status: readStatus(value.status),
|
|
16491
|
-
...tracePath === void 0 ? {} : { tracePath },
|
|
16492
|
-
artifacts: readArtifacts(value.artifacts, `manifest.results[${index}].artifacts`),
|
|
16493
|
-
diagnostics: readDiagnosticsCount(
|
|
16494
|
-
value.diagnostics,
|
|
16495
|
-
`manifest.results[${index}].diagnostics`
|
|
16496
|
-
)
|
|
16679
|
+
enabled: value.enabled,
|
|
16680
|
+
type: value.type,
|
|
16681
|
+
...value.path !== void 0 ? { path: value.path } : {}
|
|
16497
16682
|
};
|
|
16498
16683
|
}
|
|
16499
|
-
function
|
|
16500
|
-
|
|
16501
|
-
const
|
|
16502
|
-
if (!
|
|
16503
|
-
|
|
16504
|
-
if (schemaVersion !== "0.1") {
|
|
16505
|
-
throw new Error(`Unsupported reporter manifest schemaVersion: ${schemaVersion}.`);
|
|
16684
|
+
function validateWorkspaceManifest(input3) {
|
|
16685
|
+
const errors = [];
|
|
16686
|
+
const warnings = [];
|
|
16687
|
+
if (!isPlainObject(input3)) {
|
|
16688
|
+
return { ok: false, errors: ["manifest must be an object"], warnings };
|
|
16506
16689
|
}
|
|
16507
|
-
if (
|
|
16508
|
-
|
|
16690
|
+
if (input3.schemaVersion !== WORKSPACE_SCHEMA_VERSION) {
|
|
16691
|
+
errors.push(
|
|
16692
|
+
`schemaVersion must be "${WORKSPACE_SCHEMA_VERSION}" (received ${JSON.stringify(
|
|
16693
|
+
input3.schemaVersion
|
|
16694
|
+
)})`
|
|
16695
|
+
);
|
|
16696
|
+
}
|
|
16697
|
+
if (typeof input3.project !== "string" || input3.project.trim() === "") {
|
|
16698
|
+
errors.push("project must be a non-empty string");
|
|
16699
|
+
}
|
|
16700
|
+
if (typeof input3.createdAt !== "string" || input3.createdAt.trim() === "") {
|
|
16701
|
+
errors.push("createdAt must be a non-empty ISO-8601 string");
|
|
16702
|
+
} else if (Number.isNaN(Date.parse(input3.createdAt))) {
|
|
16703
|
+
errors.push("createdAt must be a valid ISO-8601 date string");
|
|
16704
|
+
}
|
|
16705
|
+
if (!Array.isArray(input3.traceDirs) || input3.traceDirs.length === 0) {
|
|
16706
|
+
errors.push("traceDirs must be a non-empty array");
|
|
16707
|
+
} else {
|
|
16708
|
+
input3.traceDirs.forEach((dir, i) => {
|
|
16709
|
+
if (typeof dir !== "string" || dir.trim() === "") {
|
|
16710
|
+
errors.push(`traceDirs[${i}] must be a non-empty string`);
|
|
16711
|
+
} else if (!isSafeRelativeWorkspacePath(dir)) {
|
|
16712
|
+
errors.push(
|
|
16713
|
+
`traceDirs[${i}] must be a relative path inside the workspace (no absolute paths or ".." traversal)`
|
|
16714
|
+
);
|
|
16715
|
+
}
|
|
16716
|
+
});
|
|
16717
|
+
}
|
|
16718
|
+
validateDirField(input3.reportsDir, "reportsDir", errors);
|
|
16719
|
+
validateDirField(input3.artifactsDir, "artifactsDir", errors);
|
|
16720
|
+
validateDirField(input3.bundlesDir, "bundlesDir", errors);
|
|
16721
|
+
validateDirField(input3.notesDir, "notesDir", errors);
|
|
16722
|
+
if (!REDACTION_PROFILES.includes(input3.redactionProfile)) {
|
|
16723
|
+
errors.push(`redactionProfile must be one of: ${REDACTION_PROFILES.join(", ")}`);
|
|
16724
|
+
}
|
|
16725
|
+
const indexErrors = [];
|
|
16726
|
+
const index = validateIndex(input3.index, indexErrors);
|
|
16727
|
+
errors.push(...indexErrors);
|
|
16728
|
+
if (index && index.type !== "none" && !index.enabled) {
|
|
16729
|
+
warnings.push(`index.type is "${index.type}" but index.enabled is false`);
|
|
16730
|
+
}
|
|
16731
|
+
if (errors.length > 0 || index === void 0) {
|
|
16732
|
+
return { ok: false, errors, warnings };
|
|
16509
16733
|
}
|
|
16510
|
-
const artifacts = readArtifacts(candidate.artifacts, "manifest.artifacts");
|
|
16511
|
-
const results = candidate.results.map((item, index) => readResult(item, index));
|
|
16512
|
-
const diagnostics = readDiagnosticsCount(candidate.diagnostics, "manifest.diagnostics");
|
|
16513
16734
|
const manifest = {
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16735
|
+
schemaVersion: WORKSPACE_SCHEMA_VERSION,
|
|
16736
|
+
project: input3.project.trim(),
|
|
16737
|
+
createdAt: input3.createdAt,
|
|
16738
|
+
traceDirs: input3.traceDirs.map((d) => d.trim()),
|
|
16739
|
+
reportsDir: input3.reportsDir.trim(),
|
|
16740
|
+
artifactsDir: input3.artifactsDir.trim(),
|
|
16741
|
+
bundlesDir: input3.bundlesDir.trim(),
|
|
16742
|
+
notesDir: input3.notesDir.trim(),
|
|
16743
|
+
redactionProfile: input3.redactionProfile,
|
|
16744
|
+
index
|
|
16523
16745
|
};
|
|
16746
|
+
return { ok: true, manifest, errors, warnings };
|
|
16524
16747
|
}
|
|
16525
|
-
function
|
|
16526
|
-
const
|
|
16527
|
-
if (
|
|
16528
|
-
return
|
|
16748
|
+
function parseWorkspaceManifest(json) {
|
|
16749
|
+
const warnings = [];
|
|
16750
|
+
if (typeof json !== "string") {
|
|
16751
|
+
return { ok: false, errors: ["manifest input must be a string"], warnings };
|
|
16529
16752
|
}
|
|
16530
|
-
|
|
16753
|
+
if (json.length > MAX_WORKSPACE_MANIFEST_BYTES) {
|
|
16754
|
+
return {
|
|
16755
|
+
ok: false,
|
|
16756
|
+
errors: [
|
|
16757
|
+
`manifest exceeds maximum size of ${MAX_WORKSPACE_MANIFEST_BYTES} bytes`
|
|
16758
|
+
],
|
|
16759
|
+
warnings
|
|
16760
|
+
};
|
|
16761
|
+
}
|
|
16762
|
+
let parsed;
|
|
16763
|
+
try {
|
|
16764
|
+
parsed = JSON.parse(json);
|
|
16765
|
+
} catch {
|
|
16766
|
+
return { ok: false, errors: ["manifest is not valid JSON"], warnings };
|
|
16767
|
+
}
|
|
16768
|
+
return validateWorkspaceManifest(parsed);
|
|
16531
16769
|
}
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
const document = readManifestDocument(JSON.parse(raw));
|
|
16536
|
-
const manifest = document.manifest;
|
|
16537
|
-
const results = manifest.results.map((result) => ({
|
|
16538
|
-
testId: safeText(result.testId),
|
|
16539
|
-
name: safeText(result.name),
|
|
16540
|
-
...result.file === void 0 ? {} : { file: safeText(path16__default.default.basename(result.file)) },
|
|
16541
|
-
status: result.status,
|
|
16542
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(path16__default.default.basename(result.tracePath)) },
|
|
16543
|
-
artifacts: result.artifacts,
|
|
16544
|
-
diagnostics: result.diagnostics
|
|
16545
|
-
}));
|
|
16546
|
-
return {
|
|
16547
|
-
...document.packageName === void 0 ? {} : { packageName: document.packageName },
|
|
16548
|
-
manifestFile: cwdRelative(absolute),
|
|
16549
|
-
framework: manifest.framework,
|
|
16550
|
-
generatedAt: manifest.generatedAt,
|
|
16551
|
-
results,
|
|
16552
|
-
artifacts: manifest.artifacts,
|
|
16553
|
-
diagnostics: document.diagnostics
|
|
16554
|
-
};
|
|
16770
|
+
function serializeWorkspaceManifest(manifest) {
|
|
16771
|
+
return `${JSON.stringify(manifest, null, 2)}
|
|
16772
|
+
`;
|
|
16555
16773
|
}
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
failed: 0,
|
|
16561
|
-
passed: 0,
|
|
16562
|
-
skipped: 0,
|
|
16563
|
-
todo: 0,
|
|
16564
|
-
artifacts: 0,
|
|
16565
|
-
diagnostics: 0
|
|
16566
|
-
};
|
|
16567
|
-
for (const manifest of manifests) {
|
|
16568
|
-
summary.artifacts += manifest.artifacts.length;
|
|
16569
|
-
summary.diagnostics += manifest.diagnostics;
|
|
16570
|
-
for (const result of manifest.results) {
|
|
16571
|
-
summary.tests += 1;
|
|
16572
|
-
if (result.status === "failed") summary.failed += 1;
|
|
16573
|
-
else if (result.status === "passed") summary.passed += 1;
|
|
16574
|
-
else if (result.status === "skipped") summary.skipped += 1;
|
|
16575
|
-
else summary.todo += 1;
|
|
16576
|
-
summary.artifacts += result.artifacts.length;
|
|
16577
|
-
summary.diagnostics += result.diagnostics;
|
|
16578
|
-
}
|
|
16579
|
-
}
|
|
16774
|
+
var INDEX_DIR_NAME = "index";
|
|
16775
|
+
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
16776
|
+
const projectRoot = path19__default.default.resolve(cwd);
|
|
16777
|
+
const workspaceDir = path19__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
16580
16778
|
return {
|
|
16581
|
-
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
note: NOTE2
|
|
16779
|
+
projectRoot,
|
|
16780
|
+
workspaceDir,
|
|
16781
|
+
manifestPath: path19__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
16585
16782
|
};
|
|
16586
16783
|
}
|
|
16587
|
-
function
|
|
16588
|
-
|
|
16784
|
+
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
16785
|
+
const base = path19__default.default.resolve(workspaceDir);
|
|
16786
|
+
const resolved = path19__default.default.resolve(base, relative);
|
|
16787
|
+
const rel = path19__default.default.relative(base, resolved);
|
|
16788
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path19__default.default.isAbsolute(rel)) {
|
|
16789
|
+
return resolved;
|
|
16790
|
+
}
|
|
16791
|
+
throw new Error(
|
|
16792
|
+
`Workspace path "${relative}" resolves outside the workspace directory`
|
|
16793
|
+
);
|
|
16589
16794
|
}
|
|
16590
|
-
function
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
"| Field | Value |",
|
|
16597
|
-
"| --- | --- |",
|
|
16598
|
-
`| Status | ${result.status} |`,
|
|
16599
|
-
`| Manifests | ${result.summary.manifests} |`,
|
|
16600
|
-
`| Tests | ${result.summary.tests} |`,
|
|
16601
|
-
`| Failed | ${result.summary.failed} |`,
|
|
16602
|
-
`| Passed | ${result.summary.passed} |`,
|
|
16603
|
-
`| Skipped | ${result.summary.skipped} |`,
|
|
16604
|
-
`| Todo | ${result.summary.todo} |`,
|
|
16605
|
-
`| Artifacts | ${result.summary.artifacts} |`,
|
|
16606
|
-
`| Diagnostics | ${result.summary.diagnostics} |`,
|
|
16607
|
-
"",
|
|
16608
|
-
"## Tests",
|
|
16609
|
-
"",
|
|
16610
|
-
"| Framework | Status | Test | File | Trace | Artifacts |",
|
|
16611
|
-
"| --- | --- | --- | --- | --- | --- |"
|
|
16612
|
-
];
|
|
16613
|
-
const rows = result.manifests.flatMap(
|
|
16614
|
-
(manifest) => manifest.results.map((test) => ({
|
|
16615
|
-
framework: manifest.framework,
|
|
16616
|
-
test
|
|
16617
|
-
}))
|
|
16618
|
-
);
|
|
16619
|
-
if (rows.length === 0) {
|
|
16620
|
-
lines.push("| unknown | unknown | No tests found | unknown | unknown | 0 |");
|
|
16621
|
-
} else {
|
|
16622
|
-
for (const row of rows) {
|
|
16623
|
-
lines.push(
|
|
16624
|
-
`| ${markdownCell(row.framework)} | ${markdownCell(row.test.status)} | ${markdownCell(row.test.name)} | ${markdownCell(row.test.file)} | ${markdownCell(row.test.tracePath)} | ${row.test.artifacts.length} |`
|
|
16625
|
-
);
|
|
16626
|
-
}
|
|
16627
|
-
}
|
|
16628
|
-
lines.push("", "## Manifests", "", "| Framework | File | Generated | Artifacts |", "| --- | --- | --- | --- |");
|
|
16629
|
-
for (const manifest of result.manifests) {
|
|
16630
|
-
lines.push(
|
|
16631
|
-
`| ${markdownCell(manifest.framework)} | ${markdownCell(manifest.manifestFile)} | ${markdownCell(manifest.generatedAt)} | ${manifest.artifacts.length} |`
|
|
16632
|
-
);
|
|
16795
|
+
async function pathExists(p) {
|
|
16796
|
+
try {
|
|
16797
|
+
await promises.access(p);
|
|
16798
|
+
return true;
|
|
16799
|
+
} catch {
|
|
16800
|
+
return false;
|
|
16633
16801
|
}
|
|
16634
|
-
|
|
16635
|
-
|
|
16636
|
-
|
|
16637
|
-
|
|
16638
|
-
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
for (const row of artifacts) {
|
|
16642
|
-
lines.push(
|
|
16643
|
-
`| ${markdownCell(row.framework)} | ${markdownCell(row.artifact.kind)} | ${markdownCell(row.artifact.path)} | ${markdownCell(row.artifact.format)} | ${markdownCell(row.artifact.redactionProfile)} |`
|
|
16644
|
-
);
|
|
16645
|
-
}
|
|
16802
|
+
}
|
|
16803
|
+
async function isWritable(p) {
|
|
16804
|
+
try {
|
|
16805
|
+
await promises.access(p, fs.constants.W_OK);
|
|
16806
|
+
return true;
|
|
16807
|
+
} catch {
|
|
16808
|
+
return false;
|
|
16646
16809
|
}
|
|
16647
|
-
lines.push("");
|
|
16648
|
-
return `${lines.join("\n")}
|
|
16649
|
-
`;
|
|
16650
16810
|
}
|
|
16651
|
-
function
|
|
16652
|
-
|
|
16653
|
-
|
|
16654
|
-
|
|
16655
|
-
|
|
16656
|
-
|
|
16657
|
-
|
|
16658
|
-
return `${redacted.slice(0, MAX_TEXT - 12)}...[truncated]`;
|
|
16811
|
+
async function listJsonl(dir) {
|
|
16812
|
+
try {
|
|
16813
|
+
const entries = await promises.readdir(dir);
|
|
16814
|
+
return entries.filter((f) => f.endsWith(".jsonl"));
|
|
16815
|
+
} catch {
|
|
16816
|
+
return [];
|
|
16817
|
+
}
|
|
16659
16818
|
}
|
|
16660
|
-
async function
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16664
|
-
|
|
16819
|
+
async function countFiles(dir) {
|
|
16820
|
+
try {
|
|
16821
|
+
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
16822
|
+
return entries.filter((e) => e.isFile()).length;
|
|
16823
|
+
} catch {
|
|
16824
|
+
return 0;
|
|
16665
16825
|
}
|
|
16666
|
-
|
|
16826
|
+
}
|
|
16827
|
+
async function readWorkspaceManifestFile(location) {
|
|
16828
|
+
let raw;
|
|
16667
16829
|
try {
|
|
16668
|
-
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
}
|
|
16672
|
-
manifests.sort((a, b) => a.manifestFile.localeCompare(b.manifestFile));
|
|
16673
|
-
result = summarize3(manifests);
|
|
16674
|
-
} catch (error) {
|
|
16675
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
16676
|
-
console.error(`[AgentInspect] ci-summary failed: ${message}`);
|
|
16677
|
-
process.exitCode = 1;
|
|
16678
|
-
return;
|
|
16830
|
+
raw = await promises.readFile(location.manifestPath, "utf-8");
|
|
16831
|
+
} catch {
|
|
16832
|
+
return { exists: false, ok: false, errors: ["workspace.json not found"], warnings: [] };
|
|
16679
16833
|
}
|
|
16680
|
-
const
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
|
|
16834
|
+
const parsed = parseWorkspaceManifest(raw);
|
|
16835
|
+
return {
|
|
16836
|
+
exists: true,
|
|
16837
|
+
ok: parsed.ok,
|
|
16838
|
+
...parsed.manifest ? { manifest: parsed.manifest } : {},
|
|
16839
|
+
errors: parsed.errors,
|
|
16840
|
+
warnings: parsed.warnings
|
|
16841
|
+
};
|
|
16842
|
+
}
|
|
16843
|
+
async function createWorkspace(options = {}) {
|
|
16844
|
+
const location = resolveWorkspaceLocation(options.cwd);
|
|
16845
|
+
const dryRun = options.dryRun === true;
|
|
16846
|
+
const existing = await readWorkspaceManifestFile(location);
|
|
16847
|
+
const topLevelTraces = await listJsonl(location.workspaceDir);
|
|
16848
|
+
const detectedExistingTraces = topLevelTraces.length > 0;
|
|
16849
|
+
let manifest;
|
|
16850
|
+
let created;
|
|
16851
|
+
let adopted;
|
|
16852
|
+
if (existing.exists && existing.ok && existing.manifest) {
|
|
16853
|
+
manifest = existing.manifest;
|
|
16854
|
+
created = false;
|
|
16855
|
+
adopted = true;
|
|
16856
|
+
} else {
|
|
16857
|
+
const project = options.project?.trim() || path19__default.default.basename(location.projectRoot) || "workspace";
|
|
16858
|
+
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
16859
|
+
manifest = createDefaultWorkspaceManifest({
|
|
16860
|
+
project,
|
|
16861
|
+
traceDirs,
|
|
16862
|
+
...options.redactionProfile ? { redactionProfile: options.redactionProfile } : {}
|
|
16863
|
+
});
|
|
16864
|
+
created = true;
|
|
16865
|
+
adopted = detectedExistingTraces || existing.exists && !existing.ok;
|
|
16685
16866
|
}
|
|
16686
|
-
const
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
16690
|
-
|
|
16691
|
-
|
|
16867
|
+
const relDirs = uniqueDirs([
|
|
16868
|
+
...manifest.traceDirs.filter((d) => d !== "."),
|
|
16869
|
+
manifest.reportsDir,
|
|
16870
|
+
manifest.artifactsDir,
|
|
16871
|
+
manifest.bundlesDir,
|
|
16872
|
+
manifest.notesDir,
|
|
16873
|
+
INDEX_DIR_NAME
|
|
16874
|
+
]);
|
|
16875
|
+
const createdDirs = [];
|
|
16876
|
+
for (const rel of relDirs) {
|
|
16877
|
+
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
16878
|
+
if (await pathExists(abs)) continue;
|
|
16879
|
+
createdDirs.push(rel);
|
|
16880
|
+
if (!dryRun) await promises.mkdir(abs, { recursive: true });
|
|
16692
16881
|
}
|
|
16693
|
-
if (
|
|
16694
|
-
|
|
16695
|
-
|
|
16696
|
-
console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
|
|
16697
|
-
console.log(`Status: ${result.status}`);
|
|
16698
|
-
} else {
|
|
16699
|
-
console.log(markdown.trimEnd());
|
|
16882
|
+
if (!dryRun && created) {
|
|
16883
|
+
await promises.mkdir(location.workspaceDir, { recursive: true });
|
|
16884
|
+
await promises.writeFile(location.manifestPath, serializeWorkspaceManifest(manifest), "utf-8");
|
|
16700
16885
|
}
|
|
16886
|
+
return {
|
|
16887
|
+
location,
|
|
16888
|
+
manifest,
|
|
16889
|
+
created,
|
|
16890
|
+
adopted,
|
|
16891
|
+
createdDirs,
|
|
16892
|
+
detectedExistingTraces,
|
|
16893
|
+
dryRun
|
|
16894
|
+
};
|
|
16701
16895
|
}
|
|
16702
|
-
|
|
16703
|
-
|
|
16704
|
-
|
|
16705
|
-
|
|
16706
|
-
|
|
16707
|
-
|
|
16708
|
-
|
|
16896
|
+
function uniqueDirs(dirs) {
|
|
16897
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16898
|
+
const out = [];
|
|
16899
|
+
for (const d of dirs) {
|
|
16900
|
+
const t = d.trim();
|
|
16901
|
+
if (t === "" || t === "." || seen.has(t)) continue;
|
|
16902
|
+
seen.add(t);
|
|
16903
|
+
out.push(t);
|
|
16709
16904
|
}
|
|
16710
|
-
|
|
16711
|
-
"Unsupported --framework value. Use ai-sdk, openai-agents, langchain, or custom."
|
|
16712
|
-
);
|
|
16905
|
+
return out;
|
|
16713
16906
|
}
|
|
16714
|
-
function
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
|
|
16727
|
-
|
|
16728
|
-
|
|
16907
|
+
async function getWorkspaceStatus(location, manifest) {
|
|
16908
|
+
let traceFiles = 0;
|
|
16909
|
+
for (const rel of manifest.traceDirs) {
|
|
16910
|
+
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
16911
|
+
traceFiles += (await listJsonl(abs)).length;
|
|
16912
|
+
}
|
|
16913
|
+
const reports = await countFiles(
|
|
16914
|
+
resolveInsideWorkspace(location.workspaceDir, manifest.reportsDir)
|
|
16915
|
+
);
|
|
16916
|
+
const artifacts = await countFiles(
|
|
16917
|
+
resolveInsideWorkspace(location.workspaceDir, manifest.artifactsDir)
|
|
16918
|
+
);
|
|
16919
|
+
const bundles = await countFiles(
|
|
16920
|
+
resolveInsideWorkspace(location.workspaceDir, manifest.bundlesDir)
|
|
16921
|
+
);
|
|
16922
|
+
const notes = await countFiles(
|
|
16923
|
+
resolveInsideWorkspace(location.workspaceDir, manifest.notesDir)
|
|
16924
|
+
);
|
|
16925
|
+
const indexPath2 = manifest.index.path ? resolveInsideWorkspace(location.workspaceDir, manifest.index.path) : resolveInsideWorkspace(location.workspaceDir, INDEX_DIR_NAME);
|
|
16926
|
+
return {
|
|
16927
|
+
project: manifest.project,
|
|
16928
|
+
traceFiles,
|
|
16929
|
+
reports,
|
|
16930
|
+
artifacts,
|
|
16931
|
+
bundles,
|
|
16932
|
+
notes,
|
|
16933
|
+
index: {
|
|
16934
|
+
enabled: manifest.index.enabled,
|
|
16935
|
+
type: manifest.index.type,
|
|
16936
|
+
exists: await pathExists(indexPath2)
|
|
16937
|
+
}
|
|
16938
|
+
};
|
|
16729
16939
|
}
|
|
16730
|
-
function
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
16740
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16940
|
+
async function doctorWorkspace(location) {
|
|
16941
|
+
const checks2 = [];
|
|
16942
|
+
const manifestResult = await readWorkspaceManifestFile(location);
|
|
16943
|
+
if (!manifestResult.exists) {
|
|
16944
|
+
checks2.push({
|
|
16945
|
+
id: "manifest",
|
|
16946
|
+
status: "fail",
|
|
16947
|
+
message: "workspace.json not found (run `agent-inspect workspace init`)"
|
|
16948
|
+
});
|
|
16949
|
+
return { ok: false, checks: checks2 };
|
|
16950
|
+
}
|
|
16951
|
+
if (!manifestResult.ok || !manifestResult.manifest) {
|
|
16952
|
+
checks2.push({
|
|
16953
|
+
id: "manifest",
|
|
16954
|
+
status: "fail",
|
|
16955
|
+
message: `workspace.json is invalid: ${manifestResult.errors.join("; ")}`
|
|
16956
|
+
});
|
|
16957
|
+
return { ok: false, checks: checks2 };
|
|
16958
|
+
}
|
|
16959
|
+
const manifest = manifestResult.manifest;
|
|
16960
|
+
checks2.push({ id: "manifest", status: "pass", message: "workspace.json is valid" });
|
|
16961
|
+
for (const warning of manifestResult.warnings) {
|
|
16962
|
+
checks2.push({ id: "manifest-warning", status: "warn", message: warning });
|
|
16963
|
+
}
|
|
16964
|
+
const dirFields = [
|
|
16965
|
+
...manifest.traceDirs.filter((d) => d !== ".").map((d, i) => [`traceDir[${i}]`, d]),
|
|
16966
|
+
["reportsDir", manifest.reportsDir],
|
|
16967
|
+
["artifactsDir", manifest.artifactsDir],
|
|
16968
|
+
["bundlesDir", manifest.bundlesDir],
|
|
16969
|
+
["notesDir", manifest.notesDir]
|
|
16970
|
+
];
|
|
16971
|
+
for (const [id, rel] of dirFields) {
|
|
16972
|
+
let abs;
|
|
16973
|
+
try {
|
|
16974
|
+
abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
16975
|
+
} catch (error) {
|
|
16976
|
+
checks2.push({
|
|
16977
|
+
id,
|
|
16978
|
+
status: "fail",
|
|
16979
|
+
message: error instanceof Error ? error.message : String(error)
|
|
16980
|
+
});
|
|
16981
|
+
continue;
|
|
16982
|
+
}
|
|
16983
|
+
if (!await pathExists(abs)) {
|
|
16984
|
+
checks2.push({ id, status: "warn", message: `${rel}/ does not exist yet` });
|
|
16985
|
+
} else if (!await isWritable(abs)) {
|
|
16986
|
+
checks2.push({ id, status: "fail", message: `${rel}/ is not writable` });
|
|
16987
|
+
} else {
|
|
16988
|
+
checks2.push({ id, status: "pass", message: `${rel}/ is present and writable` });
|
|
16989
|
+
}
|
|
16990
|
+
}
|
|
16991
|
+
let newestTraceMtime = 0;
|
|
16992
|
+
for (const rel of manifest.traceDirs) {
|
|
16993
|
+
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
16994
|
+
for (const file of await listJsonl(abs)) {
|
|
16995
|
+
try {
|
|
16996
|
+
const s = await promises.stat(path19__default.default.join(abs, file));
|
|
16997
|
+
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
16998
|
+
} catch {
|
|
16999
|
+
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
17000
|
+
}
|
|
17001
|
+
}
|
|
17002
|
+
}
|
|
17003
|
+
if (manifest.index.enabled) {
|
|
17004
|
+
const indexPath2 = manifest.index.path ? resolveInsideWorkspace(location.workspaceDir, manifest.index.path) : resolveInsideWorkspace(location.workspaceDir, INDEX_DIR_NAME);
|
|
17005
|
+
if (!await pathExists(indexPath2)) {
|
|
17006
|
+
checks2.push({ id: "index", status: "warn", message: "index enabled but not built" });
|
|
17007
|
+
} else {
|
|
17008
|
+
try {
|
|
17009
|
+
const s = await promises.stat(indexPath2);
|
|
17010
|
+
if (newestTraceMtime > s.mtimeMs) {
|
|
17011
|
+
checks2.push({ id: "index", status: "warn", message: "index is stale (traces are newer)" });
|
|
17012
|
+
} else {
|
|
17013
|
+
checks2.push({ id: "index", status: "pass", message: "index is present" });
|
|
17014
|
+
}
|
|
17015
|
+
} catch {
|
|
17016
|
+
checks2.push({ id: "index", status: "warn", message: "cannot stat index" });
|
|
17017
|
+
}
|
|
17018
|
+
}
|
|
17019
|
+
}
|
|
17020
|
+
const ok = !checks2.some((c) => c.status === "fail");
|
|
17021
|
+
return { ok, checks: checks2 };
|
|
16744
17022
|
}
|
|
16745
|
-
|
|
16746
|
-
|
|
16747
|
-
|
|
16748
|
-
|
|
16749
|
-
|
|
16750
|
-
|
|
16751
|
-
|
|
16752
|
-
|
|
16753
|
-
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
16757
|
-
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
17023
|
+
async function cleanWorkspace(location, manifest, options = {}) {
|
|
17024
|
+
const dryRun = options.confirm !== true;
|
|
17025
|
+
const targets = uniqueDirs([
|
|
17026
|
+
manifest.reportsDir,
|
|
17027
|
+
manifest.artifactsDir,
|
|
17028
|
+
manifest.bundlesDir,
|
|
17029
|
+
manifest.index.path ?? INDEX_DIR_NAME
|
|
17030
|
+
]);
|
|
17031
|
+
const removed = [];
|
|
17032
|
+
for (const rel of targets) {
|
|
17033
|
+
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
17034
|
+
let entries;
|
|
17035
|
+
try {
|
|
17036
|
+
entries = await promises.readdir(abs);
|
|
17037
|
+
} catch {
|
|
17038
|
+
continue;
|
|
17039
|
+
}
|
|
17040
|
+
for (const entry of entries) {
|
|
17041
|
+
const relPath = `${rel}/${entry}`;
|
|
17042
|
+
removed.push(relPath);
|
|
17043
|
+
if (!dryRun) {
|
|
17044
|
+
await promises.rm(path19__default.default.join(abs, entry), { recursive: true, force: true });
|
|
17045
|
+
}
|
|
17046
|
+
}
|
|
17047
|
+
}
|
|
17048
|
+
return { dryRun, removed };
|
|
16763
17049
|
}
|
|
16764
17050
|
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
16769
|
-
|
|
16770
|
-
|
|
16771
|
-
|
|
16772
|
-
|
|
16773
|
-
|
|
16774
|
-
*/
|
|
16775
|
-
import { inspectRun, step } from "agent-inspect";
|
|
16776
|
-
|
|
16777
|
-
async function main() {
|
|
16778
|
-
await inspectRun("langchain-demo", async () => {
|
|
16779
|
-
await step.tool("mock-chain", async () => "ok");
|
|
16780
|
-
}, { traceDir: ".agent-inspect", silent: true });
|
|
16781
|
-
console.log("Trace written to .agent-inspect/");
|
|
17051
|
+
// packages/cli/src/bundle.ts
|
|
17052
|
+
var BUNDLE_NOTE2 = "Generated locally by AgentInspect. Bundles are derived copies for review \u2014 not compliance or security certification.";
|
|
17053
|
+
function stable6(value) {
|
|
17054
|
+
if (Array.isArray(value)) return value.map(stable6);
|
|
17055
|
+
if (value === null || typeof value !== "object") return value;
|
|
17056
|
+
const record = value;
|
|
17057
|
+
return Object.fromEntries(
|
|
17058
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable6(record[key])])
|
|
17059
|
+
);
|
|
16782
17060
|
}
|
|
16783
|
-
|
|
16784
|
-
|
|
16785
|
-
console.error(error);
|
|
16786
|
-
process.exitCode = 1;
|
|
16787
|
-
});
|
|
17061
|
+
function writeJson4(value) {
|
|
17062
|
+
return `${JSON.stringify(stable6(value), null, 2)}
|
|
16788
17063
|
`;
|
|
16789
|
-
default:
|
|
16790
|
-
return `import { observe } from "agent-inspect";
|
|
16791
|
-
|
|
16792
|
-
class DemoAgent {
|
|
16793
|
-
async run(input: { question: string }) {
|
|
16794
|
-
return { answer: \`Echo: \${input.question}\` };
|
|
16795
|
-
}
|
|
16796
17064
|
}
|
|
16797
|
-
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
silent: true,
|
|
16801
|
-
});
|
|
16802
|
-
|
|
16803
|
-
await agent.run({ question: "hello" });
|
|
16804
|
-
console.log("Trace written to .agent-inspect/");
|
|
16805
|
-
`;
|
|
17065
|
+
function parseBundleProfile(value) {
|
|
17066
|
+
if (value === void 0 || value === "local" || value === "share" || value === "strict") {
|
|
17067
|
+
return value ?? "share";
|
|
16806
17068
|
}
|
|
17069
|
+
throw new Error(`Unsupported --profile "${value}". Use local, share, or strict.`);
|
|
16807
17070
|
}
|
|
16808
|
-
function
|
|
16809
|
-
return
|
|
16810
|
-
|
|
16811
|
-
on:
|
|
16812
|
-
workflow_dispatch:
|
|
16813
|
-
push:
|
|
16814
|
-
branches: [main]
|
|
16815
|
-
|
|
16816
|
-
jobs:
|
|
16817
|
-
trace-artifacts:
|
|
16818
|
-
runs-on: ubuntu-latest
|
|
16819
|
-
steps:
|
|
16820
|
-
- uses: actions/checkout@v4
|
|
16821
|
-
- uses: actions/setup-node@v4
|
|
16822
|
-
with:
|
|
16823
|
-
node-version: "22"
|
|
16824
|
-
- run: npm ci
|
|
16825
|
-
- run: npm test
|
|
16826
|
-
- name: Upload AgentInspect traces
|
|
16827
|
-
if: always()
|
|
16828
|
-
uses: actions/upload-artifact@v4
|
|
16829
|
-
with:
|
|
16830
|
-
name: agent-inspect-traces
|
|
16831
|
-
path: .agent-inspect/**/*.jsonl
|
|
16832
|
-
if-no-files-found: ignore
|
|
16833
|
-
`;
|
|
17071
|
+
function toReportProfile(profile) {
|
|
17072
|
+
return profile;
|
|
16834
17073
|
}
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
{ rel: GITKEEP, content: "" },
|
|
16842
|
-
{ rel: demoPath, content: demoTemplate(framework) }
|
|
16843
|
-
];
|
|
16844
|
-
if (options.ci === "github") {
|
|
16845
|
-
candidates.push({
|
|
16846
|
-
rel: ".github/workflows/agent-inspect-artifacts.yml",
|
|
16847
|
-
content: githubWorkflowTemplate()
|
|
16848
|
-
});
|
|
17074
|
+
function escapeHtml3(value) {
|
|
17075
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
17076
|
+
}
|
|
17077
|
+
function safetyStatusFromAssess(status) {
|
|
17078
|
+
if (status === "SAFE" || status === "SAFE WITH WARNINGS" || status === "UNSAFE" || status === "UNKNOWN") {
|
|
17079
|
+
return status;
|
|
16849
17080
|
}
|
|
16850
|
-
|
|
16851
|
-
|
|
16852
|
-
|
|
17081
|
+
return "UNKNOWN";
|
|
17082
|
+
}
|
|
17083
|
+
async function resolveOutputDir(options, runIds, cwd) {
|
|
17084
|
+
if (options.out !== void 0 && options.out.trim() !== "") {
|
|
17085
|
+
const normalized = normalizeBundleOutputPath(options.out);
|
|
16853
17086
|
try {
|
|
16854
|
-
|
|
16855
|
-
|
|
16856
|
-
|
|
16857
|
-
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
|
|
16862
|
-
|
|
17087
|
+
const location = resolveWorkspaceLocation(cwd);
|
|
17088
|
+
const manifest = await readWorkspaceManifestFile(location);
|
|
17089
|
+
if (manifest.ok && manifest.manifest) {
|
|
17090
|
+
const rel = path19__default.default.relative(location.workspaceDir, normalized);
|
|
17091
|
+
if (!rel.startsWith("..") && !path19__default.default.isAbsolute(rel)) {
|
|
17092
|
+
return resolveInsideWorkspace(location.workspaceDir, rel);
|
|
17093
|
+
}
|
|
17094
|
+
}
|
|
17095
|
+
} catch {
|
|
16863
17096
|
}
|
|
17097
|
+
return normalized;
|
|
16864
17098
|
}
|
|
16865
|
-
|
|
16866
|
-
|
|
16867
|
-
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16875
|
-
written.push(entry.path);
|
|
16876
|
-
continue;
|
|
17099
|
+
try {
|
|
17100
|
+
const location = resolveWorkspaceLocation(cwd);
|
|
17101
|
+
const manifest = await readWorkspaceManifestFile(location);
|
|
17102
|
+
if (manifest.ok && manifest.manifest) {
|
|
17103
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
17104
|
+
const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
|
|
17105
|
+
return resolveInsideWorkspace(
|
|
17106
|
+
location.workspaceDir,
|
|
17107
|
+
path19__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
|
|
17108
|
+
);
|
|
16877
17109
|
}
|
|
16878
|
-
|
|
16879
|
-
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
|
|
16880
|
-
await promises.writeFile(abs, content, "utf-8");
|
|
16881
|
-
written.push(entry.path);
|
|
17110
|
+
} catch {
|
|
16882
17111
|
}
|
|
16883
|
-
return
|
|
17112
|
+
return defaultBundleOutputPath(runIds);
|
|
16884
17113
|
}
|
|
16885
|
-
async function
|
|
16886
|
-
const
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
17114
|
+
async function writeBundleFile(outputDir, relativePath, content, files) {
|
|
17115
|
+
const outPath = path19__default.default.join(outputDir, relativePath);
|
|
17116
|
+
await promises.mkdir(path19__default.default.dirname(outPath), { recursive: true });
|
|
17117
|
+
await promises.writeFile(outPath, content, "utf-8");
|
|
17118
|
+
files.push(relativePath);
|
|
17119
|
+
}
|
|
17120
|
+
function renderBundleIndexHtml(parts) {
|
|
17121
|
+
const links = parts.runIds.map(
|
|
17122
|
+
(runId) => `<li><a href="assets/runs/${escapeHtml3(runId)}.html">${escapeHtml3(runId)}</a></li>`
|
|
17123
|
+
).join("");
|
|
17124
|
+
const sections = parts.runIds.map((runId) => {
|
|
17125
|
+
const html = parts.reports.get(runId) ?? "";
|
|
17126
|
+
return `<section id="run-${escapeHtml3(runId)}"><h2>${escapeHtml3(runId)}</h2>${html}</section>`;
|
|
17127
|
+
}).join("\n");
|
|
17128
|
+
return `<!doctype html>
|
|
17129
|
+
<html lang="en">
|
|
17130
|
+
<head>
|
|
17131
|
+
<meta charset="utf-8"/>
|
|
17132
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
17133
|
+
<title>AgentInspect Bundle</title>
|
|
17134
|
+
<style>
|
|
17135
|
+
body{font-family:system-ui,sans-serif;line-height:1.5;margin:1.5rem;max-width:960px;color:#111}
|
|
17136
|
+
a{color:#0366d6}
|
|
17137
|
+
section{border-top:1px solid #ddd;margin-top:1.5rem;padding-top:1rem}
|
|
17138
|
+
</style>
|
|
17139
|
+
</head>
|
|
17140
|
+
<body>
|
|
17141
|
+
<h1>AgentInspect trace bundle</h1>
|
|
17142
|
+
<p>${escapeHtml3(BUNDLE_NOTE2)}</p>
|
|
17143
|
+
<h2>Runs</h2>
|
|
17144
|
+
<ul>${links}</ul>
|
|
17145
|
+
${sections}
|
|
17146
|
+
</body>
|
|
17147
|
+
</html>
|
|
17148
|
+
`;
|
|
17149
|
+
}
|
|
17150
|
+
function extractHtmlBody(content) {
|
|
17151
|
+
const match = content.match(/<body[^>]*>([\s\S]*)<\/body>/i);
|
|
17152
|
+
return match?.[1]?.trim() ?? content;
|
|
17153
|
+
}
|
|
17154
|
+
async function bundleCommand(runIdArg, options = {}) {
|
|
17155
|
+
const profile = parseBundleProfile(options.profile);
|
|
17156
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
17157
|
+
const cwd = process.cwd();
|
|
17158
|
+
let resolveResult;
|
|
17159
|
+
try {
|
|
17160
|
+
const { runs } = await loadSessionRuns(traceDir);
|
|
17161
|
+
const staleThresholdMs = options.staleAfter && options.staleAfter.trim() !== "" ? parseDuration(options.staleAfter.trim()) : void 0;
|
|
17162
|
+
const index = buildSessionIndex(runs, {
|
|
17163
|
+
correlateByGroupId: options.correlateGroup === true,
|
|
17164
|
+
staleThresholdMs
|
|
17165
|
+
});
|
|
17166
|
+
resolveResult = resolveBundleRunIds(index, runs, {
|
|
17167
|
+
...runIdArg !== void 0 && runIdArg.trim() !== "" ? { runId: runIdArg.trim() } : {},
|
|
17168
|
+
...options.session ? { sessionId: options.session } : {},
|
|
17169
|
+
...options.since ? { since: options.since } : {}
|
|
17170
|
+
});
|
|
17171
|
+
} catch (error) {
|
|
17172
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16891
17173
|
if (options.json) {
|
|
16892
|
-
|
|
16893
|
-
|
|
16894
|
-
|
|
16895
|
-
framework: plan.framework,
|
|
16896
|
-
ci: plan.ci ?? null,
|
|
16897
|
-
dryRun: options.dryRun === true,
|
|
16898
|
-
planned: plan.files,
|
|
16899
|
-
wouldWrite: options.dryRun ? toWrite : void 0
|
|
16900
|
-
};
|
|
16901
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
16902
|
-
if (options.dryRun) return;
|
|
17174
|
+
console.log(writeJson4({ ok: false, error: message }).trimEnd());
|
|
17175
|
+
} else {
|
|
17176
|
+
console.error(`[AgentInspect] bundle failed: ${message}`);
|
|
16903
17177
|
}
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
17178
|
+
process.exitCode = 1;
|
|
17179
|
+
return;
|
|
17180
|
+
}
|
|
17181
|
+
const outputDir = await resolveOutputDir(options, resolveResult.runIds, cwd);
|
|
17182
|
+
const files = [];
|
|
17183
|
+
const checkRuns = [];
|
|
17184
|
+
const redactionRuns = [];
|
|
17185
|
+
const htmlByRun = /* @__PURE__ */ new Map();
|
|
17186
|
+
const redactedJsonlByRun = /* @__PURE__ */ new Map();
|
|
17187
|
+
let combinedJsonl = "";
|
|
17188
|
+
for (const runId of resolveResult.runIds) {
|
|
17189
|
+
const tracePath = getTraceFilePath(runId, traceDir);
|
|
17190
|
+
let rawContent;
|
|
17191
|
+
let sourceMtimeMs;
|
|
17192
|
+
try {
|
|
17193
|
+
rawContent = await promises.readFile(tracePath, "utf-8");
|
|
17194
|
+
sourceMtimeMs = (await promises.stat(tracePath)).mtimeMs;
|
|
17195
|
+
} catch (error) {
|
|
17196
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17197
|
+
if (options.json) {
|
|
17198
|
+
console.log(writeJson4({ ok: false, error: message, runId }).trimEnd());
|
|
17199
|
+
} else {
|
|
17200
|
+
console.error(`[AgentInspect] bundle failed: ${message}`);
|
|
16916
17201
|
}
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
17202
|
+
process.exitCode = 1;
|
|
17203
|
+
return;
|
|
17204
|
+
}
|
|
17205
|
+
let read;
|
|
17206
|
+
try {
|
|
17207
|
+
read = await openTrace(
|
|
17208
|
+
{ type: "file", path: tracePath },
|
|
17209
|
+
{ format: "agent-inspect-jsonl" }
|
|
17210
|
+
);
|
|
17211
|
+
} catch (error) {
|
|
17212
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17213
|
+
if (options.json) {
|
|
17214
|
+
console.log(writeJson4({ ok: false, error: message, runId }).trimEnd());
|
|
17215
|
+
} else {
|
|
17216
|
+
console.error(`[AgentInspect] bundle failed: ${message}`);
|
|
16921
17217
|
}
|
|
16922
|
-
|
|
16923
|
-
|
|
17218
|
+
process.exitCode = 1;
|
|
17219
|
+
return;
|
|
16924
17220
|
}
|
|
16925
|
-
|
|
16926
|
-
const
|
|
17221
|
+
const safety = assessOpenedTrace(read, { run: runId });
|
|
17222
|
+
const status = safetyStatusFromAssess(safety.status);
|
|
17223
|
+
checkRuns.push({
|
|
17224
|
+
runId,
|
|
17225
|
+
status,
|
|
17226
|
+
errors: safety.summary.errors,
|
|
17227
|
+
warnings: safety.summary.warnings,
|
|
17228
|
+
findings: safety.summary.findings
|
|
17229
|
+
});
|
|
17230
|
+
const redacted = redactTraceContent(rawContent, toReportProfile(profile));
|
|
17231
|
+
redactedJsonlByRun.set(runId, redacted.content);
|
|
17232
|
+
combinedJsonl += redacted.content.endsWith("\n") ? redacted.content : `${redacted.content}
|
|
17233
|
+
`;
|
|
17234
|
+
const detectors = [
|
|
17235
|
+
...new Set(redacted.findings.map((finding) => finding.detector))
|
|
17236
|
+
].sort((a, b) => a.localeCompare(b));
|
|
17237
|
+
redactionRuns.push({
|
|
17238
|
+
runId,
|
|
17239
|
+
findings: redacted.findings.length,
|
|
17240
|
+
detectors
|
|
17241
|
+
});
|
|
17242
|
+
const selected = read.runs.find((run) => run.runId === runId);
|
|
17243
|
+
const runReport = exportRunTree(selected ?? read.runs[0], {
|
|
17244
|
+
format: "html",
|
|
17245
|
+
redacted: true,
|
|
17246
|
+
redactionProfile: toReportProfile(profile)
|
|
17247
|
+
});
|
|
17248
|
+
htmlByRun.set(runId, extractHtmlBody(runReport.content));
|
|
17249
|
+
const afterMtime = (await promises.stat(tracePath)).mtimeMs;
|
|
17250
|
+
if (afterMtime !== sourceMtimeMs) {
|
|
17251
|
+
const message = `Source trace "${runId}" was modified during bundle creation.`;
|
|
17252
|
+
if (options.json) {
|
|
17253
|
+
console.log(writeJson4({ ok: false, error: message }).trimEnd());
|
|
17254
|
+
} else {
|
|
17255
|
+
console.error(`[AgentInspect] bundle failed: ${message}`);
|
|
17256
|
+
}
|
|
17257
|
+
process.exitCode = 1;
|
|
17258
|
+
return;
|
|
17259
|
+
}
|
|
17260
|
+
}
|
|
17261
|
+
const checks2 = {
|
|
17262
|
+
aggregateStatus: aggregateBundleSafeStatus(checkRuns.map((run) => run.status)),
|
|
17263
|
+
runs: checkRuns
|
|
17264
|
+
};
|
|
17265
|
+
if (bundleFailsOnSafety(checks2.aggregateStatus, options.allowUnsafe === true)) {
|
|
16927
17266
|
if (options.json) {
|
|
16928
|
-
console.log(
|
|
17267
|
+
console.log(
|
|
17268
|
+
writeJson4({
|
|
17269
|
+
ok: false,
|
|
17270
|
+
error: `Bundle safety status is ${checks2.aggregateStatus}. Pass --allow-unsafe to override.`,
|
|
17271
|
+
checks: checks2
|
|
17272
|
+
}).trimEnd()
|
|
17273
|
+
);
|
|
16929
17274
|
} else {
|
|
16930
|
-
console.error(
|
|
17275
|
+
console.error(
|
|
17276
|
+
`[AgentInspect] bundle refused: safety status is ${checks2.aggregateStatus}. Pass --allow-unsafe to override.`
|
|
17277
|
+
);
|
|
16931
17278
|
}
|
|
16932
17279
|
process.exitCode = 1;
|
|
17280
|
+
return;
|
|
16933
17281
|
}
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
"openai-agents": ["@agent-inspect/openai-agents"],
|
|
16939
|
-
langchain: ["@agent-inspect/langchain"]
|
|
16940
|
-
};
|
|
16941
|
-
function nodeVersionCheck() {
|
|
16942
|
-
const major = Number(process3__default.default.versions.node.split(".")[0]);
|
|
16943
|
-
if (Number.isNaN(major) || major < 20) {
|
|
16944
|
-
return {
|
|
16945
|
-
id: "node-version",
|
|
16946
|
-
status: "fail",
|
|
16947
|
-
message: `Node ${process3__default.default.versions.node} is below the supported minimum (20).`,
|
|
16948
|
-
remediation: "Upgrade to Node 20 LTS or newer.",
|
|
16949
|
-
evidence: process3__default.default.versions.node
|
|
16950
|
-
};
|
|
16951
|
-
}
|
|
16952
|
-
return {
|
|
16953
|
-
id: "node-version",
|
|
16954
|
-
status: "pass",
|
|
16955
|
-
message: `Node ${process3__default.default.versions.node} meets the minimum (>=20).`,
|
|
16956
|
-
evidence: process3__default.default.versions.node
|
|
17282
|
+
const redactionReport = {
|
|
17283
|
+
profile,
|
|
17284
|
+
totalFindings: redactionRuns.reduce((sum, run) => sum + run.findings, 0),
|
|
17285
|
+
runs: redactionRuns
|
|
16957
17286
|
};
|
|
16958
|
-
}
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
|
|
16966
|
-
|
|
16967
|
-
|
|
17287
|
+
await promises.mkdir(outputDir, { recursive: true });
|
|
17288
|
+
for (const runId of resolveResult.runIds) {
|
|
17289
|
+
const jsonl = redactedJsonlByRun.get(runId) ?? "";
|
|
17290
|
+
await writeBundleFile(outputDir, `assets/runs/${runId}.jsonl`, jsonl, files);
|
|
17291
|
+
const html = htmlByRun.get(runId) ?? "";
|
|
17292
|
+
await writeBundleFile(
|
|
17293
|
+
outputDir,
|
|
17294
|
+
`assets/runs/${runId}.html`,
|
|
17295
|
+
runReportWrap(html, runId),
|
|
17296
|
+
files
|
|
17297
|
+
);
|
|
16968
17298
|
}
|
|
16969
|
-
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
17299
|
+
const primaryRunId = resolveResult.runIds[0];
|
|
17300
|
+
const traceHtml = resolveResult.runIds.length === 1 ? runReportWrap(htmlByRun.get(primaryRunId) ?? "", primaryRunId) : renderBundleIndexHtml({ runIds: resolveResult.runIds, reports: htmlByRun });
|
|
17301
|
+
await writeBundleFile(outputDir, "trace.jsonl", combinedJsonl, files);
|
|
17302
|
+
await writeBundleFile(outputDir, "trace.html", traceHtml, files);
|
|
17303
|
+
await writeBundleFile(
|
|
17304
|
+
outputDir,
|
|
17305
|
+
"check-results.json",
|
|
17306
|
+
writeJson4(checks2),
|
|
17307
|
+
files
|
|
17308
|
+
);
|
|
17309
|
+
await writeBundleFile(
|
|
17310
|
+
outputDir,
|
|
17311
|
+
"eval-results.json",
|
|
17312
|
+
writeJson4(buildPlaceholderArtifact()),
|
|
17313
|
+
files
|
|
17314
|
+
);
|
|
17315
|
+
await writeBundleFile(
|
|
17316
|
+
outputDir,
|
|
17317
|
+
"redaction-report.json",
|
|
17318
|
+
writeJson4(redactionReport),
|
|
17319
|
+
files
|
|
17320
|
+
);
|
|
17321
|
+
await writeBundleFile(
|
|
17322
|
+
outputDir,
|
|
17323
|
+
"performance-summary.json",
|
|
17324
|
+
writeJson4(buildPlaceholderArtifact()),
|
|
17325
|
+
files
|
|
17326
|
+
);
|
|
17327
|
+
const metadata = buildBundleMetadata({
|
|
17328
|
+
agentInspectVersion: version,
|
|
17329
|
+
profile,
|
|
17330
|
+
resolve: resolveResult,
|
|
17331
|
+
checks: checks2,
|
|
17332
|
+
files: [...files]
|
|
17333
|
+
});
|
|
17334
|
+
await writeBundleFile(outputDir, "metadata.json", writeJson4(metadata), files);
|
|
17335
|
+
await writeBundleFile(
|
|
17336
|
+
outputDir,
|
|
17337
|
+
"summary.md",
|
|
17338
|
+
buildBundleSummaryMarkdown({ metadata, checks: checks2, redaction: redactionReport }),
|
|
17339
|
+
files
|
|
17340
|
+
);
|
|
17341
|
+
metadata.files = [...files].sort((a, b) => a.localeCompare(b));
|
|
17342
|
+
await promises.writeFile(path19__default.default.join(outputDir, "metadata.json"), writeJson4(metadata), "utf-8");
|
|
17343
|
+
if (options.json) {
|
|
17344
|
+
console.log(
|
|
17345
|
+
writeJson4({
|
|
17346
|
+
ok: true,
|
|
17347
|
+
outputDir,
|
|
17348
|
+
metadata,
|
|
17349
|
+
checks: checks2,
|
|
17350
|
+
redaction: redactionReport
|
|
17351
|
+
}).trimEnd()
|
|
17352
|
+
);
|
|
17353
|
+
return;
|
|
16995
17354
|
}
|
|
17355
|
+
console.log(`Bundle written to ${outputDir}`);
|
|
17356
|
+
console.log(`Safe status: ${metadata.safeStatus}`);
|
|
17357
|
+
console.log(`Runs: ${resolveResult.runIds.join(", ")}`);
|
|
17358
|
+
console.log(`Files: ${metadata.files.length}`);
|
|
16996
17359
|
}
|
|
16997
|
-
function
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17360
|
+
function runReportWrap(body, runId) {
|
|
17361
|
+
return `<!doctype html>
|
|
17362
|
+
<html lang="en">
|
|
17363
|
+
<head>
|
|
17364
|
+
<meta charset="utf-8"/>
|
|
17365
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
17366
|
+
<title>AgentInspect \u2014 ${escapeHtml3(runId)}</title>
|
|
17367
|
+
<style>body{font-family:system-ui,sans-serif;line-height:1.5;margin:1.5rem;max-width:960px;color:#111}</style>
|
|
17368
|
+
</head>
|
|
17369
|
+
<body>
|
|
17370
|
+
${body}
|
|
17371
|
+
</body>
|
|
17372
|
+
</html>
|
|
17373
|
+
`;
|
|
17006
17374
|
}
|
|
17007
|
-
function
|
|
17008
|
-
const
|
|
17009
|
-
const
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
message: "
|
|
17375
|
+
function validateReporterArtifactPath(options) {
|
|
17376
|
+
const outputDir = path19__default.default.resolve(options.outputDir);
|
|
17377
|
+
const diagnostics = [];
|
|
17378
|
+
const rawPath = options.relativePath;
|
|
17379
|
+
if (rawPath.length === 0) {
|
|
17380
|
+
diagnostics.push({
|
|
17381
|
+
code: "artifact_path_empty",
|
|
17382
|
+
severity: "error",
|
|
17383
|
+
message: "Reporter artifact path must not be empty."
|
|
17016
17384
|
});
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17385
|
+
return { ok: false, outputDir, diagnostics };
|
|
17386
|
+
}
|
|
17387
|
+
if (rawPath.includes("\0")) {
|
|
17388
|
+
diagnostics.push({
|
|
17389
|
+
code: "invalid_artifact_path",
|
|
17390
|
+
severity: "error",
|
|
17391
|
+
message: "Reporter artifact path must not contain null bytes.",
|
|
17392
|
+
target: rawPath
|
|
17023
17393
|
});
|
|
17394
|
+
return { ok: false, outputDir, diagnostics };
|
|
17024
17395
|
}
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17396
|
+
if (path19__default.default.isAbsolute(rawPath) || path19__default.default.win32.isAbsolute(rawPath)) {
|
|
17397
|
+
diagnostics.push({
|
|
17398
|
+
code: "artifact_path_absolute",
|
|
17399
|
+
severity: "error",
|
|
17400
|
+
message: "Reporter artifact path must be relative.",
|
|
17401
|
+
target: rawPath
|
|
17031
17402
|
});
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17403
|
+
return { ok: false, outputDir, diagnostics };
|
|
17404
|
+
}
|
|
17405
|
+
const normalized = path19__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
17406
|
+
const segments = normalized.split("/");
|
|
17407
|
+
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
17408
|
+
diagnostics.push({
|
|
17409
|
+
code: "artifact_path_escape",
|
|
17410
|
+
severity: "error",
|
|
17411
|
+
message: "Reporter artifact path must stay under the output directory.",
|
|
17412
|
+
target: rawPath
|
|
17037
17413
|
});
|
|
17414
|
+
return { ok: false, outputDir, diagnostics };
|
|
17038
17415
|
}
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
return packages.map((name) => {
|
|
17050
|
-
const resolved = resolvePackage(cwd, name);
|
|
17051
|
-
if (!resolved.ok) {
|
|
17052
|
-
return {
|
|
17053
|
-
id: `optional-package-${name}`,
|
|
17054
|
-
status: framework !== void 0 ? "warn" : "skipped",
|
|
17055
|
-
message: `${name} is not installed.`,
|
|
17056
|
-
remediation: framework !== void 0 ? `npm install ${name}` : void 0
|
|
17057
|
-
};
|
|
17058
|
-
}
|
|
17059
|
-
return {
|
|
17060
|
-
id: `optional-package-${name}`,
|
|
17061
|
-
status: "pass",
|
|
17062
|
-
message: `${name} is available.`,
|
|
17063
|
-
evidence: resolved.version
|
|
17064
|
-
};
|
|
17065
|
-
});
|
|
17066
|
-
}
|
|
17067
|
-
function versionMismatchCheck(cwd) {
|
|
17068
|
-
const root = resolvePackage(cwd, "agent-inspect");
|
|
17069
|
-
if (!root.ok || root.version === void 0) {
|
|
17070
|
-
return {
|
|
17071
|
-
id: "version-alignment",
|
|
17072
|
-
status: "skipped",
|
|
17073
|
-
message: "Skipped version alignment \u2014 agent-inspect not installed locally."
|
|
17074
|
-
};
|
|
17075
|
-
}
|
|
17076
|
-
if (root.version !== version) {
|
|
17077
|
-
return {
|
|
17078
|
-
id: "version-alignment",
|
|
17079
|
-
status: "warn",
|
|
17080
|
-
message: `CLI version ${version} differs from local agent-inspect@${root.version}.`,
|
|
17081
|
-
remediation: "Align versions with npm install agent-inspect@latest",
|
|
17082
|
-
evidence: `cli=${version};local=${root.version}`
|
|
17083
|
-
};
|
|
17416
|
+
const absolutePath = path19__default.default.resolve(outputDir, normalized);
|
|
17417
|
+
const relFromOutput = path19__default.default.relative(outputDir, absolutePath);
|
|
17418
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path19__default.default.isAbsolute(relFromOutput)) {
|
|
17419
|
+
diagnostics.push({
|
|
17420
|
+
code: "artifact_path_escape",
|
|
17421
|
+
severity: "error",
|
|
17422
|
+
message: "Reporter artifact path resolved outside the output directory.",
|
|
17423
|
+
target: rawPath
|
|
17424
|
+
});
|
|
17425
|
+
return { ok: false, outputDir, diagnostics };
|
|
17084
17426
|
}
|
|
17085
17427
|
return {
|
|
17086
|
-
|
|
17087
|
-
|
|
17088
|
-
|
|
17428
|
+
ok: true,
|
|
17429
|
+
outputDir,
|
|
17430
|
+
relativePath: normalized,
|
|
17431
|
+
absolutePath,
|
|
17432
|
+
diagnostics
|
|
17089
17433
|
};
|
|
17090
17434
|
}
|
|
17091
|
-
|
|
17092
|
-
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17101
|
-
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
if (options.checkImports !== false) {
|
|
17108
|
-
checks2.push(...importSmoke(cwd));
|
|
17109
|
-
}
|
|
17110
|
-
checks2.push(...optionalPackageChecks(cwd, options.framework));
|
|
17111
|
-
return checks2.sort((a, b) => a.id.localeCompare(b.id));
|
|
17435
|
+
|
|
17436
|
+
// packages/cli/src/ci-summary.ts
|
|
17437
|
+
var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
|
|
17438
|
+
var MAX_TEXT = 180;
|
|
17439
|
+
var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
|
|
17440
|
+
var STATUSES = /* @__PURE__ */ new Set(["passed", "failed", "skipped", "todo"]);
|
|
17441
|
+
var ARTIFACT_KINDS = /* @__PURE__ */ new Set(["trace", "report", "eval", "redaction", "summary"]);
|
|
17442
|
+
var ARTIFACT_FORMATS = /* @__PURE__ */ new Set(["json", "jsonl", "md", "html"]);
|
|
17443
|
+
var REDACTION_PROFILES2 = /* @__PURE__ */ new Set(["local", "share", "strict"]);
|
|
17444
|
+
function stable7(value) {
|
|
17445
|
+
if (Array.isArray(value)) return value.map(stable7);
|
|
17446
|
+
if (value === null || typeof value !== "object") return value;
|
|
17447
|
+
const record = value;
|
|
17448
|
+
return Object.fromEntries(
|
|
17449
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable7(record[key])])
|
|
17450
|
+
);
|
|
17112
17451
|
}
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
const warned = checks2.filter((check) => check.status === "warn").length;
|
|
17117
|
-
if (options.json) {
|
|
17118
|
-
console.log(
|
|
17119
|
-
JSON.stringify(
|
|
17120
|
-
{
|
|
17121
|
-
ok: failed === 0,
|
|
17122
|
-
version,
|
|
17123
|
-
summary: { pass: checks2.filter((c) => c.status === "pass").length, warn: warned, fail: failed },
|
|
17124
|
-
checks: checks2
|
|
17125
|
-
},
|
|
17126
|
-
null,
|
|
17127
|
-
2
|
|
17128
|
-
)
|
|
17129
|
-
);
|
|
17130
|
-
if (failed > 0) process3__default.default.exitCode = 1;
|
|
17131
|
-
return;
|
|
17132
|
-
}
|
|
17133
|
-
console.log("AgentInspect doctor");
|
|
17134
|
-
for (const check of checks2) {
|
|
17135
|
-
const tag = check.status.toUpperCase();
|
|
17136
|
-
console.log(`[${tag}] ${check.id}: ${check.message}`);
|
|
17137
|
-
if (check.remediation) console.log(` \u2192 ${check.remediation}`);
|
|
17138
|
-
}
|
|
17139
|
-
console.log(`
|
|
17140
|
-
Summary: ${failed} failed, ${warned} warnings`);
|
|
17141
|
-
if (failed > 0) process3__default.default.exitCode = 1;
|
|
17452
|
+
function writeJson5(value) {
|
|
17453
|
+
return `${JSON.stringify(stable7(value), null, 2)}
|
|
17454
|
+
`;
|
|
17142
17455
|
}
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
init_advanced();
|
|
17146
|
-
function defineIndexer(indexer) {
|
|
17147
|
-
if (!indexer.id.trim()) throw new Error("indexer id is required");
|
|
17148
|
-
return indexer;
|
|
17456
|
+
function isObject(value) {
|
|
17457
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17149
17458
|
}
|
|
17150
|
-
|
|
17151
|
-
|
|
17152
|
-
|
|
17153
|
-
const td = new TraceDirectory({ dir: traceDir });
|
|
17154
|
-
const files = await td.list();
|
|
17155
|
-
for (const file of files) {
|
|
17156
|
-
const stats = await td.getFileStats(file);
|
|
17157
|
-
if (stats.mtimeMs > builtMs) return true;
|
|
17459
|
+
function readString(value, label) {
|
|
17460
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
17461
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
17158
17462
|
}
|
|
17159
|
-
return
|
|
17160
|
-
}
|
|
17161
|
-
function createTraceDirectoryIndexer() {
|
|
17162
|
-
return defineIndexer({
|
|
17163
|
-
id: "trace-directory-metadata",
|
|
17164
|
-
async rebuild(traceDir, options = {}) {
|
|
17165
|
-
const warnings = [];
|
|
17166
|
-
const td = new TraceDirectory({ dir: traceDir });
|
|
17167
|
-
const files = await td.list();
|
|
17168
|
-
const maxEntries = options.maxEntries ?? 1e4;
|
|
17169
|
-
if (files.length > maxEntries) {
|
|
17170
|
-
warnings.push(
|
|
17171
|
-
`indexer.truncated: trace directory has ${files.length} files; indexing first ${maxEntries}`
|
|
17172
|
-
);
|
|
17173
|
-
}
|
|
17174
|
-
const slice = files.slice(0, maxEntries);
|
|
17175
|
-
const metas = await loadTraceMetadataList(
|
|
17176
|
-
traceDir,
|
|
17177
|
-
slice,
|
|
17178
|
-
(fileName) => td.getPath(fileName)
|
|
17179
|
-
);
|
|
17180
|
-
const entries = metas.map((meta2) => ({
|
|
17181
|
-
runId: meta2.runId,
|
|
17182
|
-
path: meta2.filePath,
|
|
17183
|
-
name: meta2.name,
|
|
17184
|
-
startedAt: meta2.startedAt,
|
|
17185
|
-
status: meta2.status
|
|
17186
|
-
})).sort((a, b) => a.runId.localeCompare(b.runId));
|
|
17187
|
-
if (entries.length < slice.length) {
|
|
17188
|
-
warnings.push(
|
|
17189
|
-
`indexer.partial: indexed ${entries.length} of ${slice.length} trace files`
|
|
17190
|
-
);
|
|
17191
|
-
}
|
|
17192
|
-
return {
|
|
17193
|
-
traceDir,
|
|
17194
|
-
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17195
|
-
entries,
|
|
17196
|
-
warnings
|
|
17197
|
-
};
|
|
17198
|
-
}
|
|
17199
|
-
});
|
|
17463
|
+
return safeText(value);
|
|
17200
17464
|
}
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
init_advanced();
|
|
17204
|
-
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
17205
|
-
function traceIndexPath(traceDir) {
|
|
17206
|
-
return path16__default.default.join(traceDir, INDEX_FILENAME);
|
|
17465
|
+
function readOptionalString(value) {
|
|
17466
|
+
return typeof value === "string" && value.trim() !== "" ? safeText(value) : void 0;
|
|
17207
17467
|
}
|
|
17208
|
-
function
|
|
17209
|
-
|
|
17210
|
-
|
|
17211
|
-
|
|
17212
|
-
throw new Error("--max-entries must be a positive integer.");
|
|
17468
|
+
function readFramework(value) {
|
|
17469
|
+
const framework = readString(value, "manifest.framework");
|
|
17470
|
+
if (!FRAMEWORKS.has(framework)) {
|
|
17471
|
+
throw new Error(`Unsupported reporter framework: ${framework}.`);
|
|
17213
17472
|
}
|
|
17214
|
-
return
|
|
17473
|
+
return framework;
|
|
17215
17474
|
}
|
|
17216
|
-
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
|
|
17220
|
-
} catch {
|
|
17221
|
-
return void 0;
|
|
17475
|
+
function readStatus(value) {
|
|
17476
|
+
const status = readString(value, "result.status");
|
|
17477
|
+
if (!STATUSES.has(status)) {
|
|
17478
|
+
throw new Error(`Unsupported reporter test status: ${status}.`);
|
|
17222
17479
|
}
|
|
17480
|
+
return status;
|
|
17223
17481
|
}
|
|
17224
|
-
|
|
17225
|
-
|
|
17226
|
-
|
|
17227
|
-
|
|
17228
|
-
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
17234
|
-
|
|
17235
|
-
|
|
17236
|
-
console.log(JSON.stringify({ ok: true, indexPath: indexPath2, ...snapshot }, null, 2));
|
|
17237
|
-
return;
|
|
17238
|
-
}
|
|
17239
|
-
console.log(`Built trace index: ${indexPath2}`);
|
|
17240
|
-
console.log(`Entries: ${snapshot.entries.length}`);
|
|
17241
|
-
if (snapshot.warnings.length > 0) {
|
|
17242
|
-
for (const warning of snapshot.warnings) {
|
|
17243
|
-
console.log(`warning: ${warning}`);
|
|
17244
|
-
}
|
|
17245
|
-
}
|
|
17246
|
-
} catch (e) {
|
|
17247
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
17248
|
-
console.error(`[AgentInspect] index build failed: ${msg}`);
|
|
17249
|
-
process.exitCode = 1;
|
|
17482
|
+
function readArtifact(value, index) {
|
|
17483
|
+
if (!isObject(value)) throw new Error(`manifest.artifacts[${index}] must be an object.`);
|
|
17484
|
+
const kind = readString(value.kind, `manifest.artifacts[${index}].kind`);
|
|
17485
|
+
const format = readString(value.format, `manifest.artifacts[${index}].format`);
|
|
17486
|
+
const redactionProfile = readString(
|
|
17487
|
+
value.redactionProfile,
|
|
17488
|
+
`manifest.artifacts[${index}].redactionProfile`
|
|
17489
|
+
);
|
|
17490
|
+
if (!ARTIFACT_KINDS.has(kind)) throw new Error(`Unsupported artifact kind: ${kind}.`);
|
|
17491
|
+
if (!ARTIFACT_FORMATS.has(format)) throw new Error(`Unsupported artifact format: ${format}.`);
|
|
17492
|
+
if (!REDACTION_PROFILES2.has(redactionProfile)) {
|
|
17493
|
+
throw new Error(`Unsupported artifact redaction profile: ${redactionProfile}.`);
|
|
17250
17494
|
}
|
|
17251
|
-
}
|
|
17252
|
-
|
|
17253
|
-
|
|
17254
|
-
|
|
17255
|
-
|
|
17256
|
-
|
|
17257
|
-
|
|
17258
|
-
|
|
17259
|
-
|
|
17260
|
-
|
|
17261
|
-
|
|
17262
|
-
|
|
17263
|
-
|
|
17264
|
-
|
|
17265
|
-
|
|
17495
|
+
const artifactPath = readString(value.path, `manifest.artifacts[${index}].path`);
|
|
17496
|
+
const pathCheck = validateReporterArtifactPath({
|
|
17497
|
+
outputDir: process.cwd(),
|
|
17498
|
+
relativePath: artifactPath
|
|
17499
|
+
});
|
|
17500
|
+
if (!pathCheck.ok || pathCheck.relativePath === void 0) {
|
|
17501
|
+
throw new Error(`Unsafe reporter artifact path: ${artifactPath}.`);
|
|
17502
|
+
}
|
|
17503
|
+
return {
|
|
17504
|
+
kind,
|
|
17505
|
+
path: pathCheck.relativePath,
|
|
17506
|
+
format,
|
|
17507
|
+
redactionProfile
|
|
17508
|
+
};
|
|
17509
|
+
}
|
|
17510
|
+
function readArtifacts(value, label) {
|
|
17511
|
+
if (value === void 0) return [];
|
|
17512
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
17513
|
+
return value.map((item, index) => readArtifact(item, index));
|
|
17514
|
+
}
|
|
17515
|
+
function readDiagnosticsCount(value, label) {
|
|
17516
|
+
if (value === void 0) return 0;
|
|
17517
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
17518
|
+
return value.length;
|
|
17519
|
+
}
|
|
17520
|
+
function readResult(value, index) {
|
|
17521
|
+
if (!isObject(value)) throw new Error(`manifest.results[${index}] must be an object.`);
|
|
17522
|
+
const file = readOptionalString(value.file);
|
|
17523
|
+
const tracePath = readOptionalString(value.tracePath);
|
|
17524
|
+
return {
|
|
17525
|
+
testId: readString(value.testId, `manifest.results[${index}].testId`),
|
|
17526
|
+
name: readString(value.name, `manifest.results[${index}].name`),
|
|
17527
|
+
...file === void 0 ? {} : { file },
|
|
17528
|
+
status: readStatus(value.status),
|
|
17529
|
+
...tracePath === void 0 ? {} : { tracePath },
|
|
17530
|
+
artifacts: readArtifacts(value.artifacts, `manifest.results[${index}].artifacts`),
|
|
17531
|
+
diagnostics: readDiagnosticsCount(
|
|
17532
|
+
value.diagnostics,
|
|
17533
|
+
`manifest.results[${index}].diagnostics`
|
|
17534
|
+
)
|
|
17535
|
+
};
|
|
17536
|
+
}
|
|
17537
|
+
function readManifestDocument(value) {
|
|
17538
|
+
if (!isObject(value)) throw new Error("Reporter manifest file must contain a JSON object.");
|
|
17539
|
+
const candidate = isObject(value.manifest) ? value.manifest : value;
|
|
17540
|
+
if (!isObject(candidate)) throw new Error("Reporter manifest must be a JSON object.");
|
|
17541
|
+
const schemaVersion = readString(candidate.schemaVersion, "manifest.schemaVersion");
|
|
17542
|
+
if (schemaVersion !== "0.1") {
|
|
17543
|
+
throw new Error(`Unsupported reporter manifest schemaVersion: ${schemaVersion}.`);
|
|
17544
|
+
}
|
|
17545
|
+
if (!Array.isArray(candidate.results)) {
|
|
17546
|
+
throw new Error("manifest.results must be an array.");
|
|
17547
|
+
}
|
|
17548
|
+
const artifacts = readArtifacts(candidate.artifacts, "manifest.artifacts");
|
|
17549
|
+
const results = candidate.results.map((item, index) => readResult(item, index));
|
|
17550
|
+
const diagnostics = readDiagnosticsCount(candidate.diagnostics, "manifest.diagnostics");
|
|
17551
|
+
const manifest = {
|
|
17552
|
+
framework: readFramework(candidate.framework),
|
|
17553
|
+
generatedAt: readString(candidate.generatedAt, "manifest.generatedAt"),
|
|
17554
|
+
results,
|
|
17555
|
+
artifacts
|
|
17556
|
+
};
|
|
17557
|
+
return {
|
|
17558
|
+
packageName: readOptionalString(value.package),
|
|
17559
|
+
manifest,
|
|
17560
|
+
diagnostics
|
|
17561
|
+
};
|
|
17562
|
+
}
|
|
17563
|
+
function cwdRelative(filePath) {
|
|
17564
|
+
const relative = path19__default.default.relative(process.cwd(), path19__default.default.resolve(filePath)).replace(/\\/g, "/");
|
|
17565
|
+
if (relative === "" || relative.startsWith("../") || path19__default.default.isAbsolute(relative)) {
|
|
17566
|
+
return path19__default.default.basename(filePath);
|
|
17567
|
+
}
|
|
17568
|
+
return relative;
|
|
17569
|
+
}
|
|
17570
|
+
async function readReporterManifest(filePath) {
|
|
17571
|
+
const absolute = path19__default.default.resolve(filePath);
|
|
17572
|
+
const raw = await promises.readFile(absolute, "utf-8");
|
|
17573
|
+
const document = readManifestDocument(JSON.parse(raw));
|
|
17574
|
+
const manifest = document.manifest;
|
|
17575
|
+
const results = manifest.results.map((result) => ({
|
|
17576
|
+
testId: safeText(result.testId),
|
|
17577
|
+
name: safeText(result.name),
|
|
17578
|
+
...result.file === void 0 ? {} : { file: safeText(path19__default.default.basename(result.file)) },
|
|
17579
|
+
status: result.status,
|
|
17580
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path19__default.default.basename(result.tracePath)) },
|
|
17581
|
+
artifacts: result.artifacts,
|
|
17582
|
+
diagnostics: result.diagnostics
|
|
17583
|
+
}));
|
|
17584
|
+
return {
|
|
17585
|
+
...document.packageName === void 0 ? {} : { packageName: document.packageName },
|
|
17586
|
+
manifestFile: cwdRelative(absolute),
|
|
17587
|
+
framework: manifest.framework,
|
|
17588
|
+
generatedAt: manifest.generatedAt,
|
|
17589
|
+
results,
|
|
17590
|
+
artifacts: manifest.artifacts,
|
|
17591
|
+
diagnostics: document.diagnostics
|
|
17592
|
+
};
|
|
17593
|
+
}
|
|
17594
|
+
function summarize3(manifests) {
|
|
17595
|
+
const summary = {
|
|
17596
|
+
manifests: manifests.length,
|
|
17597
|
+
tests: 0,
|
|
17598
|
+
failed: 0,
|
|
17599
|
+
passed: 0,
|
|
17600
|
+
skipped: 0,
|
|
17601
|
+
todo: 0,
|
|
17602
|
+
artifacts: 0,
|
|
17603
|
+
diagnostics: 0
|
|
17604
|
+
};
|
|
17605
|
+
for (const manifest of manifests) {
|
|
17606
|
+
summary.artifacts += manifest.artifacts.length;
|
|
17607
|
+
summary.diagnostics += manifest.diagnostics;
|
|
17608
|
+
for (const result of manifest.results) {
|
|
17609
|
+
summary.tests += 1;
|
|
17610
|
+
if (result.status === "failed") summary.failed += 1;
|
|
17611
|
+
else if (result.status === "passed") summary.passed += 1;
|
|
17612
|
+
else if (result.status === "skipped") summary.skipped += 1;
|
|
17613
|
+
else summary.todo += 1;
|
|
17614
|
+
summary.artifacts += result.artifacts.length;
|
|
17615
|
+
summary.diagnostics += result.diagnostics;
|
|
17266
17616
|
}
|
|
17267
|
-
|
|
17268
|
-
|
|
17269
|
-
|
|
17270
|
-
|
|
17271
|
-
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
17280
|
-
|
|
17617
|
+
}
|
|
17618
|
+
return {
|
|
17619
|
+
status: summary.failed > 0 ? "failed" : summary.diagnostics > 0 ? "warning" : "ok",
|
|
17620
|
+
manifests,
|
|
17621
|
+
summary,
|
|
17622
|
+
note: NOTE2
|
|
17623
|
+
};
|
|
17624
|
+
}
|
|
17625
|
+
function markdownCell(value) {
|
|
17626
|
+
return safeText(String(value ?? "unknown")).replaceAll("|", "\\|").replace(/\r?\n/g, " ");
|
|
17627
|
+
}
|
|
17628
|
+
function renderMarkdown2(result) {
|
|
17629
|
+
const lines = [
|
|
17630
|
+
"# AgentInspect CI Summary",
|
|
17631
|
+
"",
|
|
17632
|
+
NOTE2,
|
|
17633
|
+
"",
|
|
17634
|
+
"| Field | Value |",
|
|
17635
|
+
"| --- | --- |",
|
|
17636
|
+
`| Status | ${result.status} |`,
|
|
17637
|
+
`| Manifests | ${result.summary.manifests} |`,
|
|
17638
|
+
`| Tests | ${result.summary.tests} |`,
|
|
17639
|
+
`| Failed | ${result.summary.failed} |`,
|
|
17640
|
+
`| Passed | ${result.summary.passed} |`,
|
|
17641
|
+
`| Skipped | ${result.summary.skipped} |`,
|
|
17642
|
+
`| Todo | ${result.summary.todo} |`,
|
|
17643
|
+
`| Artifacts | ${result.summary.artifacts} |`,
|
|
17644
|
+
`| Diagnostics | ${result.summary.diagnostics} |`,
|
|
17645
|
+
"",
|
|
17646
|
+
"## Tests",
|
|
17647
|
+
"",
|
|
17648
|
+
"| Framework | Status | Test | File | Trace | Artifacts |",
|
|
17649
|
+
"| --- | --- | --- | --- | --- | --- |"
|
|
17650
|
+
];
|
|
17651
|
+
const rows = result.manifests.flatMap(
|
|
17652
|
+
(manifest) => manifest.results.map((test) => ({
|
|
17653
|
+
framework: manifest.framework,
|
|
17654
|
+
test
|
|
17655
|
+
}))
|
|
17656
|
+
);
|
|
17657
|
+
if (rows.length === 0) {
|
|
17658
|
+
lines.push("| unknown | unknown | No tests found | unknown | unknown | 0 |");
|
|
17659
|
+
} else {
|
|
17660
|
+
for (const row of rows) {
|
|
17661
|
+
lines.push(
|
|
17662
|
+
`| ${markdownCell(row.framework)} | ${markdownCell(row.test.status)} | ${markdownCell(row.test.name)} | ${markdownCell(row.test.file)} | ${markdownCell(row.test.tracePath)} | ${row.test.artifacts.length} |`
|
|
17663
|
+
);
|
|
17281
17664
|
}
|
|
17282
|
-
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
17289
|
-
|
|
17665
|
+
}
|
|
17666
|
+
lines.push("", "## Manifests", "", "| Framework | File | Generated | Artifacts |", "| --- | --- | --- | --- |");
|
|
17667
|
+
for (const manifest of result.manifests) {
|
|
17668
|
+
lines.push(
|
|
17669
|
+
`| ${markdownCell(manifest.framework)} | ${markdownCell(manifest.manifestFile)} | ${markdownCell(manifest.generatedAt)} | ${manifest.artifacts.length} |`
|
|
17670
|
+
);
|
|
17671
|
+
}
|
|
17672
|
+
lines.push("", "## Artifacts", "", "| Framework | Kind | Path | Format | Profile |", "| --- | --- | --- | --- | --- |");
|
|
17673
|
+
const artifacts = result.manifests.flatMap(
|
|
17674
|
+
(manifest) => manifest.artifacts.map((artifact) => ({ framework: manifest.framework, artifact }))
|
|
17675
|
+
);
|
|
17676
|
+
if (artifacts.length === 0) {
|
|
17677
|
+
lines.push("| unknown | unknown | No artifacts found | unknown | unknown |");
|
|
17678
|
+
} else {
|
|
17679
|
+
for (const row of artifacts) {
|
|
17680
|
+
lines.push(
|
|
17681
|
+
`| ${markdownCell(row.framework)} | ${markdownCell(row.artifact.kind)} | ${markdownCell(row.artifact.path)} | ${markdownCell(row.artifact.format)} | ${markdownCell(row.artifact.redactionProfile)} |`
|
|
17682
|
+
);
|
|
17290
17683
|
}
|
|
17291
|
-
} catch (e) {
|
|
17292
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
17293
|
-
console.error(`[AgentInspect] index status failed: ${msg}`);
|
|
17294
|
-
process.exitCode = 1;
|
|
17295
17684
|
}
|
|
17685
|
+
lines.push("");
|
|
17686
|
+
return `${lines.join("\n")}
|
|
17687
|
+
`;
|
|
17296
17688
|
}
|
|
17297
|
-
|
|
17689
|
+
function safeText(value) {
|
|
17690
|
+
const compact = value.replace(/\s+/g, " ").trim();
|
|
17691
|
+
const redacted = compact.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(
|
|
17692
|
+
/\b(?:api[_-]?key|authorization|token|secret|password)\s*[:=]\s*[^,\s]+/gi,
|
|
17693
|
+
"$1=[REDACTED]"
|
|
17694
|
+
);
|
|
17695
|
+
if (redacted.length <= MAX_TEXT) return redacted;
|
|
17696
|
+
return `${redacted.slice(0, MAX_TEXT - 12)}...[truncated]`;
|
|
17697
|
+
}
|
|
17698
|
+
async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
17699
|
+
if (manifestPaths.length === 0) {
|
|
17700
|
+
console.error("At least one reporter manifest path is required.");
|
|
17701
|
+
process.exitCode = 1;
|
|
17702
|
+
return;
|
|
17703
|
+
}
|
|
17704
|
+
let result;
|
|
17298
17705
|
try {
|
|
17299
|
-
const
|
|
17300
|
-
const
|
|
17301
|
-
|
|
17302
|
-
if (options.json) {
|
|
17303
|
-
console.log(JSON.stringify({ ok: true, removed: indexPath2 }, null, 2));
|
|
17304
|
-
return;
|
|
17706
|
+
const manifests = [];
|
|
17707
|
+
for (const manifestPath of manifestPaths) {
|
|
17708
|
+
manifests.push(await readReporterManifest(manifestPath));
|
|
17305
17709
|
}
|
|
17306
|
-
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17710
|
+
manifests.sort((a, b) => a.manifestFile.localeCompare(b.manifestFile));
|
|
17711
|
+
result = summarize3(manifests);
|
|
17712
|
+
} catch (error) {
|
|
17713
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17714
|
+
console.error(`[AgentInspect] ci-summary failed: ${message}`);
|
|
17310
17715
|
process.exitCode = 1;
|
|
17716
|
+
return;
|
|
17717
|
+
}
|
|
17718
|
+
const markdown = renderMarkdown2(result);
|
|
17719
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path19__default.default.resolve(options.output.trim()) : void 0;
|
|
17720
|
+
if (outputPath !== void 0) {
|
|
17721
|
+
await promises.mkdir(path19__default.default.dirname(outputPath), { recursive: true });
|
|
17722
|
+
await promises.writeFile(outputPath, markdown, "utf-8");
|
|
17311
17723
|
}
|
|
17724
|
+
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
17725
|
+
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
17726
|
+
const summaryPath = path19__default.default.resolve(summaryTarget);
|
|
17727
|
+
await promises.mkdir(path19__default.default.dirname(summaryPath), { recursive: true });
|
|
17728
|
+
await promises.appendFile(summaryPath, `
|
|
17729
|
+
${markdown}`, "utf-8");
|
|
17730
|
+
}
|
|
17731
|
+
if (options.json === true) {
|
|
17732
|
+
console.log(writeJson5(result).trimEnd());
|
|
17733
|
+
} else if (outputPath !== void 0) {
|
|
17734
|
+
console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
|
|
17735
|
+
console.log(`Status: ${result.status}`);
|
|
17736
|
+
} else {
|
|
17737
|
+
console.log(markdown.trimEnd());
|
|
17738
|
+
}
|
|
17739
|
+
}
|
|
17740
|
+
var CONFIG_FILE = "agent-inspect.config.ts";
|
|
17741
|
+
var TRACE_DIR = ".agent-inspect";
|
|
17742
|
+
var GITKEEP = ".agent-inspect/.gitkeep";
|
|
17743
|
+
function normalizeFramework(value) {
|
|
17744
|
+
const raw = (value ?? "custom").trim();
|
|
17745
|
+
if (raw === "ai-sdk" || raw === "openai-agents" || raw === "langchain" || raw === "custom") {
|
|
17746
|
+
return raw;
|
|
17747
|
+
}
|
|
17748
|
+
throw new Error(
|
|
17749
|
+
"Unsupported --framework value. Use ai-sdk, openai-agents, langchain, or custom."
|
|
17750
|
+
);
|
|
17751
|
+
}
|
|
17752
|
+
function configTemplate(framework) {
|
|
17753
|
+
const base = `/**
|
|
17754
|
+
* AgentInspect local config (metadata-only capture by default).
|
|
17755
|
+
* See https://github.com/rajudandigam/agent-inspect/blob/main/docs/SAFE-TRACE-SHARING.md
|
|
17756
|
+
*/
|
|
17757
|
+
export const agentInspectConfig = {
|
|
17758
|
+
traceDir: ".agent-inspect",
|
|
17759
|
+
enabled: process.env.AGENT_INSPECT !== "0",
|
|
17760
|
+
redactionProfile: "local" as const,
|
|
17761
|
+
};
|
|
17762
|
+
`;
|
|
17763
|
+
if (framework === "custom") return base;
|
|
17764
|
+
return `${base}
|
|
17765
|
+
export const framework = "${framework}" as const;
|
|
17766
|
+
`;
|
|
17312
17767
|
}
|
|
17768
|
+
function demoTemplate(framework) {
|
|
17769
|
+
switch (framework) {
|
|
17770
|
+
case "ai-sdk":
|
|
17771
|
+
return `/**
|
|
17772
|
+
* AI SDK starter \u2014 metadata-only telemetry (no real model calls in this demo).
|
|
17773
|
+
* Install: npm install agent-inspect @agent-inspect/ai-sdk ai
|
|
17774
|
+
*/
|
|
17775
|
+
import { inspectRun, step } from "agent-inspect";
|
|
17313
17776
|
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
17777
|
+
async function main() {
|
|
17778
|
+
await inspectRun("ai-sdk-demo", async () => {
|
|
17779
|
+
await step.tool("mock-generate", async () => ({ text: "ok" }));
|
|
17780
|
+
}, { traceDir: ".agent-inspect", silent: true });
|
|
17781
|
+
console.log("Trace written to .agent-inspect/");
|
|
17319
17782
|
}
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
17329
|
-
|
|
17783
|
+
|
|
17784
|
+
main().catch((error) => {
|
|
17785
|
+
console.error(error);
|
|
17786
|
+
process.exitCode = 1;
|
|
17787
|
+
});
|
|
17788
|
+
`;
|
|
17789
|
+
case "openai-agents":
|
|
17790
|
+
return `/**
|
|
17791
|
+
* OpenAI Agents starter \u2014 use @agent-inspect/openai-agents for local-only processors.
|
|
17792
|
+
* This demo uses manual steps (no API keys).
|
|
17793
|
+
*/
|
|
17794
|
+
import { inspectRun, step } from "agent-inspect";
|
|
17795
|
+
|
|
17796
|
+
async function main() {
|
|
17797
|
+
await inspectRun("openai-agents-demo", async () => {
|
|
17798
|
+
await step.tool("mock-agent-run", async () => "ok");
|
|
17799
|
+
}, { traceDir: ".agent-inspect", silent: true });
|
|
17800
|
+
console.log("Trace written to .agent-inspect/");
|
|
17801
|
+
}
|
|
17802
|
+
|
|
17803
|
+
main().catch((error) => {
|
|
17804
|
+
console.error(error);
|
|
17805
|
+
process.exitCode = 1;
|
|
17806
|
+
});
|
|
17807
|
+
`;
|
|
17808
|
+
case "langchain":
|
|
17809
|
+
return `/**
|
|
17810
|
+
* LangChain starter \u2014 wire @agent-inspect/langchain callbacks in your app.
|
|
17811
|
+
* This demo uses manual steps (no API keys).
|
|
17812
|
+
*/
|
|
17813
|
+
import { inspectRun, step } from "agent-inspect";
|
|
17814
|
+
|
|
17815
|
+
async function main() {
|
|
17816
|
+
await inspectRun("langchain-demo", async () => {
|
|
17817
|
+
await step.tool("mock-chain", async () => "ok");
|
|
17818
|
+
}, { traceDir: ".agent-inspect", silent: true });
|
|
17819
|
+
console.log("Trace written to .agent-inspect/");
|
|
17820
|
+
}
|
|
17821
|
+
|
|
17822
|
+
main().catch((error) => {
|
|
17823
|
+
console.error(error);
|
|
17824
|
+
process.exitCode = 1;
|
|
17825
|
+
});
|
|
17826
|
+
`;
|
|
17827
|
+
default:
|
|
17828
|
+
return `import { observe } from "agent-inspect";
|
|
17829
|
+
|
|
17830
|
+
class DemoAgent {
|
|
17831
|
+
async run(input: { question: string }) {
|
|
17832
|
+
return { answer: \`Echo: \${input.question}\` };
|
|
17833
|
+
}
|
|
17834
|
+
}
|
|
17835
|
+
|
|
17836
|
+
const agent = observe(new DemoAgent(), {
|
|
17837
|
+
traceDir: ".agent-inspect",
|
|
17838
|
+
silent: true,
|
|
17839
|
+
});
|
|
17840
|
+
|
|
17841
|
+
await agent.run({ question: "hello" });
|
|
17842
|
+
console.log("Trace written to .agent-inspect/");
|
|
17843
|
+
`;
|
|
17844
|
+
}
|
|
17845
|
+
}
|
|
17846
|
+
function githubWorkflowTemplate() {
|
|
17847
|
+
return `name: AgentInspect artifacts
|
|
17848
|
+
|
|
17849
|
+
on:
|
|
17850
|
+
workflow_dispatch:
|
|
17851
|
+
push:
|
|
17852
|
+
branches: [main]
|
|
17853
|
+
|
|
17854
|
+
jobs:
|
|
17855
|
+
trace-artifacts:
|
|
17856
|
+
runs-on: ubuntu-latest
|
|
17857
|
+
steps:
|
|
17858
|
+
- uses: actions/checkout@v4
|
|
17859
|
+
- uses: actions/setup-node@v4
|
|
17860
|
+
with:
|
|
17861
|
+
node-version: "22"
|
|
17862
|
+
- run: npm ci
|
|
17863
|
+
- run: npm test
|
|
17864
|
+
- name: Upload AgentInspect traces
|
|
17865
|
+
if: always()
|
|
17866
|
+
uses: actions/upload-artifact@v4
|
|
17867
|
+
with:
|
|
17868
|
+
name: agent-inspect-traces
|
|
17869
|
+
path: .agent-inspect/**/*.jsonl
|
|
17870
|
+
if-no-files-found: ignore
|
|
17871
|
+
`;
|
|
17872
|
+
}
|
|
17873
|
+
async function planInit(options = {}) {
|
|
17874
|
+
const framework = normalizeFramework(options.framework);
|
|
17875
|
+
const cwd = path19__default.default.resolve(options.cwd ?? process.cwd());
|
|
17876
|
+
const demoPath = framework === "custom" ? path19__default.default.join("examples", "agent-inspect-demo.mjs") : path19__default.default.join("examples", `agent-inspect-${framework}-demo.mjs`);
|
|
17877
|
+
const candidates = [
|
|
17878
|
+
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
17879
|
+
{ rel: GITKEEP, content: "" },
|
|
17880
|
+
{ rel: demoPath, content: demoTemplate(framework) }
|
|
17881
|
+
];
|
|
17882
|
+
if (options.ci === "github") {
|
|
17883
|
+
candidates.push({
|
|
17884
|
+
rel: ".github/workflows/agent-inspect-artifacts.yml",
|
|
17885
|
+
content: githubWorkflowTemplate()
|
|
17886
|
+
});
|
|
17887
|
+
}
|
|
17888
|
+
const files = [];
|
|
17889
|
+
for (const candidate of candidates) {
|
|
17890
|
+
const abs = path19__default.default.join(cwd, candidate.rel);
|
|
17891
|
+
try {
|
|
17892
|
+
await promises.access(abs);
|
|
17893
|
+
files.push({
|
|
17894
|
+
path: candidate.rel,
|
|
17895
|
+
action: "skip",
|
|
17896
|
+
reason: "file already exists"
|
|
17897
|
+
});
|
|
17898
|
+
} catch (error) {
|
|
17899
|
+
if (error.code !== "ENOENT") throw error;
|
|
17900
|
+
files.push({ path: candidate.rel, action: "create" });
|
|
17330
17901
|
}
|
|
17331
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
17332
|
-
console.error(`[AgentInspect] failed to load ${PACKAGE}: ${msg}`);
|
|
17333
|
-
process.exitCode = 1;
|
|
17334
|
-
return null;
|
|
17335
17902
|
}
|
|
17903
|
+
return { framework, ...options.ci ? { ci: options.ci } : {}, files };
|
|
17336
17904
|
}
|
|
17337
|
-
function
|
|
17338
|
-
|
|
17339
|
-
const
|
|
17340
|
-
|
|
17341
|
-
|
|
17905
|
+
async function writePlannedFiles(plan, cwd, options) {
|
|
17906
|
+
const written = [];
|
|
17907
|
+
for (const entry of plan.files) {
|
|
17908
|
+
if (entry.action === "skip") {
|
|
17909
|
+
continue;
|
|
17910
|
+
}
|
|
17911
|
+
const abs = path19__default.default.join(cwd, entry.path);
|
|
17912
|
+
if (options.dryRun) {
|
|
17913
|
+
written.push(entry.path);
|
|
17914
|
+
continue;
|
|
17915
|
+
}
|
|
17916
|
+
await promises.mkdir(path19__default.default.dirname(abs), { recursive: true });
|
|
17917
|
+
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
|
|
17918
|
+
await promises.writeFile(abs, content, "utf-8");
|
|
17919
|
+
written.push(entry.path);
|
|
17342
17920
|
}
|
|
17343
|
-
return
|
|
17921
|
+
return written;
|
|
17344
17922
|
}
|
|
17345
|
-
async function
|
|
17346
|
-
|
|
17923
|
+
async function initCommand(options = {}) {
|
|
17924
|
+
const cwd = path19__default.default.resolve(options.cwd ?? process.cwd());
|
|
17347
17925
|
try {
|
|
17348
|
-
const
|
|
17349
|
-
|
|
17350
|
-
|
|
17351
|
-
|
|
17352
|
-
|
|
17353
|
-
|
|
17354
|
-
|
|
17926
|
+
const plan = await planInit({ ...options, cwd });
|
|
17927
|
+
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
17928
|
+
const skipped = plan.files.filter((file) => file.action === "skip");
|
|
17929
|
+
if (options.json) {
|
|
17930
|
+
const payload = {
|
|
17931
|
+
ok: true,
|
|
17932
|
+
version,
|
|
17933
|
+
framework: plan.framework,
|
|
17934
|
+
ci: plan.ci ?? null,
|
|
17935
|
+
dryRun: options.dryRun === true,
|
|
17936
|
+
planned: plan.files,
|
|
17937
|
+
wouldWrite: options.dryRun ? toWrite : void 0
|
|
17938
|
+
};
|
|
17939
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
17940
|
+
if (options.dryRun) return;
|
|
17941
|
+
}
|
|
17942
|
+
const written = await writePlannedFiles(plan, cwd, options);
|
|
17943
|
+
if (!options.json) {
|
|
17944
|
+
console.log("AgentInspect init");
|
|
17945
|
+
console.log(`Framework: ${plan.framework}`);
|
|
17946
|
+
console.log(`Trace directory: ${TRACE_DIR}/`);
|
|
17947
|
+
if (options.dryRun) {
|
|
17948
|
+
console.log("Dry run \u2014 would create:");
|
|
17949
|
+
for (const file of toWrite) console.log(`- ${file}`);
|
|
17950
|
+
for (const file of skipped) {
|
|
17951
|
+
console.log(`- ${file.path} (skip: ${file.reason ?? "exists"})`);
|
|
17952
|
+
}
|
|
17953
|
+
return;
|
|
17954
|
+
}
|
|
17955
|
+
console.log("Created:");
|
|
17956
|
+
for (const file of written) console.log(`- ${file}`);
|
|
17957
|
+
for (const file of skipped) {
|
|
17958
|
+
console.log(`- ${file.path} (skipped: ${file.reason ?? "exists"})`);
|
|
17355
17959
|
}
|
|
17960
|
+
console.log("\nNext: run your demo, then `npx agent-inspect list --dir .agent-inspect`");
|
|
17961
|
+
console.log("No dependencies were installed. Add packages manually when ready.");
|
|
17356
17962
|
}
|
|
17357
|
-
} catch {
|
|
17358
|
-
|
|
17359
|
-
return newest;
|
|
17360
|
-
}
|
|
17361
|
-
async function indexSqliteBuildCommand(options = {}) {
|
|
17362
|
-
const mod = await loadIndexSqlite();
|
|
17363
|
-
if (!mod) return;
|
|
17364
|
-
const result = await mod.buildIndex({
|
|
17365
|
-
traceDir: options.dir,
|
|
17366
|
-
maxRuns: parsePositiveInt(options.maxRuns, "--max-runs")
|
|
17367
|
-
});
|
|
17368
|
-
if (options.json) {
|
|
17369
|
-
console.log(JSON.stringify({ ok: true, ...result }, null, 2));
|
|
17370
|
-
return;
|
|
17371
|
-
}
|
|
17372
|
-
console.log(`Built SQLite index: ${result.dbPath}`);
|
|
17373
|
-
console.log(`Runs: ${result.runs} Steps: ${result.steps} Errors: ${result.errors}`);
|
|
17374
|
-
for (const warning of result.warnings) console.log(`warning: ${warning}`);
|
|
17375
|
-
}
|
|
17376
|
-
async function indexSqliteStatusCommand(options = {}) {
|
|
17377
|
-
const mod = await loadIndexSqlite();
|
|
17378
|
-
if (!mod) return;
|
|
17379
|
-
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
17380
|
-
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
17381
|
-
const status = mod.indexStatus(dbPath);
|
|
17382
|
-
const stale = mod.isIndexStale(dbPath, await newestTraceMtimeMs2(traceDir));
|
|
17383
|
-
if (options.json) {
|
|
17384
|
-
console.log(JSON.stringify({ ok: true, traceDir, stale, ...status }, null, 2));
|
|
17385
|
-
return;
|
|
17386
|
-
}
|
|
17387
|
-
if (!status.exists) {
|
|
17388
|
-
console.log(`No SQLite index at ${dbPath}`);
|
|
17389
|
-
console.log("Run: agent-inspect index sqlite build");
|
|
17390
|
-
return;
|
|
17391
|
-
}
|
|
17392
|
-
console.log(`Index: ${status.dbPath}`);
|
|
17393
|
-
console.log(`Healthy: ${status.healthy ? "yes" : "no"}`);
|
|
17394
|
-
console.log(`Built: ${status.builtAt ?? "unknown"}`);
|
|
17395
|
-
console.log(`Runs: ${status.runs} Steps: ${status.steps}`);
|
|
17396
|
-
console.log(`Stale: ${stale ? "yes" : "no"}`);
|
|
17397
|
-
}
|
|
17398
|
-
async function indexSqliteQueryCommand(options = {}) {
|
|
17399
|
-
const mod = await loadIndexSqlite();
|
|
17400
|
-
if (!mod) return;
|
|
17401
|
-
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
17402
|
-
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
17403
|
-
const status = mod.indexStatus(dbPath);
|
|
17404
|
-
if (!status.exists || !status.healthy) {
|
|
17963
|
+
} catch (error) {
|
|
17964
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
17405
17965
|
if (options.json) {
|
|
17406
|
-
console.log(JSON.stringify({ ok: false,
|
|
17966
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
17407
17967
|
} else {
|
|
17408
|
-
console.
|
|
17968
|
+
console.error(`[AgentInspect] init failed: ${msg}`);
|
|
17409
17969
|
}
|
|
17410
17970
|
process.exitCode = 1;
|
|
17411
|
-
return;
|
|
17412
|
-
}
|
|
17413
|
-
const rows = mod.queryRuns(dbPath, {
|
|
17414
|
-
status: options.status,
|
|
17415
|
-
sessionId: options.session,
|
|
17416
|
-
name: options.name,
|
|
17417
|
-
kind: options.kind,
|
|
17418
|
-
tool: options.tool,
|
|
17419
|
-
limit: parsePositiveInt(options.limit, "--limit")
|
|
17420
|
-
});
|
|
17421
|
-
if (options.json) {
|
|
17422
|
-
console.log(JSON.stringify({ ok: true, count: rows.length, runs: rows }, null, 2));
|
|
17423
|
-
return;
|
|
17424
|
-
}
|
|
17425
|
-
if (rows.length === 0) {
|
|
17426
|
-
console.log("No matching runs.");
|
|
17427
|
-
return;
|
|
17428
|
-
}
|
|
17429
|
-
for (const run of rows) {
|
|
17430
|
-
const parts = [
|
|
17431
|
-
run.runId,
|
|
17432
|
-
run.status ?? "unknown",
|
|
17433
|
-
run.name ?? "",
|
|
17434
|
-
run.durationMs != null ? `${run.durationMs}ms` : ""
|
|
17435
|
-
].filter((p) => p !== "");
|
|
17436
|
-
console.log(parts.join(" "));
|
|
17437
|
-
}
|
|
17438
|
-
}
|
|
17439
|
-
async function indexSqliteCleanCommand(options = {}) {
|
|
17440
|
-
const mod = await loadIndexSqlite();
|
|
17441
|
-
if (!mod) return;
|
|
17442
|
-
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
17443
|
-
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
17444
|
-
await mod.cleanIndex(dbPath);
|
|
17445
|
-
if (options.json) {
|
|
17446
|
-
console.log(JSON.stringify({ ok: true, removed: dbPath }, null, 2));
|
|
17447
|
-
return;
|
|
17448
17971
|
}
|
|
17449
|
-
console.log(`Removed SQLite index: ${dbPath}`);
|
|
17450
17972
|
}
|
|
17451
|
-
|
|
17452
|
-
|
|
17453
|
-
|
|
17454
|
-
|
|
17455
|
-
|
|
17456
|
-
|
|
17457
|
-
// packages/core/src/workspace/manifest.ts
|
|
17458
|
-
var DEFAULT_WORKSPACE_LAYOUT = {
|
|
17459
|
-
traceDirs: ["runs"],
|
|
17460
|
-
reportsDir: "reports",
|
|
17461
|
-
artifactsDir: "artifacts",
|
|
17462
|
-
bundlesDir: "bundles",
|
|
17463
|
-
notesDir: "notes"
|
|
17973
|
+
var OPTIONAL_PACKAGES = {
|
|
17974
|
+
custom: [],
|
|
17975
|
+
"ai-sdk": ["@agent-inspect/ai-sdk"],
|
|
17976
|
+
"openai-agents": ["@agent-inspect/openai-agents"],
|
|
17977
|
+
langchain: ["@agent-inspect/langchain"]
|
|
17464
17978
|
};
|
|
17465
|
-
|
|
17466
|
-
|
|
17467
|
-
|
|
17468
|
-
|
|
17469
|
-
|
|
17470
|
-
|
|
17471
|
-
|
|
17472
|
-
|
|
17473
|
-
|
|
17474
|
-
|
|
17475
|
-
const index = {
|
|
17476
|
-
enabled: options.index?.enabled ?? false,
|
|
17477
|
-
type: options.index?.type ?? "none",
|
|
17478
|
-
...options.index?.path !== void 0 ? { path: options.index.path } : {}
|
|
17479
|
-
};
|
|
17480
|
-
return {
|
|
17481
|
-
schemaVersion: WORKSPACE_SCHEMA_VERSION,
|
|
17482
|
-
project,
|
|
17483
|
-
createdAt: options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
17484
|
-
traceDirs: options.traceDirs ? [...options.traceDirs] : [...DEFAULT_WORKSPACE_LAYOUT.traceDirs],
|
|
17485
|
-
reportsDir: options.reportsDir ?? DEFAULT_WORKSPACE_LAYOUT.reportsDir,
|
|
17486
|
-
artifactsDir: options.artifactsDir ?? DEFAULT_WORKSPACE_LAYOUT.artifactsDir,
|
|
17487
|
-
bundlesDir: options.bundlesDir ?? DEFAULT_WORKSPACE_LAYOUT.bundlesDir,
|
|
17488
|
-
notesDir: options.notesDir ?? DEFAULT_WORKSPACE_LAYOUT.notesDir,
|
|
17489
|
-
redactionProfile: options.redactionProfile ?? DEFAULT_REDACTION_PROFILE,
|
|
17490
|
-
index
|
|
17491
|
-
};
|
|
17492
|
-
}
|
|
17493
|
-
function isPlainObject(value) {
|
|
17494
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17495
|
-
}
|
|
17496
|
-
function isSafeRelativeWorkspacePath(p) {
|
|
17497
|
-
if (typeof p !== "string") return false;
|
|
17498
|
-
const trimmed = p.trim();
|
|
17499
|
-
if (trimmed === "") return false;
|
|
17500
|
-
if (trimmed.startsWith("/") || trimmed.startsWith("\\")) return false;
|
|
17501
|
-
if (/^[a-zA-Z]:/.test(trimmed)) return false;
|
|
17502
|
-
const segments = trimmed.split(/[/\\]+/);
|
|
17503
|
-
return !segments.some((seg) => seg === "..");
|
|
17504
|
-
}
|
|
17505
|
-
function validateDirField(value, field, errors) {
|
|
17506
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
17507
|
-
errors.push(`${field} must be a non-empty string`);
|
|
17508
|
-
return;
|
|
17509
|
-
}
|
|
17510
|
-
if (!isSafeRelativeWorkspacePath(value)) {
|
|
17511
|
-
errors.push(
|
|
17512
|
-
`${field} must be a relative path inside the workspace (no absolute paths or ".." traversal)`
|
|
17513
|
-
);
|
|
17979
|
+
function nodeVersionCheck() {
|
|
17980
|
+
const major = Number(process3__default.default.versions.node.split(".")[0]);
|
|
17981
|
+
if (Number.isNaN(major) || major < 20) {
|
|
17982
|
+
return {
|
|
17983
|
+
id: "node-version",
|
|
17984
|
+
status: "fail",
|
|
17985
|
+
message: `Node ${process3__default.default.versions.node} is below the supported minimum (20).`,
|
|
17986
|
+
remediation: "Upgrade to Node 20 LTS or newer.",
|
|
17987
|
+
evidence: process3__default.default.versions.node
|
|
17988
|
+
};
|
|
17514
17989
|
}
|
|
17990
|
+
return {
|
|
17991
|
+
id: "node-version",
|
|
17992
|
+
status: "pass",
|
|
17993
|
+
message: `Node ${process3__default.default.versions.node} meets the minimum (>=20).`,
|
|
17994
|
+
evidence: process3__default.default.versions.node
|
|
17995
|
+
};
|
|
17515
17996
|
}
|
|
17516
|
-
function
|
|
17517
|
-
|
|
17518
|
-
|
|
17519
|
-
return
|
|
17520
|
-
|
|
17521
|
-
|
|
17522
|
-
|
|
17523
|
-
|
|
17524
|
-
|
|
17525
|
-
errors.push(`index.type must be one of: ${INDEX_TYPES.join(", ")}`);
|
|
17526
|
-
}
|
|
17527
|
-
if (value.path !== void 0 && !isSafeRelativeWorkspacePath(value.path)) {
|
|
17528
|
-
errors.push(
|
|
17529
|
-
'index.path must be a relative path inside the workspace (no absolute paths or ".." traversal)'
|
|
17530
|
-
);
|
|
17997
|
+
function envCheck(name, optional = true) {
|
|
17998
|
+
const value = process3__default.default.env[name];
|
|
17999
|
+
if (value === void 0 || value.trim() === "") {
|
|
18000
|
+
return {
|
|
18001
|
+
id: `env-${name.toLowerCase()}`,
|
|
18002
|
+
status: optional ? "skipped" : "warn",
|
|
18003
|
+
message: `${name} is not set.`,
|
|
18004
|
+
remediation: optional ? void 0 : `Set ${name}=1 to enable tracing.`
|
|
18005
|
+
};
|
|
17531
18006
|
}
|
|
17532
|
-
if (errors.length > 0) return void 0;
|
|
17533
18007
|
return {
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
18008
|
+
id: `env-${name.toLowerCase()}`,
|
|
18009
|
+
status: "pass",
|
|
18010
|
+
message: `${name} is set.`,
|
|
18011
|
+
evidence: value
|
|
17537
18012
|
};
|
|
17538
18013
|
}
|
|
17539
|
-
function
|
|
17540
|
-
const
|
|
17541
|
-
|
|
17542
|
-
|
|
17543
|
-
|
|
17544
|
-
|
|
17545
|
-
|
|
17546
|
-
|
|
17547
|
-
`
|
|
17548
|
-
|
|
17549
|
-
|
|
17550
|
-
|
|
17551
|
-
|
|
17552
|
-
|
|
17553
|
-
|
|
18014
|
+
async function traceDirWritable(traceDir) {
|
|
18015
|
+
const resolved = path19__default.default.resolve(traceDir);
|
|
18016
|
+
try {
|
|
18017
|
+
await promises.mkdir(resolved, { recursive: true });
|
|
18018
|
+
await promises.access(resolved, promises.constants.W_OK);
|
|
18019
|
+
return {
|
|
18020
|
+
id: "trace-dir-writable",
|
|
18021
|
+
status: "pass",
|
|
18022
|
+
message: `Trace directory is writable: ${resolved}`,
|
|
18023
|
+
evidence: resolved
|
|
18024
|
+
};
|
|
18025
|
+
} catch (error) {
|
|
18026
|
+
return {
|
|
18027
|
+
id: "trace-dir-writable",
|
|
18028
|
+
status: "fail",
|
|
18029
|
+
message: `Trace directory is not writable: ${resolved}`,
|
|
18030
|
+
remediation: "Create the directory or set AGENT_INSPECT_TRACE_DIR to a writable path.",
|
|
18031
|
+
evidence: error instanceof Error ? error.message : String(error)
|
|
18032
|
+
};
|
|
17554
18033
|
}
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
18034
|
+
}
|
|
18035
|
+
function resolvePackage(cwd, name) {
|
|
18036
|
+
const require2 = module$1.createRequire(path19__default.default.join(cwd, "package.json"));
|
|
18037
|
+
try {
|
|
18038
|
+
const pkgPath = require2.resolve(`${name}/package.json`);
|
|
18039
|
+
const pkg = require2(pkgPath);
|
|
18040
|
+
return { ok: true, version: pkg.version };
|
|
18041
|
+
} catch {
|
|
18042
|
+
return { ok: false };
|
|
17559
18043
|
}
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17570
|
-
|
|
18044
|
+
}
|
|
18045
|
+
function importSmoke(cwd) {
|
|
18046
|
+
const results = [];
|
|
18047
|
+
const require2 = module$1.createRequire(path19__default.default.join(cwd, "package.json"));
|
|
18048
|
+
try {
|
|
18049
|
+
require2.resolve("agent-inspect");
|
|
18050
|
+
results.push({
|
|
18051
|
+
id: "import-agent-inspect",
|
|
18052
|
+
status: "pass",
|
|
18053
|
+
message: "agent-inspect resolves from the current project."
|
|
18054
|
+
});
|
|
18055
|
+
} catch {
|
|
18056
|
+
results.push({
|
|
18057
|
+
id: "import-agent-inspect",
|
|
18058
|
+
status: "warn",
|
|
18059
|
+
message: "agent-inspect is not installed in the current project.",
|
|
18060
|
+
remediation: "Run npm install agent-inspect (or pnpm add agent-inspect)."
|
|
17571
18061
|
});
|
|
17572
18062
|
}
|
|
17573
|
-
|
|
17574
|
-
|
|
17575
|
-
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
18063
|
+
try {
|
|
18064
|
+
require2.resolve("agent-inspect/package.json");
|
|
18065
|
+
results.push({
|
|
18066
|
+
id: "import-agent-inspect-cjs",
|
|
18067
|
+
status: "pass",
|
|
18068
|
+
message: "CJS resolution for agent-inspect succeeded."
|
|
18069
|
+
});
|
|
18070
|
+
} catch {
|
|
18071
|
+
results.push({
|
|
18072
|
+
id: "import-agent-inspect-cjs",
|
|
18073
|
+
status: "skipped",
|
|
18074
|
+
message: "CJS resolution check skipped (package not installed locally)."
|
|
18075
|
+
});
|
|
17579
18076
|
}
|
|
17580
|
-
|
|
17581
|
-
|
|
17582
|
-
|
|
17583
|
-
|
|
17584
|
-
|
|
18077
|
+
return results;
|
|
18078
|
+
}
|
|
18079
|
+
function optionalPackageChecks(cwd, framework) {
|
|
18080
|
+
const packages = framework !== void 0 ? OPTIONAL_PACKAGES[framework] : [
|
|
18081
|
+
"@agent-inspect/ai-sdk",
|
|
18082
|
+
"@agent-inspect/openai-agents",
|
|
18083
|
+
"@agent-inspect/langchain",
|
|
18084
|
+
"@agent-inspect/redact",
|
|
18085
|
+
"@agent-inspect/eval"
|
|
18086
|
+
];
|
|
18087
|
+
return packages.map((name) => {
|
|
18088
|
+
const resolved = resolvePackage(cwd, name);
|
|
18089
|
+
if (!resolved.ok) {
|
|
18090
|
+
return {
|
|
18091
|
+
id: `optional-package-${name}`,
|
|
18092
|
+
status: framework !== void 0 ? "warn" : "skipped",
|
|
18093
|
+
message: `${name} is not installed.`,
|
|
18094
|
+
remediation: framework !== void 0 ? `npm install ${name}` : void 0
|
|
18095
|
+
};
|
|
18096
|
+
}
|
|
18097
|
+
return {
|
|
18098
|
+
id: `optional-package-${name}`,
|
|
18099
|
+
status: "pass",
|
|
18100
|
+
message: `${name} is available.`,
|
|
18101
|
+
evidence: resolved.version
|
|
18102
|
+
};
|
|
18103
|
+
});
|
|
18104
|
+
}
|
|
18105
|
+
function versionMismatchCheck(cwd) {
|
|
18106
|
+
const root = resolvePackage(cwd, "agent-inspect");
|
|
18107
|
+
if (!root.ok || root.version === void 0) {
|
|
18108
|
+
return {
|
|
18109
|
+
id: "version-alignment",
|
|
18110
|
+
status: "skipped",
|
|
18111
|
+
message: "Skipped version alignment \u2014 agent-inspect not installed locally."
|
|
18112
|
+
};
|
|
17585
18113
|
}
|
|
17586
|
-
if (
|
|
17587
|
-
return {
|
|
18114
|
+
if (root.version !== version) {
|
|
18115
|
+
return {
|
|
18116
|
+
id: "version-alignment",
|
|
18117
|
+
status: "warn",
|
|
18118
|
+
message: `CLI version ${version} differs from local agent-inspect@${root.version}.`,
|
|
18119
|
+
remediation: "Align versions with npm install agent-inspect@latest",
|
|
18120
|
+
evidence: `cli=${version};local=${root.version}`
|
|
18121
|
+
};
|
|
17588
18122
|
}
|
|
17589
|
-
|
|
17590
|
-
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
traceDirs: input3.traceDirs.map((d) => d.trim()),
|
|
17594
|
-
reportsDir: input3.reportsDir.trim(),
|
|
17595
|
-
artifactsDir: input3.artifactsDir.trim(),
|
|
17596
|
-
bundlesDir: input3.bundlesDir.trim(),
|
|
17597
|
-
notesDir: input3.notesDir.trim(),
|
|
17598
|
-
redactionProfile: input3.redactionProfile,
|
|
17599
|
-
index
|
|
18123
|
+
return {
|
|
18124
|
+
id: "version-alignment",
|
|
18125
|
+
status: "pass",
|
|
18126
|
+
message: `CLI and local agent-inspect are aligned at ${version}.`
|
|
17600
18127
|
};
|
|
17601
|
-
return { ok: true, manifest, errors, warnings };
|
|
17602
18128
|
}
|
|
17603
|
-
function
|
|
17604
|
-
const
|
|
17605
|
-
|
|
17606
|
-
|
|
18129
|
+
async function runDoctorChecks(options = {}) {
|
|
18130
|
+
const cwd = path19__default.default.resolve(options.cwd ?? process3__default.default.cwd());
|
|
18131
|
+
const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
18132
|
+
const checks2 = [
|
|
18133
|
+
nodeVersionCheck(),
|
|
18134
|
+
{
|
|
18135
|
+
id: "cli-version",
|
|
18136
|
+
status: "pass",
|
|
18137
|
+
message: `agent-inspect CLI ${version}`,
|
|
18138
|
+
evidence: version
|
|
18139
|
+
},
|
|
18140
|
+
await traceDirWritable(traceDir),
|
|
18141
|
+
envCheck("AGENT_INSPECT"),
|
|
18142
|
+
envCheck("AGENT_INSPECT_TRACE_DIR"),
|
|
18143
|
+
versionMismatchCheck(cwd)
|
|
18144
|
+
];
|
|
18145
|
+
if (options.checkImports !== false) {
|
|
18146
|
+
checks2.push(...importSmoke(cwd));
|
|
17607
18147
|
}
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
18148
|
+
checks2.push(...optionalPackageChecks(cwd, options.framework));
|
|
18149
|
+
return checks2.sort((a, b) => a.id.localeCompare(b.id));
|
|
18150
|
+
}
|
|
18151
|
+
async function doctorCommand(options = {}) {
|
|
18152
|
+
const checks2 = await runDoctorChecks(options);
|
|
18153
|
+
const failed = checks2.filter((check) => check.status === "fail").length;
|
|
18154
|
+
const warned = checks2.filter((check) => check.status === "warn").length;
|
|
18155
|
+
if (options.json) {
|
|
18156
|
+
console.log(
|
|
18157
|
+
JSON.stringify(
|
|
18158
|
+
{
|
|
18159
|
+
ok: failed === 0,
|
|
18160
|
+
version,
|
|
18161
|
+
summary: { pass: checks2.filter((c) => c.status === "pass").length, warn: warned, fail: failed },
|
|
18162
|
+
checks: checks2
|
|
18163
|
+
},
|
|
18164
|
+
null,
|
|
18165
|
+
2
|
|
18166
|
+
)
|
|
18167
|
+
);
|
|
18168
|
+
if (failed > 0) process3__default.default.exitCode = 1;
|
|
18169
|
+
return;
|
|
17616
18170
|
}
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
18171
|
+
console.log("AgentInspect doctor");
|
|
18172
|
+
for (const check of checks2) {
|
|
18173
|
+
const tag = check.status.toUpperCase();
|
|
18174
|
+
console.log(`[${tag}] ${check.id}: ${check.message}`);
|
|
18175
|
+
if (check.remediation) console.log(` \u2192 ${check.remediation}`);
|
|
17622
18176
|
}
|
|
17623
|
-
|
|
17624
|
-
}
|
|
17625
|
-
|
|
17626
|
-
return `${JSON.stringify(manifest, null, 2)}
|
|
17627
|
-
`;
|
|
18177
|
+
console.log(`
|
|
18178
|
+
Summary: ${failed} failed, ${warned} warnings`);
|
|
18179
|
+
if (failed > 0) process3__default.default.exitCode = 1;
|
|
17628
18180
|
}
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
workspaceDir,
|
|
17636
|
-
manifestPath: path16__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
17637
|
-
};
|
|
18181
|
+
|
|
18182
|
+
// packages/adapter-sdk/src/indexer.ts
|
|
18183
|
+
init_advanced();
|
|
18184
|
+
function defineIndexer(indexer) {
|
|
18185
|
+
if (!indexer.id.trim()) throw new Error("indexer id is required");
|
|
18186
|
+
return indexer;
|
|
17638
18187
|
}
|
|
17639
|
-
function
|
|
17640
|
-
const
|
|
17641
|
-
|
|
17642
|
-
const
|
|
17643
|
-
|
|
17644
|
-
|
|
18188
|
+
async function indexIsStale(snapshot, traceDir) {
|
|
18189
|
+
const builtMs = Date.parse(snapshot.builtAt);
|
|
18190
|
+
if (Number.isNaN(builtMs)) return true;
|
|
18191
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
18192
|
+
const files = await td.list();
|
|
18193
|
+
for (const file of files) {
|
|
18194
|
+
const stats = await td.getFileStats(file);
|
|
18195
|
+
if (stats.mtimeMs > builtMs) return true;
|
|
17645
18196
|
}
|
|
17646
|
-
|
|
17647
|
-
`Workspace path "${relative}" resolves outside the workspace directory`
|
|
17648
|
-
);
|
|
18197
|
+
return false;
|
|
17649
18198
|
}
|
|
17650
|
-
|
|
17651
|
-
|
|
17652
|
-
|
|
17653
|
-
|
|
17654
|
-
|
|
17655
|
-
|
|
18199
|
+
function createTraceDirectoryIndexer() {
|
|
18200
|
+
return defineIndexer({
|
|
18201
|
+
id: "trace-directory-metadata",
|
|
18202
|
+
async rebuild(traceDir, options = {}) {
|
|
18203
|
+
const warnings = [];
|
|
18204
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
18205
|
+
const files = await td.list();
|
|
18206
|
+
const maxEntries = options.maxEntries ?? 1e4;
|
|
18207
|
+
if (files.length > maxEntries) {
|
|
18208
|
+
warnings.push(
|
|
18209
|
+
`indexer.truncated: trace directory has ${files.length} files; indexing first ${maxEntries}`
|
|
18210
|
+
);
|
|
18211
|
+
}
|
|
18212
|
+
const slice = files.slice(0, maxEntries);
|
|
18213
|
+
const metas = await loadTraceMetadataList(
|
|
18214
|
+
traceDir,
|
|
18215
|
+
slice,
|
|
18216
|
+
(fileName) => td.getPath(fileName)
|
|
18217
|
+
);
|
|
18218
|
+
const entries = metas.map((meta2) => ({
|
|
18219
|
+
runId: meta2.runId,
|
|
18220
|
+
path: meta2.filePath,
|
|
18221
|
+
name: meta2.name,
|
|
18222
|
+
startedAt: meta2.startedAt,
|
|
18223
|
+
status: meta2.status
|
|
18224
|
+
})).sort((a, b) => a.runId.localeCompare(b.runId));
|
|
18225
|
+
if (entries.length < slice.length) {
|
|
18226
|
+
warnings.push(
|
|
18227
|
+
`indexer.partial: indexed ${entries.length} of ${slice.length} trace files`
|
|
18228
|
+
);
|
|
18229
|
+
}
|
|
18230
|
+
return {
|
|
18231
|
+
traceDir,
|
|
18232
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18233
|
+
entries,
|
|
18234
|
+
warnings
|
|
18235
|
+
};
|
|
18236
|
+
}
|
|
18237
|
+
});
|
|
18238
|
+
}
|
|
18239
|
+
|
|
18240
|
+
// packages/cli/src/index-cmd.ts
|
|
18241
|
+
init_advanced();
|
|
18242
|
+
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
18243
|
+
function traceIndexPath(traceDir) {
|
|
18244
|
+
return path19__default.default.join(traceDir, INDEX_FILENAME);
|
|
18245
|
+
}
|
|
18246
|
+
function parseMaxEntries(raw) {
|
|
18247
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
18248
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18249
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
18250
|
+
throw new Error("--max-entries must be a positive integer.");
|
|
17656
18251
|
}
|
|
18252
|
+
return parsed;
|
|
17657
18253
|
}
|
|
17658
|
-
async function
|
|
18254
|
+
async function readSnapshot(indexPath2) {
|
|
17659
18255
|
try {
|
|
17660
|
-
await promises.
|
|
17661
|
-
return
|
|
18256
|
+
const raw = await promises.readFile(indexPath2, "utf8");
|
|
18257
|
+
return JSON.parse(raw);
|
|
17662
18258
|
} catch {
|
|
17663
|
-
return
|
|
18259
|
+
return void 0;
|
|
17664
18260
|
}
|
|
17665
18261
|
}
|
|
17666
|
-
async function
|
|
18262
|
+
async function indexBuildCommand(options = {}) {
|
|
17667
18263
|
try {
|
|
17668
|
-
const
|
|
17669
|
-
|
|
17670
|
-
|
|
17671
|
-
|
|
18264
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
18265
|
+
await promises.mkdir(traceDir, { recursive: true });
|
|
18266
|
+
const indexer = createTraceDirectoryIndexer();
|
|
18267
|
+
const snapshot = await indexer.rebuild(traceDir, {
|
|
18268
|
+
maxEntries: parseMaxEntries(options.maxEntries)
|
|
18269
|
+
});
|
|
18270
|
+
const indexPath2 = traceIndexPath(traceDir);
|
|
18271
|
+
await promises.writeFile(indexPath2, `${JSON.stringify(snapshot, null, 2)}
|
|
18272
|
+
`, "utf8");
|
|
18273
|
+
if (options.json) {
|
|
18274
|
+
console.log(JSON.stringify({ ok: true, indexPath: indexPath2, ...snapshot }, null, 2));
|
|
18275
|
+
return;
|
|
18276
|
+
}
|
|
18277
|
+
console.log(`Built trace index: ${indexPath2}`);
|
|
18278
|
+
console.log(`Entries: ${snapshot.entries.length}`);
|
|
18279
|
+
if (snapshot.warnings.length > 0) {
|
|
18280
|
+
for (const warning of snapshot.warnings) {
|
|
18281
|
+
console.log(`warning: ${warning}`);
|
|
18282
|
+
}
|
|
18283
|
+
}
|
|
18284
|
+
} catch (e) {
|
|
18285
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
18286
|
+
console.error(`[AgentInspect] index build failed: ${msg}`);
|
|
18287
|
+
process.exitCode = 1;
|
|
17672
18288
|
}
|
|
17673
18289
|
}
|
|
17674
|
-
async function
|
|
18290
|
+
async function indexStatusCommand(options = {}) {
|
|
17675
18291
|
try {
|
|
17676
|
-
const
|
|
17677
|
-
|
|
17678
|
-
|
|
17679
|
-
|
|
18292
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
18293
|
+
const indexPath2 = traceIndexPath(traceDir);
|
|
18294
|
+
const snapshot = await readSnapshot(indexPath2);
|
|
18295
|
+
if (!snapshot) {
|
|
18296
|
+
const payload2 = { ok: true, exists: false, indexPath: indexPath2, traceDir, stale: true };
|
|
18297
|
+
if (options.json) {
|
|
18298
|
+
console.log(JSON.stringify(payload2, null, 2));
|
|
18299
|
+
} else {
|
|
18300
|
+
console.log(`No index at ${indexPath2}`);
|
|
18301
|
+
console.log("Run: agent-inspect index build");
|
|
18302
|
+
}
|
|
18303
|
+
return;
|
|
18304
|
+
}
|
|
18305
|
+
const stale = await indexIsStale(snapshot, traceDir);
|
|
18306
|
+
const payload = {
|
|
18307
|
+
ok: true,
|
|
18308
|
+
exists: true,
|
|
18309
|
+
indexPath: indexPath2,
|
|
18310
|
+
traceDir,
|
|
18311
|
+
stale,
|
|
18312
|
+
builtAt: snapshot.builtAt,
|
|
18313
|
+
entries: snapshot.entries.length,
|
|
18314
|
+
warnings: snapshot.warnings
|
|
18315
|
+
};
|
|
18316
|
+
if (options.json) {
|
|
18317
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
18318
|
+
return;
|
|
18319
|
+
}
|
|
18320
|
+
console.log(`Index: ${indexPath2}`);
|
|
18321
|
+
console.log(`Built: ${snapshot.builtAt}`);
|
|
18322
|
+
console.log(`Entries: ${snapshot.entries.length}`);
|
|
18323
|
+
console.log(`Stale: ${stale ? "yes" : "no"}`);
|
|
18324
|
+
if (snapshot.warnings.length > 0) {
|
|
18325
|
+
for (const warning of snapshot.warnings) {
|
|
18326
|
+
console.log(`warning: ${warning}`);
|
|
18327
|
+
}
|
|
18328
|
+
}
|
|
18329
|
+
} catch (e) {
|
|
18330
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
18331
|
+
console.error(`[AgentInspect] index status failed: ${msg}`);
|
|
18332
|
+
process.exitCode = 1;
|
|
17680
18333
|
}
|
|
17681
18334
|
}
|
|
17682
|
-
async function
|
|
17683
|
-
let raw;
|
|
18335
|
+
async function indexCleanCommand(options = {}) {
|
|
17684
18336
|
try {
|
|
17685
|
-
|
|
17686
|
-
|
|
17687
|
-
|
|
18337
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
18338
|
+
const indexPath2 = traceIndexPath(traceDir);
|
|
18339
|
+
await promises.rm(indexPath2, { force: true });
|
|
18340
|
+
if (options.json) {
|
|
18341
|
+
console.log(JSON.stringify({ ok: true, removed: indexPath2 }, null, 2));
|
|
18342
|
+
return;
|
|
18343
|
+
}
|
|
18344
|
+
console.log(`Removed index: ${indexPath2}`);
|
|
18345
|
+
} catch (e) {
|
|
18346
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
18347
|
+
console.error(`[AgentInspect] index clean failed: ${msg}`);
|
|
18348
|
+
process.exitCode = 1;
|
|
17688
18349
|
}
|
|
17689
|
-
const parsed = parseWorkspaceManifest(raw);
|
|
17690
|
-
return {
|
|
17691
|
-
exists: true,
|
|
17692
|
-
ok: parsed.ok,
|
|
17693
|
-
...parsed.manifest ? { manifest: parsed.manifest } : {},
|
|
17694
|
-
errors: parsed.errors,
|
|
17695
|
-
warnings: parsed.warnings
|
|
17696
|
-
};
|
|
17697
18350
|
}
|
|
17698
|
-
|
|
17699
|
-
|
|
17700
|
-
|
|
17701
|
-
|
|
17702
|
-
|
|
17703
|
-
|
|
17704
|
-
let manifest;
|
|
17705
|
-
let created;
|
|
17706
|
-
let adopted;
|
|
17707
|
-
if (existing.exists && existing.ok && existing.manifest) {
|
|
17708
|
-
manifest = existing.manifest;
|
|
17709
|
-
created = false;
|
|
17710
|
-
adopted = true;
|
|
17711
|
-
} else {
|
|
17712
|
-
const project = options.project?.trim() || path16__default.default.basename(location.projectRoot) || "workspace";
|
|
17713
|
-
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
17714
|
-
manifest = createDefaultWorkspaceManifest({
|
|
17715
|
-
project,
|
|
17716
|
-
traceDirs,
|
|
17717
|
-
...options.redactionProfile ? { redactionProfile: options.redactionProfile } : {}
|
|
17718
|
-
});
|
|
17719
|
-
created = true;
|
|
17720
|
-
adopted = detectedExistingTraces || existing.exists && !existing.ok;
|
|
17721
|
-
}
|
|
17722
|
-
const relDirs = uniqueDirs([
|
|
17723
|
-
...manifest.traceDirs.filter((d) => d !== "."),
|
|
17724
|
-
manifest.reportsDir,
|
|
17725
|
-
manifest.artifactsDir,
|
|
17726
|
-
manifest.bundlesDir,
|
|
17727
|
-
manifest.notesDir,
|
|
17728
|
-
INDEX_DIR_NAME
|
|
17729
|
-
]);
|
|
17730
|
-
const createdDirs = [];
|
|
17731
|
-
for (const rel of relDirs) {
|
|
17732
|
-
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
17733
|
-
if (await pathExists(abs)) continue;
|
|
17734
|
-
createdDirs.push(rel);
|
|
17735
|
-
if (!dryRun) await promises.mkdir(abs, { recursive: true });
|
|
17736
|
-
}
|
|
17737
|
-
if (!dryRun && created) {
|
|
17738
|
-
await promises.mkdir(location.workspaceDir, { recursive: true });
|
|
17739
|
-
await promises.writeFile(location.manifestPath, serializeWorkspaceManifest(manifest), "utf-8");
|
|
17740
|
-
}
|
|
17741
|
-
return {
|
|
17742
|
-
location,
|
|
17743
|
-
manifest,
|
|
17744
|
-
created,
|
|
17745
|
-
adopted,
|
|
17746
|
-
createdDirs,
|
|
17747
|
-
detectedExistingTraces,
|
|
17748
|
-
dryRun
|
|
17749
|
-
};
|
|
18351
|
+
|
|
18352
|
+
// packages/cli/src/index-sqlite-cmd.ts
|
|
18353
|
+
init_advanced();
|
|
18354
|
+
var PACKAGE = "@agent-inspect/index-sqlite";
|
|
18355
|
+
function isModuleNotFound3(e) {
|
|
18356
|
+
return e !== null && typeof e === "object" && "code" in e && (e.code === "ERR_MODULE_NOT_FOUND" || e.code === "MODULE_NOT_FOUND");
|
|
17750
18357
|
}
|
|
17751
|
-
function
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
|
|
17757
|
-
|
|
17758
|
-
|
|
18358
|
+
async function loadIndexSqlite() {
|
|
18359
|
+
try {
|
|
18360
|
+
return await Promise.resolve().then(() => (init_src(), src_exports));
|
|
18361
|
+
} catch (e) {
|
|
18362
|
+
if (isModuleNotFound3(e)) {
|
|
18363
|
+
console.error(
|
|
18364
|
+
`The optional SQLite index is not installed. Run: npm install ${PACKAGE}`
|
|
18365
|
+
);
|
|
18366
|
+
process.exitCode = 1;
|
|
18367
|
+
return null;
|
|
18368
|
+
}
|
|
18369
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
18370
|
+
console.error(`[AgentInspect] failed to load ${PACKAGE}: ${msg}`);
|
|
18371
|
+
process.exitCode = 1;
|
|
18372
|
+
return null;
|
|
17759
18373
|
}
|
|
17760
|
-
return out;
|
|
17761
18374
|
}
|
|
17762
|
-
|
|
17763
|
-
|
|
17764
|
-
|
|
17765
|
-
|
|
17766
|
-
|
|
18375
|
+
function parsePositiveInt(raw, flag) {
|
|
18376
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
18377
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18378
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
18379
|
+
throw new Error(`${flag} must be a positive integer.`);
|
|
17767
18380
|
}
|
|
17768
|
-
|
|
17769
|
-
|
|
17770
|
-
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
return {
|
|
17782
|
-
project: manifest.project,
|
|
17783
|
-
traceFiles,
|
|
17784
|
-
reports,
|
|
17785
|
-
artifacts,
|
|
17786
|
-
bundles,
|
|
17787
|
-
notes,
|
|
17788
|
-
index: {
|
|
17789
|
-
enabled: manifest.index.enabled,
|
|
17790
|
-
type: manifest.index.type,
|
|
17791
|
-
exists: await pathExists(indexPath2)
|
|
18381
|
+
return parsed;
|
|
18382
|
+
}
|
|
18383
|
+
async function newestTraceMtimeMs2(traceDir) {
|
|
18384
|
+
let newest = 0;
|
|
18385
|
+
try {
|
|
18386
|
+
const files = await promises.readdir(traceDir);
|
|
18387
|
+
for (const file of files) {
|
|
18388
|
+
if (!file.endsWith(".jsonl")) continue;
|
|
18389
|
+
try {
|
|
18390
|
+
const s = await promises.stat(path19__default.default.join(traceDir, file));
|
|
18391
|
+
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
18392
|
+
} catch {
|
|
18393
|
+
}
|
|
17792
18394
|
}
|
|
17793
|
-
}
|
|
18395
|
+
} catch {
|
|
18396
|
+
}
|
|
18397
|
+
return newest;
|
|
17794
18398
|
}
|
|
17795
|
-
async function
|
|
17796
|
-
const
|
|
17797
|
-
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
});
|
|
17804
|
-
return
|
|
18399
|
+
async function indexSqliteBuildCommand(options = {}) {
|
|
18400
|
+
const mod = await loadIndexSqlite();
|
|
18401
|
+
if (!mod) return;
|
|
18402
|
+
const result = await mod.buildIndex({
|
|
18403
|
+
traceDir: options.dir,
|
|
18404
|
+
maxRuns: parsePositiveInt(options.maxRuns, "--max-runs")
|
|
18405
|
+
});
|
|
18406
|
+
if (options.json) {
|
|
18407
|
+
console.log(JSON.stringify({ ok: true, ...result }, null, 2));
|
|
18408
|
+
return;
|
|
17805
18409
|
}
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
18410
|
+
console.log(`Built SQLite index: ${result.dbPath}`);
|
|
18411
|
+
console.log(`Runs: ${result.runs} Steps: ${result.steps} Errors: ${result.errors}`);
|
|
18412
|
+
for (const warning of result.warnings) console.log(`warning: ${warning}`);
|
|
18413
|
+
}
|
|
18414
|
+
async function indexSqliteStatusCommand(options = {}) {
|
|
18415
|
+
const mod = await loadIndexSqlite();
|
|
18416
|
+
if (!mod) return;
|
|
18417
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
18418
|
+
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
18419
|
+
const status = mod.indexStatus(dbPath);
|
|
18420
|
+
const stale = mod.isIndexStale(dbPath, await newestTraceMtimeMs2(traceDir));
|
|
18421
|
+
if (options.json) {
|
|
18422
|
+
console.log(JSON.stringify({ ok: true, traceDir, stale, ...status }, null, 2));
|
|
18423
|
+
return;
|
|
17813
18424
|
}
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
18425
|
+
if (!status.exists) {
|
|
18426
|
+
console.log(`No SQLite index at ${dbPath}`);
|
|
18427
|
+
console.log("Run: agent-inspect index sqlite build");
|
|
18428
|
+
return;
|
|
17818
18429
|
}
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
message: error instanceof Error ? error.message : String(error)
|
|
17835
|
-
});
|
|
17836
|
-
continue;
|
|
17837
|
-
}
|
|
17838
|
-
if (!await pathExists(abs)) {
|
|
17839
|
-
checks2.push({ id, status: "warn", message: `${rel}/ does not exist yet` });
|
|
17840
|
-
} else if (!await isWritable(abs)) {
|
|
17841
|
-
checks2.push({ id, status: "fail", message: `${rel}/ is not writable` });
|
|
18430
|
+
console.log(`Index: ${status.dbPath}`);
|
|
18431
|
+
console.log(`Healthy: ${status.healthy ? "yes" : "no"}`);
|
|
18432
|
+
console.log(`Built: ${status.builtAt ?? "unknown"}`);
|
|
18433
|
+
console.log(`Runs: ${status.runs} Steps: ${status.steps}`);
|
|
18434
|
+
console.log(`Stale: ${stale ? "yes" : "no"}`);
|
|
18435
|
+
}
|
|
18436
|
+
async function indexSqliteQueryCommand(options = {}) {
|
|
18437
|
+
const mod = await loadIndexSqlite();
|
|
18438
|
+
if (!mod) return;
|
|
18439
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
18440
|
+
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
18441
|
+
const status = mod.indexStatus(dbPath);
|
|
18442
|
+
if (!status.exists || !status.healthy) {
|
|
18443
|
+
if (options.json) {
|
|
18444
|
+
console.log(JSON.stringify({ ok: false, reason: "index-missing", dbPath }, null, 2));
|
|
17842
18445
|
} else {
|
|
17843
|
-
|
|
18446
|
+
console.log("No usable SQLite index. Run: agent-inspect index sqlite build");
|
|
17844
18447
|
}
|
|
18448
|
+
process.exitCode = 1;
|
|
18449
|
+
return;
|
|
17845
18450
|
}
|
|
17846
|
-
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17852
|
-
|
|
17853
|
-
|
|
17854
|
-
|
|
17855
|
-
|
|
17856
|
-
|
|
18451
|
+
const rows = mod.queryRuns(dbPath, {
|
|
18452
|
+
status: options.status,
|
|
18453
|
+
sessionId: options.session,
|
|
18454
|
+
name: options.name,
|
|
18455
|
+
kind: options.kind,
|
|
18456
|
+
tool: options.tool,
|
|
18457
|
+
limit: parsePositiveInt(options.limit, "--limit")
|
|
18458
|
+
});
|
|
18459
|
+
if (options.json) {
|
|
18460
|
+
console.log(JSON.stringify({ ok: true, count: rows.length, runs: rows }, null, 2));
|
|
18461
|
+
return;
|
|
17857
18462
|
}
|
|
17858
|
-
if (
|
|
17859
|
-
|
|
17860
|
-
|
|
17861
|
-
|
|
17862
|
-
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
|
|
17868
|
-
|
|
17869
|
-
|
|
17870
|
-
} catch {
|
|
17871
|
-
checks2.push({ id: "index", status: "warn", message: "cannot stat index" });
|
|
17872
|
-
}
|
|
17873
|
-
}
|
|
18463
|
+
if (rows.length === 0) {
|
|
18464
|
+
console.log("No matching runs.");
|
|
18465
|
+
return;
|
|
18466
|
+
}
|
|
18467
|
+
for (const run of rows) {
|
|
18468
|
+
const parts = [
|
|
18469
|
+
run.runId,
|
|
18470
|
+
run.status ?? "unknown",
|
|
18471
|
+
run.name ?? "",
|
|
18472
|
+
run.durationMs != null ? `${run.durationMs}ms` : ""
|
|
18473
|
+
].filter((p) => p !== "");
|
|
18474
|
+
console.log(parts.join(" "));
|
|
17874
18475
|
}
|
|
17875
|
-
const ok = !checks2.some((c) => c.status === "fail");
|
|
17876
|
-
return { ok, checks: checks2 };
|
|
17877
18476
|
}
|
|
17878
|
-
async function
|
|
17879
|
-
const
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17883
|
-
|
|
17884
|
-
|
|
17885
|
-
|
|
17886
|
-
|
|
17887
|
-
for (const rel of targets) {
|
|
17888
|
-
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
17889
|
-
let entries;
|
|
17890
|
-
try {
|
|
17891
|
-
entries = await promises.readdir(abs);
|
|
17892
|
-
} catch {
|
|
17893
|
-
continue;
|
|
17894
|
-
}
|
|
17895
|
-
for (const entry of entries) {
|
|
17896
|
-
const relPath = `${rel}/${entry}`;
|
|
17897
|
-
removed.push(relPath);
|
|
17898
|
-
if (!dryRun) {
|
|
17899
|
-
await promises.rm(path16__default.default.join(abs, entry), { recursive: true, force: true });
|
|
17900
|
-
}
|
|
17901
|
-
}
|
|
18477
|
+
async function indexSqliteCleanCommand(options = {}) {
|
|
18478
|
+
const mod = await loadIndexSqlite();
|
|
18479
|
+
if (!mod) return;
|
|
18480
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
18481
|
+
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
18482
|
+
await mod.cleanIndex(dbPath);
|
|
18483
|
+
if (options.json) {
|
|
18484
|
+
console.log(JSON.stringify({ ok: true, removed: dbPath }, null, 2));
|
|
18485
|
+
return;
|
|
17902
18486
|
}
|
|
17903
|
-
|
|
18487
|
+
console.log(`Removed SQLite index: ${dbPath}`);
|
|
17904
18488
|
}
|
|
17905
18489
|
|
|
17906
18490
|
// packages/cli/src/workspace.ts
|
|
@@ -18252,6 +18836,11 @@ function createCliProgram() {
|
|
|
18252
18836
|
).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--baseline <trace-path-or-run-id>", "optional baseline trace for diff artifacts").option("--baseline-run <run-id>", "select a run from the baseline trace").option("--github-summary <path>", "append a safe summary to this file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON manifest").action((target, opts) => {
|
|
18253
18837
|
runCommand(() => artifactsCommand(target, opts));
|
|
18254
18838
|
});
|
|
18839
|
+
program.command("bundle").description("Create a share-safe offline trace bundle (local folder)").argument("[run-id]", "run id to bundle (optional with --session or --since)").option("--dir <path>", "trace directory for run/session lookup").option("--session <session-id>", "bundle all runs in a session").option("--since <duration>", "bundle runs with activity since a duration (e.g. 24h)").addOption(
|
|
18840
|
+
new commander.Option("--profile <profile>", "redaction profile for exported copies").choices(["local", "share", "strict"]).default("share")
|
|
18841
|
+
).option("--out <path>", "output directory (folder; .zip suffix is stripped)").option("--allow-unsafe", "write bundle even when verify-safe reports UNSAFE").option("--json", "print deterministic JSON manifest").action((runId, opts) => {
|
|
18842
|
+
runCommand(() => bundleCommand(runId, opts));
|
|
18843
|
+
});
|
|
18255
18844
|
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) => {
|
|
18256
18845
|
runCommand(() => ciSummaryCommand(manifest, opts));
|
|
18257
18846
|
});
|
|
@@ -18456,9 +19045,9 @@ function isPrimaryModule() {
|
|
|
18456
19045
|
if (!entry) return false;
|
|
18457
19046
|
const selfPath = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
18458
19047
|
try {
|
|
18459
|
-
return fs.realpathSync(
|
|
19048
|
+
return fs.realpathSync(path19__default.default.resolve(entry)) === fs.realpathSync(path19__default.default.resolve(selfPath));
|
|
18460
19049
|
} catch {
|
|
18461
|
-
return
|
|
19050
|
+
return path19__default.default.resolve(entry) === path19__default.default.resolve(selfPath);
|
|
18462
19051
|
}
|
|
18463
19052
|
}
|
|
18464
19053
|
if (isPrimaryModule()) {
|