agent-inspect 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +11 -1
- package/docs/ADAPTER-CONFORMANCE.md +7 -0
- package/docs/ADAPTERS.md +4 -0
- package/docs/CLI.md +2 -0
- package/docs/GETTING-STARTED.md +19 -0
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +537 -75
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +534 -72
- package/packages/cli/dist/index.mjs.map +1 -1
|
@@ -5,15 +5,16 @@ import { fileURLToPath, pathToFileURL } from 'url';
|
|
|
5
5
|
import { Command, Option } from 'commander';
|
|
6
6
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
7
7
|
import crypto, { webcrypto, createHash } from 'crypto';
|
|
8
|
-
import { unlink, stat, mkdir, writeFile, appendFile, readdir, readFile, access, open } from 'fs/promises';
|
|
8
|
+
import { unlink, stat, mkdir, writeFile, appendFile, readdir, readFile, access, open, constants } from 'fs/promises';
|
|
9
9
|
import os from 'os';
|
|
10
|
-
import
|
|
10
|
+
import process3, { stdin, stdout } from 'process';
|
|
11
11
|
import tty from 'tty';
|
|
12
12
|
import { createInterface } from 'readline';
|
|
13
13
|
import { createServer } from 'http';
|
|
14
|
+
import { createRequire } from 'module';
|
|
14
15
|
|
|
15
16
|
// package.json
|
|
16
|
-
var version = "3.
|
|
17
|
+
var version = "3.2.0";
|
|
17
18
|
|
|
18
19
|
// packages/core/src/correlation-metadata.ts
|
|
19
20
|
var TRACE_CORRELATION_KEYS = [
|
|
@@ -1177,13 +1178,13 @@ function assembleStyles() {
|
|
|
1177
1178
|
}
|
|
1178
1179
|
var ansiStyles = assembleStyles();
|
|
1179
1180
|
var ansi_styles_default = ansiStyles;
|
|
1180
|
-
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args :
|
|
1181
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process3.argv) {
|
|
1181
1182
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
1182
1183
|
const position = argv.indexOf(prefix + flag);
|
|
1183
1184
|
const terminatorPosition = argv.indexOf("--");
|
|
1184
1185
|
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
1185
1186
|
}
|
|
1186
|
-
var { env } =
|
|
1187
|
+
var { env } = process3;
|
|
1187
1188
|
var flagForceColor;
|
|
1188
1189
|
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
1189
1190
|
flagForceColor = 0;
|
|
@@ -1239,7 +1240,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
1239
1240
|
if (env.TERM === "dumb") {
|
|
1240
1241
|
return min;
|
|
1241
1242
|
}
|
|
1242
|
-
if (
|
|
1243
|
+
if (process3.platform === "win32") {
|
|
1243
1244
|
const osRelease = os.release().split(".");
|
|
1244
1245
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
1245
1246
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
@@ -3059,12 +3060,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3059
3060
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3060
3061
|
);
|
|
3061
3062
|
const ordered = [...runs].sort(compareRuns);
|
|
3062
|
-
const
|
|
3063
|
+
const path18 = [];
|
|
3063
3064
|
const visited = /* @__PURE__ */ new Set();
|
|
3064
3065
|
const pushRun = (run, confidence, source) => {
|
|
3065
3066
|
if (visited.has(run.runId)) return;
|
|
3066
3067
|
visited.add(run.runId);
|
|
3067
|
-
|
|
3068
|
+
path18.push({
|
|
3068
3069
|
runId: run.runId,
|
|
3069
3070
|
name: run.name,
|
|
3070
3071
|
startedAt: run.startedAt,
|
|
@@ -3089,7 +3090,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3089
3090
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3090
3091
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3091
3092
|
}
|
|
3092
|
-
return
|
|
3093
|
+
return path18;
|
|
3093
3094
|
}
|
|
3094
3095
|
function metaRunIdMatches(run, token, runById) {
|
|
3095
3096
|
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -8332,13 +8333,13 @@ function pairSteps(left, right) {
|
|
|
8332
8333
|
return pairs;
|
|
8333
8334
|
}
|
|
8334
8335
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
8335
|
-
const
|
|
8336
|
+
const path18 = buildPath(segments);
|
|
8336
8337
|
if (L.name !== R.name) {
|
|
8337
8338
|
out.push({
|
|
8338
8339
|
kind: "structure",
|
|
8339
8340
|
severity: "warning",
|
|
8340
8341
|
message: "Step name differs",
|
|
8341
|
-
path:
|
|
8342
|
+
path: path18,
|
|
8342
8343
|
left: L.name,
|
|
8343
8344
|
right: R.name
|
|
8344
8345
|
});
|
|
@@ -8348,7 +8349,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8348
8349
|
kind: "step-type",
|
|
8349
8350
|
severity: "warning",
|
|
8350
8351
|
message: "Step type differs",
|
|
8351
|
-
path:
|
|
8352
|
+
path: path18,
|
|
8352
8353
|
left: L.type,
|
|
8353
8354
|
right: R.type
|
|
8354
8355
|
});
|
|
@@ -8358,7 +8359,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8358
8359
|
kind: "step-status",
|
|
8359
8360
|
severity: "warning",
|
|
8360
8361
|
message: "Step status differs",
|
|
8361
|
-
path:
|
|
8362
|
+
path: path18,
|
|
8362
8363
|
left: L.status,
|
|
8363
8364
|
right: R.status
|
|
8364
8365
|
});
|
|
@@ -8370,7 +8371,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8370
8371
|
kind: "error",
|
|
8371
8372
|
severity: "error",
|
|
8372
8373
|
message: "Step error message differs",
|
|
8373
|
-
path:
|
|
8374
|
+
path: path18,
|
|
8374
8375
|
left: le || void 0,
|
|
8375
8376
|
right: re || void 0
|
|
8376
8377
|
});
|
|
@@ -8388,7 +8389,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8388
8389
|
kind: "duration",
|
|
8389
8390
|
severity: "info",
|
|
8390
8391
|
message: "Step duration differs",
|
|
8391
|
-
path:
|
|
8392
|
+
path: path18,
|
|
8392
8393
|
left: ld,
|
|
8393
8394
|
right: rd
|
|
8394
8395
|
});
|
|
@@ -8401,7 +8402,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8401
8402
|
kind: "metadata",
|
|
8402
8403
|
severity: "info",
|
|
8403
8404
|
message: "Step metadata differs",
|
|
8404
|
-
path:
|
|
8405
|
+
path: path18,
|
|
8405
8406
|
left: L.metadata,
|
|
8406
8407
|
right: R.metadata
|
|
8407
8408
|
});
|
|
@@ -8413,7 +8414,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8413
8414
|
kind: "output",
|
|
8414
8415
|
severity: "info",
|
|
8415
8416
|
message: "Output preview differs",
|
|
8416
|
-
path:
|
|
8417
|
+
path: path18,
|
|
8417
8418
|
left: L.outputPreview,
|
|
8418
8419
|
right: R.outputPreview
|
|
8419
8420
|
});
|
|
@@ -8573,11 +8574,11 @@ function diffRuns(left, right, options) {
|
|
|
8573
8574
|
}
|
|
8574
8575
|
|
|
8575
8576
|
// packages/core/src/diff/renderer.ts
|
|
8576
|
-
function formatPath(
|
|
8577
|
-
if (
|
|
8577
|
+
function formatPath(path18) {
|
|
8578
|
+
if (path18 === void 0 || path18.path.length === 0) {
|
|
8578
8579
|
return "(run)";
|
|
8579
8580
|
}
|
|
8580
|
-
return
|
|
8581
|
+
return path18.path.map((s) => s.name).join(" > ");
|
|
8581
8582
|
}
|
|
8582
8583
|
function formatValue(v, verbose) {
|
|
8583
8584
|
if (v === void 0) return "(undefined)";
|
|
@@ -9455,17 +9456,17 @@ function applyRule(rule, value, replacement) {
|
|
|
9455
9456
|
}
|
|
9456
9457
|
return value;
|
|
9457
9458
|
}
|
|
9458
|
-
function childPath(
|
|
9459
|
+
function childPath(path18, key) {
|
|
9459
9460
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
9460
|
-
return
|
|
9461
|
+
return path18 ? `${path18}.${key}` : key;
|
|
9461
9462
|
}
|
|
9462
|
-
return `${
|
|
9463
|
+
return `${path18 || "$"}[${JSON.stringify(key)}]`;
|
|
9463
9464
|
}
|
|
9464
|
-
function indexPath(
|
|
9465
|
-
return `${
|
|
9465
|
+
function indexPath(path18, index) {
|
|
9466
|
+
return `${path18 || "$"}[${index}]`;
|
|
9466
9467
|
}
|
|
9467
|
-
function makeFinding(
|
|
9468
|
-
return preview === void 0 ? { path:
|
|
9468
|
+
function makeFinding(path18, detector, action, matchKind, severity = "warning", preview) {
|
|
9469
|
+
return preview === void 0 ? { path: path18, detector, action, severity, matchKind } : { path: path18, detector, action, severity, matchKind, preview };
|
|
9469
9470
|
}
|
|
9470
9471
|
function createRedactionProfile(profile = "local") {
|
|
9471
9472
|
switch (profile) {
|
|
@@ -9534,11 +9535,11 @@ var Redactor2 = class {
|
|
|
9534
9535
|
#recordFinding(state, finding) {
|
|
9535
9536
|
if (this.#collectFindings) state.findings.push(finding);
|
|
9536
9537
|
}
|
|
9537
|
-
#redactValue(value, key,
|
|
9538
|
+
#redactValue(value, key, path18, depth, state) {
|
|
9538
9539
|
if (depth > this.#maxDepth) {
|
|
9539
9540
|
this.#recordFinding(
|
|
9540
9541
|
state,
|
|
9541
|
-
makeFinding(
|
|
9542
|
+
makeFinding(path18, "structure.maxDepth", "truncate", "value", "warning")
|
|
9542
9543
|
);
|
|
9543
9544
|
return "[Truncated]";
|
|
9544
9545
|
}
|
|
@@ -9547,19 +9548,19 @@ var Redactor2 = class {
|
|
|
9547
9548
|
if (rule) {
|
|
9548
9549
|
this.#recordFinding(
|
|
9549
9550
|
state,
|
|
9550
|
-
makeFinding(
|
|
9551
|
+
makeFinding(path18, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
9551
9552
|
);
|
|
9552
9553
|
return applyRule(rule, value, this.#replacement);
|
|
9553
9554
|
}
|
|
9554
9555
|
}
|
|
9555
9556
|
for (const detector of this.#detectors) {
|
|
9556
|
-
const detections = detector.detect({ path:
|
|
9557
|
+
const detections = detector.detect({ path: path18, key, value });
|
|
9557
9558
|
for (const detection of detections) {
|
|
9558
9559
|
const action = detection.action ?? "replace";
|
|
9559
9560
|
this.#recordFinding(
|
|
9560
9561
|
state,
|
|
9561
9562
|
makeFinding(
|
|
9562
|
-
|
|
9563
|
+
path18,
|
|
9563
9564
|
detector.id,
|
|
9564
9565
|
action,
|
|
9565
9566
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -9577,7 +9578,7 @@ var Redactor2 = class {
|
|
|
9577
9578
|
const out = [];
|
|
9578
9579
|
state.seen.set(value, out);
|
|
9579
9580
|
value.forEach((item, index) => {
|
|
9580
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
9581
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path18, index), depth + 1, state);
|
|
9581
9582
|
});
|
|
9582
9583
|
return out;
|
|
9583
9584
|
}
|
|
@@ -9589,7 +9590,7 @@ var Redactor2 = class {
|
|
|
9589
9590
|
out[entryKey] = this.#redactValue(
|
|
9590
9591
|
entryValue,
|
|
9591
9592
|
entryKey,
|
|
9592
|
-
childPath(
|
|
9593
|
+
childPath(path18 === "$" ? "" : path18, entryKey),
|
|
9593
9594
|
depth + 1,
|
|
9594
9595
|
state
|
|
9595
9596
|
);
|
|
@@ -10461,7 +10462,7 @@ function stripPrefix(name, prefixes) {
|
|
|
10461
10462
|
}
|
|
10462
10463
|
return name;
|
|
10463
10464
|
}
|
|
10464
|
-
function eventEvidence(event,
|
|
10465
|
+
function eventEvidence(event, path18) {
|
|
10465
10466
|
return {
|
|
10466
10467
|
runId: event.runId,
|
|
10467
10468
|
eventId: event.eventId,
|
|
@@ -10471,7 +10472,7 @@ function eventEvidence(event, path16) {
|
|
|
10471
10472
|
kind: event.kind,
|
|
10472
10473
|
name: event.name,
|
|
10473
10474
|
status: event.status,
|
|
10474
|
-
...
|
|
10475
|
+
...path18 ? { path: path18 } : {}
|
|
10475
10476
|
};
|
|
10476
10477
|
}
|
|
10477
10478
|
function runEvidence(run) {
|
|
@@ -10534,9 +10535,9 @@ function eventEndMs(event) {
|
|
|
10534
10535
|
function normalizedKey(value) {
|
|
10535
10536
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
10536
10537
|
}
|
|
10537
|
-
function lastPathSegment(
|
|
10538
|
-
const parts =
|
|
10539
|
-
return parts[parts.length - 1] ??
|
|
10538
|
+
function lastPathSegment(path18) {
|
|
10539
|
+
const parts = path18.split(".");
|
|
10540
|
+
return parts[parts.length - 1] ?? path18;
|
|
10540
10541
|
}
|
|
10541
10542
|
function valueType(value) {
|
|
10542
10543
|
if (Array.isArray(value)) return "array";
|
|
@@ -10550,12 +10551,12 @@ function serializedByteLength(value) {
|
|
|
10550
10551
|
return void 0;
|
|
10551
10552
|
}
|
|
10552
10553
|
}
|
|
10553
|
-
function pushValueEntries(entries, event, value,
|
|
10554
|
-
entries.push({ event, path:
|
|
10554
|
+
function pushValueEntries(entries, event, value, path18, key, depth = 0) {
|
|
10555
|
+
entries.push({ event, path: path18, key, value });
|
|
10555
10556
|
if (depth >= 8) return;
|
|
10556
10557
|
if (Array.isArray(value)) {
|
|
10557
10558
|
for (const [index, item] of value.entries()) {
|
|
10558
|
-
pushValueEntries(entries, event, item, `${
|
|
10559
|
+
pushValueEntries(entries, event, item, `${path18}.${index}`, String(index), depth + 1);
|
|
10559
10560
|
}
|
|
10560
10561
|
return;
|
|
10561
10562
|
}
|
|
@@ -10565,7 +10566,7 @@ function pushValueEntries(entries, event, value, path16, key, depth = 0) {
|
|
|
10565
10566
|
entries,
|
|
10566
10567
|
event,
|
|
10567
10568
|
value[nestedKey],
|
|
10568
|
-
`${
|
|
10569
|
+
`${path18}.${nestedKey}`,
|
|
10569
10570
|
nestedKey,
|
|
10570
10571
|
depth + 1
|
|
10571
10572
|
);
|
|
@@ -10646,9 +10647,9 @@ function eventDurationMs(event) {
|
|
|
10646
10647
|
}
|
|
10647
10648
|
function treeShape(nodes) {
|
|
10648
10649
|
const lines = [];
|
|
10649
|
-
const visit = (node,
|
|
10650
|
-
lines.push(`${
|
|
10651
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
10650
|
+
const visit = (node, path18) => {
|
|
10651
|
+
lines.push(`${path18}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
10652
|
+
node.children.forEach((child, index) => visit(child, `${path18}.${index}`));
|
|
10652
10653
|
};
|
|
10653
10654
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
10654
10655
|
return lines;
|
|
@@ -10697,9 +10698,9 @@ function retrievalShape(context) {
|
|
|
10697
10698
|
function guardrailShape(context) {
|
|
10698
10699
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
10699
10700
|
}
|
|
10700
|
-
function firstEvidenceForKind(context, kind,
|
|
10701
|
+
function firstEvidenceForKind(context, kind, path18) {
|
|
10701
10702
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
10702
|
-
return event ? [eventEvidence(event,
|
|
10703
|
+
return event ? [eventEvidence(event, path18)] : runEvidence(context.selectedRun);
|
|
10703
10704
|
}
|
|
10704
10705
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
10705
10706
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -10947,13 +10948,13 @@ function createStructureCycleRule() {
|
|
|
10947
10948
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
10948
10949
|
const findings = [];
|
|
10949
10950
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
10950
|
-
const
|
|
10951
|
+
const path18 = [];
|
|
10951
10952
|
const seenAt = /* @__PURE__ */ new Map();
|
|
10952
10953
|
let current = event;
|
|
10953
10954
|
while (current) {
|
|
10954
10955
|
const existing = seenAt.get(current.eventId);
|
|
10955
10956
|
if (existing !== void 0) {
|
|
10956
|
-
const cycle =
|
|
10957
|
+
const cycle = path18.slice(existing);
|
|
10957
10958
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
10958
10959
|
if (!seenCycles.has(key)) {
|
|
10959
10960
|
seenCycles.add(key);
|
|
@@ -10969,8 +10970,8 @@ function createStructureCycleRule() {
|
|
|
10969
10970
|
}
|
|
10970
10971
|
break;
|
|
10971
10972
|
}
|
|
10972
|
-
seenAt.set(current.eventId,
|
|
10973
|
-
|
|
10973
|
+
seenAt.set(current.eventId, path18.length);
|
|
10974
|
+
path18.push(current);
|
|
10974
10975
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
10975
10976
|
}
|
|
10976
10977
|
}
|
|
@@ -11767,23 +11768,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
11767
11768
|
}
|
|
11768
11769
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
11769
11770
|
}
|
|
11770
|
-
function validateSchemaField(value, field,
|
|
11771
|
+
function validateSchemaField(value, field, path18, evidence) {
|
|
11771
11772
|
const ruleId = "guardrail.structured-output";
|
|
11772
11773
|
if (field.type) {
|
|
11773
11774
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
11774
11775
|
if (actual !== field.type) {
|
|
11775
|
-
evidence.push({ ruleId, path:
|
|
11776
|
+
evidence.push({ ruleId, path: path18, preview: `expected ${field.type}, got ${actual}` });
|
|
11776
11777
|
return;
|
|
11777
11778
|
}
|
|
11778
11779
|
}
|
|
11779
11780
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
11780
|
-
evidence.push({ ruleId, path:
|
|
11781
|
+
evidence.push({ ruleId, path: path18, preview: "value not in enum" });
|
|
11781
11782
|
}
|
|
11782
11783
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
11783
11784
|
const record = value;
|
|
11784
11785
|
for (const key of field.required) {
|
|
11785
11786
|
if (!(key in record)) {
|
|
11786
|
-
evidence.push({ ruleId, path: `${
|
|
11787
|
+
evidence.push({ ruleId, path: `${path18}.${key}`, preview: "missing required key" });
|
|
11787
11788
|
}
|
|
11788
11789
|
}
|
|
11789
11790
|
}
|
|
@@ -12248,10 +12249,10 @@ function printHuman(result) {
|
|
|
12248
12249
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
12249
12250
|
}
|
|
12250
12251
|
for (const finding of result.findings) {
|
|
12251
|
-
const
|
|
12252
|
+
const path18 = finding.evidence[0]?.path;
|
|
12252
12253
|
const run = finding.evidence[0]?.runId;
|
|
12253
12254
|
const runPrefix = run ? `[${run}] ` : "";
|
|
12254
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
12255
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
|
|
12255
12256
|
}
|
|
12256
12257
|
}
|
|
12257
12258
|
function readErrorResult(error) {
|
|
@@ -12789,10 +12790,10 @@ async function evalRun(input3, options = {}) {
|
|
|
12789
12790
|
diagnostics: []
|
|
12790
12791
|
};
|
|
12791
12792
|
}
|
|
12792
|
-
function evidenceForRun(run,
|
|
12793
|
-
return [{ runId: run.runId, ...
|
|
12793
|
+
function evidenceForRun(run, path18) {
|
|
12794
|
+
return [{ runId: run.runId, ...path18 !== void 0 ? { path: path18 } : {} }];
|
|
12794
12795
|
}
|
|
12795
|
-
function evidenceForEvent(event,
|
|
12796
|
+
function evidenceForEvent(event, path18) {
|
|
12796
12797
|
return [
|
|
12797
12798
|
{
|
|
12798
12799
|
runId: event.runId,
|
|
@@ -12800,7 +12801,7 @@ function evidenceForEvent(event, path16) {
|
|
|
12800
12801
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
12801
12802
|
kind: event.kind,
|
|
12802
12803
|
name: event.name,
|
|
12803
|
-
...
|
|
12804
|
+
...path18 !== void 0 ? { path: path18 } : {}
|
|
12804
12805
|
}
|
|
12805
12806
|
];
|
|
12806
12807
|
}
|
|
@@ -12958,9 +12959,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
12958
12959
|
function tokenize(text) {
|
|
12959
12960
|
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));
|
|
12960
12961
|
}
|
|
12961
|
-
function firstEvidence(fields, run,
|
|
12962
|
+
function firstEvidence(fields, run, path18) {
|
|
12962
12963
|
const first = fields[0];
|
|
12963
|
-
return first === void 0 ? evidenceForRun(run,
|
|
12964
|
+
return first === void 0 ? evidenceForRun(run, path18) : evidenceForEvent(first.node.event, first.path);
|
|
12964
12965
|
}
|
|
12965
12966
|
function collectSourceIds(nodes, keys) {
|
|
12966
12967
|
const wanted = keySet(keys);
|
|
@@ -13337,8 +13338,8 @@ function renderEvalMarkdown(result) {
|
|
|
13337
13338
|
if (result.findings.length > 0) {
|
|
13338
13339
|
lines.push("", "## Findings");
|
|
13339
13340
|
for (const finding of result.findings) {
|
|
13340
|
-
const
|
|
13341
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
13341
|
+
const path18 = finding.evidence[0]?.path;
|
|
13342
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
|
|
13342
13343
|
}
|
|
13343
13344
|
}
|
|
13344
13345
|
return `${lines.join("\n")}
|
|
@@ -13531,8 +13532,8 @@ function printHuman2(result) {
|
|
|
13531
13532
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13532
13533
|
}
|
|
13533
13534
|
for (const finding of result.findings) {
|
|
13534
|
-
const
|
|
13535
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
13535
|
+
const path18 = finding.evidence[0]?.path;
|
|
13536
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
|
|
13536
13537
|
}
|
|
13537
13538
|
}
|
|
13538
13539
|
function readErrorResult2(error) {
|
|
@@ -13770,8 +13771,8 @@ function printHuman3(result) {
|
|
|
13770
13771
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13771
13772
|
}
|
|
13772
13773
|
for (const finding of result.findings) {
|
|
13773
|
-
const
|
|
13774
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
13774
|
+
const path18 = finding.evidence[0]?.path;
|
|
13775
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path18 ? ` (${path18})` : ""}`);
|
|
13775
13776
|
}
|
|
13776
13777
|
console.log(`Note: ${result.note}`);
|
|
13777
13778
|
}
|
|
@@ -13890,8 +13891,8 @@ function renderCheckSection(result) {
|
|
|
13890
13891
|
`Diagnostics: ${result.diagnostics.length}`
|
|
13891
13892
|
];
|
|
13892
13893
|
for (const finding of result.findings.slice(0, 10)) {
|
|
13893
|
-
const
|
|
13894
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
13894
|
+
const path18 = finding.evidence[0]?.path ?? "(run)";
|
|
13895
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path18})`);
|
|
13895
13896
|
}
|
|
13896
13897
|
for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
|
|
13897
13898
|
lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
@@ -14451,6 +14452,447 @@ ${markdown}`, "utf-8");
|
|
|
14451
14452
|
console.log(markdown.trimEnd());
|
|
14452
14453
|
}
|
|
14453
14454
|
}
|
|
14455
|
+
var CONFIG_FILE = "agent-inspect.config.ts";
|
|
14456
|
+
var TRACE_DIR = ".agent-inspect";
|
|
14457
|
+
var GITKEEP = ".agent-inspect/.gitkeep";
|
|
14458
|
+
function normalizeFramework(value) {
|
|
14459
|
+
const raw = (value ?? "custom").trim();
|
|
14460
|
+
if (raw === "ai-sdk" || raw === "openai-agents" || raw === "langchain" || raw === "custom") {
|
|
14461
|
+
return raw;
|
|
14462
|
+
}
|
|
14463
|
+
throw new Error(
|
|
14464
|
+
"Unsupported --framework value. Use ai-sdk, openai-agents, langchain, or custom."
|
|
14465
|
+
);
|
|
14466
|
+
}
|
|
14467
|
+
function configTemplate(framework) {
|
|
14468
|
+
const base = `/**
|
|
14469
|
+
* AgentInspect local config (metadata-only capture by default).
|
|
14470
|
+
* See https://github.com/rajudandigam/agent-inspect/blob/main/docs/SAFE-TRACE-SHARING.md
|
|
14471
|
+
*/
|
|
14472
|
+
export const agentInspectConfig = {
|
|
14473
|
+
traceDir: ".agent-inspect",
|
|
14474
|
+
enabled: process.env.AGENT_INSPECT !== "0",
|
|
14475
|
+
redactionProfile: "local" as const,
|
|
14476
|
+
};
|
|
14477
|
+
`;
|
|
14478
|
+
if (framework === "custom") return base;
|
|
14479
|
+
return `${base}
|
|
14480
|
+
export const framework = "${framework}" as const;
|
|
14481
|
+
`;
|
|
14482
|
+
}
|
|
14483
|
+
function demoTemplate(framework) {
|
|
14484
|
+
switch (framework) {
|
|
14485
|
+
case "ai-sdk":
|
|
14486
|
+
return `/**
|
|
14487
|
+
* AI SDK starter \u2014 metadata-only telemetry (no real model calls in this demo).
|
|
14488
|
+
* Install: npm install agent-inspect @agent-inspect/ai-sdk ai
|
|
14489
|
+
*/
|
|
14490
|
+
import { inspectRun, step } from "agent-inspect";
|
|
14491
|
+
|
|
14492
|
+
async function main() {
|
|
14493
|
+
await inspectRun("ai-sdk-demo", async () => {
|
|
14494
|
+
await step.tool("mock-generate", async () => ({ text: "ok" }));
|
|
14495
|
+
}, { traceDir: ".agent-inspect", silent: true });
|
|
14496
|
+
console.log("Trace written to .agent-inspect/");
|
|
14497
|
+
}
|
|
14498
|
+
|
|
14499
|
+
main().catch((error) => {
|
|
14500
|
+
console.error(error);
|
|
14501
|
+
process.exitCode = 1;
|
|
14502
|
+
});
|
|
14503
|
+
`;
|
|
14504
|
+
case "openai-agents":
|
|
14505
|
+
return `/**
|
|
14506
|
+
* OpenAI Agents starter \u2014 use @agent-inspect/openai-agents for local-only processors.
|
|
14507
|
+
* This demo uses manual steps (no API keys).
|
|
14508
|
+
*/
|
|
14509
|
+
import { inspectRun, step } from "agent-inspect";
|
|
14510
|
+
|
|
14511
|
+
async function main() {
|
|
14512
|
+
await inspectRun("openai-agents-demo", async () => {
|
|
14513
|
+
await step.tool("mock-agent-run", async () => "ok");
|
|
14514
|
+
}, { traceDir: ".agent-inspect", silent: true });
|
|
14515
|
+
console.log("Trace written to .agent-inspect/");
|
|
14516
|
+
}
|
|
14517
|
+
|
|
14518
|
+
main().catch((error) => {
|
|
14519
|
+
console.error(error);
|
|
14520
|
+
process.exitCode = 1;
|
|
14521
|
+
});
|
|
14522
|
+
`;
|
|
14523
|
+
case "langchain":
|
|
14524
|
+
return `/**
|
|
14525
|
+
* LangChain starter \u2014 wire @agent-inspect/langchain callbacks in your app.
|
|
14526
|
+
* This demo uses manual steps (no API keys).
|
|
14527
|
+
*/
|
|
14528
|
+
import { inspectRun, step } from "agent-inspect";
|
|
14529
|
+
|
|
14530
|
+
async function main() {
|
|
14531
|
+
await inspectRun("langchain-demo", async () => {
|
|
14532
|
+
await step.tool("mock-chain", async () => "ok");
|
|
14533
|
+
}, { traceDir: ".agent-inspect", silent: true });
|
|
14534
|
+
console.log("Trace written to .agent-inspect/");
|
|
14535
|
+
}
|
|
14536
|
+
|
|
14537
|
+
main().catch((error) => {
|
|
14538
|
+
console.error(error);
|
|
14539
|
+
process.exitCode = 1;
|
|
14540
|
+
});
|
|
14541
|
+
`;
|
|
14542
|
+
default:
|
|
14543
|
+
return `import { observe } from "agent-inspect";
|
|
14544
|
+
|
|
14545
|
+
class DemoAgent {
|
|
14546
|
+
async run(input: { question: string }) {
|
|
14547
|
+
return { answer: \`Echo: \${input.question}\` };
|
|
14548
|
+
}
|
|
14549
|
+
}
|
|
14550
|
+
|
|
14551
|
+
const agent = observe(new DemoAgent(), {
|
|
14552
|
+
traceDir: ".agent-inspect",
|
|
14553
|
+
silent: true,
|
|
14554
|
+
});
|
|
14555
|
+
|
|
14556
|
+
await agent.run({ question: "hello" });
|
|
14557
|
+
console.log("Trace written to .agent-inspect/");
|
|
14558
|
+
`;
|
|
14559
|
+
}
|
|
14560
|
+
}
|
|
14561
|
+
function githubWorkflowTemplate() {
|
|
14562
|
+
return `name: AgentInspect artifacts
|
|
14563
|
+
|
|
14564
|
+
on:
|
|
14565
|
+
workflow_dispatch:
|
|
14566
|
+
push:
|
|
14567
|
+
branches: [main]
|
|
14568
|
+
|
|
14569
|
+
jobs:
|
|
14570
|
+
trace-artifacts:
|
|
14571
|
+
runs-on: ubuntu-latest
|
|
14572
|
+
steps:
|
|
14573
|
+
- uses: actions/checkout@v4
|
|
14574
|
+
- uses: actions/setup-node@v4
|
|
14575
|
+
with:
|
|
14576
|
+
node-version: "22"
|
|
14577
|
+
- run: npm ci
|
|
14578
|
+
- run: npm test
|
|
14579
|
+
- name: Upload AgentInspect traces
|
|
14580
|
+
if: always()
|
|
14581
|
+
uses: actions/upload-artifact@v4
|
|
14582
|
+
with:
|
|
14583
|
+
name: agent-inspect-traces
|
|
14584
|
+
path: .agent-inspect/**/*.jsonl
|
|
14585
|
+
if-no-files-found: ignore
|
|
14586
|
+
`;
|
|
14587
|
+
}
|
|
14588
|
+
async function planInit(options = {}) {
|
|
14589
|
+
const framework = normalizeFramework(options.framework);
|
|
14590
|
+
const cwd = path14.resolve(options.cwd ?? process.cwd());
|
|
14591
|
+
const demoPath = framework === "custom" ? path14.join("examples", "agent-inspect-demo.mjs") : path14.join("examples", `agent-inspect-${framework}-demo.mjs`);
|
|
14592
|
+
const candidates = [
|
|
14593
|
+
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
14594
|
+
{ rel: GITKEEP, content: "" },
|
|
14595
|
+
{ rel: demoPath, content: demoTemplate(framework) }
|
|
14596
|
+
];
|
|
14597
|
+
if (options.ci === "github") {
|
|
14598
|
+
candidates.push({
|
|
14599
|
+
rel: ".github/workflows/agent-inspect-artifacts.yml",
|
|
14600
|
+
content: githubWorkflowTemplate()
|
|
14601
|
+
});
|
|
14602
|
+
}
|
|
14603
|
+
const files = [];
|
|
14604
|
+
for (const candidate of candidates) {
|
|
14605
|
+
const abs = path14.join(cwd, candidate.rel);
|
|
14606
|
+
try {
|
|
14607
|
+
await access(abs);
|
|
14608
|
+
files.push({
|
|
14609
|
+
path: candidate.rel,
|
|
14610
|
+
action: "skip",
|
|
14611
|
+
reason: "file already exists"
|
|
14612
|
+
});
|
|
14613
|
+
} catch (error) {
|
|
14614
|
+
if (error.code !== "ENOENT") throw error;
|
|
14615
|
+
files.push({ path: candidate.rel, action: "create" });
|
|
14616
|
+
}
|
|
14617
|
+
}
|
|
14618
|
+
return { framework, ...options.ci ? { ci: options.ci } : {}, files };
|
|
14619
|
+
}
|
|
14620
|
+
async function writePlannedFiles(plan, cwd, options) {
|
|
14621
|
+
const written = [];
|
|
14622
|
+
for (const entry of plan.files) {
|
|
14623
|
+
if (entry.action === "skip") {
|
|
14624
|
+
continue;
|
|
14625
|
+
}
|
|
14626
|
+
const abs = path14.join(cwd, entry.path);
|
|
14627
|
+
if (options.dryRun) {
|
|
14628
|
+
written.push(entry.path);
|
|
14629
|
+
continue;
|
|
14630
|
+
}
|
|
14631
|
+
await mkdir(path14.dirname(abs), { recursive: true });
|
|
14632
|
+
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
|
|
14633
|
+
await writeFile(abs, content, "utf-8");
|
|
14634
|
+
written.push(entry.path);
|
|
14635
|
+
}
|
|
14636
|
+
return written;
|
|
14637
|
+
}
|
|
14638
|
+
async function initCommand(options = {}) {
|
|
14639
|
+
const cwd = path14.resolve(options.cwd ?? process.cwd());
|
|
14640
|
+
try {
|
|
14641
|
+
const plan = await planInit({ ...options, cwd });
|
|
14642
|
+
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
14643
|
+
const skipped = plan.files.filter((file) => file.action === "skip");
|
|
14644
|
+
if (options.json) {
|
|
14645
|
+
const payload = {
|
|
14646
|
+
ok: true,
|
|
14647
|
+
version,
|
|
14648
|
+
framework: plan.framework,
|
|
14649
|
+
ci: plan.ci ?? null,
|
|
14650
|
+
dryRun: options.dryRun === true,
|
|
14651
|
+
planned: plan.files,
|
|
14652
|
+
wouldWrite: options.dryRun ? toWrite : void 0
|
|
14653
|
+
};
|
|
14654
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
14655
|
+
if (options.dryRun) return;
|
|
14656
|
+
}
|
|
14657
|
+
const written = await writePlannedFiles(plan, cwd, options);
|
|
14658
|
+
if (!options.json) {
|
|
14659
|
+
console.log("AgentInspect init");
|
|
14660
|
+
console.log(`Framework: ${plan.framework}`);
|
|
14661
|
+
console.log(`Trace directory: ${TRACE_DIR}/`);
|
|
14662
|
+
if (options.dryRun) {
|
|
14663
|
+
console.log("Dry run \u2014 would create:");
|
|
14664
|
+
for (const file of toWrite) console.log(`- ${file}`);
|
|
14665
|
+
for (const file of skipped) {
|
|
14666
|
+
console.log(`- ${file.path} (skip: ${file.reason ?? "exists"})`);
|
|
14667
|
+
}
|
|
14668
|
+
return;
|
|
14669
|
+
}
|
|
14670
|
+
console.log("Created:");
|
|
14671
|
+
for (const file of written) console.log(`- ${file}`);
|
|
14672
|
+
for (const file of skipped) {
|
|
14673
|
+
console.log(`- ${file.path} (skipped: ${file.reason ?? "exists"})`);
|
|
14674
|
+
}
|
|
14675
|
+
console.log("\nNext: run your demo, then `npx agent-inspect list --dir .agent-inspect`");
|
|
14676
|
+
console.log("No dependencies were installed. Add packages manually when ready.");
|
|
14677
|
+
}
|
|
14678
|
+
} catch (error) {
|
|
14679
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
14680
|
+
if (options.json) {
|
|
14681
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
14682
|
+
} else {
|
|
14683
|
+
console.error(`[AgentInspect] init failed: ${msg}`);
|
|
14684
|
+
}
|
|
14685
|
+
process.exitCode = 1;
|
|
14686
|
+
}
|
|
14687
|
+
}
|
|
14688
|
+
var OPTIONAL_PACKAGES = {
|
|
14689
|
+
custom: [],
|
|
14690
|
+
"ai-sdk": ["@agent-inspect/ai-sdk"],
|
|
14691
|
+
"openai-agents": ["@agent-inspect/openai-agents"],
|
|
14692
|
+
langchain: ["@agent-inspect/langchain"]
|
|
14693
|
+
};
|
|
14694
|
+
function nodeVersionCheck() {
|
|
14695
|
+
const major = Number(process3.versions.node.split(".")[0]);
|
|
14696
|
+
if (Number.isNaN(major) || major < 20) {
|
|
14697
|
+
return {
|
|
14698
|
+
id: "node-version",
|
|
14699
|
+
status: "fail",
|
|
14700
|
+
message: `Node ${process3.versions.node} is below the supported minimum (20).`,
|
|
14701
|
+
remediation: "Upgrade to Node 20 LTS or newer.",
|
|
14702
|
+
evidence: process3.versions.node
|
|
14703
|
+
};
|
|
14704
|
+
}
|
|
14705
|
+
return {
|
|
14706
|
+
id: "node-version",
|
|
14707
|
+
status: "pass",
|
|
14708
|
+
message: `Node ${process3.versions.node} meets the minimum (>=20).`,
|
|
14709
|
+
evidence: process3.versions.node
|
|
14710
|
+
};
|
|
14711
|
+
}
|
|
14712
|
+
function envCheck(name, optional = true) {
|
|
14713
|
+
const value = process3.env[name];
|
|
14714
|
+
if (value === void 0 || value.trim() === "") {
|
|
14715
|
+
return {
|
|
14716
|
+
id: `env-${name.toLowerCase()}`,
|
|
14717
|
+
status: optional ? "skipped" : "warn",
|
|
14718
|
+
message: `${name} is not set.`,
|
|
14719
|
+
remediation: optional ? void 0 : `Set ${name}=1 to enable tracing.`
|
|
14720
|
+
};
|
|
14721
|
+
}
|
|
14722
|
+
return {
|
|
14723
|
+
id: `env-${name.toLowerCase()}`,
|
|
14724
|
+
status: "pass",
|
|
14725
|
+
message: `${name} is set.`,
|
|
14726
|
+
evidence: value
|
|
14727
|
+
};
|
|
14728
|
+
}
|
|
14729
|
+
async function traceDirWritable(traceDir) {
|
|
14730
|
+
const resolved = path14.resolve(traceDir);
|
|
14731
|
+
try {
|
|
14732
|
+
await mkdir(resolved, { recursive: true });
|
|
14733
|
+
await access(resolved, constants.W_OK);
|
|
14734
|
+
return {
|
|
14735
|
+
id: "trace-dir-writable",
|
|
14736
|
+
status: "pass",
|
|
14737
|
+
message: `Trace directory is writable: ${resolved}`,
|
|
14738
|
+
evidence: resolved
|
|
14739
|
+
};
|
|
14740
|
+
} catch (error) {
|
|
14741
|
+
return {
|
|
14742
|
+
id: "trace-dir-writable",
|
|
14743
|
+
status: "fail",
|
|
14744
|
+
message: `Trace directory is not writable: ${resolved}`,
|
|
14745
|
+
remediation: "Create the directory or set AGENT_INSPECT_TRACE_DIR to a writable path.",
|
|
14746
|
+
evidence: error instanceof Error ? error.message : String(error)
|
|
14747
|
+
};
|
|
14748
|
+
}
|
|
14749
|
+
}
|
|
14750
|
+
function resolvePackage(cwd, name) {
|
|
14751
|
+
const require2 = createRequire(path14.join(cwd, "package.json"));
|
|
14752
|
+
try {
|
|
14753
|
+
const pkgPath = require2.resolve(`${name}/package.json`);
|
|
14754
|
+
const pkg = require2(pkgPath);
|
|
14755
|
+
return { ok: true, version: pkg.version };
|
|
14756
|
+
} catch {
|
|
14757
|
+
return { ok: false };
|
|
14758
|
+
}
|
|
14759
|
+
}
|
|
14760
|
+
function importSmoke(cwd) {
|
|
14761
|
+
const results = [];
|
|
14762
|
+
const require2 = createRequire(path14.join(cwd, "package.json"));
|
|
14763
|
+
try {
|
|
14764
|
+
require2.resolve("agent-inspect");
|
|
14765
|
+
results.push({
|
|
14766
|
+
id: "import-agent-inspect",
|
|
14767
|
+
status: "pass",
|
|
14768
|
+
message: "agent-inspect resolves from the current project."
|
|
14769
|
+
});
|
|
14770
|
+
} catch {
|
|
14771
|
+
results.push({
|
|
14772
|
+
id: "import-agent-inspect",
|
|
14773
|
+
status: "warn",
|
|
14774
|
+
message: "agent-inspect is not installed in the current project.",
|
|
14775
|
+
remediation: "Run npm install agent-inspect (or pnpm add agent-inspect)."
|
|
14776
|
+
});
|
|
14777
|
+
}
|
|
14778
|
+
try {
|
|
14779
|
+
require2.resolve("agent-inspect/package.json");
|
|
14780
|
+
results.push({
|
|
14781
|
+
id: "import-agent-inspect-cjs",
|
|
14782
|
+
status: "pass",
|
|
14783
|
+
message: "CJS resolution for agent-inspect succeeded."
|
|
14784
|
+
});
|
|
14785
|
+
} catch {
|
|
14786
|
+
results.push({
|
|
14787
|
+
id: "import-agent-inspect-cjs",
|
|
14788
|
+
status: "skipped",
|
|
14789
|
+
message: "CJS resolution check skipped (package not installed locally)."
|
|
14790
|
+
});
|
|
14791
|
+
}
|
|
14792
|
+
return results;
|
|
14793
|
+
}
|
|
14794
|
+
function optionalPackageChecks(cwd, framework) {
|
|
14795
|
+
const packages = framework !== void 0 ? OPTIONAL_PACKAGES[framework] : [
|
|
14796
|
+
"@agent-inspect/ai-sdk",
|
|
14797
|
+
"@agent-inspect/openai-agents",
|
|
14798
|
+
"@agent-inspect/langchain",
|
|
14799
|
+
"@agent-inspect/redact",
|
|
14800
|
+
"@agent-inspect/eval"
|
|
14801
|
+
];
|
|
14802
|
+
return packages.map((name) => {
|
|
14803
|
+
const resolved = resolvePackage(cwd, name);
|
|
14804
|
+
if (!resolved.ok) {
|
|
14805
|
+
return {
|
|
14806
|
+
id: `optional-package-${name}`,
|
|
14807
|
+
status: framework !== void 0 ? "warn" : "skipped",
|
|
14808
|
+
message: `${name} is not installed.`,
|
|
14809
|
+
remediation: framework !== void 0 ? `npm install ${name}` : void 0
|
|
14810
|
+
};
|
|
14811
|
+
}
|
|
14812
|
+
return {
|
|
14813
|
+
id: `optional-package-${name}`,
|
|
14814
|
+
status: "pass",
|
|
14815
|
+
message: `${name} is available.`,
|
|
14816
|
+
evidence: resolved.version
|
|
14817
|
+
};
|
|
14818
|
+
});
|
|
14819
|
+
}
|
|
14820
|
+
function versionMismatchCheck(cwd) {
|
|
14821
|
+
const root = resolvePackage(cwd, "agent-inspect");
|
|
14822
|
+
if (!root.ok || root.version === void 0) {
|
|
14823
|
+
return {
|
|
14824
|
+
id: "version-alignment",
|
|
14825
|
+
status: "skipped",
|
|
14826
|
+
message: "Skipped version alignment \u2014 agent-inspect not installed locally."
|
|
14827
|
+
};
|
|
14828
|
+
}
|
|
14829
|
+
if (root.version !== version) {
|
|
14830
|
+
return {
|
|
14831
|
+
id: "version-alignment",
|
|
14832
|
+
status: "warn",
|
|
14833
|
+
message: `CLI version ${version} differs from local agent-inspect@${root.version}.`,
|
|
14834
|
+
remediation: "Align versions with npm install agent-inspect@latest",
|
|
14835
|
+
evidence: `cli=${version};local=${root.version}`
|
|
14836
|
+
};
|
|
14837
|
+
}
|
|
14838
|
+
return {
|
|
14839
|
+
id: "version-alignment",
|
|
14840
|
+
status: "pass",
|
|
14841
|
+
message: `CLI and local agent-inspect are aligned at ${version}.`
|
|
14842
|
+
};
|
|
14843
|
+
}
|
|
14844
|
+
async function runDoctorChecks(options = {}) {
|
|
14845
|
+
const cwd = path14.resolve(options.cwd ?? process3.cwd());
|
|
14846
|
+
const traceDir = options.traceDir?.trim() || process3.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
14847
|
+
const checks2 = [
|
|
14848
|
+
nodeVersionCheck(),
|
|
14849
|
+
{
|
|
14850
|
+
id: "cli-version",
|
|
14851
|
+
status: "pass",
|
|
14852
|
+
message: `agent-inspect CLI ${version}`,
|
|
14853
|
+
evidence: version
|
|
14854
|
+
},
|
|
14855
|
+
await traceDirWritable(traceDir),
|
|
14856
|
+
envCheck("AGENT_INSPECT"),
|
|
14857
|
+
envCheck("AGENT_INSPECT_TRACE_DIR"),
|
|
14858
|
+
versionMismatchCheck(cwd)
|
|
14859
|
+
];
|
|
14860
|
+
if (options.checkImports !== false) {
|
|
14861
|
+
checks2.push(...importSmoke(cwd));
|
|
14862
|
+
}
|
|
14863
|
+
checks2.push(...optionalPackageChecks(cwd, options.framework));
|
|
14864
|
+
return checks2.sort((a, b) => a.id.localeCompare(b.id));
|
|
14865
|
+
}
|
|
14866
|
+
async function doctorCommand(options = {}) {
|
|
14867
|
+
const checks2 = await runDoctorChecks(options);
|
|
14868
|
+
const failed = checks2.filter((check) => check.status === "fail").length;
|
|
14869
|
+
const warned = checks2.filter((check) => check.status === "warn").length;
|
|
14870
|
+
if (options.json) {
|
|
14871
|
+
console.log(
|
|
14872
|
+
JSON.stringify(
|
|
14873
|
+
{
|
|
14874
|
+
ok: failed === 0,
|
|
14875
|
+
version,
|
|
14876
|
+
summary: { pass: checks2.filter((c) => c.status === "pass").length, warn: warned, fail: failed },
|
|
14877
|
+
checks: checks2
|
|
14878
|
+
},
|
|
14879
|
+
null,
|
|
14880
|
+
2
|
|
14881
|
+
)
|
|
14882
|
+
);
|
|
14883
|
+
if (failed > 0) process3.exitCode = 1;
|
|
14884
|
+
return;
|
|
14885
|
+
}
|
|
14886
|
+
console.log("AgentInspect doctor");
|
|
14887
|
+
for (const check of checks2) {
|
|
14888
|
+
const tag = check.status.toUpperCase();
|
|
14889
|
+
console.log(`[${tag}] ${check.id}: ${check.message}`);
|
|
14890
|
+
if (check.remediation) console.log(` \u2192 ${check.remediation}`);
|
|
14891
|
+
}
|
|
14892
|
+
console.log(`
|
|
14893
|
+
Summary: ${failed} failed, ${warned} warnings`);
|
|
14894
|
+
if (failed > 0) process3.exitCode = 1;
|
|
14895
|
+
}
|
|
14454
14896
|
|
|
14455
14897
|
// packages/cli/src/index.ts
|
|
14456
14898
|
function runCommand(action) {
|
|
@@ -14750,6 +15192,26 @@ function createCliProgram() {
|
|
|
14750
15192
|
).action((target, opts) => {
|
|
14751
15193
|
runCommand(() => explainCommand(target, opts));
|
|
14752
15194
|
});
|
|
15195
|
+
program.command("init").description("Initialize a minimal local AgentInspect setup (no dependency install)").addOption(
|
|
15196
|
+
new Option("--framework <framework>", "starter framework path").choices([
|
|
15197
|
+
"ai-sdk",
|
|
15198
|
+
"openai-agents",
|
|
15199
|
+
"langchain",
|
|
15200
|
+
"custom"
|
|
15201
|
+
])
|
|
15202
|
+
).addOption(new Option("--ci <provider>", "optional CI snippet").choices(["github"])).option("--dry-run", "print planned files without writing").option("--yes", "non-interactive; skip existing files").option("--json", "print deterministic JSON plan/result").action((opts) => {
|
|
15203
|
+
runCommand(() => initCommand(opts));
|
|
15204
|
+
});
|
|
15205
|
+
program.command("doctor").description("Diagnose local AgentInspect setup (no network, no installs)").option("--json", "print deterministic JSON results").option("--trace-dir <path>", "trace directory to validate (default .agent-inspect)").option("--check-imports", "check local package resolution", true).option("--no-check-imports", "skip import resolution checks").addOption(
|
|
15206
|
+
new Option("--framework <framework>", "check optional adapter packages").choices([
|
|
15207
|
+
"ai-sdk",
|
|
15208
|
+
"openai-agents",
|
|
15209
|
+
"langchain",
|
|
15210
|
+
"custom"
|
|
15211
|
+
])
|
|
15212
|
+
).action((opts) => {
|
|
15213
|
+
runCommand(() => doctorCommand(opts));
|
|
15214
|
+
});
|
|
14753
15215
|
return program;
|
|
14754
15216
|
}
|
|
14755
15217
|
function isPrimaryModule() {
|