@tangle-network/traces 0.16.4 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,13 +9,13 @@ function sourceFileId(path) {
9
9
  function pointerPart(value) {
10
10
  return value.replaceAll("~", "~0").replaceAll("/", "~1");
11
11
  }
12
- function locateSourceObjects(value, path, bytes, offset = 0) {
12
+ function locateSourceObjects(value, path, bytes2, offset = 0) {
13
13
  if (!value || typeof value !== "object") return;
14
14
  const record2 = {
15
15
  sourceId: sourceFileId(path),
16
16
  recordOffset: offset,
17
- recordBytes: bytes.length,
18
- recordSha256: createHash("sha256").update(bytes).digest("hex")
17
+ recordBytes: bytes2.length,
18
+ recordSha256: createHash("sha256").update(bytes2).digest("hex")
19
19
  };
20
20
  const pending = [{ value, pointer: "#" }];
21
21
  while (pending.length > 0) {
@@ -317,35 +317,35 @@ function serialize(value) {
317
317
  return { value: canonicalJson(value), mimeType: "application/json" };
318
318
  }
319
319
  function utf8Prefix(value, maxBytes) {
320
- let bytes = 0;
320
+ let bytes2 = 0;
321
321
  let end = 0;
322
322
  for (const char of value) {
323
323
  const charBytes = Buffer.byteLength(char);
324
- if (bytes + charBytes > maxBytes) break;
325
- bytes += charBytes;
324
+ if (bytes2 + charBytes > maxBytes) break;
325
+ bytes2 += charBytes;
326
326
  end += char.length;
327
327
  }
328
328
  return Buffer.from(value.slice(0, end), "utf8").toString("utf8");
329
329
  }
330
- function truncatedValue(value, bytes) {
330
+ function truncatedValue(value, bytes2) {
331
331
  const longestMarker = `
332
- [truncated ${bytes} bytes]`;
332
+ [truncated ${bytes2} bytes]`;
333
333
  const prefix = utf8Prefix(value, TOOL_IO_VALUE_MAX_BYTES - Buffer.byteLength(longestMarker));
334
- const omittedBytes = bytes - Buffer.byteLength(prefix);
334
+ const omittedBytes = bytes2 - Buffer.byteLength(prefix);
335
335
  return `${prefix}
336
336
  [truncated ${omittedBytes} bytes]`;
337
337
  }
338
338
  function valueAttributes(side, raw) {
339
339
  const serialized = serialize(raw);
340
340
  if (!serialized) return {};
341
- const bytes = Buffer.byteLength(serialized.value);
341
+ const bytes2 = Buffer.byteLength(serialized.value);
342
342
  const sha2562 = createHash2("sha256").update(serialized.value).digest("hex");
343
- const truncated = bytes > TOOL_IO_VALUE_MAX_BYTES;
344
- const value = truncated ? truncatedValue(serialized.value, bytes) : serialized.value;
343
+ const truncated = bytes2 > TOOL_IO_VALUE_MAX_BYTES;
344
+ const value = truncated ? truncatedValue(serialized.value, bytes2) : serialized.value;
345
345
  return {
346
346
  [`${side}.value`]: value,
347
347
  [`${side}.mime_type`]: serialized.mimeType,
348
- [`traces.${side}.bytes`]: bytes,
348
+ [`traces.${side}.bytes`]: bytes2,
349
349
  [`traces.${side}.sha256`]: sha2562,
350
350
  [`traces.${side}.truncated`]: truncated
351
351
  };
@@ -1011,16 +1011,36 @@ function toOpenInferenceSpan(s) {
1011
1011
  }
1012
1012
  function serializeSpans(spans) {
1013
1013
  if (spans.length === 0) return "";
1014
- const validated = validateOtlpSpans(spans, "serialized spans");
1015
- return `${validated.map((s) => JSON.stringify(toOpenInferenceSpan(s))).join("\n")}
1014
+ let out = "";
1015
+ for (const line of iterSerializedSpans(spans)) out += line;
1016
+ return out;
1017
+ }
1018
+ function* iterSerializedSpans(spans) {
1019
+ for (const s of validateOtlpSpans(spans, "serialized spans")) {
1020
+ yield `${JSON.stringify(toOpenInferenceSpan(s))}
1016
1021
  `;
1022
+ }
1017
1023
  }
1024
+ var OTLP_WRITE_CHUNK_CHARS = 4 * 1024 * 1024;
1018
1025
  async function writeOtlpFile(spans, outPath) {
1019
- const { mkdtemp: mkdtemp8, writeFile: writeFile13 } = await import("fs/promises");
1026
+ const { mkdtemp: mkdtemp8, open: open2 } = await import("fs/promises");
1020
1027
  const { tmpdir: tmpdir8 } = await import("os");
1021
1028
  const { join: join35 } = await import("path");
1022
1029
  const path = outPath ?? join35(await mkdtemp8(join35(tmpdir8(), "traces-")), "spans.otlp.jsonl");
1023
- await writeFile13(path, serializeSpans(spans), "utf8");
1030
+ const handle = await open2(path, "w");
1031
+ try {
1032
+ let chunk = "";
1033
+ for (const line of iterSerializedSpans(spans)) {
1034
+ chunk += line;
1035
+ if (chunk.length >= OTLP_WRITE_CHUNK_CHARS) {
1036
+ await handle.write(chunk);
1037
+ chunk = "";
1038
+ }
1039
+ }
1040
+ if (chunk.length > 0) await handle.write(chunk);
1041
+ } finally {
1042
+ await handle.close();
1043
+ }
1024
1044
  return path;
1025
1045
  }
1026
1046
 
@@ -1367,18 +1387,18 @@ function isMissingJsonSource(error) {
1367
1387
  }
1368
1388
  async function readJsonFile(path, options = {}) {
1369
1389
  let raw;
1370
- let bytes;
1390
+ let bytes2;
1371
1391
  try {
1372
1392
  if (options.captureSources) {
1373
- bytes = await readFile3(path);
1374
- raw = bytes.toString("utf8");
1393
+ bytes2 = await readFile3(path);
1394
+ raw = bytes2.toString("utf8");
1375
1395
  } else raw = await readFile3(path, "utf8");
1376
1396
  } catch (error) {
1377
1397
  throw new JsonSourceError(path, "read", error);
1378
1398
  }
1379
1399
  try {
1380
1400
  const value = JSON.parse(raw);
1381
- if (bytes) locateSourceObjects(value, path, bytes);
1401
+ if (bytes2) locateSourceObjects(value, path, bytes2);
1382
1402
  return value;
1383
1403
  } catch (error) {
1384
1404
  throw new JsonSourceError(path, "parse", pathSafeParseCause(error));
@@ -1585,9 +1605,9 @@ function parseLine(rawLine, path, lineNumber, byteOffset, options) {
1585
1605
  const jsonBytes = rawLine.at(-1) === 13 ? rawLine.subarray(0, -1) : rawLine;
1586
1606
  if (jsonBytes.length === 0) return void 0;
1587
1607
  if (!isUtf8(jsonBytes)) return handleCorruption(rawLine, path, lineNumber, byteOffset, options);
1588
- const json2 = jsonBytes.toString("utf8");
1589
- if (json2.trim().length === 0) return void 0;
1590
1608
  try {
1609
+ const json2 = jsonBytes.toString("utf8");
1610
+ if (json2.trim().length === 0) return void 0;
1591
1611
  const value = JSON.parse(json2);
1592
1612
  if (options.captureSources) locateSourceObjects(value, path, rawLine, byteOffset);
1593
1613
  return value;
@@ -1615,12 +1635,12 @@ async function* readJsonl(path, options = { mode: "strict" }) {
1615
1635
  try {
1616
1636
  for await (const chunk of input) {
1617
1637
  options.signal?.throwIfAborted();
1618
- const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1638
+ const bytes2 = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1619
1639
  let start = 0;
1620
- let newline = bytes.indexOf(10);
1640
+ let newline = bytes2.indexOf(10);
1621
1641
  while (newline !== -1) {
1622
1642
  options.signal?.throwIfAborted();
1623
- fragments.push(bytes.subarray(start, newline));
1643
+ fragments.push(bytes2.subarray(start, newline));
1624
1644
  const rawLine = fragments.length === 1 ? fragments[0] : Buffer.concat(fragments);
1625
1645
  fragments = [];
1626
1646
  lineNumber += 1;
@@ -1628,9 +1648,9 @@ async function* readJsonl(path, options = { mode: "strict" }) {
1628
1648
  if (parsed !== void 0) yield parsed;
1629
1649
  byteOffset += rawLine.length + 1;
1630
1650
  start = newline + 1;
1631
- newline = bytes.indexOf(10, start);
1651
+ newline = bytes2.indexOf(10, start);
1632
1652
  }
1633
- if (start < bytes.length) fragments.push(bytes.subarray(start));
1653
+ if (start < bytes2.length) fragments.push(bytes2.subarray(start));
1634
1654
  }
1635
1655
  if (fragments.length > 0) {
1636
1656
  options.signal?.throwIfAborted();
@@ -2229,6 +2249,7 @@ function createClaudeStream(startStep) {
2229
2249
  step: startStep,
2230
2250
  sawUserTurn: false,
2231
2251
  promptSpans: [],
2252
+ promptSpanByUid: /* @__PURE__ */ new Map(),
2232
2253
  sawRecordedOrigin: false,
2233
2254
  firstRecordAt: null,
2234
2255
  lastRecordAt: null
@@ -2261,6 +2282,9 @@ function projectToolResult(toolUseId, isError, output, structuredWorkflowRun, ou
2261
2282
  }
2262
2283
  function projectClaudeEvent(event) {
2263
2284
  const timestamp = event.timestamp ?? EPOCH;
2285
+ if (event.type === "system" && event.subtype === "compact_boundary") {
2286
+ return { kind: "compaction", timestamp: event.timestamp ?? "", metadata: event.compactMetadata ?? {}, parentToolUseId: event.parent_tool_use_id };
2287
+ }
2264
2288
  if (event.type === "assistant" && event.message) {
2265
2289
  const tools = [];
2266
2290
  for (const block of asBlocks(event.message.content)) {
@@ -2402,7 +2426,7 @@ function indexWorkflowProjection(projection, index) {
2402
2426
  function fingerprintClaudeEvent(event) {
2403
2427
  return createHash6("sha256").update(JSON.stringify(
2404
2428
  event,
2405
- (key, value) => key === "contentSource" || key.startsWith(SOURCE_ATTRIBUTE_PREFIX) ? void 0 : value
2429
+ (key, value) => key === "contentSource" || key === "originKind" || key.startsWith(SOURCE_ATTRIBUTE_PREFIX) ? void 0 : value
2406
2430
  )).digest("hex");
2407
2431
  }
2408
2432
  function startsClaudeTask(projection) {
@@ -2416,21 +2440,43 @@ function startsClaudeTask(projection) {
2416
2440
  function distinctClaudeEvent(event, seen, sourcePath, fallbackUid) {
2417
2441
  const projection = projectClaudeEvent(event);
2418
2442
  if (event.uuid) {
2443
+ const uid = event.uuid;
2419
2444
  const fingerprint = fingerprintClaudeEvent(projection);
2420
- const previous = seen.get(event.uuid);
2421
- if (previous !== void 0) {
2422
- if (previous !== fingerprint) {
2423
- throw new ClaudeEventConflictError(sourcePath, event.uuid);
2445
+ const originKind = (projection.kind === "user" || projection.kind === "queued-prompt" ? projection.originKind : null) ?? null;
2446
+ const previous = seen.get(uid);
2447
+ if (previous) {
2448
+ if (previous.fingerprint !== fingerprint) {
2449
+ throw new ClaudeEventConflictError(sourcePath, uid);
2450
+ }
2451
+ if (previous.originKind === null && originKind !== null) return { originEnrichment: originKind, uid };
2452
+ if (previous.originKind !== null && originKind !== null && previous.originKind !== originKind) {
2453
+ throw new ClaudeEventConflictError(sourcePath, uid);
2424
2454
  }
2425
2455
  return void 0;
2426
2456
  }
2427
- seen.set(event.uuid, fingerprint);
2457
+ seen.set(uid, { fingerprint, originKind });
2428
2458
  }
2429
2459
  return { projection, uid: event.uuid ?? fallbackUid };
2430
2460
  }
2461
+ function applyOriginEnrichment(uid, originKind, state) {
2462
+ const prompt = state.promptSpanByUid.get(uid);
2463
+ if (!prompt) return;
2464
+ if (prompt.attributes[ORIGIN_RECORDED_ATTR] === true) return;
2465
+ state.sawRecordedOrigin = true;
2466
+ prompt.attributes[ORIGIN_RECORDED_ATTR] = true;
2467
+ prompt.attributes[ORIGIN_KIND_ATTR] = originKind;
2468
+ prompt.attributes[ACTOR_ATTR] = claudeActorFromOrigin(
2469
+ originKind,
2470
+ () => prompt.attributes[ACTOR_ATTR]
2471
+ );
2472
+ }
2431
2473
  function consumeDistinctClaudeEvent(event, ctx, state, seen, sourcePath) {
2432
2474
  const accepted = distinctClaudeEvent(event, seen, sourcePath, `step${state.step}`);
2433
2475
  if (!accepted) return false;
2476
+ if ("originEnrichment" in accepted) {
2477
+ applyOriginEnrichment(accepted.uid, accepted.originEnrichment, state);
2478
+ return false;
2479
+ }
2434
2480
  consumeClaudeEvent(accepted.projection, accepted.uid, ctx, state);
2435
2481
  return true;
2436
2482
  }
@@ -2440,6 +2486,34 @@ function inStreamParent(parentToolUseId, state) {
2440
2486
  return parentTool ? { span: parentTool, confidence: "explicit" } : void 0;
2441
2487
  }
2442
2488
  function consumeClaudeEvent(event, uid, ctx, state) {
2489
+ if (event.kind === "compaction") {
2490
+ const extra = {};
2491
+ const numericFields = {
2492
+ preTokens: "traces.compaction.tokens_before",
2493
+ postTokens: "traces.compaction.tokens_after",
2494
+ durationMs: "traces.compaction.latency_ms",
2495
+ cumulativeDroppedTokens: "traces.compaction.cumulative_dropped_tokens"
2496
+ };
2497
+ for (const [field, key] of Object.entries(numericFields)) {
2498
+ const value = event.metadata[field];
2499
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) extra[key] = value;
2500
+ }
2501
+ if (typeof event.metadata.trigger === "string") extra["traces.compaction.trigger"] = event.metadata.trigger;
2502
+ const parent = inStreamParent(event.parentToolUseId, state);
2503
+ state.spans.push(span({
2504
+ traceId: ctx.traceId,
2505
+ spanId: ctx.idPrefix + uid + ":compacted",
2506
+ parentSpanId: parent ? parent.span.span_id : ctx.rootParent,
2507
+ name: "session.compacted",
2508
+ kind: "CHAIN",
2509
+ startTime: event.timestamp,
2510
+ service: SERVICE2,
2511
+ agent: ctx.agent,
2512
+ step: state.step++,
2513
+ extra
2514
+ }));
2515
+ return;
2516
+ }
2443
2517
  if (event.kind === "assistant") {
2444
2518
  const messageId = event.messageId ?? uid;
2445
2519
  let llmSpan = state.llmSpanByMessageId.get(messageId);
@@ -2553,6 +2627,7 @@ function consumeClaudeEvent(event, uid, ctx, state) {
2553
2627
  if (userParent) prompt.attributes[ATTR3.parentConfidence] = userParent.confidence;
2554
2628
  state.spans.push(prompt);
2555
2629
  state.promptSpans.push(prompt);
2630
+ state.promptSpanByUid.set(uid, prompt);
2556
2631
  state.step += 1;
2557
2632
  }
2558
2633
  for (const result of event.results) {
@@ -2582,6 +2657,7 @@ function consumeClaudeEvent(event, uid, ctx, state) {
2582
2657
  }
2583
2658
  state.spans.push(prompt);
2584
2659
  state.promptSpans.push(prompt);
2660
+ state.promptSpanByUid.set(uid, prompt);
2585
2661
  state.step += 1;
2586
2662
  } else if (event.kind === "file-change") {
2587
2663
  state.spans.push(span({
@@ -2743,7 +2819,7 @@ async function readClaudeWorkflowBindings(ref, options) {
2743
2819
  options.signal?.throwIfAborted();
2744
2820
  const accepted = distinctClaudeEvent(event, seen, ref.path, `source${row}`);
2745
2821
  row += 1;
2746
- if (accepted) indexWorkflowProjection(accepted.projection, index);
2822
+ if (accepted && "projection" in accepted) indexWorkflowProjection(accepted.projection, index);
2747
2823
  }
2748
2824
  return bindWorkflowRuns(index);
2749
2825
  }
@@ -2895,7 +2971,10 @@ var ClaudeAdapter = class {
2895
2971
  runResult = { failed: event.is_error, subtype: event.subtype ?? "unknown" };
2896
2972
  }
2897
2973
  const accepted = distinctClaudeEvent(event, seen, ref.path, `step${state.step}`);
2898
- if (!accepted) continue;
2974
+ if (!accepted || "originEnrichment" in accepted) {
2975
+ if (accepted) applyOriginEnrichment(accepted.uid, accepted.originEnrichment, state);
2976
+ continue;
2977
+ }
2899
2978
  indexWorkflowProjection(accepted.projection, workflowIndex);
2900
2979
  const startsTask = startsClaudeTask(accepted.projection);
2901
2980
  if (startsTask && taskScope === "latest") {
@@ -4301,12 +4380,12 @@ var CodexAdapter = class {
4301
4380
  spans.push(turnSpan);
4302
4381
  step += 1;
4303
4382
  };
4304
- const recordInheritedContext = (l, ts) => {
4383
+ const recordInheritedContext = (l, ts, inScope = false) => {
4305
4384
  if (l.type === "compacted") {
4306
4385
  const payload = l.payload;
4307
4386
  if (!payload) return;
4308
4387
  const summary = capText(typeof payload.message === "string" ? payload.message : "");
4309
- if (summary && claimInheritedSpan()) {
4388
+ if (claimInheritedSpan()) {
4310
4389
  spans.push(span({
4311
4390
  traceId,
4312
4391
  spanId: `inherited:${step}:compacted`,
@@ -4321,7 +4400,7 @@ var CodexAdapter = class {
4321
4400
  contentSource: textSources(payload, "message"),
4322
4401
  extra: {
4323
4402
  [INHERITED_SPAN_ATTR]: true,
4324
- [INHERITED_SOURCE_ATTR]: "compacted",
4403
+ [INHERITED_SOURCE_ATTR]: inScope ? "compacted" : "pre-task-prefix",
4325
4404
  ...typeof payload.window_number === "number" ? { "traces.codex.compaction_window_number": payload.window_number } : {},
4326
4405
  ...payload.window_id ? { "traces.codex.compaction_window_id": payload.window_id } : {},
4327
4406
  ...payload.previous_window_id ? { "traces.codex.compaction_previous_window_id": payload.previous_window_id } : {}
@@ -4495,7 +4574,7 @@ var CodexAdapter = class {
4495
4574
  step += 1;
4496
4575
  }
4497
4576
  } else if (l.type === "compacted") {
4498
- recordInheritedContext(l, ts);
4577
+ recordInheritedContext(l, ts, true);
4499
4578
  } else if (l.type === "response_item" && (l.payload?.type === "function_call" || l.payload?.type === "custom_tool_call")) {
4500
4579
  const outerName = l.payload.name ?? "tool";
4501
4580
  const callId = l.payload.call_id ?? `${step}`;
@@ -6158,6 +6237,27 @@ var PiAdapter = class {
6158
6237
  if (!sessionLine && l.type === "session") {
6159
6238
  sessionLine = { id: l.id, timestamp: l.timestamp };
6160
6239
  }
6240
+ if (l.type === "compaction") {
6241
+ spans.push(span({
6242
+ traceId: sourceTraceId,
6243
+ spanId: "compacted:" + (l.id ?? step),
6244
+ parentSpanId: sourceRootId,
6245
+ name: "session.compacted",
6246
+ kind: "CHAIN",
6247
+ service: SERVICE9,
6248
+ agent: SERVICE9,
6249
+ startTime: l.timestamp ?? "",
6250
+ step: step++,
6251
+ content: typeof l.summary === "string" ? capText(l.summary) : void 0,
6252
+ contentSource: sourceOf(l, "summary"),
6253
+ extra: {
6254
+ ...typeof l.tokensBefore === "number" && Number.isFinite(l.tokensBefore) && l.tokensBefore >= 0 ? { "traces.compaction.tokens_before": l.tokensBefore } : {},
6255
+ ...typeof l.firstKeptEntryId === "string" ? { "traces.pi.first_kept_entry_id": l.firstKeptEntryId } : {},
6256
+ ...l.systemMessage !== void 0 ? { "gen_ai.system_instructions": JSON.stringify(l.systemMessage) } : {}
6257
+ }
6258
+ }));
6259
+ continue;
6260
+ }
6161
6261
  if (l.type !== "message" || !l.message) continue;
6162
6262
  const ts = l.timestamp ?? (/* @__PURE__ */ new Date(0)).toISOString();
6163
6263
  const mid = l.id ?? `m${step}`;
@@ -7395,7 +7495,7 @@ async function readLoopRuns(cwds, sessionIds) {
7395
7495
  }
7396
7496
  return { linkedCounts, unlinkedCounts, filesRead };
7397
7497
  }
7398
- async function analyzeAdoption(spans, opts = {}) {
7498
+ function computeAdoption(spans) {
7399
7499
  const { sessionByTrace, conflicts } = indexSessionIdsByTrace(spans);
7400
7500
  const identifiedSessions = new Set(sessionByTrace.values());
7401
7501
  const unassignedTraceIds = new Set(
@@ -7452,11 +7552,9 @@ async function analyzeAdoption(spans, opts = {}) {
7452
7552
  subagentSpawns[type] = (subagentSpawns[type] ?? 0) + 1;
7453
7553
  }
7454
7554
  }
7455
- const {
7456
- linkedCounts: loopDispatchedRuns,
7457
- unlinkedCounts: unlinkedLoopDispatchedRuns,
7458
- filesRead
7459
- } = await readLoopRuns(opts.cwds ?? [], identifiedSessions);
7555
+ const loopDispatchedRuns = {};
7556
+ const unlinkedLoopDispatchedRuns = {};
7557
+ const filesRead = 0;
7460
7558
  const totalSkillInvocations = Object.values(skillInvocations).reduce((a, b) => a + b, 0);
7461
7559
  const totalSkillDocumentReads = Object.values(skillDocumentReads).reduce((a, b) => a + b, 0);
7462
7560
  const totalSubagentSpawns = Object.values(subagentSpawns).reduce((a, b) => a + b, 0);
@@ -7500,6 +7598,19 @@ async function analyzeAdoption(spans, opts = {}) {
7500
7598
  totalUnlinkedLoopDispatchedRuns
7501
7599
  };
7502
7600
  }
7601
+ async function analyzeAdoption(spans, opts = {}) {
7602
+ const report = computeAdoption(spans);
7603
+ const { sessionByTrace } = indexSessionIdsByTrace(spans);
7604
+ const history = await readLoopRuns(opts.cwds ?? [], new Set(sessionByTrace.values()));
7605
+ return {
7606
+ ...report,
7607
+ loopDispatchedRuns: history.linkedCounts,
7608
+ totalLoopDispatchedRuns: Object.values(history.linkedCounts).reduce((sum, count2) => sum + count2, 0),
7609
+ unlinkedLoopDispatchedRuns: history.unlinkedCounts,
7610
+ totalUnlinkedLoopDispatchedRuns: Object.values(history.unlinkedCounts).reduce((sum, count2) => sum + count2, 0),
7611
+ skillRunFilesRead: history.filesRead
7612
+ };
7613
+ }
7503
7614
 
7504
7615
  // src/agentic-routing.ts
7505
7616
  import {
@@ -8458,13 +8569,13 @@ function mergeEvent(record2, recordIndex, words) {
8458
8569
  const target = positional[0] ?? null;
8459
8570
  const numberInCommand = target === null ? null : /^#?(\d+)$/.exec(target)?.[1] ?? numbersInLine(target)[0] ?? null;
8460
8571
  const numberInOutput = numberInCommand === null ? MERGED_NUMBER.exec(record2.output)?.[1] ?? null : null;
8461
- const number = numberInCommand ?? numberInOutput;
8462
- if (!reachedGh(record2, "merge", number !== null)) return null;
8572
+ const number2 = numberInCommand ?? numberInOutput;
8573
+ if (!reachedGh(record2, "merge", number2 !== null)) return null;
8463
8574
  const evidence3 = numberInCommand !== null ? "the pull request the command names" : numberInOutput !== null ? `the merge line this command printed, in span ${record2.spanId}` : target !== null ? "the branch the command names; no output that joins to it stated a number" : "none: the command named neither a pull request nor a branch";
8464
8575
  return {
8465
8576
  action: "merge",
8466
- number,
8467
- headBranch: number === null ? target : null,
8577
+ number: number2,
8578
+ headBranch: number2 === null ? target : null,
8468
8579
  command: words.join(" "),
8469
8580
  evidence: evidence3,
8470
8581
  spanIds: [record2.spanId],
@@ -8503,7 +8614,7 @@ function numberFromLaterOutput(records, after, headBranch) {
8503
8614
  ${record2.output}`.split("\n")) {
8504
8615
  const line = raw.replace(ANSI, "");
8505
8616
  if (!line.includes(headBranch)) continue;
8506
- for (const number of numbersInLine(line)) found.add(number);
8617
+ for (const number2 of numbersInLine(line)) found.add(number2);
8507
8618
  }
8508
8619
  if (found.size === 1) return { number: [...found][0], spanId: record2.spanId };
8509
8620
  }
@@ -8592,9 +8703,144 @@ function readPullRequests(spans) {
8592
8703
  };
8593
8704
  }
8594
8705
 
8706
+ // src/session-facts.ts
8707
+ import { createHash as createHash7 } from "crypto";
8708
+
8709
+ // src/session-measurements.ts
8710
+ var number = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
8711
+ function measure(spans, read, reason) {
8712
+ let total = 0;
8713
+ let measured2 = 0;
8714
+ for (const span2 of spans) {
8715
+ const value = read(span2);
8716
+ if (value !== null) {
8717
+ total += value;
8718
+ measured2 += 1;
8719
+ }
8720
+ }
8721
+ return {
8722
+ total: measured2 > 0 || spans.length === 0 ? total : null,
8723
+ measured: measured2,
8724
+ eligible: spans.length,
8725
+ unavailable: measured2 === spans.length ? null : reason
8726
+ };
8727
+ }
8728
+ function bytes(span2, side) {
8729
+ const recorded = number(span2.attributes[`traces.${side}.bytes`]);
8730
+ if (recorded !== null) return recorded;
8731
+ const text2 = span2.attributes[`${side}.value`];
8732
+ if (typeof text2 !== "string" || span2.attributes[`traces.${side}.truncated`] === true) return null;
8733
+ return Buffer.byteLength(text2);
8734
+ }
8735
+ function toolMeasurements(tools) {
8736
+ const groups = /* @__PURE__ */ new Map();
8737
+ for (const tool of tools) {
8738
+ const name = typeof tool.attributes["tool.name"] === "string" ? tool.attributes["tool.name"] : tool.name;
8739
+ const group = groups.get(name);
8740
+ if (group) group.push(tool);
8741
+ else groups.set(name, [tool]);
8742
+ }
8743
+ return [...groups].sort(([a], [b]) => a.localeCompare(b)).map(([name, spans]) => ({
8744
+ name,
8745
+ calls: spans.length,
8746
+ outcomes: {
8747
+ ok: spans.filter((span2) => span2.status.code === "OK").length,
8748
+ error: spans.filter((span2) => span2.status.code === "ERROR").length,
8749
+ unset: spans.filter((span2) => span2.status.code === "UNSET").length
8750
+ },
8751
+ inputBytes: measure(spans, (span2) => bytes(span2, "input"), "Input byte count missing or truncated without a size receipt."),
8752
+ outputBytes: measure(spans, (span2) => bytes(span2, "output"), "Output byte count missing or truncated without a size receipt."),
8753
+ callToResultMs: measure(spans, (span2) => {
8754
+ if (span2.status.code === "UNSET") return null;
8755
+ const elapsed2 = Date.parse(span2.end_time) - Date.parse(span2.start_time);
8756
+ return Number.isFinite(elapsed2) && elapsed2 > 0 ? elapsed2 : null;
8757
+ }, "A completed span with distinct recorded endpoints is required; equal endpoints may be an adapter default."),
8758
+ spanIds: spans.map((span2) => span2.span_id)
8759
+ }));
8760
+ }
8761
+ function compactions(spans) {
8762
+ const events = spans.filter((span2) => span2.name === "session.compacted" && span2.attributes[INHERITED_SOURCE_ATTR] !== "pre-task-prefix").sort((a, b) => Date.parse(a.start_time) - Date.parse(b.start_time));
8763
+ if (events.length === 0) return {
8764
+ value: null,
8765
+ spanIds: [],
8766
+ unavailable: "No compaction boundary was captured. This does not establish that no compaction occurred."
8767
+ };
8768
+ return {
8769
+ value: events.map((span2, i) => {
8770
+ const previous = i > 0 ? events[i - 1] : void 0;
8771
+ const interval = previous ? Date.parse(span2.start_time) - Date.parse(previous.start_time) : NaN;
8772
+ return {
8773
+ spanId: span2.span_id,
8774
+ at: span2.start_time,
8775
+ sincePreviousMs: Number.isFinite(interval) && interval >= 0 ? interval : null,
8776
+ latencyMs: number(span2.attributes["traces.compaction.latency_ms"]),
8777
+ tokensBefore: number(span2.attributes["traces.compaction.tokens_before"]),
8778
+ tokensAfter: number(span2.attributes["traces.compaction.tokens_after"])
8779
+ };
8780
+ }),
8781
+ spanIds: events.map((span2) => span2.span_id),
8782
+ unavailable: null,
8783
+ partial: "Observed boundaries only. Latency and context sizes are null unless the source explicitly records them."
8784
+ };
8785
+ }
8786
+ function contextFootprints(spans) {
8787
+ const out = [];
8788
+ for (const span2 of spans) {
8789
+ const fields = ["gen_ai.tool.definitions", "gen_ai.system_instructions"];
8790
+ if (span2.name === "message.system" || span2.name === "message.developer" || span2.name === "user.prompt" && span2.attributes["tangle.actor"] === "injected") fields.push("content");
8791
+ for (const field of fields) {
8792
+ const value = span2.attributes[field];
8793
+ if (value === void 0 || value === null) continue;
8794
+ const text2 = typeof value === "string" ? value : canonicalJson(value);
8795
+ let entries = Array.isArray(value) ? value.length : null;
8796
+ if (typeof value === "string") {
8797
+ try {
8798
+ const parsed = JSON.parse(value);
8799
+ if (Array.isArray(parsed)) entries = parsed.length;
8800
+ } catch {
8801
+ }
8802
+ }
8803
+ out.push({ spanId: span2.span_id, field, bytes: Buffer.byteLength(text2), lines: text2.split("\n").length, entries, scope: "captured-attribute" });
8804
+ }
8805
+ }
8806
+ return out;
8807
+ }
8808
+ function computeSessionMeasurements(spans, tools, sessionId, harness) {
8809
+ const spawns = tools.filter((span2) => span2.attributes["traces.agent.spawn"] === true || span2.attributes["traces.codex.agent_operation"] === "spawn_agent").sort((a, b) => Date.parse(a.start_time) - Date.parse(b.start_time));
8810
+ return {
8811
+ observedSpawns: spawns.length,
8812
+ spawnIntervalsMs: spawns.map((span2, i) => {
8813
+ const previous = spawns[i - 1];
8814
+ const interval = previous ? Date.parse(span2.start_time) - Date.parse(previous.start_time) : NaN;
8815
+ return { spanId: span2.span_id, intervalMs: Number.isFinite(interval) && interval >= 0 ? interval : null };
8816
+ }),
8817
+ execution: spans.length > 0 ? summarizeSpanExecution(spans) : null,
8818
+ adoption: computeAdoption(spans),
8819
+ relationship: describeSessionRelationship({
8820
+ sessionId: sessionId ?? spans[0]?.trace_id ?? "",
8821
+ harness: harness ?? "",
8822
+ path: "",
8823
+ cwd: null,
8824
+ mtimeMs: 0
8825
+ }, spans),
8826
+ tools: toolMeasurements(tools),
8827
+ compactions: compactions(spans),
8828
+ contextFootprints: contextFootprints(spans),
8829
+ coverage: {
8830
+ profile: "Native spans do not establish the authored or effective AgentProfile revision; join the Runtime profile receipt by recorded identity.",
8831
+ materializedResources: "Captured attributes measure only the visible representation. Missing tools, skills, MCP definitions, and resources are unknown.",
8832
+ contextTokens: "No tokenizer estimates are substituted for the actual request. Per-component context token counts require producer telemetry.",
8833
+ toolTokens: "Tool byte counts are not model input tokens; token attribution to tool content is not captured.",
8834
+ compaction: "Only recorded boundaries are counted. Zero-duration adapter defaults are not measured compaction latency.",
8835
+ semanticAssessments: "Success at the task, useful skill application, waste, reward hacking, safety, and dishonesty require separately attributed evaluation."
8836
+ }
8837
+ };
8838
+ }
8839
+
8595
8840
  // src/session-facts.ts
8596
8841
  import { OPENINFERENCE_SPAN_KIND as OPENINFERENCE_SPAN_KIND4, TOOL_NAME as TOOL_NAME5 } from "@tangle-network/agent-eval/trace-attributes";
8597
8842
  import { ingestSpans, rankFirstFailure } from "@tangle-network/agent-eval/diagnosis";
8843
+ var SESSION_FACTS_MEASUREMENT_VERSION = "3";
8598
8844
  var SESSION_TOKEN_TOTAL_ATTR = "traces.session.total_tokens";
8599
8845
  var SPAN_SYNTHESIZED_ATTR = "traces.codex.span_synthesized";
8600
8846
  var CORRUPTION_COUNT_ATTR = "traces.session.corruption_count";
@@ -8869,15 +9115,17 @@ function humanTurnsOf(spans) {
8869
9115
  excluded: [...excluded].sort(([left], [right]) => left.localeCompare(right)).map(([reason, spanIds]) => ({ reason, turns: spanIds.length, spanIds }))
8870
9116
  };
8871
9117
  }
8872
- function computeSessionFacts(spans) {
9118
+ function computeSessionFacts(spans, options = {}) {
8873
9119
  const { sessionByTrace } = indexSessionIdsByTrace(spans);
8874
9120
  const byTrace = /* @__PURE__ */ new Map();
8875
9121
  for (const span2 of spans) {
8876
- byTrace.set(span2.trace_id, [...byTrace.get(span2.trace_id) ?? [], span2]);
9122
+ const group = byTrace.get(span2.trace_id);
9123
+ if (group) group.push(span2);
9124
+ else byTrace.set(span2.trace_id, [span2]);
8877
9125
  }
8878
- return [...byTrace].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([traceId, traceSpans]) => sessionFactsForTrace(traceId, sessionByTrace.get(traceId) ?? null, traceSpans));
9126
+ return [...byTrace].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([traceId, traceSpans]) => sessionFactsForTrace(traceId, sessionByTrace.get(traceId) ?? null, traceSpans, options));
8879
9127
  }
8880
- function sessionFactsForTrace(traceId, sessionId, unordered) {
9128
+ function sessionFactsForTrace(traceId, sessionId, unordered, options) {
8881
9129
  const spans = [...unordered].sort(byTraceOrder);
8882
9130
  const harness = spans.map((span2) => stringAttr2(span2, "service.name")).find((name) => name !== null) ?? null;
8883
9131
  const ownSpans = spans.filter((span2) => !isSubagentSpan(span2.attributes));
@@ -8916,7 +9164,7 @@ function sessionFactsForTrace(traceId, sessionId, unordered) {
8916
9164
  (span2) => span2.parent_span_id !== null && span2.attributes[CORRUPTION_RECEIPT_VERSION_ATTR] === void 0
8917
9165
  ).length;
8918
9166
  const corruptionSpan = spans.find((span2) => typeof span2.attributes[CORRUPTION_COUNT_ATTR] === "number");
8919
- return {
9167
+ const facts = {
8920
9168
  schemaVersion: 1,
8921
9169
  kind: "traces.session_facts",
8922
9170
  traceId,
@@ -8933,6 +9181,7 @@ function sessionFactsForTrace(traceId, sessionId, unordered) {
8933
9181
  spanIds: [],
8934
9182
  unavailable: `no span carries ${CORRUPTION_COUNT_ATTR}; this trace was not read through the session integrity path, so whether any record was skipped is unknown`
8935
9183
  },
9184
+ measurements: computeSessionMeasurements(ownSpans, invoked, sessionId, harness),
8936
9185
  toolCalls: {
8937
9186
  value: invoked.length,
8938
9187
  spanIds: invoked.map((span2) => span2.span_id),
@@ -8985,15 +9234,50 @@ function sessionFactsForTrace(traceId, sessionId, unordered) {
8985
9234
  unavailable: `no span carries ${SESSION_TOKEN_TOTAL_ATTR}; the per-turn llm.turn deltas in this trace are a different quantity and summing them would not be the harness total`
8986
9235
  }
8987
9236
  };
9237
+ if (options.includeContent !== false) return facts;
9238
+ const withheld = () => ({
9239
+ value: null,
9240
+ spanIds: [],
9241
+ unavailable: "Content was not requested."
9242
+ });
9243
+ return {
9244
+ ...facts,
9245
+ humanTurns: withheld(),
9246
+ finalMessages: withheld(),
9247
+ changedFiles: withheld(),
9248
+ pullRequests: withheld(),
9249
+ subagents: {
9250
+ ...facts.subagents,
9251
+ value: facts.subagents.value?.map((entry) => ({
9252
+ ...entry,
9253
+ taskName: null,
9254
+ taskNameUnavailable: "Assignment text was not requested."
9255
+ })) ?? null
9256
+ },
9257
+ firstFailure: facts.firstFailure.status === "found" ? { ...facts.firstFailure, message: null, classification: facts.firstFailure.classification ? { ...facts.firstFailure.classification, reason: "Content was not requested." } : null } : facts.firstFailure
9258
+ };
8988
9259
  }
8989
9260
  function buildSessionFactsReport(spans, options = {}) {
9261
+ const digest = createHash7("sha256");
9262
+ const ordered2 = [...spans].sort((a, b) => a.trace_id.localeCompare(b.trace_id) || a.span_id.localeCompare(b.span_id));
9263
+ let evidenceThrough = null;
9264
+ for (const span2 of ordered2) {
9265
+ digest.update(canonicalJson(span2)).update("\n");
9266
+ for (const time of [span2.start_time, span2.end_time]) {
9267
+ if (Number.isFinite(Date.parse(time)) && (evidenceThrough === null || Date.parse(time) > Date.parse(evidenceThrough))) evidenceThrough = time;
9268
+ }
9269
+ }
8990
9270
  return {
8991
9271
  schemaVersion: 1,
8992
9272
  kind: "traces.session_facts_report",
9273
+ measurementVersion: SESSION_FACTS_MEASUREMENT_VERSION,
9274
+ sourceDigest: "sha256:" + digest.digest("hex"),
9275
+ evidenceThrough,
9276
+ contentIncluded: options.includeContent !== false,
8993
9277
  generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
8994
9278
  harness: options.harness ?? null,
8995
9279
  spanCount: spans.length,
8996
- sessions: computeSessionFacts(spans)
9280
+ sessions: computeSessionFacts(spans, options)
8997
9281
  };
8998
9282
  }
8999
9283
  function factLine(label2, fact, rendered) {
@@ -9042,6 +9326,8 @@ function renderSessionFacts(report) {
9042
9326
  lines.push(factLine("changed files", facts.changedFiles, String(facts.changedFiles.value?.length ?? 0)));
9043
9327
  lines.push(factLine("first record", facts.firstRecordAt, String(facts.firstRecordAt.value)));
9044
9328
  lines.push(factLine("last record", facts.lastRecordAt, String(facts.lastRecordAt.value)));
9329
+ lines.push(factLine("compactions", facts.measurements.compactions, String(facts.measurements.compactions.value?.length ?? 0)));
9330
+ lines.push(" skills: " + facts.measurements.adoption.totalSkillInvocations + " recorded invocation(s), " + facts.measurements.adoption.totalSkillDocumentReads + " document read(s); telemetry " + facts.measurements.adoption.skillTelemetryStatus);
9045
9331
  lines.push(factLine("token total", facts.tokenTotal, String(facts.tokenTotal.value)));
9046
9332
  lines.push(` first failure: ${renderFirstFailure(facts.firstFailure)}`);
9047
9333
  if ((facts.unreadRecords.value ?? 0) > 0) {
@@ -9087,6 +9373,9 @@ ${JSON.stringify({ sessions, ...dropped2.length ? { omitted_fields: dropped2 } :
9087
9373
  ["tool_call_span_ids", (facts) => {
9088
9374
  facts.tool_calls.span_ids = [];
9089
9375
  }],
9376
+ ["measurements", (facts) => {
9377
+ delete facts.measurements;
9378
+ }],
9090
9379
  ["tool_calls_by_name", (facts) => {
9091
9380
  delete facts.tool_calls_by_name;
9092
9381
  }],
@@ -9211,7 +9500,8 @@ function compactFacts(facts) {
9211
9500
  first_record_at: factJson(facts.firstRecordAt),
9212
9501
  last_record_at: factJson(facts.lastRecordAt),
9213
9502
  token_total: factJson(facts.tokenTotal),
9214
- first_failure: compactFirstFailure(facts.firstFailure)
9503
+ first_failure: compactFirstFailure(facts.firstFailure),
9504
+ measurements: facts.measurements
9215
9505
  };
9216
9506
  }
9217
9507
  function compactFirstFailure(failure2) {
@@ -9240,7 +9530,7 @@ function sessionFactsContext(spans, options = {}) {
9240
9530
  if (report.sessions.length === 0) return void 0;
9241
9531
  return renderSessionFactsContext(report, options);
9242
9532
  }
9243
- var SESSION_FACTS_VERSION_SUFFIX = "session-facts.2";
9533
+ var SESSION_FACTS_VERSION_SUFFIX = "session-facts." + SESSION_FACTS_MEASUREMENT_VERSION;
9244
9534
  function withSessionFactsContext(definitions, spans, options = {}) {
9245
9535
  const sheet = sessionFactsContext(spans, options);
9246
9536
  if (sheet === void 0) return [...definitions];
@@ -9267,13 +9557,13 @@ import { OtlpFileTraceStore } from "@tangle-network/agent-eval/traces";
9267
9557
 
9268
9558
  // src/bundle-source.ts
9269
9559
  import { isUtf8 as isUtf82 } from "buffer";
9270
- import { createHash as createHash9 } from "crypto";
9560
+ import { createHash as createHash10 } from "crypto";
9271
9561
  import { constants } from "fs";
9272
9562
  import { lstat as lstat2, open, realpath as realpath3 } from "fs/promises";
9273
9563
  import { dirname as dirname8, isAbsolute as isAbsolute4, join as join20, relative as relative5, resolve as resolve7, sep as sep2 } from "path";
9274
9564
 
9275
9565
  // src/bundle.ts
9276
- import { createHash as createHash8 } from "crypto";
9566
+ import { createHash as createHash9 } from "crypto";
9277
9567
  import { copyFile, cp, lstat, mkdir as mkdir2, readdir as readdir16, readFile as readFile7, stat as stat14, writeFile as writeFile5 } from "fs/promises";
9278
9568
  import { dirname as dirname7, join as join19, relative as relative4, resolve as resolve6, sep } from "path";
9279
9569
 
@@ -10502,7 +10792,7 @@ function measured(value, render) {
10502
10792
  }
10503
10793
  function distributionRow(label2, distribution, unit = "") {
10504
10794
  if (distribution.n === 0) return `| ${label2} | 0 | not captured | not captured | not captured | not captured | not captured |`;
10505
- const value = (number) => measured(number, (captured) => `${decimal(captured)}${unit}`);
10795
+ const value = (number2) => measured(number2, (captured) => `${decimal(captured)}${unit}`);
10506
10796
  return `| ${label2} | ${count(distribution.n)} | ${value(distribution.min)} | ${value(distribution.mean)} | ${value(distribution.p50)} | ${value(distribution.p95)} | ${value(distribution.max)} |`;
10507
10797
  }
10508
10798
  function tokenRows(usage) {
@@ -11853,7 +12143,7 @@ async function writeSessionIndexFile(index, outPath) {
11853
12143
  }
11854
12144
 
11855
12145
  // src/session-selection.ts
11856
- import { createHash as createHash7 } from "crypto";
12146
+ import { createHash as createHash8 } from "crypto";
11857
12147
  import { createReadStream as createReadStream2 } from "fs";
11858
12148
 
11859
12149
  // src/session-workflow.ts
@@ -12179,7 +12469,7 @@ async function collectSessionWorkflow(adapter, seeds, options = {}) {
12179
12469
  // src/session-selection.ts
12180
12470
  async function fileSha256(path, signal) {
12181
12471
  signal?.throwIfAborted();
12182
- const hash2 = createHash7("sha256");
12472
+ const hash2 = createHash8("sha256");
12183
12473
  try {
12184
12474
  for await (const chunk of createReadStream2(path, { signal })) {
12185
12475
  signal?.throwIfAborted();
@@ -12207,7 +12497,7 @@ async function sourceSnapshot(adapter, ref, signal) {
12207
12497
  signal?.throwIfAborted();
12208
12498
  files.push({ path, sha256: await fileSha256(path, signal) });
12209
12499
  }
12210
- const sha2562 = files.length === 1 ? files[0].sha256 : createHash7("sha256").update(JSON.stringify(files)).digest("hex");
12500
+ const sha2562 = files.length === 1 ? files[0].sha256 : createHash8("sha256").update(JSON.stringify(files)).digest("hex");
12211
12501
  return { sha256: sha2562, files };
12212
12502
  }
12213
12503
  function summarizeWorkflows(workflows) {
@@ -12333,8 +12623,8 @@ var KNOWN_LIMITS = [
12333
12623
  "progress.md is copied whole; no session-dated section extraction is performed",
12334
12624
  "open pull-request state is not captured: the bundler makes no network calls"
12335
12625
  ];
12336
- function sha256Hex(bytes) {
12337
- return createHash8("sha256").update(bytes).digest("hex");
12626
+ function sha256Hex(bytes2) {
12627
+ return createHash9("sha256").update(bytes2).digest("hex");
12338
12628
  }
12339
12629
  function bundlePath(...parts) {
12340
12630
  return parts.join("/");
@@ -12741,13 +13031,13 @@ async function verifySessionBundle(bundleDir) {
12741
13031
  let source;
12742
13032
  if (manifest.projection) {
12743
13033
  const sourceManifest = join19(manifest.projection.sourceDirectory, "manifest.json");
12744
- const bytes = await readFile7(sourceManifest).catch((error) => {
13034
+ const bytes2 = await readFile7(sourceManifest).catch((error) => {
12745
13035
  if (isMissingPathError(error)) return null;
12746
13036
  throw error;
12747
13037
  });
12748
13038
  source = {
12749
13039
  directory: manifest.projection.sourceDirectory,
12750
- status: bytes === null ? "unavailable" : sha256Hex(bytes) === manifest.projection.sourceManifestSha256 ? "match" : "mismatch"
13040
+ status: bytes2 === null ? "unavailable" : sha256Hex(bytes2) === manifest.projection.sourceManifestSha256 ? "match" : "mismatch"
12751
13041
  };
12752
13042
  }
12753
13043
  return {
@@ -12791,8 +13081,8 @@ async function openBundleFile(root, file) {
12791
13081
  return handle;
12792
13082
  }
12793
13083
  async function fileDigest(handle, signal) {
12794
- const hash2 = createHash9("sha256");
12795
- for await (const bytes of handle.createReadStream({ start: 0, autoClose: false, signal })) hash2.update(bytes);
13084
+ const hash2 = createHash10("sha256");
13085
+ for await (const bytes2 of handle.createReadStream({ start: 0, autoClose: false, signal })) hash2.update(bytes2);
12796
13086
  return hash2.digest("hex");
12797
13087
  }
12798
13088
  async function validateFile(root, file, signal) {
@@ -12892,7 +13182,7 @@ async function createBundleSourceReader(directory, spans, options = {}) {
12892
13182
  handle = await openBundleFile(root, file);
12893
13183
  const before = await handle.stat();
12894
13184
  if (await fileDigest(handle, signal) !== file.sha256) return unavailable("retained source digest mismatch");
12895
- const hash2 = createHash9("sha256");
13185
+ const hash2 = createHash10("sha256");
12896
13186
  const record2 = Buffer.alloc(ref.recordBytes);
12897
13187
  let position = 0;
12898
13188
  for await (const raw of handle.createReadStream({
@@ -12901,10 +13191,10 @@ async function createBundleSourceReader(directory, spans, options = {}) {
12901
13191
  autoClose: false,
12902
13192
  signal
12903
13193
  })) {
12904
- const bytes2 = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
12905
- hash2.update(bytes2);
12906
- bytes2.copy(record2, position);
12907
- position += bytes2.length;
13194
+ const bytes3 = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
13195
+ hash2.update(bytes3);
13196
+ bytes3.copy(record2, position);
13197
+ position += bytes3.length;
12908
13198
  }
12909
13199
  const after = await handle.stat();
12910
13200
  if (position !== ref.recordBytes || hash2.digest("hex") !== ref.recordSha256 || before.size !== after.size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs) {
@@ -12927,22 +13217,22 @@ async function createBundleSourceReader(directory, spans, options = {}) {
12927
13217
  if (input.offset > field.length) return unavailable("source offset is outside the selected field");
12928
13218
  const window = field.subarray(input.offset, Math.min(field.length, input.offset + input.limit));
12929
13219
  if (window.length > 0 && (window[0] & 192) === 128) return unavailable("offset splits a UTF-8 character");
12930
- let bytes = window;
13220
+ let bytes2 = window;
12931
13221
  for (let omitted = 0; omitted <= 3; omitted += 1) {
12932
- bytes = window.subarray(0, Math.max(0, window.length - omitted));
12933
- if (isUtf82(bytes)) break;
13222
+ bytes2 = window.subarray(0, Math.max(0, window.length - omitted));
13223
+ if (isUtf82(bytes2)) break;
12934
13224
  }
12935
- if (!isUtf82(bytes) || bytes.length === 0 && input.offset < field.length) {
13225
+ if (!isUtf82(bytes2) || bytes2.length === 0 && input.offset < field.length) {
12936
13226
  return unavailable("window cannot contain a complete UTF-8 character");
12937
13227
  }
12938
- const next = input.offset + bytes.length;
13228
+ const next = input.offset + bytes2.length;
12939
13229
  return {
12940
13230
  status: "available",
12941
13231
  trace_id: input.trace_id,
12942
13232
  span_id: input.span_id,
12943
13233
  attribute: input.attribute,
12944
13234
  source_index: sourceIndex,
12945
- text: bytes.toString("utf8"),
13235
+ text: bytes2.toString("utf8"),
12946
13236
  offset: input.offset,
12947
13237
  total_bytes: field.length,
12948
13238
  next_offset: next < field.length ? next : null,
@@ -13075,7 +13365,7 @@ async function analyzeSpans(spans, opts = {}) {
13075
13365
  }
13076
13366
 
13077
13367
  // src/chat-trajectory.ts
13078
- import { createHash as createHash10 } from "crypto";
13368
+ import { createHash as createHash11 } from "crypto";
13079
13369
  function isChatTrajectoryMessage(value) {
13080
13370
  return isObject2(value) && typeof value.role === "string" && typeof value.content === "string";
13081
13371
  }
@@ -13160,7 +13450,7 @@ function trajectoryId(trajectory) {
13160
13450
  const value = trajectory.trajectory_id ?? trajectory.traj_id ?? trajectory.instance_id;
13161
13451
  if (typeof value === "string" && value.trim()) return value;
13162
13452
  if (typeof value === "number" && Number.isSafeInteger(value)) return String(value);
13163
- return `trajectory-${createHash10("sha256").update(JSON.stringify(trajectory.messages)).digest("hex").slice(0, 24)}`;
13453
+ return `trajectory-${createHash11("sha256").update(JSON.stringify(trajectory.messages)).digest("hex").slice(0, 24)}`;
13164
13454
  }
13165
13455
  function messageKind(role) {
13166
13456
  const normalized = role.trim().toLowerCase();
@@ -13217,8 +13507,8 @@ function parseTime2(value) {
13217
13507
  }
13218
13508
  function finiteNumber(value, key) {
13219
13509
  if (!isObject2(value)) return void 0;
13220
- const number = value[key];
13221
- return typeof number === "number" && Number.isFinite(number) ? number : void 0;
13510
+ const number2 = value[key];
13511
+ return typeof number2 === "number" && Number.isFinite(number2) ? number2 : void 0;
13222
13512
  }
13223
13513
  function stringValue2(value) {
13224
13514
  return typeof value === "string" && value.trim() ? value : void 0;
@@ -13240,7 +13530,7 @@ import {
13240
13530
  import { basename as basename13, dirname as dirname10, join as join23, resolve as resolve9 } from "path";
13241
13531
 
13242
13532
  // src/codetracebench-files.ts
13243
- import { createHash as createHash11, randomUUID } from "crypto";
13533
+ import { createHash as createHash12, randomUUID } from "crypto";
13244
13534
  import {
13245
13535
  link,
13246
13536
  lstat as lstat3,
@@ -13438,7 +13728,7 @@ async function atomicWriteFile(path, content, signal) {
13438
13728
  }
13439
13729
  }
13440
13730
  function sha256(value) {
13441
- return createHash11("sha256").update(value).digest("hex");
13731
+ return createHash12("sha256").update(value).digest("hex");
13442
13732
  }
13443
13733
  function isObject3(value) {
13444
13734
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -13675,10 +13965,10 @@ async function readOptionalTask(trajectoryDirectory, caseDirectory, row, signal)
13675
13965
  content: `Task: ${row.taskName}`
13676
13966
  };
13677
13967
  }
13678
- const bytes = await readFile9(path, { signal });
13679
- const content = bytes.toString("utf8").trim();
13968
+ const bytes2 = await readFile9(path, { signal });
13969
+ const content = bytes2.toString("utf8").trim();
13680
13970
  if (!content) throw new Error(`${row.trajId}/task.md is empty`);
13681
- return { source: "task.md", content, path, bytes };
13971
+ return { source: "task.md", content, path, bytes: bytes2 };
13682
13972
  }
13683
13973
  function assertNoLabelLeak(spans, row) {
13684
13974
  for (const item of spans) {
@@ -14328,7 +14618,7 @@ async function cmdVerifyFindings(argv) {
14328
14618
  }
14329
14619
 
14330
14620
  // src/hodoscope.ts
14331
- import { createHash as createHash12 } from "crypto";
14621
+ import { createHash as createHash13 } from "crypto";
14332
14622
  import { mkdir as mkdir5, mkdtemp as mkdtemp5, readFile as readFile11, readdir as readdir17, writeFile as writeFile7 } from "fs/promises";
14333
14623
  import { endianness, tmpdir as tmpdir5 } from "os";
14334
14624
  import { join as join24, resolve as resolve10 } from "path";
@@ -14367,7 +14657,7 @@ async function writeHodoscopeInput(otlpPath, options = {}) {
14367
14657
  throw new Error(`Hodoscope trace '${traceId}' contains no assistant actions`);
14368
14658
  }
14369
14659
  actionCount += actions;
14370
- const file = `${createHash12("sha256").update(traceId).digest("hex").slice(0, 24)}.json`;
14660
+ const file = `${createHash13("sha256").update(traceId).digest("hex").slice(0, 24)}.json`;
14371
14661
  await writeFile7(join24(samples, file), `${JSON.stringify(trajectory, null, 2)}
14372
14662
  `, "utf8");
14373
14663
  }
@@ -14879,7 +15169,7 @@ function validateEmbedding(encoded, dimensions, path) {
14879
15169
  `Hodoscope ${path} encodes ${encoded.length} characters; expected ${expectedLength} for ${dimensions} float32 values`
14880
15170
  );
14881
15171
  }
14882
- const bytes = new Uint8Array(dimensions * 4);
15172
+ const bytes2 = new Uint8Array(dimensions * 4);
14883
15173
  for (let group = 0; group < dimensions; group += 1) {
14884
15174
  let value = 0;
14885
15175
  const encodedOffset = group * 5;
@@ -14895,12 +15185,12 @@ function validateEmbedding(encoded, dimensions, path) {
14895
15185
  throw new Error(`Hodoscope ${path} contains an overflowing base85 block at index ${group}`);
14896
15186
  }
14897
15187
  const byteOffset = group * 4;
14898
- bytes[byteOffset] = Math.floor(value / 16777216) & 255;
14899
- bytes[byteOffset + 1] = Math.floor(value / 65536) & 255;
14900
- bytes[byteOffset + 2] = Math.floor(value / 256) & 255;
14901
- bytes[byteOffset + 3] = value & 255;
15188
+ bytes2[byteOffset] = Math.floor(value / 16777216) & 255;
15189
+ bytes2[byteOffset + 1] = Math.floor(value / 65536) & 255;
15190
+ bytes2[byteOffset + 2] = Math.floor(value / 256) & 255;
15191
+ bytes2[byteOffset + 3] = value & 255;
14902
15192
  }
14903
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
15193
+ const view = new DataView(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength);
14904
15194
  const littleEndian = endianness() === "LE";
14905
15195
  for (let index = 0; index < dimensions; index += 1) {
14906
15196
  if (!Number.isFinite(view.getFloat32(index * 4, littleEndian))) {
@@ -15015,7 +15305,7 @@ function assertPositiveInteger(name, value) {
15015
15305
  }
15016
15306
 
15017
15307
  // src/analyst-engine-prime.ts
15018
- import { createHash as createHash13 } from "crypto";
15308
+ import { createHash as createHash14 } from "crypto";
15019
15309
  import { request as httpRequest } from "http";
15020
15310
  import { request as httpsRequest } from "https";
15021
15311
  var DEFAULT_BRIDGE_URL = "http://localhost:4181";
@@ -15028,6 +15318,17 @@ var MAX_FINDINGS = 10;
15028
15318
  var MAX_SPAN_IDS_PER_FINDING = 8;
15029
15319
  var SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info"]);
15030
15320
  var ANALYST_ID = "prime";
15321
+ var TRAJECTORY_FILE_NAME = "trajectory.otlp.jsonl";
15322
+ async function fileDelivery(otlpPath, perAttributeCharCap, signal) {
15323
+ signal?.throwIfAborted();
15324
+ const { copyFile: copyFile2, mkdtemp: mkdtemp8, stat: stat19 } = await import("fs/promises");
15325
+ const { tmpdir: tmpdir8 } = await import("os");
15326
+ const { join: join35 } = await import("path");
15327
+ const cwd = await mkdtemp8(join35(tmpdir8(), "traces-prime-"));
15328
+ await copyFile2(otlpPath, join35(cwd, TRAJECTORY_FILE_NAME));
15329
+ const artifactBytes = (await stat19(otlpPath)).size;
15330
+ return { mode: "file-cwd", perAttributeCharCap, renderedChars: artifactBytes, cwd, fileName: TRAJECTORY_FILE_NAME };
15331
+ }
15031
15332
  function positiveIntegerEnv(name) {
15032
15333
  const raw = process.env[name];
15033
15334
  if (raw === void 0 || raw === "") return void 0;
@@ -15078,7 +15379,7 @@ function capRowAttributes(row, cap) {
15078
15379
  }
15079
15380
  return { ...row, attributes: capped };
15080
15381
  }
15081
- async function projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, signal) {
15382
+ async function projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, deliveryMode, signal) {
15082
15383
  const rows = [];
15083
15384
  const spanTraces = /* @__PURE__ */ new Map();
15084
15385
  let index = 0;
@@ -15102,9 +15403,18 @@ async function projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, si
15102
15403
  }
15103
15404
  if (rows.length === 0) throw new Error(`${otlpPath} contains no spans`);
15104
15405
  const traceCount = new Set(rows.map((row) => row.trace_id)).size;
15406
+ if (deliveryMode === "file") {
15407
+ return {
15408
+ rows,
15409
+ rendered: null,
15410
+ delivery: await fileDelivery(otlpPath, perAttributeCharCap, signal),
15411
+ traceCount,
15412
+ spanTraces
15413
+ };
15414
+ }
15105
15415
  let projected = rows;
15106
15416
  let rendered = JSON.stringify(projected);
15107
- const delivery = {
15417
+ let delivery = {
15108
15418
  mode: "inline-json",
15109
15419
  perAttributeCharCap: null,
15110
15420
  renderedChars: rendered.length
@@ -15112,18 +15422,30 @@ async function projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, si
15112
15422
  if (rendered.length > maxInlineChars) {
15113
15423
  projected = rows.map((row) => capRowAttributes(row, perAttributeCharCap));
15114
15424
  rendered = JSON.stringify(projected);
15115
- delivery.perAttributeCharCap = perAttributeCharCap;
15116
- delivery.renderedChars = rendered.length;
15425
+ delivery = {
15426
+ mode: "inline-json",
15427
+ perAttributeCharCap,
15428
+ renderedChars: rendered.length
15429
+ };
15117
15430
  }
15118
15431
  if (rendered.length > maxInlineChars) {
15119
- throw new Error(
15120
- `trajectory renders to ${rendered.length} chars even at per-attribute cap ${perAttributeCharCap} (budget ${maxInlineChars}); inline delivery impossible`
15121
- );
15432
+ if (deliveryMode === "inline") {
15433
+ throw new Error(
15434
+ `trajectory renders to ${rendered.length} chars even at per-attribute cap ${perAttributeCharCap} (budget ${maxInlineChars}); inline delivery impossible`
15435
+ );
15436
+ }
15437
+ return {
15438
+ rows,
15439
+ rendered: null,
15440
+ delivery: await fileDelivery(otlpPath, perAttributeCharCap, signal),
15441
+ traceCount,
15442
+ spanTraces
15443
+ };
15122
15444
  }
15123
15445
  return { rows: projected, rendered, delivery, traceCount, spanTraces };
15124
15446
  }
15125
15447
  var OUTPUT_CONTRACT_LINES = [
15126
- "OUTPUT CONTRACT (you have no trace tools and no REPL):",
15448
+ "OUTPUT CONTRACT (inline delivery \u2014 the whole trajectory is in this prompt):",
15127
15449
  "You are a one-shot analyst. Every fact you need is in the TRAJECTORY JSON below.",
15128
15450
  "Do not run shell commands, do not read or write files, do not use any tools.",
15129
15451
  "Reply with EXACTLY one fenced ```json code block and no other fenced block. The JSON object has exactly two fields:",
@@ -15139,7 +15461,35 @@ var OUTPUT_CONTRACT_LINES = [
15139
15461
  `Report at most ${MAX_FINDINGS} findings; a finding cites 1..${MAX_SPAN_IDS_PER_FINDING} span_ids, each copied VERBATIM from a span in the trajectory below.`,
15140
15462
  '"findings" is [] only for a clean trajectory.'
15141
15463
  ];
15464
+ var FILE_DELIVERY_CONTRACT_LINES = [
15465
+ "OUTPUT CONTRACT (file delivery \u2014 the trajectory is a FILE in your working directory):",
15466
+ `You are a recursive language model with a REPL. The trajectory is ${TRAJECTORY_FILE_NAME} in your`,
15467
+ "working directory: OpenInference JSONL, one span object per line. Load it yourself and inspect it with code",
15468
+ '(e.g. rows = [json.loads(line) for line in open("trajectory.otlp.jsonl")]), paging rather than printing it whole;',
15469
+ "fan out with rlm() for sub-questions when that pays for itself. Stay inside your working directory.",
15470
+ "Reply with EXACTLY one fenced ```json code block and no other fenced block. The JSON object has exactly two fields:",
15471
+ ' "answer": string \u2014 ONE short sentence (max 300 chars) summarizing your verdict.',
15472
+ ' "findings": array (possibly empty) of finding rows, each exactly:',
15473
+ ' {"span_ids": [string, ...],',
15474
+ ' "severity": "critical"|"high"|"medium"|"low"|"info",',
15475
+ ' "area": string (short kebab-case topic, max 40 chars),',
15476
+ ' "claim": string (ONE short sentence, max 200 chars),',
15477
+ ' "action": string (optional, ONE short imperative sentence, max 200 chars),',
15478
+ ' "confidence": number 0..1}',
15479
+ "Do NOT include a rationale field. Keep every string SHORT \u2014 long strings get corrupted in transport and void your work.",
15480
+ `Report at most ${MAX_FINDINGS} findings; a finding cites 1..${MAX_SPAN_IDS_PER_FINDING} span_ids, each copied VERBATIM from a span in ${TRAJECTORY_FILE_NAME}.`,
15481
+ '"findings" is [] only for a clean trajectory.'
15482
+ ];
15142
15483
  function buildPrompt(question, projection) {
15484
+ if (projection.delivery.mode === "file-cwd") {
15485
+ return [
15486
+ `QUESTION: ${question}`,
15487
+ "",
15488
+ ...FILE_DELIVERY_CONTRACT_LINES,
15489
+ "",
15490
+ `TRAJECTORY (${projection.traceCount} trace(s); ${projection.rows.length} spans): the file ${projection.delivery.fileName} in your working directory (${projection.delivery.renderedChars} bytes). It is NOT inlined in this prompt.`
15491
+ ].join("\n");
15492
+ }
15143
15493
  return [
15144
15494
  `QUESTION: ${question}`,
15145
15495
  "",
@@ -15239,7 +15589,7 @@ function toAnalystFinding(row, index, spanTraces, model, producedAt) {
15239
15589
  const traces = spanTraces.get(spanId);
15240
15590
  return spanEvidenceUri([...traces][0], spanId);
15241
15591
  });
15242
- const findingId = `prime-${createHash13("sha256").update(`${index}
15592
+ const findingId = `prime-${createHash14("sha256").update(`${index}
15243
15593
  ${row.claim}
15244
15594
  ${uris.join("\n")}`).digest("hex").slice(0, 12)}`;
15245
15595
  return {
@@ -15286,7 +15636,7 @@ var httpJsonTransport = ({ url, body, signal }) => {
15286
15636
  };
15287
15637
  var PrimeBridgeError = class extends Error {
15288
15638
  };
15289
- async function callBridge(transport, url, model, content, timeoutMs, callerSignal, turn) {
15639
+ async function callBridge(transport, url, model, content, timeoutMs, callerSignal, turn, cwd) {
15290
15640
  const controller = new AbortController();
15291
15641
  const timer = setTimeout(
15292
15642
  () => controller.abort(new Error(`${turn}bridge call exceeded ${timeoutMs}ms`)),
@@ -15299,7 +15649,7 @@ async function callBridge(transport, url, model, content, timeoutMs, callerSigna
15299
15649
  try {
15300
15650
  response = await transport({
15301
15651
  url,
15302
- body: { model, messages: [{ role: "user", content }] },
15652
+ body: { model, messages: [{ role: "user", content }], ...cwd ? { cwd } : {} },
15303
15653
  signal: controller.signal
15304
15654
  });
15305
15655
  } catch (error) {
@@ -15346,6 +15696,10 @@ function primeAnalyzer(opts = {}) {
15346
15696
  throw new RangeError("perAttributeCharCap must be a positive safe integer");
15347
15697
  }
15348
15698
  const repairEnabled = opts.repair ?? true;
15699
+ const deliveryMode = opts.delivery ?? "auto";
15700
+ if (deliveryMode !== "auto" && deliveryMode !== "file" && deliveryMode !== "inline") {
15701
+ throw new RangeError(`delivery must be 'auto', 'file', or 'inline', got '${String(deliveryMode)}'`);
15702
+ }
15349
15703
  const transport = opts.transport ?? httpJsonTransport;
15350
15704
  const url = `${bridgeUrl}/v1/chat/completions`;
15351
15705
  return {
@@ -15353,12 +15707,19 @@ function primeAnalyzer(opts = {}) {
15353
15707
  async analyze(otlpPath, analyzeOpts = {}) {
15354
15708
  let projection;
15355
15709
  try {
15356
- projection = await projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, analyzeOpts.signal);
15710
+ projection = await projectArtifact(
15711
+ otlpPath,
15712
+ maxInlineChars,
15713
+ perAttributeCharCap,
15714
+ deliveryMode,
15715
+ analyzeOpts.signal
15716
+ );
15357
15717
  } catch (error) {
15358
15718
  return failure("", error instanceof Error ? error.message : String(error));
15359
15719
  }
15360
15720
  const question = analyzeOpts.prompt ?? opts.defaultPrompt ?? DEFAULT_QUESTION;
15361
- const deliveryLine = `delivery: ${projection.delivery.mode} (${projection.delivery.renderedChars} chars, per-attribute cap ${projection.delivery.perAttributeCharCap ?? "none"})`;
15721
+ const deliveryLine = projection.delivery.mode === "file-cwd" ? `delivery: file-cwd (${projection.rows.length} spans; ${projection.delivery.fileName} in cwd ${projection.delivery.cwd}, ${projection.delivery.renderedChars} bytes; per-attribute cap not applied)` : `delivery: ${projection.delivery.mode} (${projection.delivery.renderedChars} chars, per-attribute cap ${projection.delivery.perAttributeCharCap ?? "none"})`;
15722
+ const deliveryCwd = projection.delivery.mode === "file-cwd" ? projection.delivery.cwd : void 0;
15362
15723
  let reply;
15363
15724
  try {
15364
15725
  reply = await callBridge(
@@ -15368,7 +15729,8 @@ function primeAnalyzer(opts = {}) {
15368
15729
  buildPrompt(question, projection),
15369
15730
  timeoutMs,
15370
15731
  analyzeOpts.signal,
15371
- ""
15732
+ "",
15733
+ deliveryCwd
15372
15734
  );
15373
15735
  } catch (error) {
15374
15736
  if (!(error instanceof PrimeBridgeError)) throw error;
@@ -15525,7 +15887,7 @@ async function applyRedactor(spans, redactor) {
15525
15887
  }
15526
15888
 
15527
15889
  // src/file-export.ts
15528
- import { createHash as createHash14 } from "crypto";
15890
+ import { createHash as createHash15 } from "crypto";
15529
15891
  import { mkdtemp as mkdtemp6, readFile as readFile12, writeFile as writeFile8 } from "fs/promises";
15530
15892
  import { tmpdir as tmpdir6 } from "os";
15531
15893
  import { join as join25 } from "path";
@@ -15563,7 +15925,7 @@ function stableJson(value) {
15563
15925
  });
15564
15926
  }
15565
15927
  function hashId(value, chars = 16) {
15566
- return createHash14("sha256").update(stableJson(value)).digest("hex").slice(0, chars);
15928
+ return createHash15("sha256").update(stableJson(value)).digest("hex").slice(0, chars);
15567
15929
  }
15568
15930
  function isoTime2(value) {
15569
15931
  if (typeof value === "string") {
@@ -16502,7 +16864,7 @@ async function writeInspectionReportFile(report, outPath) {
16502
16864
  }
16503
16865
 
16504
16866
  // src/live.ts
16505
- import { createHash as createHash15 } from "crypto";
16867
+ import { createHash as createHash16 } from "crypto";
16506
16868
  var VERIFY_RE = /\b(test|tests|vitest|jest|pytest|go test|cargo test|tsc|typecheck|lint|biome|eslint|build|check:invariants|preflight)\b/i;
16507
16869
  var CHANGE_RE = /\b(apply_patch|edit|write|create|delete|rename|replace|update|git apply|sed -i|perl -pi|tee\s|cat\s+>)/i;
16508
16870
  var CLAIM_DONE_RE = /\b(done|fixed|complete|completed|implemented|merged|verified|all green|tests pass|ready|works now)\b/i;
@@ -16522,7 +16884,7 @@ var sleep = (ms2, signal) => new Promise((resolve13) => {
16522
16884
  signal?.addEventListener("abort", onAbort, { once: true });
16523
16885
  });
16524
16886
  function hash(parts) {
16525
- return createHash15("sha256").update(parts.join("\0")).digest("hex").slice(0, 16);
16887
+ return createHash16("sha256").update(parts.join("\0")).digest("hex").slice(0, 16);
16526
16888
  }
16527
16889
  function asString(value) {
16528
16890
  if (typeof value === "string" && value.trim()) return value;
@@ -18748,7 +19110,7 @@ async function watchSessions(opts) {
18748
19110
  }
18749
19111
 
18750
19112
  // src/bundle-view.ts
18751
- import { createHash as createHash16 } from "crypto";
19113
+ import { createHash as createHash17 } from "crypto";
18752
19114
  import { mkdir as mkdir7, readdir as readdir20, readFile as readFile16, writeFile as writeFile11 } from "fs/promises";
18753
19115
  import { dirname as dirname11, join as join31, resolve as resolve12 } from "path";
18754
19116
  var EVIDENCE_ONLY_ALLOW_LIST = [
@@ -18941,8 +19303,8 @@ async function projectSessionBundle(opts) {
18941
19303
  const candidates = [];
18942
19304
  for (const path of await listSessionBundleFiles(sourceDir)) {
18943
19305
  if (path === "manifest.json") continue;
18944
- const bytes = await readFile16(join31(sourceDir, path));
18945
- const sha2562 = createHash16("sha256").update(bytes).digest("hex");
19306
+ const bytes2 = await readFile16(join31(sourceDir, path));
19307
+ const sha2562 = createHash17("sha256").update(bytes2).digest("hex");
18946
19308
  const recorded = sourceHashes.get(path);
18947
19309
  if (!recorded) {
18948
19310
  throw new Error(
@@ -18956,10 +19318,10 @@ async function projectSessionBundle(opts) {
18956
19318
  }
18957
19319
  const verdict = classifyEvidenceOnlyPath(path);
18958
19320
  if (!verdict.carried) {
18959
- excluded.push({ path, bytes: bytes.length, sha256: sha2562, rule: verdict.rule, reason: verdict.reason });
19321
+ excluded.push({ path, bytes: bytes2.length, sha256: sha2562, rule: verdict.rule, reason: verdict.reason });
18960
19322
  continue;
18961
19323
  }
18962
- candidates.push({ path, bytes, sha256: sha2562, carries: verdict.carries, owned: verdict.owned });
19324
+ candidates.push({ path, bytes: bytes2, sha256: sha2562, carries: verdict.carries, owned: verdict.owned });
18963
19325
  }
18964
19326
  const report = await findSessionTextLeaks({
18965
19327
  viewDir: sourceDir,
@@ -19018,7 +19380,7 @@ async function projectSessionBundle(opts) {
19018
19380
  knownLimits: [...source.knownLimits, ...EVIDENCE_ONLY_LIMITS],
19019
19381
  projection: {
19020
19382
  sourceDirectory: sourceDir,
19021
- sourceManifestSha256: createHash16("sha256").update(sourceManifestBytes).digest("hex"),
19383
+ sourceManifestSha256: createHash17("sha256").update(sourceManifestBytes).digest("hex"),
19022
19384
  leakCheck
19023
19385
  }
19024
19386
  };
@@ -19442,14 +19804,14 @@ async function verifySafe(target, options = {}) {
19442
19804
  const files = await listFiles(target, unreadable);
19443
19805
  for (const file of files) {
19444
19806
  const label2 = relative7(target, file) || basename17(file);
19445
- let bytes;
19807
+ let bytes2;
19446
19808
  try {
19447
- bytes = await readFile19(file);
19809
+ bytes2 = await readFile19(file);
19448
19810
  } catch (error) {
19449
19811
  unreadable.push(`${label2}: ${error instanceof Error ? error.message : String(error)}`);
19450
19812
  continue;
19451
19813
  }
19452
- const text2 = decodeUtf8(bytes);
19814
+ const text2 = decodeUtf8(bytes2);
19453
19815
  if (text2 === void 0) {
19454
19816
  unreadable.push(`${label2}: not UTF-8 text`);
19455
19817
  continue;
@@ -19498,10 +19860,10 @@ async function listFiles(target, unreadable) {
19498
19860
  await walk(target);
19499
19861
  return out;
19500
19862
  }
19501
- function decodeUtf8(bytes) {
19502
- if (bytes.includes(0)) return void 0;
19863
+ function decodeUtf8(bytes2) {
19864
+ if (bytes2.includes(0)) return void 0;
19503
19865
  try {
19504
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
19866
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
19505
19867
  } catch {
19506
19868
  return void 0;
19507
19869
  }
@@ -19572,6 +19934,7 @@ export {
19572
19934
  EXPORT_RULE,
19573
19935
  toOpenInferenceSpan,
19574
19936
  serializeSpans,
19937
+ iterSerializedSpans,
19575
19938
  writeOtlpFile,
19576
19939
  summarizeOtlpExecution,
19577
19940
  summarizeSpanExecution,
@@ -19633,6 +19996,7 @@ export {
19633
19996
  serializePolicyEvidence,
19634
19997
  writePolicyEvidenceFile,
19635
19998
  countSkillRunsJsonl,
19999
+ computeAdoption,
19636
20000
  analyzeAdoption,
19637
20001
  planTraceAgenticRoute,
19638
20002
  traceAgenticKinds,
@@ -19644,6 +20008,7 @@ export {
19644
20008
  shellCommands,
19645
20009
  commandTextFromInput,
19646
20010
  readPullRequests,
20011
+ SESSION_FACTS_MEASUREMENT_VERSION,
19647
20012
  SESSION_TOKEN_TOTAL_ATTR,
19648
20013
  SPAN_SYNTHESIZED_ATTR,
19649
20014
  FACT_TEXT_CAP,