@tangle-network/traces 0.15.3 → 0.15.5
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/README.md +80 -12
- package/dist/{chunk-U4EB4HK7.js → chunk-RERVIGLH.js} +590 -285
- package/dist/cli.js +252 -31
- package/dist/index.d.ts +140 -32
- package/dist/index.js +27 -9
- package/docs/trace-analysts.md +1 -1
- package/package.json +4 -4
|
@@ -881,8 +881,8 @@ function traceContractBuildId(fromFile = import.meta.url) {
|
|
|
881
881
|
}
|
|
882
882
|
var buildIdCache = /* @__PURE__ */ new Map();
|
|
883
883
|
function traceContractBuildIdOrNull(fromFile = import.meta.url) {
|
|
884
|
-
const
|
|
885
|
-
if (
|
|
884
|
+
const cached2 = buildIdCache.get(fromFile);
|
|
885
|
+
if (cached2 !== void 0) return cached2;
|
|
886
886
|
let resolved;
|
|
887
887
|
try {
|
|
888
888
|
resolved = traceContractBuildId(fromFile);
|
|
@@ -1018,8 +1018,8 @@ function serializeSpans(spans) {
|
|
|
1018
1018
|
async function writeOtlpFile(spans, outPath) {
|
|
1019
1019
|
const { mkdtemp: mkdtemp8, writeFile: writeFile13 } = await import("fs/promises");
|
|
1020
1020
|
const { tmpdir: tmpdir8 } = await import("os");
|
|
1021
|
-
const { join:
|
|
1022
|
-
const path = outPath ??
|
|
1021
|
+
const { join: join35 } = await import("path");
|
|
1022
|
+
const path = outPath ?? join35(await mkdtemp8(join35(tmpdir8(), "traces-")), "spans.otlp.jsonl");
|
|
1023
1023
|
await writeFile13(path, serializeSpans(spans), "utf8");
|
|
1024
1024
|
return path;
|
|
1025
1025
|
}
|
|
@@ -2225,6 +2225,7 @@ function projectClaudeEvent(event) {
|
|
|
2225
2225
|
cacheWriteInputTokens: event.message.usage?.cache_creation_input_tokens ?? null,
|
|
2226
2226
|
content: textOf2(event.message.content) || null,
|
|
2227
2227
|
contentSource: textSources(event.message, "content"),
|
|
2228
|
+
parentToolUseId: event.parent_tool_use_id ?? null,
|
|
2228
2229
|
tools
|
|
2229
2230
|
};
|
|
2230
2231
|
}
|
|
@@ -2255,6 +2256,7 @@ function projectClaudeEvent(event) {
|
|
|
2255
2256
|
timestamp,
|
|
2256
2257
|
prompt: prompt || null,
|
|
2257
2258
|
contentSource: textSources(event.message, "content"),
|
|
2259
|
+
parentToolUseId: event.parent_tool_use_id ?? null,
|
|
2258
2260
|
...prompt ? {
|
|
2259
2261
|
isSidechain: event.isSidechain === true,
|
|
2260
2262
|
isMeta: event.isMeta === true,
|
|
@@ -2374,15 +2376,21 @@ function consumeDistinctClaudeEvent(event, ctx, state, seen, sourcePath) {
|
|
|
2374
2376
|
consumeClaudeEvent(accepted.projection, accepted.uid, ctx, state);
|
|
2375
2377
|
return true;
|
|
2376
2378
|
}
|
|
2379
|
+
function inStreamParent(parentToolUseId, state) {
|
|
2380
|
+
if (!parentToolUseId) return void 0;
|
|
2381
|
+
const parentTool = state.toolSpanByUseId.get(parentToolUseId);
|
|
2382
|
+
return parentTool ? { span: parentTool, confidence: "explicit" } : void 0;
|
|
2383
|
+
}
|
|
2377
2384
|
function consumeClaudeEvent(event, uid, ctx, state) {
|
|
2378
2385
|
if (event.kind === "assistant") {
|
|
2379
2386
|
const messageId = event.messageId ?? uid;
|
|
2380
2387
|
let llmSpan = state.llmSpanByMessageId.get(messageId);
|
|
2381
2388
|
if (!llmSpan) {
|
|
2389
|
+
const parent = inStreamParent(event.parentToolUseId, state);
|
|
2382
2390
|
llmSpan = span({
|
|
2383
2391
|
traceId: ctx.traceId,
|
|
2384
2392
|
spanId: `${ctx.idPrefix}${uid}`,
|
|
2385
|
-
parentSpanId: ctx.rootParent,
|
|
2393
|
+
parentSpanId: parent ? parent.span.span_id : ctx.rootParent,
|
|
2386
2394
|
name: "llm.turn",
|
|
2387
2395
|
kind: "LLM",
|
|
2388
2396
|
startTime: event.timestamp,
|
|
@@ -2395,6 +2403,7 @@ function consumeClaudeEvent(event, uid, ctx, state) {
|
|
|
2395
2403
|
cacheWriteInputTokens: event.cacheWriteInputTokens,
|
|
2396
2404
|
step: state.step
|
|
2397
2405
|
});
|
|
2406
|
+
if (parent) llmSpan.attributes[ATTR3.parentConfidence] = parent.confidence;
|
|
2398
2407
|
state.spans.push(llmSpan);
|
|
2399
2408
|
state.llmSpanByMessageId.set(messageId, llmSpan);
|
|
2400
2409
|
state.step += 1;
|
|
@@ -2466,10 +2475,11 @@ function consumeClaudeEvent(event, uid, ctx, state) {
|
|
|
2466
2475
|
}));
|
|
2467
2476
|
state.sawUserTurn = true;
|
|
2468
2477
|
if (event.originKind) state.sawRecordedOrigin = true;
|
|
2478
|
+
const userParent = inStreamParent(event.parentToolUseId, state);
|
|
2469
2479
|
const prompt = userPromptSpan({
|
|
2470
2480
|
traceId: ctx.traceId,
|
|
2471
2481
|
spanId: `${ctx.idPrefix}${uid}:user`,
|
|
2472
|
-
parentSpanId: ctx.rootParent,
|
|
2482
|
+
parentSpanId: userParent ? userParent.span.span_id : ctx.rootParent,
|
|
2473
2483
|
startTime: event.timestamp,
|
|
2474
2484
|
service: SERVICE2,
|
|
2475
2485
|
agent: ctx.agent,
|
|
@@ -2482,6 +2492,7 @@ function consumeClaudeEvent(event, uid, ctx, state) {
|
|
|
2482
2492
|
prompt.attributes[ORIGIN_RECORDED_ATTR] = true;
|
|
2483
2493
|
prompt.attributes[ORIGIN_KIND_ATTR] = event.originKind;
|
|
2484
2494
|
}
|
|
2495
|
+
if (userParent) prompt.attributes[ATTR3.parentConfidence] = userParent.confidence;
|
|
2485
2496
|
state.spans.push(prompt);
|
|
2486
2497
|
state.promptSpans.push(prompt);
|
|
2487
2498
|
state.step += 1;
|
|
@@ -3833,9 +3844,9 @@ function itemCountsJson(counts) {
|
|
|
3833
3844
|
}
|
|
3834
3845
|
function placeInnerSpans(pending, windows) {
|
|
3835
3846
|
return pending.map((entry) => {
|
|
3836
|
-
const { parent, join:
|
|
3847
|
+
const { parent, join: join35 } = joinItem(windows, entry.startMs, entry.endMs);
|
|
3837
3848
|
if (parent) entry.span.parent_span_id = parent.span_id;
|
|
3838
|
-
entry.span.attributes["traces.codex.item_join"] =
|
|
3849
|
+
entry.span.attributes["traces.codex.item_join"] = join35;
|
|
3839
3850
|
return entry.span;
|
|
3840
3851
|
});
|
|
3841
3852
|
}
|
|
@@ -4159,8 +4170,8 @@ var CodexAdapter = class {
|
|
|
4159
4170
|
const completedItemKeys = /* @__PURE__ */ new Set();
|
|
4160
4171
|
const unmodeledItemCounts = /* @__PURE__ */ new Map();
|
|
4161
4172
|
const droppedItemCounts = /* @__PURE__ */ new Map();
|
|
4162
|
-
const countItem = (counts,
|
|
4163
|
-
counts.set(
|
|
4173
|
+
const countItem = (counts, label2) => {
|
|
4174
|
+
counts.set(label2, (counts.get(label2) ?? 0) + 1);
|
|
4164
4175
|
};
|
|
4165
4176
|
let taskIndex = 0;
|
|
4166
4177
|
const unpairedUserItems = [];
|
|
@@ -4670,11 +4681,11 @@ var CodexAdapter = class {
|
|
|
4670
4681
|
const input = reportedCount(sessionTotalUsage.input_tokens);
|
|
4671
4682
|
const output = reportedCount(sessionTotalUsage.output_tokens);
|
|
4672
4683
|
const reasoning = reportedCount(sessionTotalUsage.reasoning_output_tokens);
|
|
4673
|
-
const
|
|
4684
|
+
const cached2 = reportedCount(sessionTotalUsage.cached_input_tokens);
|
|
4674
4685
|
if (input !== void 0) root.attributes[SESSION_TOTAL_INPUT_TOKENS] = input;
|
|
4675
4686
|
if (output !== void 0) root.attributes[SESSION_TOTAL_OUTPUT_TOKENS] = output;
|
|
4676
4687
|
if (reasoning !== void 0) root.attributes[SESSION_TOTAL_REASONING_TOKENS] = reasoning;
|
|
4677
|
-
if (
|
|
4688
|
+
if (cached2 !== void 0) root.attributes[SESSION_TOTAL_CACHED_INPUT_TOKENS] = cached2;
|
|
4678
4689
|
}
|
|
4679
4690
|
}
|
|
4680
4691
|
if (inheritedSpansEmitted > 0) root.attributes[INHERITED_SPAN_COUNT_ATTR] = inheritedSpansEmitted;
|
|
@@ -4748,14 +4759,14 @@ function earlier(left, right) {
|
|
|
4748
4759
|
function later(left, right) {
|
|
4749
4760
|
return Date.parse(left) >= Date.parse(right) ? left : right;
|
|
4750
4761
|
}
|
|
4751
|
-
function requireObject2(value, sourcePath,
|
|
4762
|
+
function requireObject2(value, sourcePath, label2) {
|
|
4752
4763
|
const object = objectValue(value);
|
|
4753
|
-
if (!object) throw new CodexExecStreamError(sourcePath, `${
|
|
4764
|
+
if (!object) throw new CodexExecStreamError(sourcePath, `${label2} must be an object`);
|
|
4754
4765
|
return object;
|
|
4755
4766
|
}
|
|
4756
|
-
function requireString(value, sourcePath,
|
|
4767
|
+
function requireString(value, sourcePath, label2) {
|
|
4757
4768
|
const string = stringValue(value);
|
|
4758
|
-
if (!string) throw new CodexExecStreamError(sourcePath, `${
|
|
4769
|
+
if (!string) throw new CodexExecStreamError(sourcePath, `${label2} must be a non-empty string`);
|
|
4759
4770
|
return string;
|
|
4760
4771
|
}
|
|
4761
4772
|
function optionalTokenCount(usage, key, sourcePath) {
|
|
@@ -6708,7 +6719,7 @@ function extractAbsolutePaths(spans) {
|
|
|
6708
6719
|
async function resolveRepoAttrs(cwd) {
|
|
6709
6720
|
if (!cwd) return {};
|
|
6710
6721
|
const attrs = { [ATTR.CWD]: cwd };
|
|
6711
|
-
const
|
|
6722
|
+
const basename19 = (() => {
|
|
6712
6723
|
const trimmed = cwd.replace(/\/+$/g, "");
|
|
6713
6724
|
const idx = trimmed.lastIndexOf("/");
|
|
6714
6725
|
const name = idx === -1 ? trimmed : trimmed.slice(idx + 1);
|
|
@@ -6730,7 +6741,7 @@ async function resolveRepoAttrs(cwd) {
|
|
|
6730
6741
|
if (commit) attrs[ATTR.GIT_COMMIT] = commit;
|
|
6731
6742
|
} catch {
|
|
6732
6743
|
}
|
|
6733
|
-
attrs[ATTR.SUBJECT_KEY] =
|
|
6744
|
+
attrs[ATTR.SUBJECT_KEY] = basename19;
|
|
6734
6745
|
return attrs;
|
|
6735
6746
|
}
|
|
6736
6747
|
async function repoCandidateForPath(path) {
|
|
@@ -6786,8 +6797,8 @@ function replaceRepoAttrs(spans, attrs) {
|
|
|
6786
6797
|
}
|
|
6787
6798
|
}
|
|
6788
6799
|
async function resolutionForWorkdirEvidence(evidence3, cache) {
|
|
6789
|
-
const
|
|
6790
|
-
if (
|
|
6800
|
+
const cached2 = cache.get(evidence3.path);
|
|
6801
|
+
if (cached2 !== void 0) return cached2;
|
|
6791
6802
|
const cwd = await repoCandidateForPath(evidence3.path);
|
|
6792
6803
|
if (!cwd) {
|
|
6793
6804
|
cache.set(evidence3.path, null);
|
|
@@ -6891,9 +6902,9 @@ async function locateSessions(adapter, opts = {}) {
|
|
|
6891
6902
|
for (const ref of refs) {
|
|
6892
6903
|
let matched = cwdMatchesSelection(ref.cwd, cwdSelections);
|
|
6893
6904
|
if (!matched && ref.cwd !== null) {
|
|
6894
|
-
const
|
|
6895
|
-
matched =
|
|
6896
|
-
if (
|
|
6905
|
+
const cached2 = resolvedMatch.get(ref.cwd);
|
|
6906
|
+
matched = cached2 ?? await cwdMatchesSelectionResolved(ref.cwd, cwdSelections);
|
|
6907
|
+
if (cached2 === void 0) resolvedMatch.set(ref.cwd, matched);
|
|
6897
6908
|
}
|
|
6898
6909
|
if (!matched && !(ref.cwd === null && ref.integrity)) continue;
|
|
6899
6910
|
byKey.set(refKey(ref), ref);
|
|
@@ -7523,106 +7534,106 @@ var RESULT_FAILURE_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "ou
|
|
|
7523
7534
|
var RESULT_REPORT_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "output"]);
|
|
7524
7535
|
var RESULT_FINDING_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "output", "findings"]);
|
|
7525
7536
|
var RESULT_DISCOVERY_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "output", "candidates"]);
|
|
7526
|
-
function record(value,
|
|
7537
|
+
function record(value, label2) {
|
|
7527
7538
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7528
|
-
throw new TypeError(`${
|
|
7539
|
+
throw new TypeError(`${label2} must be an object`);
|
|
7529
7540
|
}
|
|
7530
7541
|
return value;
|
|
7531
7542
|
}
|
|
7532
|
-
function assertOnlyKeys(value, allowed,
|
|
7543
|
+
function assertOnlyKeys(value, allowed, label2) {
|
|
7533
7544
|
for (const key of Object.keys(value)) {
|
|
7534
|
-
if (!allowed.has(key)) throw new TypeError(`${
|
|
7545
|
+
if (!allowed.has(key)) throw new TypeError(`${label2} contains unexpected field '${key}'`);
|
|
7535
7546
|
}
|
|
7536
7547
|
}
|
|
7537
|
-
function text(value,
|
|
7538
|
-
if (typeof value !== "string") throw new TypeError(`${
|
|
7548
|
+
function text(value, label2) {
|
|
7549
|
+
if (typeof value !== "string") throw new TypeError(`${label2} must be a string`);
|
|
7539
7550
|
return value;
|
|
7540
7551
|
}
|
|
7541
|
-
function nonEmptyString3(value,
|
|
7542
|
-
const decoded = text(value,
|
|
7543
|
-
if (decoded.length === 0) throw new TypeError(`${
|
|
7552
|
+
function nonEmptyString3(value, label2) {
|
|
7553
|
+
const decoded = text(value, label2);
|
|
7554
|
+
if (decoded.length === 0) throw new TypeError(`${label2} must be a non-empty string`);
|
|
7544
7555
|
return decoded;
|
|
7545
7556
|
}
|
|
7546
|
-
function optionalString(value,
|
|
7547
|
-
return value === void 0 ? void 0 : text(value,
|
|
7557
|
+
function optionalString(value, label2) {
|
|
7558
|
+
return value === void 0 ? void 0 : text(value, label2);
|
|
7548
7559
|
}
|
|
7549
|
-
function boolean(value,
|
|
7550
|
-
if (typeof value !== "boolean") throw new TypeError(`${
|
|
7560
|
+
function boolean(value, label2) {
|
|
7561
|
+
if (typeof value !== "boolean") throw new TypeError(`${label2} must be a boolean`);
|
|
7551
7562
|
return value;
|
|
7552
7563
|
}
|
|
7553
|
-
function integer(value,
|
|
7564
|
+
function integer(value, label2, minimum) {
|
|
7554
7565
|
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
7555
|
-
throw new TypeError(`${
|
|
7566
|
+
throw new TypeError(`${label2} must be a safe integer >= ${minimum}`);
|
|
7556
7567
|
}
|
|
7557
7568
|
return value;
|
|
7558
7569
|
}
|
|
7559
|
-
function optionalRecord(value,
|
|
7560
|
-
return value === void 0 ? void 0 : record(value,
|
|
7570
|
+
function optionalRecord(value, label2) {
|
|
7571
|
+
return value === void 0 ? void 0 : record(value, label2);
|
|
7561
7572
|
}
|
|
7562
7573
|
function spanEvidenceUri(traceId, spanId) {
|
|
7563
7574
|
return `trace://${encodeURIComponent(traceId)}/span/${encodeURIComponent(spanId)}`;
|
|
7564
7575
|
}
|
|
7565
|
-
function validateSpanEvidence(uri, knownSpanUris,
|
|
7576
|
+
function validateSpanEvidence(uri, knownSpanUris, label2) {
|
|
7566
7577
|
if (knownSpanUris && !knownSpanUris.has(uri)) {
|
|
7567
|
-
throw new TypeError(`${
|
|
7578
|
+
throw new TypeError(`${label2} references unknown span evidence URI '${uri}'`);
|
|
7568
7579
|
}
|
|
7569
7580
|
}
|
|
7570
|
-
function decodeEvidenceRef(value,
|
|
7571
|
-
const ref = record(value,
|
|
7572
|
-
assertOnlyKeys(ref, EVIDENCE_KEYS,
|
|
7573
|
-
const kind = nonEmptyString3(ref.kind, `${
|
|
7581
|
+
function decodeEvidenceRef(value, label2, knownSpanUris) {
|
|
7582
|
+
const ref = record(value, label2);
|
|
7583
|
+
assertOnlyKeys(ref, EVIDENCE_KEYS, label2);
|
|
7584
|
+
const kind = nonEmptyString3(ref.kind, `${label2}.kind`);
|
|
7574
7585
|
if (!["span", "event", "artifact", "finding", "metric"].includes(kind)) {
|
|
7575
|
-
throw new TypeError(`${
|
|
7586
|
+
throw new TypeError(`${label2}.kind is unsupported`);
|
|
7576
7587
|
}
|
|
7577
|
-
const uri = nonEmptyString3(ref.uri, `${
|
|
7578
|
-
if (kind === "span") validateSpanEvidence(uri, knownSpanUris,
|
|
7579
|
-
const excerpt = optionalString(ref.excerpt, `${
|
|
7588
|
+
const uri = nonEmptyString3(ref.uri, `${label2}.uri`);
|
|
7589
|
+
if (kind === "span") validateSpanEvidence(uri, knownSpanUris, label2);
|
|
7590
|
+
const excerpt = optionalString(ref.excerpt, `${label2}.excerpt`);
|
|
7580
7591
|
return {
|
|
7581
7592
|
kind,
|
|
7582
7593
|
uri,
|
|
7583
7594
|
...excerpt === void 0 ? {} : { excerpt }
|
|
7584
7595
|
};
|
|
7585
7596
|
}
|
|
7586
|
-
function decodeFinding(value,
|
|
7587
|
-
const finding2 = record(value,
|
|
7588
|
-
assertOnlyKeys(finding2, FINDING_KEYS,
|
|
7597
|
+
function decodeFinding(value, label2, knownSpanUris) {
|
|
7598
|
+
const finding2 = record(value, label2);
|
|
7599
|
+
assertOnlyKeys(finding2, FINDING_KEYS, label2);
|
|
7589
7600
|
if (finding2.schema_version !== "1.0.0") {
|
|
7590
|
-
throw new TypeError(`${
|
|
7601
|
+
throw new TypeError(`${label2}.schema_version must be '1.0.0'`);
|
|
7591
7602
|
}
|
|
7592
|
-
const findingId = nonEmptyString3(finding2.finding_id, `${
|
|
7593
|
-
const analystId = nonEmptyString3(finding2.analyst_id, `${
|
|
7594
|
-
const producedAt = nonEmptyString3(finding2.produced_at, `${
|
|
7603
|
+
const findingId = nonEmptyString3(finding2.finding_id, `${label2}.finding_id`);
|
|
7604
|
+
const analystId = nonEmptyString3(finding2.analyst_id, `${label2}.analyst_id`);
|
|
7605
|
+
const producedAt = nonEmptyString3(finding2.produced_at, `${label2}.produced_at`);
|
|
7595
7606
|
if (!Number.isFinite(Date.parse(producedAt))) {
|
|
7596
|
-
throw new TypeError(`${
|
|
7607
|
+
throw new TypeError(`${label2}.produced_at must be a valid timestamp`);
|
|
7597
7608
|
}
|
|
7598
|
-
const severity = nonEmptyString3(finding2.severity, `${
|
|
7609
|
+
const severity = nonEmptyString3(finding2.severity, `${label2}.severity`);
|
|
7599
7610
|
if (!["critical", "high", "medium", "low", "info"].includes(severity)) {
|
|
7600
|
-
throw new TypeError(`${
|
|
7611
|
+
throw new TypeError(`${label2}.severity is unsupported`);
|
|
7601
7612
|
}
|
|
7602
7613
|
if (!Array.isArray(finding2.evidence_refs)) {
|
|
7603
|
-
throw new TypeError(`${
|
|
7614
|
+
throw new TypeError(`${label2}.evidence_refs must be an array`);
|
|
7604
7615
|
}
|
|
7605
7616
|
if (typeof finding2.confidence !== "number" || !Number.isFinite(finding2.confidence) || finding2.confidence < 0 || finding2.confidence > 1) {
|
|
7606
|
-
throw new TypeError(`${
|
|
7617
|
+
throw new TypeError(`${label2}.confidence must be a finite number from 0 to 1`);
|
|
7607
7618
|
}
|
|
7608
|
-
const rationale = optionalString(finding2.rationale, `${
|
|
7619
|
+
const rationale = optionalString(finding2.rationale, `${label2}.rationale`);
|
|
7609
7620
|
const recommendedAction = optionalString(
|
|
7610
7621
|
finding2.recommended_action,
|
|
7611
|
-
`${
|
|
7622
|
+
`${label2}.recommended_action`
|
|
7612
7623
|
);
|
|
7613
|
-
const validationPlan = optionalString(finding2.validation_plan, `${
|
|
7614
|
-
const subject = optionalString(finding2.subject, `${
|
|
7615
|
-
const derivedFromJudge = finding2.derived_from_judge === void 0 ? void 0 : boolean(finding2.derived_from_judge, `${
|
|
7616
|
-
const metadata = optionalRecord(finding2.metadata, `${
|
|
7624
|
+
const validationPlan = optionalString(finding2.validation_plan, `${label2}.validation_plan`);
|
|
7625
|
+
const subject = optionalString(finding2.subject, `${label2}.subject`);
|
|
7626
|
+
const derivedFromJudge = finding2.derived_from_judge === void 0 ? void 0 : boolean(finding2.derived_from_judge, `${label2}.derived_from_judge`);
|
|
7627
|
+
const metadata = optionalRecord(finding2.metadata, `${label2}.metadata`);
|
|
7617
7628
|
return {
|
|
7618
7629
|
schema_version: "1.0.0",
|
|
7619
7630
|
finding_id: findingId,
|
|
7620
7631
|
analyst_id: analystId,
|
|
7621
7632
|
produced_at: producedAt,
|
|
7622
7633
|
severity,
|
|
7623
|
-
area: nonEmptyString3(finding2.area, `${
|
|
7624
|
-
claim: nonEmptyString3(finding2.claim, `${
|
|
7625
|
-
evidence_refs: finding2.evidence_refs.map((ref, index) => decodeEvidenceRef(ref, `${
|
|
7634
|
+
area: nonEmptyString3(finding2.area, `${label2}.area`),
|
|
7635
|
+
claim: nonEmptyString3(finding2.claim, `${label2}.claim`),
|
|
7636
|
+
evidence_refs: finding2.evidence_refs.map((ref, index) => decodeEvidenceRef(ref, `${label2}.evidence_refs[${index}]`, knownSpanUris)),
|
|
7626
7637
|
confidence: finding2.confidence,
|
|
7627
7638
|
...rationale === void 0 ? {} : { rationale },
|
|
7628
7639
|
...recommendedAction === void 0 ? {} : { recommended_action: recommendedAction },
|
|
@@ -7632,32 +7643,32 @@ function decodeFinding(value, label, knownSpanUris) {
|
|
|
7632
7643
|
...metadata === void 0 ? {} : { metadata }
|
|
7633
7644
|
};
|
|
7634
7645
|
}
|
|
7635
|
-
function decodeCandidate(value,
|
|
7636
|
-
const candidate = record(value,
|
|
7637
|
-
assertOnlyKeys(candidate, CANDIDATE_KEYS,
|
|
7646
|
+
function decodeCandidate(value, label2, knownSpanUris) {
|
|
7647
|
+
const candidate = record(value, label2);
|
|
7648
|
+
assertOnlyKeys(candidate, CANDIDATE_KEYS, label2);
|
|
7638
7649
|
if (candidate.status !== "needs_review") {
|
|
7639
|
-
throw new TypeError(`${
|
|
7650
|
+
throw new TypeError(`${label2}.status must be 'needs_review'`);
|
|
7640
7651
|
}
|
|
7641
|
-
const traceId = nonEmptyString3(candidate.traceId, `${
|
|
7642
|
-
const spanId = nonEmptyString3(candidate.spanId, `${
|
|
7643
|
-
const evidenceUri = nonEmptyString3(candidate.evidenceUri, `${
|
|
7652
|
+
const traceId = nonEmptyString3(candidate.traceId, `${label2}.traceId`);
|
|
7653
|
+
const spanId = nonEmptyString3(candidate.spanId, `${label2}.spanId`);
|
|
7654
|
+
const evidenceUri = nonEmptyString3(candidate.evidenceUri, `${label2}.evidenceUri`);
|
|
7644
7655
|
if (evidenceUri !== spanEvidenceUri(traceId, spanId)) {
|
|
7645
|
-
throw new TypeError(`${
|
|
7656
|
+
throw new TypeError(`${label2}.evidenceUri does not match its traceId and spanId`);
|
|
7646
7657
|
}
|
|
7647
|
-
validateSpanEvidence(evidenceUri, knownSpanUris,
|
|
7648
|
-
const metadata = optionalRecord(candidate.metadata, `${
|
|
7658
|
+
validateSpanEvidence(evidenceUri, knownSpanUris, label2);
|
|
7659
|
+
const metadata = optionalRecord(candidate.metadata, `${label2}.metadata`);
|
|
7649
7660
|
return {
|
|
7650
|
-
engine: nonEmptyString3(candidate.engine, `${
|
|
7651
|
-
engineVersion: nonEmptyString3(candidate.engineVersion, `${
|
|
7661
|
+
engine: nonEmptyString3(candidate.engine, `${label2}.engine`),
|
|
7662
|
+
engineVersion: nonEmptyString3(candidate.engineVersion, `${label2}.engineVersion`),
|
|
7652
7663
|
status: "needs_review",
|
|
7653
|
-
group: nonEmptyString3(candidate.group, `${
|
|
7654
|
-
rank: integer(candidate.rank, `${
|
|
7655
|
-
groupSize: integer(candidate.groupSize, `${
|
|
7664
|
+
group: nonEmptyString3(candidate.group, `${label2}.group`),
|
|
7665
|
+
rank: integer(candidate.rank, `${label2}.rank`, 0),
|
|
7666
|
+
groupSize: integer(candidate.groupSize, `${label2}.groupSize`, 1),
|
|
7656
7667
|
traceId,
|
|
7657
7668
|
spanId,
|
|
7658
7669
|
evidenceUri,
|
|
7659
|
-
summary: nonEmptyString3(candidate.summary, `${
|
|
7660
|
-
actionText: nonEmptyString3(candidate.actionText, `${
|
|
7670
|
+
summary: nonEmptyString3(candidate.summary, `${label2}.summary`),
|
|
7671
|
+
actionText: nonEmptyString3(candidate.actionText, `${label2}.actionText`),
|
|
7661
7672
|
...metadata === void 0 ? {} : { metadata }
|
|
7662
7673
|
};
|
|
7663
7674
|
}
|
|
@@ -7691,57 +7702,57 @@ function decodeExternalAnalysisPayload(value) {
|
|
|
7691
7702
|
throw new TypeError(`external analyzer payload.kind '${kind}' is unsupported`);
|
|
7692
7703
|
}
|
|
7693
7704
|
function decodeExternalAnalysisResult(value, analyzerName, knownSpanUris) {
|
|
7694
|
-
const
|
|
7695
|
-
const result = record(value,
|
|
7696
|
-
const reportedAnalyzer = nonEmptyString3(result.analyzer, `${
|
|
7705
|
+
const label2 = `external analyzer '${analyzerName}' result`;
|
|
7706
|
+
const result = record(value, label2);
|
|
7707
|
+
const reportedAnalyzer = nonEmptyString3(result.analyzer, `${label2}.analyzer`);
|
|
7697
7708
|
if (reportedAnalyzer !== analyzerName) {
|
|
7698
7709
|
throw new TypeError(
|
|
7699
7710
|
`external analyzer '${analyzerName}' reported analyzer '${reportedAnalyzer}'`
|
|
7700
7711
|
);
|
|
7701
7712
|
}
|
|
7702
|
-
const kind = nonEmptyString3(result.kind, `${
|
|
7713
|
+
const kind = nonEmptyString3(result.kind, `${label2}.kind`);
|
|
7703
7714
|
if (!["report", "findings", "discovery"].includes(kind)) {
|
|
7704
|
-
throw new TypeError(`${
|
|
7715
|
+
throw new TypeError(`${label2}.kind '${kind}' is unsupported`);
|
|
7705
7716
|
}
|
|
7706
|
-
const ok = boolean(result.ok, `${
|
|
7707
|
-
const output = text(result.output, `${
|
|
7717
|
+
const ok = boolean(result.ok, `${label2}.ok`);
|
|
7718
|
+
const output = text(result.output, `${label2}.output`);
|
|
7708
7719
|
if (!ok) {
|
|
7709
|
-
assertOnlyKeys(result, RESULT_FAILURE_KEYS,
|
|
7720
|
+
assertOnlyKeys(result, RESULT_FAILURE_KEYS, label2);
|
|
7710
7721
|
return {
|
|
7711
7722
|
analyzer: analyzerName,
|
|
7712
7723
|
kind,
|
|
7713
7724
|
ok: false,
|
|
7714
7725
|
output,
|
|
7715
|
-
error: nonEmptyString3(result.error, `${
|
|
7726
|
+
error: nonEmptyString3(result.error, `${label2}.error`)
|
|
7716
7727
|
};
|
|
7717
7728
|
}
|
|
7718
7729
|
if (kind === "report") {
|
|
7719
|
-
assertOnlyKeys(result, RESULT_REPORT_KEYS,
|
|
7730
|
+
assertOnlyKeys(result, RESULT_REPORT_KEYS, label2);
|
|
7720
7731
|
return { analyzer: analyzerName, kind, ok: true, output };
|
|
7721
7732
|
}
|
|
7722
7733
|
if (kind === "findings") {
|
|
7723
|
-
assertOnlyKeys(result, RESULT_FINDING_KEYS,
|
|
7734
|
+
assertOnlyKeys(result, RESULT_FINDING_KEYS, label2);
|
|
7724
7735
|
if (!Array.isArray(result.findings)) {
|
|
7725
|
-
throw new TypeError(`${
|
|
7736
|
+
throw new TypeError(`${label2}.findings must be an array`);
|
|
7726
7737
|
}
|
|
7727
7738
|
return {
|
|
7728
7739
|
analyzer: analyzerName,
|
|
7729
7740
|
kind,
|
|
7730
7741
|
ok: true,
|
|
7731
7742
|
output,
|
|
7732
|
-
findings: result.findings.map((finding2, index) => decodeFinding(finding2, `${
|
|
7743
|
+
findings: result.findings.map((finding2, index) => decodeFinding(finding2, `${label2}.findings[${index}]`, knownSpanUris))
|
|
7733
7744
|
};
|
|
7734
7745
|
}
|
|
7735
|
-
assertOnlyKeys(result, RESULT_DISCOVERY_KEYS,
|
|
7746
|
+
assertOnlyKeys(result, RESULT_DISCOVERY_KEYS, label2);
|
|
7736
7747
|
if (!Array.isArray(result.candidates)) {
|
|
7737
|
-
throw new TypeError(`${
|
|
7748
|
+
throw new TypeError(`${label2}.candidates must be an array`);
|
|
7738
7749
|
}
|
|
7739
7750
|
return {
|
|
7740
7751
|
analyzer: analyzerName,
|
|
7741
7752
|
kind: "discovery",
|
|
7742
7753
|
ok: true,
|
|
7743
7754
|
output,
|
|
7744
|
-
candidates: result.candidates.map((candidate, index) => decodeCandidate(candidate, `${
|
|
7755
|
+
candidates: result.candidates.map((candidate, index) => decodeCandidate(candidate, `${label2}.candidates[${index}]`, knownSpanUris))
|
|
7745
7756
|
};
|
|
7746
7757
|
}
|
|
7747
7758
|
|
|
@@ -8524,6 +8535,7 @@ function readPullRequests(spans) {
|
|
|
8524
8535
|
|
|
8525
8536
|
// src/session-facts.ts
|
|
8526
8537
|
import { OPENINFERENCE_SPAN_KIND as OPENINFERENCE_SPAN_KIND4, TOOL_NAME as TOOL_NAME5 } from "@tangle-network/agent-eval/trace-attributes";
|
|
8538
|
+
import { ingestSpans, rankFirstFailure } from "@tangle-network/agent-eval/diagnosis";
|
|
8527
8539
|
var SESSION_TOKEN_TOTAL_ATTR = "traces.session.total_tokens";
|
|
8528
8540
|
var SPAN_SYNTHESIZED_ATTR = "traces.codex.span_synthesized";
|
|
8529
8541
|
var CORRUPTION_COUNT_ATTR = "traces.session.corruption_count";
|
|
@@ -8899,6 +8911,11 @@ function sessionFactsForTrace(traceId, sessionId, unordered) {
|
|
|
8899
8911
|
changedFiles: changedFilesFact(files, truncatedInputs, unresolvedPaths),
|
|
8900
8912
|
firstRecordAt: firstSpan ? { value: firstSpan.start_time, spanIds: [firstSpan.span_id], unavailable: null } : { value: null, spanIds: [], unavailable: "no span of this session's own records carries a parseable start time" },
|
|
8901
8913
|
lastRecordAt: lastSpan ? { value: lastSpan.end_time, spanIds: [lastSpan.span_id], unavailable: null } : { value: null, spanIds: [], unavailable: "no span of this session's own records carries a parseable end time" },
|
|
8914
|
+
// rankFirstFailure throws on an empty list (distinct from "every span is
|
|
8915
|
+
// UNSET", which it reports as status 'unknown'); a trace whose spans are
|
|
8916
|
+
// all traces.span.subagent — every record folded into subagents' own
|
|
8917
|
+
// reports — legitimately has no records of its own to rank.
|
|
8918
|
+
firstFailure: ownSpans.length === 0 ? { status: "unknown", traceId, unsetCount: 0, reason: "no span of this session's own records" } : rankFirstFailure(ingestSpans(ownSpans, { contentIncluded: true }).spans),
|
|
8902
8919
|
tokenTotal: tokenSpan ? {
|
|
8903
8920
|
value: tokenSpan.attributes[SESSION_TOKEN_TOTAL_ATTR],
|
|
8904
8921
|
spanIds: [tokenSpan.span_id],
|
|
@@ -8920,10 +8937,10 @@ function buildSessionFactsReport(spans, options = {}) {
|
|
|
8920
8937
|
sessions: computeSessionFacts(spans)
|
|
8921
8938
|
};
|
|
8922
8939
|
}
|
|
8923
|
-
function factLine(
|
|
8924
|
-
if (fact.value === null) return ` ${
|
|
8940
|
+
function factLine(label2, fact, rendered) {
|
|
8941
|
+
if (fact.value === null) return ` ${label2}: unavailable \u2014 ${fact.unavailable}`;
|
|
8925
8942
|
const partial = fact.partial ? ` (partial: ${fact.partial})` : "";
|
|
8926
|
-
return ` ${
|
|
8943
|
+
return ` ${label2}: ${rendered}${partial}`;
|
|
8927
8944
|
}
|
|
8928
8945
|
function renderSessionFacts(report) {
|
|
8929
8946
|
const lines = [
|
|
@@ -8967,6 +8984,7 @@ function renderSessionFacts(report) {
|
|
|
8967
8984
|
lines.push(factLine("first record", facts.firstRecordAt, String(facts.firstRecordAt.value)));
|
|
8968
8985
|
lines.push(factLine("last record", facts.lastRecordAt, String(facts.lastRecordAt.value)));
|
|
8969
8986
|
lines.push(factLine("token total", facts.tokenTotal, String(facts.tokenTotal.value)));
|
|
8987
|
+
lines.push(` first failure: ${renderFirstFailure(facts.firstFailure)}`);
|
|
8970
8988
|
if ((facts.unreadRecords.value ?? 0) > 0) {
|
|
8971
8989
|
lines.push(` unread records: ${facts.unreadRecords.value} (the facts above are computed from the rest)`);
|
|
8972
8990
|
}
|
|
@@ -8977,6 +8995,15 @@ function renderSessionFacts(report) {
|
|
|
8977
8995
|
return `${lines.join("\n")}
|
|
8978
8996
|
`;
|
|
8979
8997
|
}
|
|
8998
|
+
function renderFirstFailure(failure2) {
|
|
8999
|
+
if (failure2.status === "unknown") return `unknown \u2014 not recorded whether this run failed (${failure2.reason})`;
|
|
9000
|
+
if (failure2.status === "none") return `none recorded (${failure2.reason})`;
|
|
9001
|
+
if (failure2.status === "ambiguous") {
|
|
9002
|
+
return `ambiguous ${failure2.stage}: ${failure2.reason} (${failure2.candidates.join(", ")})`;
|
|
9003
|
+
}
|
|
9004
|
+
const message = failure2.message ? ` \u2014 ${failure2.message.split("\n")[0]?.slice(0, 160)}` : "";
|
|
9005
|
+
return `${failure2.stage} ${failure2.kind} "${failure2.name}" [${failure2.spanId}], blame ${failure2.blame}${message}`;
|
|
9006
|
+
}
|
|
8980
9007
|
var PREPARED_CONTEXT_BYTE_CEILING = 3e4;
|
|
8981
9008
|
function renderSessionFactsContext(report, options = {}) {
|
|
8982
9009
|
const ceiling = options.byteCeiling ?? PREPARED_CONTEXT_BYTE_CEILING;
|
|
@@ -9124,7 +9151,26 @@ function compactFacts(facts) {
|
|
|
9124
9151
|
},
|
|
9125
9152
|
first_record_at: factJson(facts.firstRecordAt),
|
|
9126
9153
|
last_record_at: factJson(facts.lastRecordAt),
|
|
9127
|
-
token_total: factJson(facts.tokenTotal)
|
|
9154
|
+
token_total: factJson(facts.tokenTotal),
|
|
9155
|
+
first_failure: compactFirstFailure(facts.firstFailure)
|
|
9156
|
+
};
|
|
9157
|
+
}
|
|
9158
|
+
function compactFirstFailure(failure2) {
|
|
9159
|
+
if (failure2.status === "unknown") {
|
|
9160
|
+
return { status: "unknown", reason: failure2.reason, unset_count: failure2.unsetCount };
|
|
9161
|
+
}
|
|
9162
|
+
if (failure2.status === "none") return { status: "none", reason: failure2.reason };
|
|
9163
|
+
if (failure2.status === "ambiguous") {
|
|
9164
|
+
return { status: "ambiguous", stage: failure2.stage, reason: failure2.reason, span_ids: failure2.candidates };
|
|
9165
|
+
}
|
|
9166
|
+
return {
|
|
9167
|
+
status: "found",
|
|
9168
|
+
stage: failure2.stage,
|
|
9169
|
+
span_id: failure2.spanId,
|
|
9170
|
+
name: failure2.name,
|
|
9171
|
+
kind: failure2.kind,
|
|
9172
|
+
blame: failure2.blame,
|
|
9173
|
+
message: failure2.message
|
|
9128
9174
|
};
|
|
9129
9175
|
}
|
|
9130
9176
|
function sessionFactsContext(spans, options = {}) {
|
|
@@ -9135,7 +9181,7 @@ function sessionFactsContext(spans, options = {}) {
|
|
|
9135
9181
|
if (report.sessions.length === 0) return void 0;
|
|
9136
9182
|
return renderSessionFactsContext(report, options);
|
|
9137
9183
|
}
|
|
9138
|
-
var SESSION_FACTS_VERSION_SUFFIX = "session-facts.
|
|
9184
|
+
var SESSION_FACTS_VERSION_SUFFIX = "session-facts.2";
|
|
9139
9185
|
function withSessionFactsContext(definitions, spans, options = {}) {
|
|
9140
9186
|
const sheet = sessionFactsContext(spans, options);
|
|
9141
9187
|
if (sheet === void 0) return [...definitions];
|
|
@@ -9169,7 +9215,6 @@ import { dirname as dirname8, isAbsolute as isAbsolute4, join as join20, relativ
|
|
|
9169
9215
|
|
|
9170
9216
|
// src/bundle.ts
|
|
9171
9217
|
import { createHash as createHash8 } from "crypto";
|
|
9172
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
9173
9218
|
import { copyFile, cp, lstat, mkdir as mkdir2, readdir as readdir16, readFile as readFile7, stat as stat14, writeFile as writeFile5 } from "fs/promises";
|
|
9174
9219
|
import { dirname as dirname7, join as join19, relative as relative4, resolve as resolve6, sep } from "path";
|
|
9175
9220
|
|
|
@@ -9196,34 +9241,13 @@ var SEVERITY_BADGE = {
|
|
|
9196
9241
|
info: "\u2139\uFE0F INFO"
|
|
9197
9242
|
};
|
|
9198
9243
|
var CAPABILITY_ANALYSES = {
|
|
9199
|
-
"token-accounting":
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
"
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
},
|
|
9207
|
-
"tool-usage": {
|
|
9208
|
-
analysis: "tool-usage table + per-tool duplicate/retry/error rates + stuck-loop detection",
|
|
9209
|
-
built: true
|
|
9210
|
-
},
|
|
9211
|
-
"loop-convergence": {
|
|
9212
|
-
analysis: "round-over-round convergence (did round N+1 improve on N)",
|
|
9213
|
-
built: true
|
|
9214
|
-
},
|
|
9215
|
-
"tree-comparison": {
|
|
9216
|
-
analysis: "arm-vs-arm comparison across branches of one run \u2014 NOT YET IMPLEMENTED in this package",
|
|
9217
|
-
built: false
|
|
9218
|
-
},
|
|
9219
|
-
"steering-chain": {
|
|
9220
|
-
analysis: "steering chain (which verdict caused which retry)",
|
|
9221
|
-
built: true
|
|
9222
|
-
},
|
|
9223
|
-
"latency-analysis": {
|
|
9224
|
-
analysis: "latency + critical-path timing distributions",
|
|
9225
|
-
built: true
|
|
9226
|
-
}
|
|
9244
|
+
"token-accounting": "execution facts \u2192 Direct model usage (input/output/reasoning/cache token totals)",
|
|
9245
|
+
"cost-attribution": "execution facts \u2192 Cost coverage (observed vs estimated USD)",
|
|
9246
|
+
"tool-usage": "tool-usage table + per-tool duplicate/retry/error rates + stuck-loop detection",
|
|
9247
|
+
"loop-convergence": "round-over-round convergence (did round N+1 improve on N)",
|
|
9248
|
+
"tree-comparison": "arm-vs-arm comparison: `traces diff <file>#branch=<a> <file>#branch=<b>` marks where two arms first diverge",
|
|
9249
|
+
"steering-chain": "steering chain (which verdict caused which retry)",
|
|
9250
|
+
"latency-analysis": "latency + critical-path timing distributions"
|
|
9227
9251
|
};
|
|
9228
9252
|
function unavailableCapabilities(validation) {
|
|
9229
9253
|
return new Map(
|
|
@@ -9300,13 +9324,10 @@ function conformanceOfSpans(spans) {
|
|
|
9300
9324
|
function skippedAnalyses(validation) {
|
|
9301
9325
|
return validation.capabilities.filter((capability) => !capability.available).map((capability) => ({
|
|
9302
9326
|
capability: capability.name,
|
|
9303
|
-
analysis: CAPABILITY_ANALYSES[capability.name]
|
|
9327
|
+
analysis: CAPABILITY_ANALYSES[capability.name] ?? "analyses keyed off this capability",
|
|
9304
9328
|
reason: capability.reason ?? "no reason recorded"
|
|
9305
9329
|
}));
|
|
9306
9330
|
}
|
|
9307
|
-
function unbuiltAnalyses(validation) {
|
|
9308
|
-
return validation.capabilities.filter((capability) => capability.available && CAPABILITY_ANALYSES[capability.name]?.built === false).map((capability) => capability.name);
|
|
9309
|
-
}
|
|
9310
9331
|
function tableCell(value) {
|
|
9311
9332
|
return value.replace(/\s+/g, " ").replaceAll("|", "\\|").trim();
|
|
9312
9333
|
}
|
|
@@ -9317,12 +9338,8 @@ function spanIdSample(finding2) {
|
|
|
9317
9338
|
return ids.length > SPAN_ID_SAMPLE ? `${shown} +${ids.length - SPAN_ID_SAMPLE} more` : shown;
|
|
9318
9339
|
}
|
|
9319
9340
|
function capabilityRow(capability) {
|
|
9320
|
-
const
|
|
9321
|
-
|
|
9322
|
-
if (!capability.available) {
|
|
9323
|
-
return `| \`${capability.name}\` | \u274C unavailable | ${tableCell(analysis)} | ${tableCell(capability.reason ?? "no reason recorded")} |`;
|
|
9324
|
-
}
|
|
9325
|
-
return entry?.built === false ? `| \`${capability.name}\` | \u26A0\uFE0F available, unused | ${tableCell(analysis)} | the trace supports it; this package has no analysis for it yet |` : `| \`${capability.name}\` | \u2705 available | ${tableCell(analysis)} | \u2014 |`;
|
|
9341
|
+
const analysis = CAPABILITY_ANALYSES[capability.name] ?? "\u2014";
|
|
9342
|
+
return capability.available ? `| \`${capability.name}\` | \u2705 available | ${tableCell(analysis)} | \u2014 |` : `| \`${capability.name}\` | \u274C unavailable | ${tableCell(analysis)} | ${tableCell(capability.reason ?? "no reason recorded")} |`;
|
|
9326
9343
|
}
|
|
9327
9344
|
function renderInheritedLoss(lines, unreadable) {
|
|
9328
9345
|
if (unreadable === void 0 || unreadable.inherited === 0) return;
|
|
@@ -9445,26 +9462,17 @@ function conformanceBody(validation, opts) {
|
|
|
9445
9462
|
for (const capability of validation.capabilities) lines.push(capabilityRow(capability));
|
|
9446
9463
|
lines.push("");
|
|
9447
9464
|
const skipped = skippedAnalyses(validation);
|
|
9448
|
-
|
|
9449
|
-
if (skipped.length > 0 || unbuilt.length > 0) {
|
|
9465
|
+
if (skipped.length > 0) {
|
|
9450
9466
|
lines.push(`${heading}# analyses skipped, and why`);
|
|
9451
9467
|
lines.push("");
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
lines.push(`- **${entry.analysis}** \u2014 skipped: ${entry.reason} (\`${entry.capability}\`).`);
|
|
9459
|
-
}
|
|
9460
|
-
lines.push("");
|
|
9461
|
-
}
|
|
9462
|
-
if (unbuilt.length > 0) {
|
|
9463
|
-
lines.push(
|
|
9464
|
-
`These are supported by the trace and **not yet implemented here**: ${unbuilt.map((name) => `\`${name}\``).join(", ")}. The spans carry what they need; the analysis does not exist, so nothing about them appears below.`
|
|
9465
|
-
);
|
|
9466
|
-
lines.push("");
|
|
9468
|
+
lines.push(
|
|
9469
|
+
"These reported nothing because the trace never carried what they read \u2014 not because the run was uneventful. Every section they feed is marked at the table, not only here."
|
|
9470
|
+
);
|
|
9471
|
+
lines.push("");
|
|
9472
|
+
for (const entry of skipped) {
|
|
9473
|
+
lines.push(`- **${entry.analysis}** \u2014 skipped: ${entry.reason} (\`${entry.capability}\`).`);
|
|
9467
9474
|
}
|
|
9475
|
+
lines.push("");
|
|
9468
9476
|
}
|
|
9469
9477
|
return lines.join("\n");
|
|
9470
9478
|
}
|
|
@@ -9829,10 +9837,10 @@ async function readLinuxProcProcessTable() {
|
|
|
9829
9837
|
const rows = await Promise.all(
|
|
9830
9838
|
entries.filter((entry) => entry.isDirectory() && /^\d+$/.test(entry.name)).map(async (entry) => {
|
|
9831
9839
|
try {
|
|
9832
|
-
const
|
|
9833
|
-
const commandEnd =
|
|
9840
|
+
const stat19 = await readFile5(`/proc/${entry.name}/stat`, "utf8");
|
|
9841
|
+
const commandEnd = stat19.lastIndexOf(")");
|
|
9834
9842
|
if (commandEnd < 0) return void 0;
|
|
9835
|
-
const fields =
|
|
9843
|
+
const fields = stat19.slice(commandEnd + 1).trim().split(/\s+/);
|
|
9836
9844
|
const pid = Number(entry.name);
|
|
9837
9845
|
const parentPid = Number(fields[1]);
|
|
9838
9846
|
if (!Number.isSafeInteger(pid) || pid < 1 || !Number.isSafeInteger(parentPid) || parentPid < 0) {
|
|
@@ -10051,16 +10059,16 @@ async function spanUrisFromArtifact(otlpPath, signal) {
|
|
|
10051
10059
|
const uris = /* @__PURE__ */ new Set();
|
|
10052
10060
|
let index = 0;
|
|
10053
10061
|
for await (const value of readJsonl(otlpPath, { signal })) {
|
|
10054
|
-
const
|
|
10062
|
+
const label2 = `${otlpPath}:${index + 1}`;
|
|
10055
10063
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
10056
|
-
throw new TypeError(`${
|
|
10064
|
+
throw new TypeError(`${label2} must contain an object`);
|
|
10057
10065
|
}
|
|
10058
10066
|
const row = value;
|
|
10059
10067
|
if (typeof row.trace_id !== "string" || row.trace_id.trim().length === 0) {
|
|
10060
|
-
throw new TypeError(`${
|
|
10068
|
+
throw new TypeError(`${label2}.trace_id must be a non-empty string`);
|
|
10061
10069
|
}
|
|
10062
10070
|
if (typeof row.span_id !== "string" || row.span_id.trim().length === 0) {
|
|
10063
|
-
throw new TypeError(`${
|
|
10071
|
+
throw new TypeError(`${label2}.span_id must be a non-empty string`);
|
|
10064
10072
|
}
|
|
10065
10073
|
uris.add(spanEvidenceUri(row.trace_id, row.span_id));
|
|
10066
10074
|
index += 1;
|
|
@@ -10433,10 +10441,10 @@ function decimal(value, digits = 1) {
|
|
|
10433
10441
|
function measured(value, render) {
|
|
10434
10442
|
return value === null ? "not captured" : render(value);
|
|
10435
10443
|
}
|
|
10436
|
-
function distributionRow(
|
|
10437
|
-
if (distribution.n === 0) return `| ${
|
|
10444
|
+
function distributionRow(label2, distribution, unit = "") {
|
|
10445
|
+
if (distribution.n === 0) return `| ${label2} | 0 | not captured | not captured | not captured | not captured | not captured |`;
|
|
10438
10446
|
const value = (number) => measured(number, (captured) => `${decimal(captured)}${unit}`);
|
|
10439
|
-
return `| ${
|
|
10447
|
+
return `| ${label2} | ${count(distribution.n)} | ${value(distribution.min)} | ${value(distribution.mean)} | ${value(distribution.p50)} | ${value(distribution.p95)} | ${value(distribution.max)} |`;
|
|
10440
10448
|
}
|
|
10441
10449
|
function tokenRows(usage) {
|
|
10442
10450
|
const rows = [
|
|
@@ -10447,7 +10455,7 @@ function tokenRows(usage) {
|
|
|
10447
10455
|
["Cache write", usage.totals.cacheWrite, usage.cacheWrite]
|
|
10448
10456
|
];
|
|
10449
10457
|
return rows.map(
|
|
10450
|
-
([
|
|
10458
|
+
([label2, total, values]) => `| ${label2} | ${count(total)} | ${count(values.n)} | ${measured(values.mean, decimal)} | ${measured(values.p50, decimal)} | ${measured(values.p95, decimal)} | ${measured(values.max, count)} |`
|
|
10451
10459
|
);
|
|
10452
10460
|
}
|
|
10453
10461
|
function analysisCost(result) {
|
|
@@ -10940,9 +10948,9 @@ function renderAdoption(ar) {
|
|
|
10940
10948
|
"- **Prompt, tools, MCP, hooks, and full agent profile:** not assessed; no baseline profile was supplied."
|
|
10941
10949
|
);
|
|
10942
10950
|
if (ar.skillPenetration === null) {
|
|
10943
|
-
const
|
|
10951
|
+
const label2 = ar.skillTelemetryStatus === "unsupported" ? "uncaptured/unsupported" : "uncaptured/unknown";
|
|
10944
10952
|
lines.push(
|
|
10945
|
-
`- **Explicit skill invocation rate:** ${
|
|
10953
|
+
`- **Explicit skill invocation rate:** ${label2} (${ar.skillTelemetrySessions}/${ar.executionGroupCount} observed group(s) expose a dedicated Skill event)`
|
|
10946
10954
|
);
|
|
10947
10955
|
} else {
|
|
10948
10956
|
const excluded = ar.executionGroupCount - ar.skillTelemetrySessions;
|
|
@@ -12246,6 +12254,17 @@ async function collectSessionSelection(groups, options = {}) {
|
|
|
12246
12254
|
return { rows, ...workflow ? { workflow } : {} };
|
|
12247
12255
|
}
|
|
12248
12256
|
|
|
12257
|
+
// src/version.ts
|
|
12258
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
12259
|
+
var cached;
|
|
12260
|
+
function tracesVersion() {
|
|
12261
|
+
if (cached) return cached;
|
|
12262
|
+
const pkg = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
|
|
12263
|
+
if (typeof pkg.version !== "string" || !pkg.version) throw new Error("package.json is missing version");
|
|
12264
|
+
cached = pkg.version;
|
|
12265
|
+
return cached;
|
|
12266
|
+
}
|
|
12267
|
+
|
|
12249
12268
|
// src/bundle.ts
|
|
12250
12269
|
var SESSION_WINDOW_PAD_MS = 15 * 60 * 1e3;
|
|
12251
12270
|
var KNOWN_LIMITS = [
|
|
@@ -12538,7 +12557,7 @@ async function assembleSessionBundle(opts) {
|
|
|
12538
12557
|
transcriptPath: resolve6(ref.path),
|
|
12539
12558
|
transcriptSha256,
|
|
12540
12559
|
contextRoot,
|
|
12541
|
-
tracesVersion:
|
|
12560
|
+
tracesVersion: tracesVersion(),
|
|
12542
12561
|
sessionWindow: { firstSpanAt, lastSpanAt, padMs: SESSION_WINDOW_PAD_MS }
|
|
12543
12562
|
},
|
|
12544
12563
|
files,
|
|
@@ -12682,16 +12701,6 @@ async function verifySessionBundle(bundleDir) {
|
|
|
12682
12701
|
...source ? { source } : {}
|
|
12683
12702
|
};
|
|
12684
12703
|
}
|
|
12685
|
-
var cachedVersion;
|
|
12686
|
-
function tracesPackageVersion() {
|
|
12687
|
-
if (cachedVersion) return cachedVersion;
|
|
12688
|
-
const pkg = JSON.parse(
|
|
12689
|
-
readFileSync2(new URL("../package.json", import.meta.url), "utf8")
|
|
12690
|
-
);
|
|
12691
|
-
if (typeof pkg.version !== "string" || !pkg.version) throw new Error("package.json is missing version");
|
|
12692
|
-
cachedVersion = pkg.version;
|
|
12693
|
-
return cachedVersion;
|
|
12694
|
-
}
|
|
12695
12704
|
|
|
12696
12705
|
// src/bundle-source.ts
|
|
12697
12706
|
var SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -13319,9 +13328,9 @@ async function containedDirectory(path) {
|
|
|
13319
13328
|
}
|
|
13320
13329
|
return canonical;
|
|
13321
13330
|
}
|
|
13322
|
-
async function containedFile(root, candidate,
|
|
13331
|
+
async function containedFile(root, candidate, label2) {
|
|
13323
13332
|
const path = await optionalContainedFile(root, candidate);
|
|
13324
|
-
if (!path) throw new Error(`${
|
|
13333
|
+
if (!path) throw new Error(`${label2} is missing`);
|
|
13325
13334
|
return path;
|
|
13326
13335
|
}
|
|
13327
13336
|
async function optionalContainedFile(root, candidate) {
|
|
@@ -13553,49 +13562,49 @@ function parseSteps(text2, row) {
|
|
|
13553
13562
|
);
|
|
13554
13563
|
}
|
|
13555
13564
|
return parsed.map((value, index) => {
|
|
13556
|
-
const
|
|
13557
|
-
if (!isObject3(value)) throw new TypeError(`${
|
|
13558
|
-
const stepId = positiveInteger2(value.step_id, `${
|
|
13565
|
+
const label2 = `${row.trajId}/steps.json[${index}]`;
|
|
13566
|
+
if (!isObject3(value)) throw new TypeError(`${label2} must be an object`);
|
|
13567
|
+
const stepId = positiveInteger2(value.step_id, `${label2}.step_id`);
|
|
13559
13568
|
if (stepId !== index + 1) {
|
|
13560
|
-
throw new Error(`${
|
|
13569
|
+
throw new Error(`${label2}.step_id is ${stepId}; expected ${index + 1}`);
|
|
13561
13570
|
}
|
|
13562
13571
|
if (!Object.hasOwn(value, "observation")) {
|
|
13563
|
-
throw new TypeError(`${
|
|
13572
|
+
throw new TypeError(`${label2}.observation is required and may be null`);
|
|
13564
13573
|
}
|
|
13565
13574
|
const observation = value.observation;
|
|
13566
13575
|
if (observation !== null && typeof observation !== "string") {
|
|
13567
|
-
throw new TypeError(`${
|
|
13576
|
+
throw new TypeError(`${label2}.observation must be a string or null`);
|
|
13568
13577
|
}
|
|
13569
13578
|
return {
|
|
13570
13579
|
step_id: stepId,
|
|
13571
|
-
action: requiredString(value.action, `${
|
|
13580
|
+
action: requiredString(value.action, `${label2}.action`),
|
|
13572
13581
|
observation,
|
|
13573
|
-
...value.thinking === void 0 ? {} : { thinking: requiredString(value.thinking, `${
|
|
13582
|
+
...value.thinking === void 0 ? {} : { thinking: requiredString(value.thinking, `${label2}.thinking`) },
|
|
13574
13583
|
...value.parallel_group === void 0 ? {} : {
|
|
13575
13584
|
parallel_group: nonNegativeInteger(
|
|
13576
13585
|
value.parallel_group,
|
|
13577
|
-
`${
|
|
13586
|
+
`${label2}.parallel_group`
|
|
13578
13587
|
)
|
|
13579
13588
|
},
|
|
13580
|
-
...value.tool_type === void 0 ? {} : { tool_type: requiredString(value.tool_type, `${
|
|
13581
|
-
action_ref: fileRef(value.action_ref, `${
|
|
13582
|
-
observation_ref: fileRef(value.observation_ref, `${
|
|
13589
|
+
...value.tool_type === void 0 ? {} : { tool_type: requiredString(value.tool_type, `${label2}.tool_type`) },
|
|
13590
|
+
action_ref: fileRef(value.action_ref, `${label2}.action_ref`),
|
|
13591
|
+
observation_ref: fileRef(value.observation_ref, `${label2}.observation_ref`)
|
|
13583
13592
|
};
|
|
13584
13593
|
});
|
|
13585
13594
|
}
|
|
13586
|
-
function fileRef(value,
|
|
13595
|
+
function fileRef(value, label2) {
|
|
13587
13596
|
if (value === null) return null;
|
|
13588
|
-
if (!isObject3(value)) throw new TypeError(`${
|
|
13589
|
-
const lineStart = positiveInteger2(value.line_start, `${
|
|
13590
|
-
const lineEnd = positiveInteger2(value.line_end, `${
|
|
13597
|
+
if (!isObject3(value)) throw new TypeError(`${label2} must be an object or null`);
|
|
13598
|
+
const lineStart = positiveInteger2(value.line_start, `${label2}.line_start`);
|
|
13599
|
+
const lineEnd = positiveInteger2(value.line_end, `${label2}.line_end`);
|
|
13591
13600
|
if (lineEnd < lineStart) {
|
|
13592
|
-
throw new RangeError(`${
|
|
13601
|
+
throw new RangeError(`${label2}.line_end must not precede line_start`);
|
|
13593
13602
|
}
|
|
13594
13603
|
return {
|
|
13595
|
-
path: requiredString(value.path, `${
|
|
13604
|
+
path: requiredString(value.path, `${label2}.path`),
|
|
13596
13605
|
line_start: lineStart,
|
|
13597
13606
|
line_end: lineEnd,
|
|
13598
|
-
content: stringField(value.content, `${
|
|
13607
|
+
content: stringField(value.content, `${label2}.content`)
|
|
13599
13608
|
};
|
|
13600
13609
|
}
|
|
13601
13610
|
async function readOptionalTask(trajectoryDirectory, caseDirectory, row, signal) {
|
|
@@ -13652,26 +13661,26 @@ function normalizedLabels(value) {
|
|
|
13652
13661
|
function compact(value) {
|
|
13653
13662
|
return value.replace(/\s+/g, "");
|
|
13654
13663
|
}
|
|
13655
|
-
function positiveInteger2(value,
|
|
13664
|
+
function positiveInteger2(value, label2) {
|
|
13656
13665
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
|
|
13657
|
-
throw new TypeError(`${
|
|
13666
|
+
throw new TypeError(`${label2} must be a positive integer`);
|
|
13658
13667
|
}
|
|
13659
13668
|
return value;
|
|
13660
13669
|
}
|
|
13661
|
-
function nonNegativeInteger(value,
|
|
13670
|
+
function nonNegativeInteger(value, label2) {
|
|
13662
13671
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
13663
|
-
throw new TypeError(`${
|
|
13672
|
+
throw new TypeError(`${label2} must be a non-negative integer`);
|
|
13664
13673
|
}
|
|
13665
13674
|
return value;
|
|
13666
13675
|
}
|
|
13667
|
-
function requiredString(value,
|
|
13676
|
+
function requiredString(value, label2) {
|
|
13668
13677
|
if (typeof value !== "string" || !value.trim()) {
|
|
13669
|
-
throw new TypeError(`${
|
|
13678
|
+
throw new TypeError(`${label2} must be a non-empty string`);
|
|
13670
13679
|
}
|
|
13671
13680
|
return value.trim();
|
|
13672
13681
|
}
|
|
13673
|
-
function stringField(value,
|
|
13674
|
-
if (typeof value !== "string") throw new TypeError(`${
|
|
13682
|
+
function stringField(value, label2) {
|
|
13683
|
+
if (typeof value !== "string") throw new TypeError(`${label2} must be a string`);
|
|
13675
13684
|
return value;
|
|
13676
13685
|
}
|
|
13677
13686
|
function errorMessage(error) {
|
|
@@ -15015,16 +15024,16 @@ async function projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, si
|
|
|
15015
15024
|
const spanTraces = /* @__PURE__ */ new Map();
|
|
15016
15025
|
let index = 0;
|
|
15017
15026
|
for await (const value of readJsonl(otlpPath, { signal })) {
|
|
15018
|
-
const
|
|
15027
|
+
const label2 = `${otlpPath}:${index + 1}`;
|
|
15019
15028
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
15020
|
-
throw new TypeError(`${
|
|
15029
|
+
throw new TypeError(`${label2} must contain an object`);
|
|
15021
15030
|
}
|
|
15022
15031
|
const row = value;
|
|
15023
15032
|
if (typeof row.trace_id !== "string" || row.trace_id.length === 0) {
|
|
15024
|
-
throw new TypeError(`${
|
|
15033
|
+
throw new TypeError(`${label2}.trace_id must be a non-empty string`);
|
|
15025
15034
|
}
|
|
15026
15035
|
if (typeof row.span_id !== "string" || row.span_id.length === 0) {
|
|
15027
|
-
throw new TypeError(`${
|
|
15036
|
+
throw new TypeError(`${label2}.span_id must be a non-empty string`);
|
|
15028
15037
|
}
|
|
15029
15038
|
rows.push(row);
|
|
15030
15039
|
const traces = spanTraces.get(row.span_id) ?? /* @__PURE__ */ new Set();
|
|
@@ -15366,53 +15375,55 @@ function primeAnalyzer(opts = {}) {
|
|
|
15366
15375
|
}
|
|
15367
15376
|
|
|
15368
15377
|
// src/redact.ts
|
|
15369
|
-
import {
|
|
15370
|
-
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
},
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15396
|
-
{
|
|
15397
|
-
id: "url-secret-param",
|
|
15398
|
-
pattern: /[?&](?:access[_-]?token|api[_-]?key|apikey|auth|token|secret|password|sig|signature)=[^&\s"'#)]+/gi
|
|
15399
|
-
}
|
|
15400
|
-
];
|
|
15401
|
-
var TRACES_REDACTION_RULES = [...DEFAULT_REDACTION_RULES, ...CODING_REDACTION_RULES];
|
|
15402
|
-
function redactSpans(spans, rules = TRACES_REDACTION_RULES) {
|
|
15403
|
-
const report = { redactionCount: 0, byRule: {} };
|
|
15404
|
-
const out = spans.map((s) => {
|
|
15405
|
-
const attributes2 = redactValue(stripSourceAttributes(s.attributes), rules, report).value;
|
|
15406
|
-
normalizeToolIoAttributes(attributes2);
|
|
15407
|
-
let status = s.status;
|
|
15408
|
-
if (status.message) {
|
|
15409
|
-
const m = redactValue(status.message, rules, report).value;
|
|
15410
|
-
if (typeof m === "string" && m !== status.message) status = { ...status, message: m };
|
|
15411
|
-
}
|
|
15412
|
-
return { ...s, attributes: attributes2, status };
|
|
15378
|
+
import {
|
|
15379
|
+
assessShareSafety,
|
|
15380
|
+
combineVerdicts,
|
|
15381
|
+
redact
|
|
15382
|
+
} from "@tangle-network/agent-eval/traces";
|
|
15383
|
+
function redactSpans(spans, options = {}) {
|
|
15384
|
+
const parts = spans.map((span2) => ({
|
|
15385
|
+
name: span2.name,
|
|
15386
|
+
attributes: stripSourceAttributes(span2.attributes),
|
|
15387
|
+
message: span2.status.message,
|
|
15388
|
+
links: span2.links?.map((link2) => ({
|
|
15389
|
+
...link2,
|
|
15390
|
+
...link2.attributes ? { attributes: stripSourceAttributes(link2.attributes) } : {}
|
|
15391
|
+
}))
|
|
15392
|
+
}));
|
|
15393
|
+
const { value, report } = redact(parts, options);
|
|
15394
|
+
const out = spans.map((span2, index) => {
|
|
15395
|
+
const part = value[index];
|
|
15396
|
+
normalizeToolIoAttributes(part.attributes);
|
|
15397
|
+
const status = part.message !== void 0 && part.message !== span2.status.message ? { ...span2.status, message: part.message } : span2.status;
|
|
15398
|
+
return {
|
|
15399
|
+
...span2,
|
|
15400
|
+
name: part.name,
|
|
15401
|
+
attributes: part.attributes,
|
|
15402
|
+
status,
|
|
15403
|
+
...part.links ? { links: part.links } : {}
|
|
15404
|
+
};
|
|
15413
15405
|
});
|
|
15414
15406
|
return { spans: out, report };
|
|
15415
15407
|
}
|
|
15408
|
+
function assessSpans(spans, profile = "default") {
|
|
15409
|
+
return combineVerdicts(
|
|
15410
|
+
profile,
|
|
15411
|
+
spans.map((span2) => {
|
|
15412
|
+
const verdict = assessShareSafety(
|
|
15413
|
+
{ name: span2.name, attributes: span2.attributes, status: span2.status, links: span2.links },
|
|
15414
|
+
{ profile }
|
|
15415
|
+
);
|
|
15416
|
+
return {
|
|
15417
|
+
...verdict,
|
|
15418
|
+
findings: verdict.findings.map((finding2) => ({
|
|
15419
|
+
...finding2,
|
|
15420
|
+
paths: finding2.paths.map((path) => `span:${span2.span_id}${path}`)
|
|
15421
|
+
})),
|
|
15422
|
+
unreadable: verdict.unreadable.map((entry) => `span:${span2.span_id}${entry}`)
|
|
15423
|
+
};
|
|
15424
|
+
})
|
|
15425
|
+
);
|
|
15426
|
+
}
|
|
15416
15427
|
async function applyRedactor(spans, redactor) {
|
|
15417
15428
|
const capturedKeys = ["content", ...TOOL_IO_VALUE_KEYS];
|
|
15418
15429
|
const fields = [];
|
|
@@ -16078,7 +16089,7 @@ function exportTraceEvidenceRows(rows, opts = {}, wrapper) {
|
|
|
16078
16089
|
format,
|
|
16079
16090
|
spans: validated,
|
|
16080
16091
|
redactionCount: redacted.report.redactionCount,
|
|
16081
|
-
|
|
16092
|
+
redactionsByDetector: redacted.report.byDetector
|
|
16082
16093
|
};
|
|
16083
16094
|
}
|
|
16084
16095
|
function exportTraceEvidenceText(text2, opts = {}) {
|
|
@@ -16091,7 +16102,7 @@ async function exportTraceEvidenceFile(inputPath, opts = {}) {
|
|
|
16091
16102
|
const spans = [];
|
|
16092
16103
|
const sandboxRows = [];
|
|
16093
16104
|
let redactionCount = 0;
|
|
16094
|
-
const
|
|
16105
|
+
const redactionsByDetector = {};
|
|
16095
16106
|
for await (const row of readJsonl(inputPath)) {
|
|
16096
16107
|
format ??= detectFormat([row], opts.format ?? "auto");
|
|
16097
16108
|
if (format === "sandbox-events") {
|
|
@@ -16105,8 +16116,8 @@ async function exportTraceEvidenceFile(inputPath, opts = {}) {
|
|
|
16105
16116
|
});
|
|
16106
16117
|
appendAll(spans, converted.spans);
|
|
16107
16118
|
redactionCount += converted.redactionCount;
|
|
16108
|
-
for (const [rule, count2] of Object.entries(converted.
|
|
16109
|
-
|
|
16119
|
+
for (const [rule, count2] of Object.entries(converted.redactionsByDetector)) {
|
|
16120
|
+
redactionsByDetector[rule] = (redactionsByDetector[rule] ?? 0) + count2;
|
|
16110
16121
|
}
|
|
16111
16122
|
}
|
|
16112
16123
|
if (!format) throw new Error("input file is empty");
|
|
@@ -16121,7 +16132,7 @@ async function exportTraceEvidenceFile(inputPath, opts = {}) {
|
|
|
16121
16132
|
format,
|
|
16122
16133
|
spans: validateOtlpSpans(spans, `${format} file export`),
|
|
16123
16134
|
redactionCount,
|
|
16124
|
-
|
|
16135
|
+
redactionsByDetector
|
|
16125
16136
|
};
|
|
16126
16137
|
}
|
|
16127
16138
|
const text2 = await readFile12(inputPath, "utf8");
|
|
@@ -16539,8 +16550,8 @@ function sessionFrom(spans, opts) {
|
|
|
16539
16550
|
...opts.session?.path ? { path: opts.session.path } : {}
|
|
16540
16551
|
};
|
|
16541
16552
|
}
|
|
16542
|
-
function evidence2(kind,
|
|
16543
|
-
return { kind, label, value, ...spanIds && spanIds.length > 0 ? { spanIds } : {} };
|
|
16553
|
+
function evidence2(kind, label2, value, spanIds) {
|
|
16554
|
+
return { kind, label: label2, value, ...spanIds && spanIds.length > 0 ? { spanIds } : {} };
|
|
16544
16555
|
}
|
|
16545
16556
|
function finding(input) {
|
|
16546
16557
|
const fingerprint = hash([input.ruleId, ...input.signature]);
|
|
@@ -17417,8 +17428,8 @@ function buildSpanRunTree(spans, source) {
|
|
|
17417
17428
|
for (const root of childrenOf.get(null) ?? []) walk(root, null, null, 0);
|
|
17418
17429
|
const subtotal = /* @__PURE__ */ new Map();
|
|
17419
17430
|
const subtotalOf = (key) => {
|
|
17420
|
-
const
|
|
17421
|
-
if (
|
|
17431
|
+
const cached2 = subtotal.get(key);
|
|
17432
|
+
if (cached2 !== void 0) return cached2;
|
|
17422
17433
|
const node = building.get(key);
|
|
17423
17434
|
if (node === void 0) return ZERO_ROLL;
|
|
17424
17435
|
subtotal.set(key, ZERO_ROLL);
|
|
@@ -18956,6 +18967,169 @@ async function projectSessionBundle(opts) {
|
|
|
18956
18967
|
return { directory: outDir, manifestPath, manifest, leakCheck };
|
|
18957
18968
|
}
|
|
18958
18969
|
|
|
18970
|
+
// src/diff.ts
|
|
18971
|
+
import { stat as stat18 } from "fs/promises";
|
|
18972
|
+
import { ATTR as ATTR5 } from "@tangle-network/agent-trace-contract";
|
|
18973
|
+
import { ingestSpans as ingestSpans2 } from "@tangle-network/agent-eval/diagnosis";
|
|
18974
|
+
import { diffSteps, diffStepsFromSpans } from "@tangle-network/agent-eval/pipelines";
|
|
18975
|
+
async function readSpans(path) {
|
|
18976
|
+
const otlp = await readOtlpInput(path);
|
|
18977
|
+
if (otlp.spans.length > 0) return [...otlp.spans];
|
|
18978
|
+
if (!(await stat18(path)).isFile()) {
|
|
18979
|
+
throw new Error(`${path}: no OTLP spans found (${otlp.issues.length} unusable row(s))`);
|
|
18980
|
+
}
|
|
18981
|
+
return (await exportTraceEvidenceFile(path)).spans;
|
|
18982
|
+
}
|
|
18983
|
+
function branchSpans(spans, branch) {
|
|
18984
|
+
const byId = /* @__PURE__ */ new Map();
|
|
18985
|
+
for (const span2 of spans) byId.set(span2.span_id, span2);
|
|
18986
|
+
const children = /* @__PURE__ */ new Map();
|
|
18987
|
+
for (const span2 of spans) {
|
|
18988
|
+
if (!span2.parent_span_id) continue;
|
|
18989
|
+
const list = children.get(span2.parent_span_id);
|
|
18990
|
+
if (list) list.push(span2);
|
|
18991
|
+
else children.set(span2.parent_span_id, [span2]);
|
|
18992
|
+
}
|
|
18993
|
+
const matched = spans.filter(
|
|
18994
|
+
(span2) => span2.attributes[ATTR5.branchId] === branch || span2.attributes[ATTR5.branchArm] === branch
|
|
18995
|
+
);
|
|
18996
|
+
const matchedIds = new Set(matched.map((span2) => span2.span_id));
|
|
18997
|
+
const hasMatchedAncestor = (span2) => {
|
|
18998
|
+
let current = span2;
|
|
18999
|
+
while (current.parent_span_id) {
|
|
19000
|
+
const parent = byId.get(current.parent_span_id);
|
|
19001
|
+
if (!parent) return false;
|
|
19002
|
+
if (matchedIds.has(parent.span_id)) return true;
|
|
19003
|
+
current = parent;
|
|
19004
|
+
}
|
|
19005
|
+
return false;
|
|
19006
|
+
};
|
|
19007
|
+
const roots = matched.filter((span2) => !hasMatchedAncestor(span2));
|
|
19008
|
+
if (roots.length > 1) {
|
|
19009
|
+
const named = roots.map((span2) => `${span2.span_id} (${ATTR5.branchId}=${JSON.stringify(span2.attributes[ATTR5.branchId] ?? null)})`).join(", ");
|
|
19010
|
+
throw new Error(
|
|
19011
|
+
`"${branch}" matches ${roots.length} separate subtrees, not one arm: ${named} \u2014 sibling arms can share a branch id; select by span id, or narrow the input to one arm first`
|
|
19012
|
+
);
|
|
19013
|
+
}
|
|
19014
|
+
const selected = /* @__PURE__ */ new Set();
|
|
19015
|
+
const stack = [...matched];
|
|
19016
|
+
while (stack.length > 0) {
|
|
19017
|
+
const span2 = stack.pop();
|
|
19018
|
+
if (selected.has(span2)) continue;
|
|
19019
|
+
selected.add(span2);
|
|
19020
|
+
stack.push(...children.get(span2.span_id) ?? []);
|
|
19021
|
+
}
|
|
19022
|
+
return spans.filter((span2) => selected.has(span2));
|
|
19023
|
+
}
|
|
19024
|
+
async function readRunSide(ref, options = {}) {
|
|
19025
|
+
const hash2 = ref.lastIndexOf("#");
|
|
19026
|
+
const path = hash2 > 0 ? ref.slice(0, hash2) : ref;
|
|
19027
|
+
const selector = hash2 > 0 ? ref.slice(hash2 + 1) : void 0;
|
|
19028
|
+
const branch = selector?.startsWith("branch=") ? selector.slice("branch=".length) : void 0;
|
|
19029
|
+
const all = await readSpans(path);
|
|
19030
|
+
let spans;
|
|
19031
|
+
let traceId;
|
|
19032
|
+
if (branch !== void 0) {
|
|
19033
|
+
spans = branchSpans(all, branch);
|
|
19034
|
+
if (spans.length === 0) throw new Error(`${path} holds no span with ${ATTR5.branchId} or ${ATTR5.branchArm} "${branch}"`);
|
|
19035
|
+
const traces = new Set(spans.map((span2) => span2.trace_id));
|
|
19036
|
+
if (traces.size !== 1) throw new Error(`${path}: branch "${branch}" appears in ${traces.size} runs; export one run per file first`);
|
|
19037
|
+
traceId = [...traces][0];
|
|
19038
|
+
} else {
|
|
19039
|
+
const byTrace = /* @__PURE__ */ new Map();
|
|
19040
|
+
for (const span2 of all) {
|
|
19041
|
+
const list = byTrace.get(span2.trace_id);
|
|
19042
|
+
if (list) list.push(span2);
|
|
19043
|
+
else byTrace.set(span2.trace_id, [span2]);
|
|
19044
|
+
}
|
|
19045
|
+
if (selector === void 0 && byTrace.size !== 1) {
|
|
19046
|
+
throw new Error(
|
|
19047
|
+
`${path} holds ${byTrace.size} runs; pick one with ${path}#<trace id>: ${[...byTrace.keys()].slice(0, 10).join(", ")}`
|
|
19048
|
+
);
|
|
19049
|
+
}
|
|
19050
|
+
traceId = selector ?? [...byTrace.keys()][0];
|
|
19051
|
+
const picked = byTrace.get(traceId);
|
|
19052
|
+
if (!picked) throw new Error(`${path} holds no run with trace id ${traceId}`);
|
|
19053
|
+
spans = picked;
|
|
19054
|
+
}
|
|
19055
|
+
const { spans: ingested } = ingestSpans2(spans, { contentIncluded: false });
|
|
19056
|
+
const kinds = options.kinds?.length ? new Set(options.kinds.map((kind) => kind.toUpperCase())) : null;
|
|
19057
|
+
const steps = diffStepsFromSpans(ingested).filter((step) => kinds === null || kinds.has(step.kind));
|
|
19058
|
+
return { path, traceId, ...branch === void 0 ? {} : { branch }, spans: spans.length, steps };
|
|
19059
|
+
}
|
|
19060
|
+
function hasDefiniteStatus(steps) {
|
|
19061
|
+
return steps.some((step) => step.fields.status === "OK" || step.fields.status === "ERROR");
|
|
19062
|
+
}
|
|
19063
|
+
function hasToolStep(steps) {
|
|
19064
|
+
return steps.some((step) => step.kind === "TOOL");
|
|
19065
|
+
}
|
|
19066
|
+
function agreementCaveat(a, b) {
|
|
19067
|
+
const reasons = [];
|
|
19068
|
+
if (!hasDefiniteStatus(a) && !hasDefiniteStatus(b)) {
|
|
19069
|
+
reasons.push("no step on either side carries a definitive OK or ERROR status (all UNSET)");
|
|
19070
|
+
}
|
|
19071
|
+
if (!hasToolStep(a) && !hasToolStep(b)) {
|
|
19072
|
+
reasons.push("no TOOL step on either side");
|
|
19073
|
+
}
|
|
19074
|
+
return reasons.length > 0 ? reasons.join("; ") : void 0;
|
|
19075
|
+
}
|
|
19076
|
+
async function diffRuns(a, b, options = {}) {
|
|
19077
|
+
const [left, right] = await Promise.all([readRunSide(a, options), readRunSide(b, options)]);
|
|
19078
|
+
const diff = diffSteps(left.steps, right.steps);
|
|
19079
|
+
const caveat = diff.firstDivergence ? void 0 : agreementCaveat(left.steps, right.steps);
|
|
19080
|
+
return {
|
|
19081
|
+
kind: "traces.run_diff",
|
|
19082
|
+
...options.kinds?.length ? { kinds: options.kinds.map((kind) => kind.toUpperCase()) } : {},
|
|
19083
|
+
a: left,
|
|
19084
|
+
b: right,
|
|
19085
|
+
diff,
|
|
19086
|
+
...caveat ? { caveat } : {}
|
|
19087
|
+
};
|
|
19088
|
+
}
|
|
19089
|
+
var TEXT_STEP_LIMIT = 40;
|
|
19090
|
+
function sideLabel(side) {
|
|
19091
|
+
const branch = side.branch === void 0 ? "" : `, branch ${side.branch}`;
|
|
19092
|
+
return `${side.path} (trace ${side.traceId}${branch}, ${side.steps.length} steps)`;
|
|
19093
|
+
}
|
|
19094
|
+
function label(step) {
|
|
19095
|
+
const status = step.fields.status;
|
|
19096
|
+
return `${step.kind} ${JSON.stringify(step.name)}${status === "ERROR" ? " ERROR" : ""}`;
|
|
19097
|
+
}
|
|
19098
|
+
function renderRunDiff(report) {
|
|
19099
|
+
const { a, b, diff } = report;
|
|
19100
|
+
const byPairing = { id: 0, position: 0, name: 0 };
|
|
19101
|
+
for (const pair of diff.pairs) byPairing[pair.pairedBy] += 1;
|
|
19102
|
+
const lines = [
|
|
19103
|
+
...report.kinds ? [`steps limited to kind ${report.kinds.join(", ")}`] : [],
|
|
19104
|
+
`A: ${sideLabel(a)}`,
|
|
19105
|
+
`B: ${sideLabel(b)}`,
|
|
19106
|
+
`paired ${diff.pairs.length} (by id ${byPairing.id}, position ${byPairing.position}, name ${byPairing.name}), only in A ${diff.onlyInA.length}, only in B ${diff.onlyInB.length}, common prefix ${diff.commonPrefixLen}`
|
|
19107
|
+
];
|
|
19108
|
+
const first = diff.firstDivergence;
|
|
19109
|
+
if (!first) {
|
|
19110
|
+
lines.push(
|
|
19111
|
+
report.caveat ? `same steps, same order \u2014 but this is not agreement on outcome: ${report.caveat}` : "no divergence: the runs agree step for step"
|
|
19112
|
+
);
|
|
19113
|
+
return `${lines.join("\n")}
|
|
19114
|
+
`;
|
|
19115
|
+
}
|
|
19116
|
+
lines.push(`first divergence [${first.kind}] at step ${first.index}: ${first.reason}`);
|
|
19117
|
+
const details = [];
|
|
19118
|
+
for (const pair of diff.pairs) {
|
|
19119
|
+
if (pair.differences.length === 0) continue;
|
|
19120
|
+
const changes = pair.differences.map((d) => `${d.field} ${String(d.a)} -> ${String(d.b)}`).join("; ");
|
|
19121
|
+
details.push(` changed A[${pair.a}]~B[${pair.b}] ${label(a.steps[pair.a])}: ${changes}`);
|
|
19122
|
+
}
|
|
19123
|
+
for (const index of diff.onlyInA) details.push(` only in A A[${index}] ${label(a.steps[index])}`);
|
|
19124
|
+
for (const index of diff.onlyInB) details.push(` only in B B[${index}] ${label(b.steps[index])}`);
|
|
19125
|
+
lines.push(...details.slice(0, TEXT_STEP_LIMIT));
|
|
19126
|
+
if (details.length > TEXT_STEP_LIMIT) {
|
|
19127
|
+
lines.push(` \u2026 ${details.length - TEXT_STEP_LIMIT} more (use --format json for all)`);
|
|
19128
|
+
}
|
|
19129
|
+
return `${lines.join("\n")}
|
|
19130
|
+
`;
|
|
19131
|
+
}
|
|
19132
|
+
|
|
18959
19133
|
// src/upload-state.ts
|
|
18960
19134
|
import { mkdir as mkdir8, readFile as readFile17, writeFile as writeFile12 } from "fs/promises";
|
|
18961
19135
|
import { homedir as homedir12 } from "os";
|
|
@@ -18997,7 +19171,7 @@ import { createRequire as createRequire2 } from "module";
|
|
|
18997
19171
|
import { hostname as hostname2 } from "os";
|
|
18998
19172
|
import { basename as basename17, join as join33 } from "path";
|
|
18999
19173
|
import { hostedClientFromEnv } from "@tangle-network/agent-eval/hosted";
|
|
19000
|
-
import { REDACTION_VERSION } from "@tangle-network/agent-eval/traces";
|
|
19174
|
+
import { assessShareSafety as assessShareSafety2, REDACTION_VERSION, redact as redact2, shareAllowed } from "@tangle-network/agent-eval/traces";
|
|
19001
19175
|
var require2 = createRequire2(import.meta.url);
|
|
19002
19176
|
var TRACES_VERSION = require2("../package.json").version;
|
|
19003
19177
|
async function planUpload(opts = {}) {
|
|
@@ -19038,7 +19212,7 @@ async function sessionMeta(item) {
|
|
|
19038
19212
|
if (item.ref.cwd) meta[ATTR.CWD] = item.ref.cwd;
|
|
19039
19213
|
const branch = await gitBranch(item.ref.cwd);
|
|
19040
19214
|
if (branch) meta[ATTR.GIT_BRANCH] = branch;
|
|
19041
|
-
return meta;
|
|
19215
|
+
return redact2(meta).value;
|
|
19042
19216
|
}
|
|
19043
19217
|
var msToNano = (epochMs2) => (BigInt(epochMs2) * 1000000n).toString();
|
|
19044
19218
|
function toTraceSpanEvents(spans, rootMeta) {
|
|
@@ -19104,6 +19278,7 @@ async function prepareOutbound(plan, opts, uploadedAt) {
|
|
|
19104
19278
|
redactionVersion: REDACTION_VERSION
|
|
19105
19279
|
};
|
|
19106
19280
|
const items = [];
|
|
19281
|
+
const refused = [];
|
|
19107
19282
|
for (const item of candidates) {
|
|
19108
19283
|
const key = uploadKey(item.ref.harness, item.ref.sessionId);
|
|
19109
19284
|
const previous = plan.state[key];
|
|
@@ -19118,13 +19293,18 @@ async function prepareOutbound(plan, opts, uploadedAt) {
|
|
|
19118
19293
|
events = eventsAt(eventTimestamp2);
|
|
19119
19294
|
hash2 = outboundHash(events, identity2);
|
|
19120
19295
|
}
|
|
19296
|
+
const verdict = assessShareSafety2(events);
|
|
19297
|
+
if (!shareAllowed(verdict)) {
|
|
19298
|
+
refused.push({ harness: item.ref.harness, sessionId: item.ref.sessionId, verdict });
|
|
19299
|
+
continue;
|
|
19300
|
+
}
|
|
19121
19301
|
items.push({ item, events, hash: hash2 });
|
|
19122
19302
|
}
|
|
19123
|
-
return { items, skipped: plan.items.length - items.length };
|
|
19303
|
+
return { items, skipped: plan.items.length - items.length - refused.length, refused };
|
|
19124
19304
|
}
|
|
19125
19305
|
async function executeUpload(plan, opts = {}) {
|
|
19126
19306
|
const uploadedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19127
|
-
const { items, skipped } = await prepareOutbound(plan, opts, uploadedAt);
|
|
19307
|
+
const { items, skipped, refused } = await prepareOutbound(plan, opts, uploadedAt);
|
|
19128
19308
|
const redactionCount = items.reduce((n, { item }) => n + item.redaction.redactionCount, 0);
|
|
19129
19309
|
if (opts.dryRun) {
|
|
19130
19310
|
const allSpans = items.flatMap(({ item }) => item.spans);
|
|
@@ -19135,7 +19315,8 @@ async function executeUpload(plan, opts = {}) {
|
|
|
19135
19315
|
acceptedSpans: 0,
|
|
19136
19316
|
redactionCount,
|
|
19137
19317
|
dryRun: true,
|
|
19138
|
-
otlpPath: path
|
|
19318
|
+
otlpPath: path,
|
|
19319
|
+
refused
|
|
19139
19320
|
};
|
|
19140
19321
|
}
|
|
19141
19322
|
if (items.length === 0) {
|
|
@@ -19144,7 +19325,8 @@ async function executeUpload(plan, opts = {}) {
|
|
|
19144
19325
|
skippedSessions: skipped,
|
|
19145
19326
|
acceptedSpans: 0,
|
|
19146
19327
|
redactionCount,
|
|
19147
|
-
dryRun: false
|
|
19328
|
+
dryRun: false,
|
|
19329
|
+
refused
|
|
19148
19330
|
};
|
|
19149
19331
|
}
|
|
19150
19332
|
const client = opts.backend ?? hostedClientFromEnv();
|
|
@@ -19180,9 +19362,124 @@ async function executeUpload(plan, opts = {}) {
|
|
|
19180
19362
|
skippedSessions: skipped,
|
|
19181
19363
|
acceptedSpans,
|
|
19182
19364
|
redactionCount,
|
|
19183
|
-
dryRun: false
|
|
19365
|
+
dryRun: false,
|
|
19366
|
+
refused
|
|
19367
|
+
};
|
|
19368
|
+
}
|
|
19369
|
+
|
|
19370
|
+
// src/verify-safe.ts
|
|
19371
|
+
import { lstat as lstat4, readdir as readdir21, readFile as readFile19 } from "fs/promises";
|
|
19372
|
+
import { basename as basename18, extname, join as join34, relative as relative7 } from "path";
|
|
19373
|
+
import {
|
|
19374
|
+
assessShareSafety as assessShareSafety3,
|
|
19375
|
+
combineVerdicts as combineVerdicts2
|
|
19376
|
+
} from "@tangle-network/agent-eval/traces";
|
|
19377
|
+
var JSON_LINES = /* @__PURE__ */ new Set([".jsonl", ".ndjson"]);
|
|
19378
|
+
async function verifySafe(target, options = {}) {
|
|
19379
|
+
const profile = options.profile ?? "share";
|
|
19380
|
+
const assess = { profile, knownSecrets: options.knownSecrets };
|
|
19381
|
+
const verdicts = [];
|
|
19382
|
+
const unreadable = [];
|
|
19383
|
+
const files = await listFiles(target, unreadable);
|
|
19384
|
+
for (const file of files) {
|
|
19385
|
+
const label2 = relative7(target, file) || basename18(file);
|
|
19386
|
+
let bytes;
|
|
19387
|
+
try {
|
|
19388
|
+
bytes = await readFile19(file);
|
|
19389
|
+
} catch (error) {
|
|
19390
|
+
unreadable.push(`${label2}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19391
|
+
continue;
|
|
19392
|
+
}
|
|
19393
|
+
const text2 = decodeUtf8(bytes);
|
|
19394
|
+
if (text2 === void 0) {
|
|
19395
|
+
unreadable.push(`${label2}: not UTF-8 text`);
|
|
19396
|
+
continue;
|
|
19397
|
+
}
|
|
19398
|
+
const extension = extname(file).toLowerCase();
|
|
19399
|
+
if (JSON_LINES.has(extension)) {
|
|
19400
|
+
text2.split("\n").forEach((line, index) => {
|
|
19401
|
+
if (!line.trim()) return;
|
|
19402
|
+
const parsed = parseJson(line);
|
|
19403
|
+
if (parsed === void 0) unreadable.push(`${label2}:${index + 1}: not JSON`);
|
|
19404
|
+
else verdicts.push(located(assessShareSafety3(parsed.value, assess), `${label2}:${index + 1}`));
|
|
19405
|
+
});
|
|
19406
|
+
} else if (extension === ".json") {
|
|
19407
|
+
const parsed = parseJson(text2);
|
|
19408
|
+
if (parsed === void 0) unreadable.push(`${label2}: not JSON`);
|
|
19409
|
+
else verdicts.push(located(assessShareSafety3(parsed.value, assess), label2));
|
|
19410
|
+
} else {
|
|
19411
|
+
verdicts.push(located(assessShareSafety3(text2, assess), label2));
|
|
19412
|
+
}
|
|
19413
|
+
}
|
|
19414
|
+
if (files.length === 0 && unreadable.length === 0) unreadable.push(`${target}: no files to check`);
|
|
19415
|
+
return { ...combineVerdicts2(profile, verdicts, unreadable), target, files: files.length };
|
|
19416
|
+
}
|
|
19417
|
+
async function listFiles(target, unreadable) {
|
|
19418
|
+
let stat19;
|
|
19419
|
+
try {
|
|
19420
|
+
stat19 = await lstat4(target);
|
|
19421
|
+
} catch (error) {
|
|
19422
|
+
unreadable.push(`${target}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19423
|
+
return [];
|
|
19424
|
+
}
|
|
19425
|
+
if (stat19.isFile()) return [target];
|
|
19426
|
+
if (!stat19.isDirectory()) {
|
|
19427
|
+
unreadable.push(`${target}: not a regular file or directory`);
|
|
19428
|
+
return [];
|
|
19429
|
+
}
|
|
19430
|
+
const out = [];
|
|
19431
|
+
const walk = async (dir) => {
|
|
19432
|
+
for (const entry of (await readdir21(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
19433
|
+
const path = join34(dir, entry.name);
|
|
19434
|
+
if (entry.isDirectory()) await walk(path);
|
|
19435
|
+
else if (entry.isFile()) out.push(path);
|
|
19436
|
+
else unreadable.push(`${relative7(target, path)}: not a regular file`);
|
|
19437
|
+
}
|
|
19438
|
+
};
|
|
19439
|
+
await walk(target);
|
|
19440
|
+
return out;
|
|
19441
|
+
}
|
|
19442
|
+
function decodeUtf8(bytes) {
|
|
19443
|
+
if (bytes.includes(0)) return void 0;
|
|
19444
|
+
try {
|
|
19445
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
19446
|
+
} catch {
|
|
19447
|
+
return void 0;
|
|
19448
|
+
}
|
|
19449
|
+
}
|
|
19450
|
+
function parseJson(text2) {
|
|
19451
|
+
try {
|
|
19452
|
+
return { value: JSON.parse(text2) };
|
|
19453
|
+
} catch {
|
|
19454
|
+
return void 0;
|
|
19455
|
+
}
|
|
19456
|
+
}
|
|
19457
|
+
function located(verdict, where) {
|
|
19458
|
+
return {
|
|
19459
|
+
...verdict,
|
|
19460
|
+
findings: verdict.findings.map((finding2) => ({
|
|
19461
|
+
...finding2,
|
|
19462
|
+
paths: finding2.paths.map((path) => `${where}#${path}`)
|
|
19463
|
+
})),
|
|
19464
|
+
unreadable: verdict.unreadable.map((entry) => `${where}#${entry}`)
|
|
19184
19465
|
};
|
|
19185
19466
|
}
|
|
19467
|
+
function verdictExitCode(verdict) {
|
|
19468
|
+
if (verdict.status === "UNKNOWN") return 2;
|
|
19469
|
+
return verdict.status === "UNSAFE" ? 1 : 0;
|
|
19470
|
+
}
|
|
19471
|
+
function formatVerdict(result) {
|
|
19472
|
+
const lines = [`${result.status} ${result.target} (${result.files} file(s), profile ${result.profile})`];
|
|
19473
|
+
for (const finding2 of result.findings) {
|
|
19474
|
+
lines.push(
|
|
19475
|
+
` ${finding2.severity.padEnd(7)} ${finding2.category}/${finding2.detector} x${finding2.count} ${finding2.paths.join(", ")}`
|
|
19476
|
+
);
|
|
19477
|
+
}
|
|
19478
|
+
for (const entry of result.unreadable) lines.push(` unread ${entry}`);
|
|
19479
|
+
if (result.status === "UNSAFE") lines.push("Refuse to share. Redact with the same profile, then run verify-safe again.");
|
|
19480
|
+
if (result.status === "UNKNOWN") lines.push("Refuse to share: part of the input could not be read, so its safety is unknown.");
|
|
19481
|
+
return lines.join("\n");
|
|
19482
|
+
}
|
|
19186
19483
|
|
|
19187
19484
|
export {
|
|
19188
19485
|
SOURCE_ATTRIBUTE_PREFIX,
|
|
@@ -19279,6 +19576,8 @@ export {
|
|
|
19279
19576
|
analyzeAdoption,
|
|
19280
19577
|
planTraceAgenticRoute,
|
|
19281
19578
|
traceAgenticKinds,
|
|
19579
|
+
writeAnalysisTraceFile,
|
|
19580
|
+
openAgenticTraceStore,
|
|
19282
19581
|
CITATION_NORMALIZATION_VERSION,
|
|
19283
19582
|
normalizeAnalystCitations,
|
|
19284
19583
|
MAX_SHELL_DEPTH,
|
|
@@ -19342,6 +19641,7 @@ export {
|
|
|
19342
19641
|
collectSessionWorkflow,
|
|
19343
19642
|
fileSha256,
|
|
19344
19643
|
collectSessionSelection,
|
|
19644
|
+
tracesVersion,
|
|
19345
19645
|
listSessionBundleFiles,
|
|
19346
19646
|
assembleSessionBundle,
|
|
19347
19647
|
hashSessionBundleFiles,
|
|
@@ -19366,9 +19666,8 @@ export {
|
|
|
19366
19666
|
hodoscopeAnalyzer,
|
|
19367
19667
|
httpJsonTransport,
|
|
19368
19668
|
primeAnalyzer,
|
|
19369
|
-
CODING_REDACTION_RULES,
|
|
19370
|
-
TRACES_REDACTION_RULES,
|
|
19371
19669
|
redactSpans,
|
|
19670
|
+
assessSpans,
|
|
19372
19671
|
applyRedactor,
|
|
19373
19672
|
exportTraceEvidenceRows,
|
|
19374
19673
|
exportTraceEvidenceText,
|
|
@@ -19445,6 +19744,9 @@ export {
|
|
|
19445
19744
|
findSessionTextLeaks,
|
|
19446
19745
|
classifyEvidenceOnlyPath,
|
|
19447
19746
|
projectSessionBundle,
|
|
19747
|
+
readRunSide,
|
|
19748
|
+
diffRuns,
|
|
19749
|
+
renderRunDiff,
|
|
19448
19750
|
uploadKey,
|
|
19449
19751
|
sessionHash,
|
|
19450
19752
|
outboundHash,
|
|
@@ -19454,5 +19756,8 @@ export {
|
|
|
19454
19756
|
planUpload,
|
|
19455
19757
|
toTraceSpanEvents,
|
|
19456
19758
|
PartialUploadError,
|
|
19457
|
-
executeUpload
|
|
19759
|
+
executeUpload,
|
|
19760
|
+
verifySafe,
|
|
19761
|
+
verdictExitCode,
|
|
19762
|
+
formatVerdict
|
|
19458
19763
|
};
|