@tangle-network/traces 0.10.3 → 0.11.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.
@@ -14,8 +14,8 @@ function parseSince(value) {
14
14
  const m = value.match(/^(\d+)\s*([mhd])$/i);
15
15
  if (m) {
16
16
  const unit = m[2].toLowerCase();
17
- const ms = unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5;
18
- return Date.now() - Number(m[1]) * ms;
17
+ const ms2 = unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5;
18
+ return Date.now() - Number(m[1]) * ms2;
19
19
  }
20
20
  const t = Date.parse(value);
21
21
  if (Number.isNaN(t)) throw new Error(`--since: expected 30m / 2h / 7d or an ISO date, got "${value}"`);
@@ -167,8 +167,8 @@ function serializeSpans(spans) {
167
167
  async function writeOtlpFile(spans, outPath) {
168
168
  const { mkdtemp: mkdtemp8, writeFile: writeFile9 } = await import("fs/promises");
169
169
  const { tmpdir: tmpdir7 } = await import("os");
170
- const { join: join25 } = await import("path");
171
- const path = outPath ?? join25(await mkdtemp8(join25(tmpdir7(), "traces-")), "spans.otlp.jsonl");
170
+ const { join: join28 } = await import("path");
171
+ const path = outPath ?? join28(await mkdtemp8(join28(tmpdir7(), "traces-")), "spans.otlp.jsonl");
172
172
  await writeFile9(path, serializeSpans(spans), "utf8");
173
173
  return path;
174
174
  }
@@ -2795,13 +2795,12 @@ var ClaudeAdapter = class {
2795
2795
  agents.push(agent);
2796
2796
  }
2797
2797
  const agentsById = /* @__PURE__ */ new Map();
2798
+ const ambiguousAgentIds = /* @__PURE__ */ new Set();
2798
2799
  const childrenByParent = /* @__PURE__ */ new Map();
2799
2800
  for (const agent of agents) {
2800
- if (agentsById.has(agent.agentId)) {
2801
- throw new Error(`Duplicate Claude subagent id: ${agent.agentId}`);
2802
- }
2803
- agentsById.set(agent.agentId, agent);
2804
- if (agent.meta.parentAgentId) {
2801
+ if (agentsById.has(agent.agentId)) ambiguousAgentIds.add(agent.agentId);
2802
+ else agentsById.set(agent.agentId, agent);
2803
+ if (agent.meta.parentAgentId && !ambiguousAgentIds.has(agent.meta.parentAgentId)) {
2805
2804
  const siblings = childrenByParent.get(agent.meta.parentAgentId) ?? [];
2806
2805
  siblings.push(agent);
2807
2806
  childrenByParent.set(agent.meta.parentAgentId, siblings);
@@ -4873,8 +4872,8 @@ import { readdir as readdir10, stat as stat9 } from "fs/promises";
4873
4872
  import { homedir as homedir9 } from "os";
4874
4873
  import { join as join12 } from "path";
4875
4874
  var SERVICE8 = "opencode";
4876
- function isoOf(ms) {
4877
- return new Date(ms ?? 0).toISOString();
4875
+ function isoOf(ms2) {
4876
+ return new Date(ms2 ?? 0).toISOString();
4878
4877
  }
4879
4878
  function textOf7(parts) {
4880
4879
  return capText(
@@ -5729,7 +5728,7 @@ function extractAbsolutePaths(spans) {
5729
5728
  async function resolveRepoAttrs(cwd) {
5730
5729
  if (!cwd) return {};
5731
5730
  const attrs = { [ATTR.CWD]: cwd };
5732
- const basename14 = (() => {
5731
+ const basename15 = (() => {
5733
5732
  const trimmed = cwd.replace(/\/+$/g, "");
5734
5733
  const idx = trimmed.lastIndexOf("/");
5735
5734
  const name = idx === -1 ? trimmed : trimmed.slice(idx + 1);
@@ -5751,7 +5750,7 @@ async function resolveRepoAttrs(cwd) {
5751
5750
  if (commit) attrs[ATTR.GIT_COMMIT] = commit;
5752
5751
  } catch {
5753
5752
  }
5754
- attrs[ATTR.SUBJECT_KEY] = basename14;
5753
+ attrs[ATTR.SUBJECT_KEY] = basename15;
5755
5754
  return attrs;
5756
5755
  }
5757
5756
  async function repoCandidateForPath(path) {
@@ -6546,10 +6545,10 @@ async function readLinuxProcProcessTable() {
6546
6545
  const rows = await Promise.all(
6547
6546
  entries.filter((entry) => entry.isDirectory() && /^\d+$/.test(entry.name)).map(async (entry) => {
6548
6547
  try {
6549
- const stat14 = await readFile5(`/proc/${entry.name}/stat`, "utf8");
6550
- const commandEnd = stat14.lastIndexOf(")");
6548
+ const stat16 = await readFile5(`/proc/${entry.name}/stat`, "utf8");
6549
+ const commandEnd = stat16.lastIndexOf(")");
6551
6550
  if (commandEnd < 0) return void 0;
6552
- const fields = stat14.slice(commandEnd + 1).trim().split(/\s+/);
6551
+ const fields = stat16.slice(commandEnd + 1).trim().split(/\s+/);
6553
6552
  const pid = Number(entry.name);
6554
6553
  const parentPid = Number(fields[1]);
6555
6554
  if (!Number.isSafeInteger(pid) || pid < 1 || !Number.isSafeInteger(parentPid) || parentPid < 0) {
@@ -7742,12 +7741,12 @@ function isoTime2(value) {
7742
7741
  if (typeof value === "string") {
7743
7742
  const trimmed = value.trim();
7744
7743
  const normalized = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(trimmed) ? `${trimmed.replace(" ", "T")}Z` : trimmed;
7745
- const ms = Date.parse(normalized);
7746
- return Number.isFinite(ms) ? new Date(ms).toISOString() : void 0;
7744
+ const ms2 = Date.parse(normalized);
7745
+ return Number.isFinite(ms2) ? new Date(ms2).toISOString() : void 0;
7747
7746
  }
7748
7747
  if (typeof value === "number" && Number.isFinite(value)) {
7749
- const ms = value < 1e10 ? value * 1e3 : value;
7750
- return new Date(ms).toISOString();
7748
+ const ms2 = value < 1e10 ? value * 1e3 : value;
7749
+ return new Date(ms2).toISOString();
7751
7750
  }
7752
7751
  return void 0;
7753
7752
  }
@@ -8446,7 +8445,7 @@ function addSessionFindings(index, findings) {
8446
8445
  refs: errorSessions.slice(0, 5).map((row) => row.session.path)
8447
8446
  });
8448
8447
  }
8449
- const largeSessions = sessions.map((row) => ({ row, tokens: row.metrics.inputTokens + row.metrics.outputTokens })).filter(({ tokens: tokens2 }) => tokens2 >= 5e5).sort((a, b) => b.tokens - a.tokens);
8448
+ const largeSessions = sessions.map((row) => ({ row, tokens: row.metrics.inputTokens + row.metrics.outputTokens })).filter(({ tokens: tokens3 }) => tokens3 >= 5e5).sort((a, b) => b.tokens - a.tokens);
8450
8449
  if (largeSessions.length > 0) {
8451
8450
  const largest = largeSessions[0]?.tokens ?? 0;
8452
8451
  findings.push({
@@ -8455,7 +8454,7 @@ function addSessionFindings(index, findings) {
8455
8454
  area: "session",
8456
8455
  title: `${largeSessions.length} session(s) reported at least 500k summed tokens`,
8457
8456
  impact: largest,
8458
- evidence: largeSessions.slice(0, 5).map(({ row, tokens: tokens2 }) => `${sessionLabel(row)}: ${tokens2.toLocaleString()} reported summed tokens (${row.metrics.inputTokens.toLocaleString()} in, ${row.metrics.outputTokens.toLocaleString()} out)`),
8457
+ evidence: largeSessions.slice(0, 5).map(({ row, tokens: tokens3 }) => `${sessionLabel(row)}: ${tokens3.toLocaleString()} reported summed tokens (${row.metrics.inputTokens.toLocaleString()} in, ${row.metrics.outputTokens.toLocaleString()} out)`),
8459
8458
  next: "Check whether these sessions need shorter handoffs, smaller files, split tasks, or clearer token accounting before optimizing anything else.",
8460
8459
  refs: largeSessions.slice(0, 5).map(({ row }) => row.session.path)
8461
8460
  });
@@ -10134,7 +10133,7 @@ import { createHash as createHash9 } from "crypto";
10134
10133
  var VERIFY_RE = /\b(test|tests|vitest|jest|pytest|go test|cargo test|tsc|typecheck|lint|biome|eslint|build|check:invariants|preflight)\b/i;
10135
10134
  var CHANGE_RE = /\b(apply_patch|edit|write|create|delete|rename|replace|update|git apply|sed -i|perl -pi|tee\s|cat\s+>)/i;
10136
10135
  var CLAIM_DONE_RE = /\b(done|fixed|complete|completed|implemented|merged|verified|all green|tests pass|ready|works now)\b/i;
10137
- var sleep = (ms, signal) => new Promise((resolve7) => {
10136
+ var sleep = (ms2, signal) => new Promise((resolve7) => {
10138
10137
  if (signal?.aborted) {
10139
10138
  resolve7();
10140
10139
  return;
@@ -10146,7 +10145,7 @@ var sleep = (ms, signal) => new Promise((resolve7) => {
10146
10145
  const t = setTimeout(() => {
10147
10146
  signal?.removeEventListener("abort", onAbort);
10148
10147
  resolve7();
10149
- }, ms);
10148
+ }, ms2);
10150
10149
  signal?.addEventListener("abort", onAbort, { once: true });
10151
10150
  });
10152
10151
  function hash(parts) {
@@ -10554,6 +10553,1085 @@ async function streamSessions(opts) {
10554
10553
  }
10555
10554
  }
10556
10555
 
10556
+ // src/supervisor-run-context.ts
10557
+ import { readFile as readFile10, stat as stat13 } from "fs/promises";
10558
+ import { basename as basename13, join as join22 } from "path";
10559
+ import { materializeTreeView } from "@tangle-network/agent-runtime/kernel";
10560
+ import {
10561
+ NO_SOURCE_LIMITS
10562
+ } from "@tangle-network/agent-eval/supervisor-run";
10563
+ var SPAWN_JOURNAL_FILE = "spawn-journal.jsonl";
10564
+ var COORDINATION_LOG_FILE = "coordination-log.jsonl";
10565
+ var RESULT_FILE = "result.json";
10566
+ var BLOBS_DIR = "blobs";
10567
+ async function readMaybe(path) {
10568
+ return readFile10(path, "utf8").catch(() => null);
10569
+ }
10570
+ function readJsonlLines(text2) {
10571
+ if (text2 === null) {
10572
+ return { rows: [], invalidRows: 0, partialTail: false, present: false };
10573
+ }
10574
+ const lines = text2.split("\n");
10575
+ const partialTail = text2.length > 0 && !text2.endsWith("\n");
10576
+ if (partialTail) lines.pop();
10577
+ const rows = [];
10578
+ let invalidRows = 0;
10579
+ for (const line of lines) {
10580
+ const trimmed = line.trim();
10581
+ if (trimmed.length === 0) continue;
10582
+ try {
10583
+ const parsed = JSON.parse(trimmed);
10584
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
10585
+ rows.push(parsed);
10586
+ } else invalidRows += 1;
10587
+ } catch {
10588
+ invalidRows += 1;
10589
+ }
10590
+ }
10591
+ return { rows, invalidRows, partialTail, present: true };
10592
+ }
10593
+ function asRecord(v) {
10594
+ return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
10595
+ }
10596
+ function str(v) {
10597
+ return typeof v === "string" && v.length > 0 ? v : null;
10598
+ }
10599
+ function readRunContextJournal(text2) {
10600
+ const parsed = readJsonlLines(text2);
10601
+ let root = null;
10602
+ let begunAt = null;
10603
+ const events = [];
10604
+ let invalidRows = parsed.invalidRows;
10605
+ for (const record2 of parsed.rows) {
10606
+ const recordRoot = str(record2.root);
10607
+ if (root === null && recordRoot !== null) root = recordRoot;
10608
+ if (record2.kind === "begin") {
10609
+ if (begunAt === null) begunAt = str(record2.at);
10610
+ continue;
10611
+ }
10612
+ if (record2.kind !== "event") {
10613
+ invalidRows += 1;
10614
+ continue;
10615
+ }
10616
+ const event = asRecord(record2.event);
10617
+ if (str(event.kind) === null || str(event.id) === null) {
10618
+ invalidRows += 1;
10619
+ continue;
10620
+ }
10621
+ events.push(event);
10622
+ }
10623
+ const supervisorIds = /* @__PURE__ */ new Set();
10624
+ for (const event of events) {
10625
+ if (event.kind !== "spawned" && event.kind !== "waiting") continue;
10626
+ const parent = event.parent;
10627
+ if (typeof parent === "string" && parent.length > 0) supervisorIds.add(parent);
10628
+ }
10629
+ return {
10630
+ root,
10631
+ begunAt,
10632
+ events,
10633
+ supervisorIds,
10634
+ invalidRows,
10635
+ partialTail: parsed.partialTail,
10636
+ present: parsed.present
10637
+ };
10638
+ }
10639
+ function inferRole(id, parent, supervisorIds) {
10640
+ if (parent === null || parent === void 0) return "supervisor";
10641
+ return supervisorIds.has(id) ? "supervisor" : "worker";
10642
+ }
10643
+ var EMPTY_COORDINATION = {
10644
+ present: false,
10645
+ steers: [],
10646
+ deliveries: [],
10647
+ questions: [],
10648
+ invalidRows: 0,
10649
+ partialTail: false
10650
+ };
10651
+ function readCoordinationLog(text2) {
10652
+ const parsed = readJsonlLines(text2);
10653
+ if (!parsed.present) return EMPTY_COORDINATION;
10654
+ const steers = [];
10655
+ const deliveries = [];
10656
+ const questions = [];
10657
+ let invalidRows = parsed.invalidRows;
10658
+ for (const row of parsed.rows) {
10659
+ const record2 = asRecord(row.record);
10660
+ const event = asRecord(Object.keys(record2).length > 0 ? record2.event : row.event);
10661
+ const at = typeof record2.at === "number" ? record2.at : parseInstant(row.at);
10662
+ switch (event.type) {
10663
+ case "steer": {
10664
+ const down = asRecord(event.down);
10665
+ steers.push({
10666
+ messageId: str(down.messageId),
10667
+ toWorker: str(down.toWorker),
10668
+ instruction: typeof down.instruction === "string" ? down.instruction : "",
10669
+ deliveryMode: str(down.deliveryMode),
10670
+ at
10671
+ });
10672
+ break;
10673
+ }
10674
+ case "delivery": {
10675
+ const receipt = asRecord(event.receipt);
10676
+ deliveries.push({
10677
+ messageId: str(receipt.messageId),
10678
+ delivered: typeof receipt.delivered === "boolean" ? receipt.delivered : null
10679
+ });
10680
+ break;
10681
+ }
10682
+ case "question": {
10683
+ const q = asRecord(event.question);
10684
+ const urgency = str(q.urgency);
10685
+ questions.push({
10686
+ id: str(q.id),
10687
+ from: str(q.from),
10688
+ question: typeof q.question === "string" ? q.question : "",
10689
+ reason: str(q.reason),
10690
+ urgency,
10691
+ status: str(q.status),
10692
+ blocking: urgency === "blocks-run",
10693
+ at: typeof q.openedAt === "number" ? q.openedAt : at
10694
+ });
10695
+ break;
10696
+ }
10697
+ case "settled":
10698
+ break;
10699
+ default:
10700
+ if (str(event.type) === null) invalidRows += 1;
10701
+ }
10702
+ }
10703
+ return {
10704
+ present: true,
10705
+ steers,
10706
+ deliveries,
10707
+ questions,
10708
+ invalidRows,
10709
+ partialTail: parsed.partialTail
10710
+ };
10711
+ }
10712
+ function parseInstant(v) {
10713
+ if (typeof v === "number" && Number.isFinite(v)) return v;
10714
+ if (typeof v !== "string") return null;
10715
+ const t = Date.parse(v);
10716
+ return Number.isFinite(t) ? t : null;
10717
+ }
10718
+ async function readFileRunContext(runDir, opts = {}) {
10719
+ const journalText = await readMaybe(join22(runDir, SPAWN_JOURNAL_FILE));
10720
+ const journal = readRunContextJournal(journalText);
10721
+ const coordination = readCoordinationLog(await readMaybe(join22(runDir, COORDINATION_LOG_FILE)));
10722
+ const result = await readMaybe(join22(runDir, RESULT_FILE));
10723
+ return {
10724
+ runRef: runDir,
10725
+ instanceId: opts.instanceId !== void 0 ? opts.instanceId : journal.root,
10726
+ arm: opts.arm !== void 0 ? opts.arm : basename13(runDir),
10727
+ // The journal is the store, and it lives directly in the run directory —
10728
+ // this layout has no separate supervisor sub-directory.
10729
+ supRunDir: journal.present ? runDir : null,
10730
+ journal: journal.present ? flattenJournal(journal) : null,
10731
+ // Per-brain-call taps and progress streams are loops artifacts; this layout
10732
+ // writes neither, so truncation genuinely cannot be ruled out.
10733
+ brainLog: null,
10734
+ state: journal.present ? runState(journal, result) : null,
10735
+ progress: null,
10736
+ ...workerSources(journal, coordination),
10737
+ result,
10738
+ judge: null,
10739
+ judgeSource: null,
10740
+ patch: null,
10741
+ driverLog: null,
10742
+ harnessWorkerTokens: null,
10743
+ harnessMissingReason: "the file run context journals each child\u2019s own settled spend, so no external harness join is used",
10744
+ limits: sourceLimits(journal, coordination),
10745
+ rootTranscriptRef: journal.present ? join22(runDir, SPAWN_JOURNAL_FILE) : null,
10746
+ traceCommand: `traces watch ${runDir}`
10747
+ };
10748
+ }
10749
+ function fileRunContextSupervisorRunReader(runDir, opts = {}) {
10750
+ return { runRef: runDir, read: () => readFileRunContext(runDir, opts) };
10751
+ }
10752
+ async function isFileRunContextDir(runDir) {
10753
+ return stat13(join22(runDir, SPAWN_JOURNAL_FILE)).then((s) => s.isFile()).catch(() => false);
10754
+ }
10755
+ function flattenJournal(journal) {
10756
+ return journal.events.map((event) => {
10757
+ if (event.kind !== "spawned") return JSON.stringify(event);
10758
+ return JSON.stringify({
10759
+ ...event,
10760
+ role: inferRole(event.id, event.parent, journal.supervisorIds)
10761
+ });
10762
+ }).join("\n");
10763
+ }
10764
+ function runState(journal, resultText) {
10765
+ const result = parseJsonObject(resultText);
10766
+ const state = {};
10767
+ if (journal.begunAt !== null) state.startedAt = journal.begunAt;
10768
+ if (result !== null) {
10769
+ const kind = str(result.kind);
10770
+ const reason = str(result.reason);
10771
+ if (kind !== null) state.status = kind;
10772
+ if (reason !== null) state.verdict = reason;
10773
+ const spentTotal = asRecord(result.spentTotal);
10774
+ if (typeof spentTotal.usd === "number" && spentTotal.usdKnown !== false) {
10775
+ state.result = { spentUsd: spentTotal.usd };
10776
+ }
10777
+ }
10778
+ return JSON.stringify(state);
10779
+ }
10780
+ function parseJsonObject(text2) {
10781
+ if (text2 === null) return null;
10782
+ try {
10783
+ const parsed = JSON.parse(text2);
10784
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null;
10785
+ } catch {
10786
+ return null;
10787
+ }
10788
+ }
10789
+ function workerSources(journal, coordination) {
10790
+ if (!journal.present) {
10791
+ return { workers: null, workersMissingReason: `${SPAWN_JOURNAL_FILE} absent` };
10792
+ }
10793
+ const view = safeTreeView(journal.events);
10794
+ if (view === null) {
10795
+ return { workers: null, workersMissingReason: "spawn journal could not be folded into a tree" };
10796
+ }
10797
+ const deliveredById = /* @__PURE__ */ new Map();
10798
+ for (const receipt of coordination.deliveries) {
10799
+ if (receipt.messageId !== null) deliveredById.set(receipt.messageId, receipt.delivered);
10800
+ }
10801
+ const spendById = settledSpendById(journal.events);
10802
+ const workers = [];
10803
+ for (const node of view.nodes) {
10804
+ if (node.parent === void 0) continue;
10805
+ const steers = coordination.steers.filter((s) => s.toWorker === node.id);
10806
+ const questions = coordination.questions.filter((q) => q.from === node.id);
10807
+ const spend = spendById.get(node.id) ?? null;
10808
+ workers.push({
10809
+ workerId: node.id,
10810
+ label: node.label,
10811
+ events: coordination.present ? [
10812
+ ...steers.map(
10813
+ (s) => JSON.stringify({
10814
+ kind: "message",
10815
+ requestId: s.messageId,
10816
+ delivered: s.messageId === null ? null : deliveredById.get(s.messageId) ?? null
10817
+ })
10818
+ ),
10819
+ ...questions.map((q) => JSON.stringify({ kind: "message", direction: "up", id: q.id }))
10820
+ ].join("\n") : null,
10821
+ inbox: coordination.present ? steers.map((s) => JSON.stringify({ id: s.messageId, message: s.instruction })).join("\n") : null,
10822
+ // Content-addressed result blobs are not patches; this layout retains no
10823
+ // per-worker diff, so byte counts would be a fabricated zero.
10824
+ patchBytes: null,
10825
+ transcriptRef: null,
10826
+ patchPath: null,
10827
+ tokensIn: spend?.tokens.input ?? null,
10828
+ tokensOut: spend?.tokens.output ?? null
10829
+ });
10830
+ }
10831
+ return { workers, workersMissingReason: null };
10832
+ }
10833
+ function settledSpendById(events) {
10834
+ const out = /* @__PURE__ */ new Map();
10835
+ for (const event of events) {
10836
+ if (event.kind !== "settled") continue;
10837
+ out.set(event.id, event.spent);
10838
+ }
10839
+ return out;
10840
+ }
10841
+ function sourceLimits(journal, coordination) {
10842
+ const unpriced = unpricedNodes(journal.events);
10843
+ const verdicts = journal.events.filter(
10844
+ (event) => event.kind === "settled" && event.verdict !== void 0
10845
+ ).length;
10846
+ const settlements = journal.events.filter((event) => event.kind === "settled").length;
10847
+ return {
10848
+ ...NO_SOURCE_LIMITS,
10849
+ // Both are journaled per node: `metered` for a driver's own inference,
10850
+ // `settled.spent` for what a child consumed.
10851
+ managerTokens: null,
10852
+ workerTokens: null,
10853
+ spendUsd: unpriced.length === 0 ? null : `${unpriced.length} spend record(s) carry usdKnown:false (${unpriced.slice(0, 4).join(", ")}${unpriced.length > 4 ? ", \u2026" : ""}) \u2014 the run\u2019s dollar total is unknown, not $0`,
10854
+ workerVerdicts: settlements === 0 || verdicts > 0 ? null : "no settled event carried a verdict; this layout records a done/down status only",
10855
+ deliverables: `${BLOBS_DIR}/ holds content-addressed result artifacts, not patches`
10856
+ };
10857
+ }
10858
+ function unpricedNodes(events) {
10859
+ const ids = [];
10860
+ for (const event of events) {
10861
+ const spend = event.kind === "settled" ? event.spent : event.kind === "metered" ? event.spend : null;
10862
+ if (spend?.usdKnown === false) ids.push(event.id);
10863
+ }
10864
+ return [...new Set(ids)];
10865
+ }
10866
+ var ZERO_ROLL = {
10867
+ records: 0,
10868
+ iterations: 0,
10869
+ tokensIn: 0,
10870
+ tokensOut: 0,
10871
+ usd: 0,
10872
+ usdKnownRecords: 0,
10873
+ usdUnknownRecords: 0
10874
+ };
10875
+ function addSpend(roll, spend) {
10876
+ const known = spend.usdKnown !== false;
10877
+ return {
10878
+ records: roll.records + 1,
10879
+ iterations: roll.iterations + (spend.iterations ?? 0),
10880
+ tokensIn: roll.tokensIn + (spend.tokens?.input ?? 0),
10881
+ tokensOut: roll.tokensOut + (spend.tokens?.output ?? 0),
10882
+ usd: roll.usd + (known ? spend.usd ?? 0 : 0),
10883
+ usdKnownRecords: roll.usdKnownRecords + (known ? 1 : 0),
10884
+ usdUnknownRecords: roll.usdUnknownRecords + (known ? 0 : 1)
10885
+ };
10886
+ }
10887
+ function mergeRolls(a, b) {
10888
+ return {
10889
+ records: a.records + b.records,
10890
+ iterations: a.iterations + b.iterations,
10891
+ tokensIn: a.tokensIn + b.tokensIn,
10892
+ tokensOut: a.tokensOut + b.tokensOut,
10893
+ usd: a.usd + b.usd,
10894
+ usdKnownRecords: a.usdKnownRecords + b.usdKnownRecords,
10895
+ usdUnknownRecords: a.usdUnknownRecords + b.usdUnknownRecords
10896
+ };
10897
+ }
10898
+ async function readRunContextSnapshot(runDir) {
10899
+ const journal = readRunContextJournal(await readMaybe(join22(runDir, SPAWN_JOURNAL_FILE)));
10900
+ const coordination = readCoordinationLog(await readMaybe(join22(runDir, COORDINATION_LOG_FILE)));
10901
+ const resultText = await readMaybe(join22(runDir, RESULT_FILE));
10902
+ const result = parseResult(resultText);
10903
+ const view = safeTreeView(journal.events);
10904
+ const nodes = view === null ? [] : orderNodes(view, journal);
10905
+ return {
10906
+ runDir,
10907
+ runId: journal.root,
10908
+ present: journal.present,
10909
+ nodes,
10910
+ maxDepth: nodes.reduce((max, n) => Math.max(max, n.depth), 0),
10911
+ begunAt: parseInstant(journal.begunAt),
10912
+ lastEventAt: journal.events.reduce((latest, event) => {
10913
+ const at = parseInstant(event.at);
10914
+ return at === null ? latest : latest === null ? at : Math.max(latest, at);
10915
+ }, null),
10916
+ questions: coordination.questions,
10917
+ steers: coordination.steers,
10918
+ result,
10919
+ terminal: resultText !== null,
10920
+ invalidJournalRows: journal.invalidRows,
10921
+ invalidCoordinationRows: coordination.invalidRows,
10922
+ partialTail: journal.partialTail || coordination.partialTail,
10923
+ treeError: view === null && journal.present ? "spawn journal could not be folded into a tree (a settle or cancel names a node that was never spawned)" : null
10924
+ };
10925
+ }
10926
+ function safeTreeView(events) {
10927
+ if (events.length === 0) return null;
10928
+ try {
10929
+ return materializeTreeView([...events]);
10930
+ } catch {
10931
+ return null;
10932
+ }
10933
+ }
10934
+ function orderNodes(view, journal) {
10935
+ const driver = /* @__PURE__ */ new Map();
10936
+ const settled = /* @__PURE__ */ new Map();
10937
+ const childRoll = /* @__PURE__ */ new Map();
10938
+ const spawnedAt = /* @__PURE__ */ new Map();
10939
+ const settledAt = /* @__PURE__ */ new Map();
10940
+ const cancelReason = /* @__PURE__ */ new Map();
10941
+ const parentOf = new Map(view.nodes.map((n) => [n.id, n.parent]));
10942
+ for (const event of journal.events) {
10943
+ const at = parseInstant(event.at);
10944
+ if (event.kind === "spawned" || event.kind === "waiting") {
10945
+ spawnedAt.set(event.id, at);
10946
+ } else if (event.kind === "metered") {
10947
+ driver.set(event.id, addSpend(driver.get(event.id) ?? ZERO_ROLL, event.spend));
10948
+ } else if (event.kind === "settled") {
10949
+ settled.set(event.id, addSpend(settled.get(event.id) ?? ZERO_ROLL, event.spent));
10950
+ settledAt.set(event.id, at);
10951
+ const parent = parentOf.get(event.id);
10952
+ if (parent !== void 0) {
10953
+ childRoll.set(parent, addSpend(childRoll.get(parent) ?? ZERO_ROLL, event.spent));
10954
+ }
10955
+ } else if (event.kind === "cancelled") {
10956
+ settledAt.set(event.id, at);
10957
+ cancelReason.set(event.id, event.reason);
10958
+ } else if (event.kind === "woken") {
10959
+ settledAt.set(event.id, at);
10960
+ }
10961
+ }
10962
+ const byParent = /* @__PURE__ */ new Map();
10963
+ for (const node of view.nodes) {
10964
+ const key = node.parent ?? null;
10965
+ const bucket = byParent.get(key);
10966
+ if (bucket) bucket.push(node);
10967
+ else byParent.set(key, [node]);
10968
+ }
10969
+ const out = [];
10970
+ const seen = /* @__PURE__ */ new Set();
10971
+ const walk = (id, depth) => {
10972
+ if (seen.has(id)) return;
10973
+ seen.add(id);
10974
+ const node = view.nodes.find((n) => n.id === id);
10975
+ if (node === void 0) return;
10976
+ const spawned = spawnedAt.get(id) ?? null;
10977
+ const closed = settledAt.get(id) ?? null;
10978
+ out.push({
10979
+ id: node.id,
10980
+ parent: node.parent ?? null,
10981
+ label: node.label,
10982
+ depth,
10983
+ role: inferRole(node.id, node.parent, journal.supervisorIds),
10984
+ status: node.status,
10985
+ runtime: node.runtime ?? null,
10986
+ budget: node.budget,
10987
+ driver: driver.get(id) ?? ZERO_ROLL,
10988
+ children: childRoll.get(id) ?? ZERO_ROLL,
10989
+ settled: settled.get(id) ?? ZERO_ROLL,
10990
+ spawnedAt: spawned,
10991
+ settledAt: closed,
10992
+ wallMs: spawned !== null && closed !== null ? closed - spawned : null,
10993
+ outRef: node.outRef ?? null,
10994
+ cancelReason: cancelReason.get(id) ?? null
10995
+ });
10996
+ for (const child of byParent.get(id) ?? []) walk(child.id, depth + 1);
10997
+ };
10998
+ walk(view.root, 0);
10999
+ for (const node of view.nodes) if (!seen.has(node.id)) walk(node.id, 0);
11000
+ return out;
11001
+ }
11002
+ function parseResult(text2) {
11003
+ const result = parseJsonObject(text2);
11004
+ if (result === null) return null;
11005
+ const error = asRecord(result.error);
11006
+ return {
11007
+ kind: str(result.kind),
11008
+ reason: str(result.reason),
11009
+ errorName: str(error.name),
11010
+ errorMessage: str(error.message)
11011
+ };
11012
+ }
11013
+
11014
+ // src/run-view-format.ts
11015
+ var RULE = "\u2500".repeat(76);
11016
+ function int(n) {
11017
+ return n.toLocaleString("en-US");
11018
+ }
11019
+ function ms(value) {
11020
+ if (value === null) return "\u2014";
11021
+ if (value < 1e3) return `${value}ms`;
11022
+ if (value < 6e4) return `${(value / 1e3).toFixed(1)}s`;
11023
+ const minutes = Math.floor(value / 6e4);
11024
+ return `${minutes}m${String(Math.round(value % 6e4 / 1e3)).padStart(2, "0")}s`;
11025
+ }
11026
+ function usd(roll) {
11027
+ if (roll.usdKnownRecords === 0) {
11028
+ return roll.usdUnknownRecords === 0 ? "no spend recorded" : `cost unknown (${roll.usdUnknownRecords} unpriced)`;
11029
+ }
11030
+ const priced = zeroPricedCost(roll) ? `$${roll.usd.toFixed(4)} (zero across ${roll.usdKnownRecords} priced)` : `$${roll.usd.toFixed(4)}`;
11031
+ return roll.usdUnknownRecords === 0 ? priced : `${priced} + ${roll.usdUnknownRecords} unpriced`;
11032
+ }
11033
+ function zeroPricedCost(roll) {
11034
+ return roll.usdKnownRecords > 0 && roll.usd === 0 && roll.tokensIn + roll.tokensOut > 0;
11035
+ }
11036
+ function tokens2(roll) {
11037
+ return `in ${int(roll.tokensIn)} \xB7 out ${int(roll.tokensOut)}`;
11038
+ }
11039
+ var STATUS_MARK = {
11040
+ pending: "\xB7",
11041
+ acquiring: "\u25D0",
11042
+ running: "\u25B6",
11043
+ waiting: "\u23F8",
11044
+ done: "\u2713",
11045
+ failed: "\u2717",
11046
+ cancelled: "\u2298"
11047
+ };
11048
+ function connectors(depth, lastAtDepth) {
11049
+ if (depth === 0) return { head: "\u25CF ", detail: " " };
11050
+ let stem = "";
11051
+ for (let level = 1; level < depth; level++) stem += lastAtDepth[level] ? " " : "\u2502 ";
11052
+ const isLast = lastAtDepth[depth] ?? true;
11053
+ return { head: `${stem}${isLast ? "\u2514\u2500 " : "\u251C\u2500 "}`, detail: `${stem}${isLast ? " " : "\u2502 "} ` };
11054
+ }
11055
+ function forEachTreeNode(nodes, parentKey, selfKey, visit) {
11056
+ const lastChildOf = /* @__PURE__ */ new Map();
11057
+ for (const node of nodes) lastChildOf.set(parentKey(node), selfKey(node));
11058
+ const lastAtDepth = [];
11059
+ for (const node of nodes) {
11060
+ lastAtDepth[node.depth] = lastChildOf.get(parentKey(node)) === selfKey(node);
11061
+ lastAtDepth.length = node.depth + 1;
11062
+ visit(node, lastAtDepth);
11063
+ }
11064
+ }
11065
+ function wrap(text2, indent) {
11066
+ const width = Math.max(40, (process.stdout.columns ?? 100) - indent - 2);
11067
+ const pad = " ".repeat(indent);
11068
+ const out = [];
11069
+ for (const paragraph of text2.split("\n")) {
11070
+ let line = "";
11071
+ for (const word of paragraph.split(/\s+/).filter(Boolean)) {
11072
+ if (line.length > 0 && line.length + 1 + word.length > width) {
11073
+ out.push(pad + line);
11074
+ line = word;
11075
+ } else line = line.length === 0 ? word : `${line} ${word}`;
11076
+ }
11077
+ out.push(pad + line);
11078
+ }
11079
+ return out;
11080
+ }
11081
+
11082
+ // src/run-span-tree.ts
11083
+ import { readdir as readdir15 } from "fs/promises";
11084
+ import { join as join23 } from "path";
11085
+ import {
11086
+ firstNumberAttr as firstNumberAttr2,
11087
+ LLM_COST_ATTR_KEYS as LLM_COST_ATTR_KEYS2,
11088
+ LLM_INPUT_TOKEN_ATTR_KEYS as LLM_INPUT_TOKEN_ATTR_KEYS2,
11089
+ LLM_OUTPUT_TOKEN_ATTR_KEYS as LLM_OUTPUT_TOKEN_ATTR_KEYS2,
11090
+ SPAN_KIND_ATTR_KEYS
11091
+ } from "@tangle-network/agent-eval/trace-attributes";
11092
+ var AGENT_NAME_ATTR_KEYS = ["agent.name", "inference.agent_name", "gen_ai.agent.name"];
11093
+ var SERVICE_NAME_ATTR_KEYS = ["service.name", "tangle.runtime"];
11094
+ var AGENT_OPERATIONS = /* @__PURE__ */ new Set(["invoke_agent", "invoke_workflow"]);
11095
+ var OPERATION_ATTR_KEY = "gen_ai.operation.name";
11096
+ function firstStringAttr(attributes, keys) {
11097
+ for (const key of keys) {
11098
+ const value = attributes[key];
11099
+ if (typeof value === "string" && value.length > 0) return value;
11100
+ }
11101
+ return null;
11102
+ }
11103
+ var EMPTY_SPAN_RUN_SNAPSHOT = {
11104
+ present: false,
11105
+ nodes: [],
11106
+ maxDepth: 0,
11107
+ traceIds: [],
11108
+ spanCount: 0,
11109
+ startMs: null,
11110
+ endMs: null,
11111
+ llmSpansWithoutTokens: 0,
11112
+ llmSpansWithoutCost: 0,
11113
+ orphanSpans: 0,
11114
+ readError: null
11115
+ };
11116
+ function spanKind3(span2) {
11117
+ return firstStringAttr(span2.attributes, SPAN_KIND_ATTR_KEYS);
11118
+ }
11119
+ function isNodeBoundary(span2, enclosingNodeId, enclosingAgent) {
11120
+ if (span2.parent_span_id === null || enclosingNodeId === null) return true;
11121
+ if (spanKind3(span2) === "AGENT") return true;
11122
+ if (AGENT_OPERATIONS.has(String(span2.attributes[OPERATION_ATTR_KEY] ?? ""))) return true;
11123
+ const agent = firstStringAttr(span2.attributes, AGENT_NAME_ATTR_KEYS);
11124
+ return agent !== null && enclosingAgent !== null && agent !== enclosingAgent;
11125
+ }
11126
+ function spanSpend(span2) {
11127
+ const cost = firstNumberAttr2(span2.attributes, LLM_COST_ATTR_KEYS2);
11128
+ return {
11129
+ iterations: 0,
11130
+ tokens: {
11131
+ input: firstNumberAttr2(span2.attributes, LLM_INPUT_TOKEN_ATTR_KEYS2) ?? 0,
11132
+ output: firstNumberAttr2(span2.attributes, LLM_OUTPUT_TOKEN_ATTR_KEYS2) ?? 0
11133
+ },
11134
+ usd: cost ?? 0,
11135
+ ...cost === null ? { usdKnown: false } : {},
11136
+ ms: 0
11137
+ };
11138
+ }
11139
+ function epoch(value) {
11140
+ const parsed = Date.parse(value);
11141
+ return Number.isFinite(parsed) ? parsed : 0;
11142
+ }
11143
+ function buildSpanRunTree(spans, source) {
11144
+ if (spans.length === 0) return { ...EMPTY_SPAN_RUN_SNAPSHOT, source };
11145
+ const byId = /* @__PURE__ */ new Map();
11146
+ for (const span2 of spans) byId.set(spanKey(span2), span2);
11147
+ const childrenOf = /* @__PURE__ */ new Map();
11148
+ let orphanSpans = 0;
11149
+ for (const span2 of spans) {
11150
+ const parentKey = span2.parent_span_id === null ? null : byId.has(`${span2.trace_id}\0${span2.parent_span_id}`) ? `${span2.trace_id}\0${span2.parent_span_id}` : null;
11151
+ if (span2.parent_span_id !== null && parentKey === null) orphanSpans += 1;
11152
+ const bucket = childrenOf.get(parentKey);
11153
+ if (bucket) bucket.push(span2);
11154
+ else childrenOf.set(parentKey, [span2]);
11155
+ }
11156
+ for (const bucket of childrenOf.values()) {
11157
+ bucket.sort((a, b) => epoch(a.start_time) - epoch(b.start_time) || a.span_id.localeCompare(b.span_id));
11158
+ }
11159
+ const building = /* @__PURE__ */ new Map();
11160
+ const order = [];
11161
+ let llmSpansWithoutTokens = 0;
11162
+ let llmSpansWithoutCost = 0;
11163
+ const walk = (span2, enclosingNodeId, enclosingAgent, depth) => {
11164
+ const key = spanKey(span2);
11165
+ const agent = firstStringAttr(span2.attributes, AGENT_NAME_ATTR_KEYS) ?? enclosingAgent;
11166
+ let nodeId = enclosingNodeId;
11167
+ let nodeAgent = enclosingAgent;
11168
+ let childDepth = depth;
11169
+ if (isNodeBoundary(span2, enclosingNodeId, enclosingAgent)) {
11170
+ const node = {
11171
+ span: span2,
11172
+ parentNodeId: enclosingNodeId,
11173
+ depth,
11174
+ agent,
11175
+ driver: ZERO_ROLL,
11176
+ toolCalls: 0,
11177
+ startMs: epoch(span2.start_time),
11178
+ endMs: epoch(span2.end_time),
11179
+ errors: [],
11180
+ childNodeIds: []
11181
+ };
11182
+ building.set(key, node);
11183
+ order.push(key);
11184
+ if (enclosingNodeId !== null) building.get(enclosingNodeId)?.childNodeIds.push(key);
11185
+ nodeId = key;
11186
+ nodeAgent = agent;
11187
+ childDepth = depth + 1;
11188
+ }
11189
+ const host = nodeId === null ? void 0 : building.get(nodeId);
11190
+ if (host !== void 0) {
11191
+ const kind = spanKind3(span2);
11192
+ if (kind === "LLM") {
11193
+ host.driver = addSpend(host.driver, spanSpend(span2));
11194
+ if (firstNumberAttr2(span2.attributes, LLM_INPUT_TOKEN_ATTR_KEYS2) === null && firstNumberAttr2(span2.attributes, LLM_OUTPUT_TOKEN_ATTR_KEYS2) === null) {
11195
+ llmSpansWithoutTokens += 1;
11196
+ }
11197
+ if (firstNumberAttr2(span2.attributes, LLM_COST_ATTR_KEYS2) === null) llmSpansWithoutCost += 1;
11198
+ } else if (kind === "TOOL") host.toolCalls += 1;
11199
+ host.startMs = Math.min(host.startMs, epoch(span2.start_time));
11200
+ host.endMs = Math.max(host.endMs, epoch(span2.end_time));
11201
+ if (span2.status.code === "ERROR") {
11202
+ host.errors.push(`${span2.name}: ${span2.status.message ?? "ERROR"}`);
11203
+ }
11204
+ }
11205
+ for (const child of childrenOf.get(key) ?? []) walk(child, nodeId, nodeAgent, childDepth);
11206
+ };
11207
+ for (const root of childrenOf.get(null) ?? []) walk(root, null, null, 0);
11208
+ const subtotal = /* @__PURE__ */ new Map();
11209
+ const subtotalOf = (key) => {
11210
+ const cached = subtotal.get(key);
11211
+ if (cached !== void 0) return cached;
11212
+ const node = building.get(key);
11213
+ if (node === void 0) return ZERO_ROLL;
11214
+ subtotal.set(key, ZERO_ROLL);
11215
+ let total = node.driver;
11216
+ for (const child of node.childNodeIds) total = mergeRolls(total, subtotalOf(child));
11217
+ subtotal.set(key, total);
11218
+ return total;
11219
+ };
11220
+ const nodes = order.map((key) => {
11221
+ const node = building.get(key);
11222
+ let children = ZERO_ROLL;
11223
+ for (const child of node.childNodeIds) children = mergeRolls(children, subtotalOf(child));
11224
+ return {
11225
+ traceId: node.span.trace_id,
11226
+ spanId: node.span.span_id,
11227
+ parentNodeId: node.parentNodeId === null ? null : building.get(node.parentNodeId).span.span_id,
11228
+ label: node.agent ?? node.span.name,
11229
+ depth: node.depth,
11230
+ role: node.childNodeIds.length > 0 ? "driver" : "leaf",
11231
+ status: node.errors.length > 0 || node.span.status.code === "ERROR" ? "failed" : node.span.status.code === "UNSET" ? "running" : "done",
11232
+ runtime: firstStringAttr(node.span.attributes, SERVICE_NAME_ATTR_KEYS),
11233
+ driver: node.driver,
11234
+ children,
11235
+ toolCalls: node.toolCalls,
11236
+ startMs: node.startMs,
11237
+ endMs: node.endMs,
11238
+ wallMs: Math.max(0, node.endMs - node.startMs),
11239
+ errors: node.errors
11240
+ };
11241
+ });
11242
+ return {
11243
+ source,
11244
+ present: true,
11245
+ nodes,
11246
+ maxDepth: nodes.reduce((max, n) => Math.max(max, n.depth), 0),
11247
+ traceIds: [...new Set(spans.map((s) => s.trace_id))],
11248
+ spanCount: spans.length,
11249
+ startMs: nodes.reduce((min, n) => min === null ? n.startMs : Math.min(min, n.startMs), null),
11250
+ endMs: nodes.reduce((max, n) => max === null ? n.endMs : Math.max(max, n.endMs), null),
11251
+ llmSpansWithoutTokens,
11252
+ llmSpansWithoutCost,
11253
+ orphanSpans,
11254
+ readError: null
11255
+ };
11256
+ }
11257
+ function spanKey(span2) {
11258
+ return `${span2.trace_id}\0${span2.span_id}`;
11259
+ }
11260
+ async function readSpanRunSnapshot(path) {
11261
+ try {
11262
+ const exported = await exportTraceEvidenceFile(path);
11263
+ return buildSpanRunTree(exported.spans, path);
11264
+ } catch (error) {
11265
+ return {
11266
+ ...EMPTY_SPAN_RUN_SNAPSHOT,
11267
+ source: path,
11268
+ readError: error instanceof Error ? error.message : String(error)
11269
+ };
11270
+ }
11271
+ }
11272
+ function spanRunTotals(snapshot) {
11273
+ let driver = ZERO_ROLL;
11274
+ let leaves = ZERO_ROLL;
11275
+ for (const node of snapshot.nodes) {
11276
+ if (node.role === "driver") driver = mergeRolls(driver, node.driver);
11277
+ else leaves = mergeRolls(leaves, node.driver);
11278
+ }
11279
+ return { driver, leaves };
11280
+ }
11281
+ function renderSpanRunSnapshot(snapshot) {
11282
+ const lines = [];
11283
+ lines.push(`spans ${snapshot.source}`);
11284
+ if (snapshot.readError !== null) {
11285
+ lines.push(` unreadable: ${snapshot.readError}`);
11286
+ return lines.join("\n");
11287
+ }
11288
+ if (!snapshot.present || snapshot.nodes.length === 0) {
11289
+ lines.push(" no spans yet \u2014 the emitter has written nothing this view can place");
11290
+ return lines.join("\n");
11291
+ }
11292
+ const totals = spanRunTotals(snapshot);
11293
+ lines.push(
11294
+ ` ${snapshot.nodes.length} node(s) \xB7 depth ${snapshot.maxDepth} \xB7 ${int(snapshot.spanCount)} span(s) \xB7 ${snapshot.traceIds.length} trace(s) \xB7 elapsed ${ms(snapshot.endMs === null || snapshot.startMs === null ? null : snapshot.endMs - snapshot.startMs)}`
11295
+ );
11296
+ const delegating = snapshot.nodes.some((node) => node.role === "driver");
11297
+ lines.push(` driver inference ${tokens2(totals.driver)} \xB7 ${usd(totals.driver)}`);
11298
+ lines.push(` leaf inference ${tokens2(totals.leaves)} \xB7 ${usd(totals.leaves)}`);
11299
+ if (!delegating) {
11300
+ lines.push(" (no delegation in these spans: every turn belongs to one agent, so the driver half is empty)");
11301
+ }
11302
+ lines.push("");
11303
+ forEachTreeNode(
11304
+ snapshot.nodes,
11305
+ (n) => n.parentNodeId,
11306
+ (n) => n.spanId,
11307
+ (node, lastAtDepth) => {
11308
+ const { head: prefix, detail } = connectors(node.depth, lastAtDepth);
11309
+ const mark = node.status === "failed" ? "\u2717" : node.status === "running" ? "\u25B6" : "\u2713";
11310
+ lines.push(
11311
+ [
11312
+ `${prefix}${mark} ${node.label}`,
11313
+ `[${node.status}]`,
11314
+ node.role,
11315
+ node.runtime ?? "no-runtime",
11316
+ "budget not in spans",
11317
+ `wall ${ms(node.wallMs)}`
11318
+ ].join(" ")
11319
+ );
11320
+ lines.push(
11321
+ `${detail}driver ${node.driver.records} turn(s) \xB7 ${tokens2(node.driver)} \xB7 ${usd(node.driver)} \xB7 ${node.toolCalls} tool call(s)`
11322
+ );
11323
+ if (node.role === "driver") {
11324
+ lines.push(
11325
+ `${detail}children ${node.children.records} turn(s) \xB7 ${tokens2(node.children)} \xB7 ${usd(node.children)}`
11326
+ );
11327
+ }
11328
+ for (const error of node.errors.slice(0, 3)) lines.push(`${detail}error ${error}`);
11329
+ }
11330
+ );
11331
+ const problems = [];
11332
+ if (snapshot.llmSpansWithoutCost > 0) {
11333
+ problems.push(
11334
+ `${snapshot.llmSpansWithoutCost} of the LLM span(s) carry no cost attribute \u2014 that spend is UNKNOWN, not $0 (this emitter writes tokens without a price)`
11335
+ );
11336
+ }
11337
+ if (snapshot.llmSpansWithoutTokens > 0) {
11338
+ problems.push(`${snapshot.llmSpansWithoutTokens} LLM span(s) carry no token count`);
11339
+ }
11340
+ if (snapshot.orphanSpans > 0) {
11341
+ problems.push(
11342
+ `${snapshot.orphanSpans} span(s) name a parent_span_id absent from this file \u2014 re-rooted, not dropped`
11343
+ );
11344
+ }
11345
+ problems.push(
11346
+ "spans carry no authored budget in either the OpenInference or the GenAI vocabulary; point this at a run directory with a spawn journal to see ceilings and settlement"
11347
+ );
11348
+ lines.push("");
11349
+ for (const problem of problems) lines.push(` ! ${problem}`);
11350
+ return lines.join("\n");
11351
+ }
11352
+ var SPAN_FILE_PATTERN = /\.(?:otlp|spans|traces|openinference)\.(?:jsonl|ndjson)$|^traces?\.jsonl$|^spans\.jsonl$/i;
11353
+ async function findSpanSourceFiles(dir) {
11354
+ const found = [];
11355
+ const entries = await readdir15(dir, { withFileTypes: true }).catch(() => []);
11356
+ for (const entry of entries) {
11357
+ const child = join23(dir, entry.name);
11358
+ if (entry.isFile()) {
11359
+ if (SPAN_FILE_PATTERN.test(entry.name)) found.push(child);
11360
+ continue;
11361
+ }
11362
+ if (!entry.isDirectory()) continue;
11363
+ const nested = await readdir15(child, { withFileTypes: true }).catch(() => []);
11364
+ for (const inner of nested) {
11365
+ if (inner.isFile() && SPAN_FILE_PATTERN.test(inner.name)) found.push(join23(child, inner.name));
11366
+ }
11367
+ }
11368
+ return found.sort();
11369
+ }
11370
+
11371
+ // src/supervisor-run-watch.ts
11372
+ import { readdir as readdir16 } from "fs/promises";
11373
+ import { join as join24 } from "path";
11374
+ function budget(node) {
11375
+ const parts = [`${int(node.budget.maxIterations)}it`, `${int(node.budget.maxTokens)}tok`];
11376
+ if (node.budget.maxUsd !== void 0) parts.push(`$${node.budget.maxUsd.toFixed(2)}`);
11377
+ if (node.budget.deadlineMs !== void 0) parts.push(ms(node.budget.deadlineMs));
11378
+ return parts.join("/");
11379
+ }
11380
+ function budgetUse(node, spent) {
11381
+ const parts = [];
11382
+ if (node.budget.maxIterations > 0 && spent.iterations > 0) {
11383
+ parts.push(`${Math.round(spent.iterations / node.budget.maxIterations * 100)}% it`);
11384
+ }
11385
+ const used = spent.tokensIn + spent.tokensOut;
11386
+ if (node.budget.maxTokens > 0 && used > 0) {
11387
+ parts.push(`${Math.round(used / node.budget.maxTokens * 100)}% tok`);
11388
+ }
11389
+ return parts.length === 0 ? "" : ` \xB7 ${parts.join(", ")} of budget`;
11390
+ }
11391
+ function renderNode(node, lastAtDepth, lines) {
11392
+ const mark = STATUS_MARK[node.status] ?? "?";
11393
+ const { head: prefix, detail } = connectors(node.depth, lastAtDepth);
11394
+ const head = [
11395
+ `${prefix}${mark} ${node.label}`,
11396
+ `[${node.status}]`,
11397
+ node.role,
11398
+ node.runtime ?? "no-runtime",
11399
+ `budget ${budget(node)}`
11400
+ ];
11401
+ if (node.wallMs !== null) head.push(`wall ${ms(node.wallMs)}`);
11402
+ lines.push(head.join(" "));
11403
+ if (node.driver.records > 0 || node.role === "supervisor") {
11404
+ lines.push(
11405
+ `${detail}driver ${node.driver.records} turn(s) \xB7 ${tokens2(node.driver)} \xB7 ${usd(node.driver)}` + budgetUse(node, node.driver)
11406
+ );
11407
+ }
11408
+ if (node.children.records > 0 || node.role === "supervisor") {
11409
+ lines.push(
11410
+ `${detail}children ${node.children.records} settled \xB7 ${tokens2(node.children)} \xB7 ${usd(node.children)}`
11411
+ );
11412
+ }
11413
+ if (node.settled.records > 0) {
11414
+ lines.push(
11415
+ `${detail}settled ${node.settled.iterations}it \xB7 ${tokens2(node.settled)} \xB7 ${usd(node.settled)}` + budgetUse(node, node.settled)
11416
+ );
11417
+ }
11418
+ if (node.cancelReason !== null) lines.push(`${detail}cancelled: ${node.cancelReason}`);
11419
+ if (node.outRef !== null) lines.push(`${detail}out ${node.outRef}`);
11420
+ }
11421
+ function renderQuestion(q, lines) {
11422
+ const mark = q.blocking ? "BLOCKING" : q.urgency ?? "question";
11423
+ lines.push(` \u26A0 ${mark} from ${q.from ?? "unknown"}${q.status === null ? "" : ` [${q.status}]`}`);
11424
+ for (const line of wrap(q.question, 4)) lines.push(line);
11425
+ if (q.reason !== null) for (const line of wrap(`why: ${q.reason}`, 4)) lines.push(line);
11426
+ }
11427
+ function renderRunContextSnapshot(snapshot) {
11428
+ const lines = [];
11429
+ if (!snapshot.present) {
11430
+ lines.push(`run ${snapshot.runDir}`);
11431
+ lines.push(" no spawn-journal.jsonl yet \u2014 the run has not begun writing");
11432
+ return lines.join("\n");
11433
+ }
11434
+ const totals = runTotals(snapshot);
11435
+ lines.push(`run ${snapshot.runId ?? snapshot.runDir}`);
11436
+ lines.push(
11437
+ ` ${snapshot.nodes.length} node(s) \xB7 depth ${snapshot.maxDepth} \xB7 elapsed ${ms(elapsed(snapshot))}${snapshot.terminal ? "" : " \xB7 live"}`
11438
+ );
11439
+ lines.push(` driver total ${tokens2(totals.driver)} \xB7 ${usd(totals.driver)}`);
11440
+ lines.push(` worker total ${tokens2(totals.workers)} \xB7 ${usd(totals.workers)}`);
11441
+ lines.push("");
11442
+ if (snapshot.nodes.length === 0) lines.push(" (no node spawned yet)");
11443
+ forEachTreeNode(
11444
+ snapshot.nodes,
11445
+ (n) => n.parent,
11446
+ (n) => n.id,
11447
+ (node, lastAtDepth) => renderNode(node, lastAtDepth, lines)
11448
+ );
11449
+ if (snapshot.questions.length > 0) {
11450
+ lines.push("");
11451
+ for (const q of snapshot.questions) renderQuestion(q, lines);
11452
+ }
11453
+ if (snapshot.steers.length > 0) {
11454
+ lines.push("");
11455
+ for (const steer of snapshot.steers) {
11456
+ lines.push(` \u2192 steer ${steer.messageId ?? "(no id)"} to ${steer.toWorker ?? "(no target)"}`);
11457
+ for (const line of wrap(steer.instruction, 4)) lines.push(line);
11458
+ }
11459
+ }
11460
+ const problems = [];
11461
+ if (snapshot.invalidJournalRows > 0) problems.push(`${snapshot.invalidJournalRows} unreadable journal row(s)`);
11462
+ if (snapshot.invalidCoordinationRows > 0) {
11463
+ problems.push(`${snapshot.invalidCoordinationRows} unreadable coordination row(s)`);
11464
+ }
11465
+ if (snapshot.treeError !== null) problems.push(snapshot.treeError);
11466
+ if (snapshot.partialTail) problems.push("an artifact ends mid-line \u2014 the writer is still appending");
11467
+ if (zeroPricedCost(totals.driver) || zeroPricedCost(totals.workers)) {
11468
+ problems.push(
11469
+ "spend recorded $0 with tokens spent: usdKnown was never set false, so this reads as FREE rather than unmetered. A harness-billed brain (a CLI on a subscription) looks exactly like this."
11470
+ );
11471
+ }
11472
+ const unsettled = snapshot.nodes.filter(
11473
+ (node) => node.status !== "done" && node.status !== "failed" && node.status !== "cancelled"
11474
+ );
11475
+ if (snapshot.terminal && unsettled.length > 0) {
11476
+ problems.push(
11477
+ `${unsettled.length} node(s) have no journaled settlement (${unsettled.map((n) => n.label).join(", ")}) \u2014 a driver reports its outcome through result.json, not the spawn journal`
11478
+ );
11479
+ }
11480
+ if (problems.length > 0) {
11481
+ lines.push("");
11482
+ for (const problem of problems) lines.push(` ! ${problem}`);
11483
+ }
11484
+ if (snapshot.result !== null) {
11485
+ lines.push("");
11486
+ lines.push(
11487
+ `RESULT ${snapshot.result.kind ?? "unknown-kind"}${snapshot.result.reason === null ? "" : ` \xB7 ${snapshot.result.reason}`}`
11488
+ );
11489
+ if (snapshot.result.errorMessage !== null) {
11490
+ lines.push(` driver error (${snapshot.result.errorName ?? "Error"}):`);
11491
+ for (const line of wrap(snapshot.result.errorMessage, 4)) lines.push(line);
11492
+ }
11493
+ }
11494
+ return lines.join("\n");
11495
+ }
11496
+ function runTotals(snapshot) {
11497
+ let driver = ZERO_ROLL;
11498
+ let workers = ZERO_ROLL;
11499
+ for (const node of snapshot.nodes) {
11500
+ driver = mergeRolls(driver, node.driver);
11501
+ if (node.role === "worker") workers = mergeRolls(workers, node.settled);
11502
+ }
11503
+ return { driver, workers };
11504
+ }
11505
+ function elapsed(snapshot) {
11506
+ if (snapshot.begunAt === null) return null;
11507
+ const end = snapshot.terminal ? snapshot.lastEventAt ?? Date.now() : Date.now();
11508
+ return Math.max(0, end - snapshot.begunAt);
11509
+ }
11510
+ async function resolveRunContextDir(dir) {
11511
+ if (await isFileRunContextDir(dir)) return dir;
11512
+ const entries = await readdir16(dir, { withFileTypes: true }).catch(() => null);
11513
+ if (entries === null) throw new Error(`cannot read ${dir}`);
11514
+ const candidates = [];
11515
+ for (const entry of entries) {
11516
+ if (!entry.isDirectory()) continue;
11517
+ const child = join24(dir, entry.name);
11518
+ if (await isFileRunContextDir(child)) candidates.push(child);
11519
+ }
11520
+ if (candidates.length === 1) return candidates[0];
11521
+ if (candidates.length === 0) {
11522
+ throw new Error(
11523
+ `no spawn-journal.jsonl in ${dir} or any immediate subdirectory \u2014 point at a directory written by agent-runtime createFileRunContext()`
11524
+ );
11525
+ }
11526
+ throw new Error(
11527
+ `${candidates.length} run directories under ${dir}; name one:
11528
+ ${candidates.join("\n ")}`
11529
+ );
11530
+ }
11531
+
11532
+ // src/run-watch.ts
11533
+ import { stat as stat14 } from "fs/promises";
11534
+ async function resolveRunWatchTarget(target) {
11535
+ const info = await stat14(target).catch(() => null);
11536
+ if (info === null) throw new Error(`cannot read ${target}`);
11537
+ if (info.isFile()) return { runDir: null, spanFiles: [target], requested: target };
11538
+ const spanFiles = await findSpanSourceFiles(target);
11539
+ if (await isFileRunContextDir(target)) return { runDir: target, spanFiles, requested: target };
11540
+ const nested = await resolveRunContextDir(target).catch(() => null);
11541
+ if (nested !== null) {
11542
+ const nestedSpans = await findSpanSourceFiles(nested);
11543
+ return {
11544
+ runDir: nested,
11545
+ spanFiles: [.../* @__PURE__ */ new Set([...spanFiles, ...nestedSpans])].sort(),
11546
+ requested: target
11547
+ };
11548
+ }
11549
+ if (spanFiles.length > 0) return { runDir: null, spanFiles, requested: target };
11550
+ throw new Error(
11551
+ `nothing to watch in ${target} \u2014 found neither spawn-journal.jsonl (agent-runtime createFileRunContext, at this level or one below) nor an OTLP span file (*.otlp.jsonl / *.spans.jsonl / *.traces.jsonl / *.openinference.jsonl)`
11552
+ );
11553
+ }
11554
+ async function readRunWatchSnapshot(target) {
11555
+ const journal = target.runDir === null ? null : await readRunContextSnapshot(target.runDir);
11556
+ const spans = await Promise.all(target.spanFiles.map((file) => readSpanRunSnapshot(file)));
11557
+ return {
11558
+ target,
11559
+ journal,
11560
+ spans,
11561
+ // A span file alone never declares itself finished — an emitter can always
11562
+ // append one more span — so only the journal's `result.json` ends a watch.
11563
+ terminal: journal !== null && journal.terminal
11564
+ };
11565
+ }
11566
+ function sourceHeader(snapshot) {
11567
+ const lines = ["sources"];
11568
+ if (snapshot.journal !== null) {
11569
+ lines.push(
11570
+ ` journal ${snapshot.target.runDir}/spawn-journal.jsonl \u2192 authored budget, settled spend, settlement status (authoritative)`
11571
+ );
11572
+ }
11573
+ for (const span2 of snapshot.spans) {
11574
+ lines.push(
11575
+ ` spans ${span2.source} \u2192 tree shape and per-turn detail${span2.readError === null ? "" : " (unreadable)"}`
11576
+ );
11577
+ }
11578
+ if (snapshot.journal === null) {
11579
+ lines.push(" (no spawn journal here: budget and settlement are UNAVAILABLE, not zero)");
11580
+ }
11581
+ if (snapshot.spans.length === 0) {
11582
+ lines.push(" (no OTLP span file here: per-turn shape is UNAVAILABLE, not empty)");
11583
+ }
11584
+ return lines;
11585
+ }
11586
+ function renderRunWatchSnapshot(snapshot) {
11587
+ const blocks = [sourceHeader(snapshot).join("\n")];
11588
+ if (snapshot.journal !== null) blocks.push(renderRunContextSnapshot(snapshot.journal));
11589
+ for (const span2 of snapshot.spans) blocks.push(renderSpanRunSnapshot(span2));
11590
+ return blocks.join("\n\n");
11591
+ }
11592
+ async function watchRunTarget(target, opts = {}) {
11593
+ const write = opts.write ?? ((text2) => process.stdout.write(text2));
11594
+ const intervalMs = opts.intervalMs ?? 2e3;
11595
+ let previous = "";
11596
+ for (; ; ) {
11597
+ const snapshot = await readRunWatchSnapshot(target);
11598
+ const rendered = renderRunWatchSnapshot(snapshot);
11599
+ if (opts.once) {
11600
+ write(`${rendered}
11601
+ `);
11602
+ return snapshot;
11603
+ }
11604
+ if (rendered !== previous) {
11605
+ write(`
11606
+ ${RULE}
11607
+ ${(/* @__PURE__ */ new Date()).toISOString()}
11608
+ ${rendered}
11609
+ `);
11610
+ previous = rendered;
11611
+ }
11612
+ if (snapshot.terminal && opts.follow !== true) return snapshot;
11613
+ if (aborted(opts.signal)) return snapshot;
11614
+ await sleep2(intervalMs, opts.signal);
11615
+ if (aborted(opts.signal)) return await readRunWatchSnapshot(target);
11616
+ }
11617
+ }
11618
+ function aborted(signal) {
11619
+ return signal !== void 0 && signal.aborted;
11620
+ }
11621
+ function sleep2(msDelay, signal) {
11622
+ return new Promise((resolve7) => {
11623
+ const timer = setTimeout(resolve7, msDelay);
11624
+ signal?.addEventListener(
11625
+ "abort",
11626
+ () => {
11627
+ clearTimeout(timer);
11628
+ resolve7();
11629
+ },
11630
+ { once: true }
11631
+ );
11632
+ });
11633
+ }
11634
+
10557
11635
  // src/observer.ts
10558
11636
  function loopKey(loop) {
10559
11637
  return `${loop.sessionId}:${loop.toolName}:${loop.argHash}`;
@@ -11014,9 +12092,9 @@ async function collectSessionSelection(groups, options = {}) {
11014
12092
  }
11015
12093
 
11016
12094
  // src/session-index.ts
11017
- import { mkdtemp as mkdtemp7, readdir as readdir15, readFile as readFile10, stat as stat13, writeFile as writeFile7 } from "fs/promises";
12095
+ import { mkdtemp as mkdtemp7, readdir as readdir17, readFile as readFile11, stat as stat15, writeFile as writeFile7 } from "fs/promises";
11018
12096
  import { tmpdir as tmpdir6 } from "os";
11019
- import { dirname as dirname7, join as join22 } from "path";
12097
+ import { dirname as dirname7, join as join25 } from "path";
11020
12098
  function indexRow(record2) {
11021
12099
  return {
11022
12100
  session: record2.session,
@@ -11071,7 +12149,7 @@ function buildSessionIndex(records, opts = {}) {
11071
12149
  }
11072
12150
  async function pathStat2(path) {
11073
12151
  try {
11074
- return await stat13(path);
12152
+ return await stat15(path);
11075
12153
  } catch {
11076
12154
  return null;
11077
12155
  }
@@ -11089,7 +12167,7 @@ async function findContextRoot(cwd) {
11089
12167
  if (!s) return null;
11090
12168
  if (!s.isDirectory()) current = dirname7(current);
11091
12169
  for (; ; ) {
11092
- if (await pathStat2(join22(current, ".git")) || await dirExists(join22(current, ".evolve")) || await fileExists(join22(current, "AGENTS.md")) || await fileExists(join22(current, "CLAUDE.md"))) {
12170
+ if (await pathStat2(join25(current, ".git")) || await dirExists(join25(current, ".evolve")) || await fileExists(join25(current, "AGENTS.md")) || await fileExists(join25(current, "CLAUDE.md"))) {
11093
12171
  return current;
11094
12172
  }
11095
12173
  const parent = dirname7(current);
@@ -11132,7 +12210,7 @@ async function summarizeFile(path, kind) {
11132
12210
  const base = { kind, path, bytes: Number(s.size), mtimeMs: Number(s.mtimeMs) };
11133
12211
  if (!path.endsWith(".md") && !path.endsWith(".jsonl")) return base;
11134
12212
  try {
11135
- const text2 = await readFile10(path, "utf8");
12213
+ const text2 = await readFile11(path, "utf8");
11136
12214
  const lines = countLines(text2);
11137
12215
  const jsonl2 = path.endsWith(".jsonl") ? summarizeJsonl(text2) : void 0;
11138
12216
  return {
@@ -11151,13 +12229,13 @@ async function walkMarkdown(root, kind, maxFiles = 100) {
11151
12229
  if (out.length >= maxFiles) return;
11152
12230
  let entries;
11153
12231
  try {
11154
- entries = await readdir15(dir, { withFileTypes: true });
12232
+ entries = await readdir17(dir, { withFileTypes: true });
11155
12233
  } catch {
11156
12234
  return;
11157
12235
  }
11158
12236
  for (const entry of entries) {
11159
12237
  if (out.length >= maxFiles) return;
11160
- const path = join22(dir, entry.name);
12238
+ const path = join25(dir, entry.name);
11161
12239
  if (entry.isDirectory()) {
11162
12240
  await walk(path);
11163
12241
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -11172,20 +12250,20 @@ async function walkMarkdown(root, kind, maxFiles = 100) {
11172
12250
  async function collectContextRoot(root) {
11173
12251
  const files = [];
11174
12252
  for (const name of ["AGENTS.md", "CLAUDE.md", "GEMINI.md"]) {
11175
- const summary = await summarizeFile(join22(root, name), "instruction-doc");
12253
+ const summary = await summarizeFile(join25(root, name), "instruction-doc");
11176
12254
  if (summary) files.push(summary);
11177
12255
  }
11178
- const evolve = join22(root, ".evolve");
12256
+ const evolve = join25(root, ".evolve");
11179
12257
  for (const name of ["skill-runs.jsonl", "governor.jsonl", "experiments.jsonl"]) {
11180
- const summary = await summarizeFile(join22(evolve, name), "evolve-jsonl");
12258
+ const summary = await summarizeFile(join25(evolve, name), "evolve-jsonl");
11181
12259
  if (summary) files.push(summary);
11182
12260
  }
11183
12261
  for (const name of ["scorecard.json"]) {
11184
- const summary = await summarizeFile(join22(evolve, name), "evolve-json");
12262
+ const summary = await summarizeFile(join25(evolve, name), "evolve-json");
11185
12263
  if (summary) files.push(summary);
11186
12264
  }
11187
- files.push(...await walkMarkdown(join22(evolve, "reflections"), "reflection"));
11188
- files.push(...await walkMarkdown(join22(evolve, "handoffs"), "handoff"));
12265
+ files.push(...await walkMarkdown(join25(evolve, "reflections"), "reflection"));
12266
+ files.push(...await walkMarkdown(join25(evolve, "handoffs"), "handoff"));
11189
12267
  return { root, files: files.sort((a, b) => a.path.localeCompare(b.path)) };
11190
12268
  }
11191
12269
  async function collectContextIndex(records) {
@@ -11231,19 +12309,19 @@ function serializeSessionIndex(index) {
11231
12309
  `;
11232
12310
  }
11233
12311
  async function writeSessionIndexFile(index, outPath) {
11234
- const path = outPath ?? join22(await mkdtemp7(join22(tmpdir6(), "traces-index-")), "session-index.json");
12312
+ const path = outPath ?? join25(await mkdtemp7(join25(tmpdir6(), "traces-index-")), "session-index.json");
11235
12313
  await writeFile7(path, serializeSessionIndex(index), "utf8");
11236
12314
  return path;
11237
12315
  }
11238
12316
 
11239
12317
  // src/upload-state.ts
11240
- import { mkdir as mkdir5, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
12318
+ import { mkdir as mkdir5, readFile as readFile12, writeFile as writeFile8 } from "fs/promises";
11241
12319
  import { homedir as homedir12 } from "os";
11242
- import { dirname as dirname8, join as join23 } from "path";
12320
+ import { dirname as dirname8, join as join26 } from "path";
11243
12321
  import { contentHash } from "@tangle-network/agent-eval";
11244
12322
  function stateFile() {
11245
- const base = process.env.XDG_STATE_HOME ?? join23(homedir12(), ".local", "state");
11246
- return join23(base, "tangle-traces", "uploaded.json");
12323
+ const base = process.env.XDG_STATE_HOME ?? join26(homedir12(), ".local", "state");
12324
+ return join26(base, "tangle-traces", "uploaded.json");
11247
12325
  }
11248
12326
  function uploadKey(harness, sessionId) {
11249
12327
  return `${harness}:${sessionId}`;
@@ -11256,7 +12334,7 @@ function outboundHash(events, identity) {
11256
12334
  }
11257
12335
  async function loadState() {
11258
12336
  try {
11259
- return JSON.parse(await readFile11(stateFile(), "utf8"));
12337
+ return JSON.parse(await readFile12(stateFile(), "utf8"));
11260
12338
  } catch {
11261
12339
  return {};
11262
12340
  }
@@ -11272,10 +12350,10 @@ function alreadyUploaded(state, harness, sessionId, hash2) {
11272
12350
  }
11273
12351
 
11274
12352
  // src/upload.ts
11275
- import { readFile as readFile12 } from "fs/promises";
12353
+ import { readFile as readFile13 } from "fs/promises";
11276
12354
  import { createRequire } from "module";
11277
12355
  import { hostname as hostname2 } from "os";
11278
- import { basename as basename13, join as join24 } from "path";
12356
+ import { basename as basename14, join as join27 } from "path";
11279
12357
  import { hostedClientFromEnv } from "@tangle-network/agent-eval/hosted";
11280
12358
  import { REDACTION_VERSION } from "@tangle-network/agent-eval/traces";
11281
12359
  var require2 = createRequire(import.meta.url);
@@ -11299,7 +12377,7 @@ async function planUpload(opts = {}) {
11299
12377
  async function gitBranch(cwd) {
11300
12378
  if (!cwd) return void 0;
11301
12379
  try {
11302
- const head = await readFile12(join24(cwd, ".git", "HEAD"), "utf8");
12380
+ const head = await readFile13(join27(cwd, ".git", "HEAD"), "utf8");
11303
12381
  const m = head.match(/^ref:\s*refs\/heads\/(.+)$/m);
11304
12382
  return m?.[1]?.trim();
11305
12383
  } catch {
@@ -11309,7 +12387,7 @@ async function gitBranch(cwd) {
11309
12387
  async function sessionMeta(item) {
11310
12388
  const meta = {
11311
12389
  [ATTR.HARNESS]: item.ref.harness,
11312
- [ATTR.SESSION_FILE]: basename13(item.ref.path),
12390
+ [ATTR.SESSION_FILE]: basename14(item.ref.path),
11313
12391
  [ATTR.HOST]: hostname2(),
11314
12392
  [ATTR.UPLOADER]: `tangle-traces@${TRACES_VERSION}`,
11315
12393
  [ATTR.REDACTION_VERSION]: REDACTION_VERSION,
@@ -11582,6 +12660,43 @@ export {
11582
12660
  traceStreamEventsFromSpans,
11583
12661
  serializeTraceStreamEvent,
11584
12662
  streamSessions,
12663
+ SPAWN_JOURNAL_FILE,
12664
+ COORDINATION_LOG_FILE,
12665
+ RESULT_FILE,
12666
+ BLOBS_DIR,
12667
+ readRunContextJournal,
12668
+ inferRole,
12669
+ readCoordinationLog,
12670
+ readFileRunContext,
12671
+ fileRunContextSupervisorRunReader,
12672
+ isFileRunContextDir,
12673
+ ZERO_ROLL,
12674
+ addSpend,
12675
+ mergeRolls,
12676
+ readRunContextSnapshot,
12677
+ RULE,
12678
+ int,
12679
+ ms,
12680
+ usd,
12681
+ zeroPricedCost,
12682
+ tokens2 as tokens,
12683
+ STATUS_MARK,
12684
+ connectors,
12685
+ forEachTreeNode,
12686
+ wrap,
12687
+ EMPTY_SPAN_RUN_SNAPSHOT,
12688
+ buildSpanRunTree,
12689
+ readSpanRunSnapshot,
12690
+ spanRunTotals,
12691
+ renderSpanRunSnapshot,
12692
+ findSpanSourceFiles,
12693
+ renderRunContextSnapshot,
12694
+ runTotals,
12695
+ resolveRunContextDir,
12696
+ resolveRunWatchTarget,
12697
+ readRunWatchSnapshot,
12698
+ renderRunWatchSnapshot,
12699
+ watchRunTarget,
11585
12700
  watchSessions,
11586
12701
  collectSessionWorkflow,
11587
12702
  collectSessionSelection,