@tangle-network/traces 0.10.2 → 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.
package/dist/cli.js CHANGED
@@ -12,11 +12,13 @@ import {
12
12
  describeSessionRelationship,
13
13
  executeUpload,
14
14
  exportTraceEvidenceFile,
15
+ fileRunContextSupervisorRunReader,
15
16
  haloAnalyzer,
16
17
  hodoscopeAnalyzer,
17
18
  importCodeTraceBench,
18
19
  indexSessionIdsByTrace,
19
20
  inspectSessionIndex,
21
+ isFileRunContextDir,
20
22
  knownHarnesses,
21
23
  loadTracesConfig,
22
24
  locateSessions,
@@ -27,6 +29,7 @@ import {
27
29
  readSessionIndexFile,
28
30
  renderInspectionReport,
29
31
  resolveAdapter,
32
+ resolveRunWatchTarget,
30
33
  runTraceImprovement,
31
34
  runTraceInvestigation,
32
35
  saveReport,
@@ -39,18 +42,19 @@ import {
39
42
  streamSessions,
40
43
  totalAgenticFailureMessage,
41
44
  traceStreamEventsFromSpans,
45
+ watchRunTarget,
42
46
  watchSessions,
43
47
  writeInspectionReportFile,
44
48
  writeOtlpFile,
45
49
  writePolicyEvidenceFile,
46
50
  writeSessionIndexFile,
47
51
  writeTraceEvidenceExportFile
48
- } from "./chunk-LC66I5TE.js";
52
+ } from "./chunk-JCI5YXNT.js";
49
53
 
50
54
  // src/cli.ts
51
55
  import { readFileSync } from "fs";
52
- import { readFile, stat } from "fs/promises";
53
- import { basename, resolve } from "path";
56
+ import { readdir, readFile, stat } from "fs/promises";
57
+ import { basename, join, resolve } from "path";
54
58
  import {
55
59
  analyzeSupervisorRun,
56
60
  findSupervisorRunDirs,
@@ -81,6 +85,7 @@ function parseArgs(argv) {
81
85
  maxWorkflowSessions: 100,
82
86
  llm: false,
83
87
  interval: 5,
88
+ intervalExplicit: false,
84
89
  window: 30,
85
90
  minLoop: 3,
86
91
  dryRun: false,
@@ -88,6 +93,7 @@ function parseArgs(argv) {
88
93
  noContent: false,
89
94
  analyzers: [],
90
95
  replay: false,
96
+ once: false,
91
97
  noSpans: false,
92
98
  noFindings: false,
93
99
  attrs: [],
@@ -174,6 +180,7 @@ function parseArgs(argv) {
174
180
  }
175
181
  case "--interval":
176
182
  a.interval = Number(next());
183
+ a.intervalExplicit = true;
177
184
  break;
178
185
  case "--window":
179
186
  a.window = Number(next());
@@ -188,7 +195,12 @@ function parseArgs(argv) {
188
195
  a.noContent = true;
189
196
  break;
190
197
  case "--replay":
198
+ a.replay = true;
199
+ break;
200
+ // `stream --once` has always meant "one pass"; `watch --once` means the
201
+ // same thing over a run directory, so one flag drives both.
191
202
  case "--once":
203
+ a.once = true;
192
204
  a.replay = true;
193
205
  break;
194
206
  case "--no-spans":
@@ -668,9 +680,23 @@ async function cmdAnalyze(args) {
668
680
  assertAgenticAnalystsRan(args, result.agenticPerAnalyst);
669
681
  }
670
682
  async function cmdAnalyzeSupervisorRun(runDir, args) {
671
- const nested = await findSupervisorRunDirs(runDir);
683
+ const runContextDirs = await findFileRunContextDirs(runDir);
684
+ const nested = runContextDirs.length > 0 ? [] : await findSupervisorRunDirs(runDir);
672
685
  let markdown;
673
- if (nested.length > 0) {
686
+ if (runContextDirs.length > 1) {
687
+ markdown = renderSupervisorRollupMarkdown(
688
+ rollupSupervisorRuns(
689
+ await Promise.all(
690
+ runContextDirs.map((dir) => analyzeSupervisorRun(fileRunContextSupervisorRunReader(dir)))
691
+ )
692
+ ),
693
+ `Supervisor rollup \u2014 ${runDir}`
694
+ );
695
+ } else if (runContextDirs.length === 1) {
696
+ markdown = renderSupervisorRunMarkdown(
697
+ await analyzeSupervisorRun(fileRunContextSupervisorRunReader(runContextDirs[0]))
698
+ );
699
+ } else if (nested.length > 0) {
674
700
  markdown = renderSupervisorRollupMarkdown(
675
701
  rollupSupervisorRuns(await Promise.all(nested.map((dir) => analyzeSupervisorRun(dir)))),
676
702
  `Supervisor rollup \u2014 ${runDir}`
@@ -679,20 +705,30 @@ async function cmdAnalyzeSupervisorRun(runDir, args) {
679
705
  const report = await analyzeSupervisorRun(runDir);
680
706
  if (isUnavailable(report.orchestration.workersSpawned)) {
681
707
  throw new Error(
682
- `no supervisor run found at ${runDir} \u2014 expected <runDir>/ws/.agent/supervisor/<id> (or the pre-rename <runDir>/ws/.loops/supervisor/<id>), or a parent directory containing such runs`
708
+ `no supervisor run found at ${runDir} \u2014 expected <runDir>/spawn-journal.jsonl (agent-runtime createFileRunContext), <runDir>/ws/.agent/supervisor/<id> (or the pre-rename <runDir>/ws/.loops/supervisor/<id>), or a parent directory containing such runs`
683
709
  );
684
710
  }
685
711
  markdown = renderSupervisorRunMarkdown(report);
686
712
  }
713
+ const runs = Math.max(runContextDirs.length, nested.length, 1);
687
714
  if (args.out) {
688
715
  await saveReport(args.out, markdown);
689
- console.log(
690
- `supervisor report \u2192 ${args.out} (${nested.length > 0 ? `${nested.length} runs` : "1 run"})`
691
- );
716
+ console.log(`supervisor report \u2192 ${args.out} (${runs === 1 ? "1 run" : `${runs} runs`})`);
692
717
  } else {
693
718
  console.log(markdown);
694
719
  }
695
720
  }
721
+ async function findFileRunContextDirs(dir) {
722
+ if (await isFileRunContextDir(dir)) return [dir];
723
+ const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
724
+ const found = [];
725
+ for (const entry of entries) {
726
+ if (!entry.isDirectory()) continue;
727
+ const child = join(dir, entry.name);
728
+ if (await isFileRunContextDir(child)) found.push(child);
729
+ }
730
+ return found.sort();
731
+ }
696
732
  async function collectImportedSpans(args) {
697
733
  if (!args.input) throw new Error("input file missing");
698
734
  const attributes = await loadExportAttributes(args);
@@ -911,6 +947,8 @@ async function cmdStream(args) {
911
947
  });
912
948
  }
913
949
  async function cmdWatch(args) {
950
+ const target = args.supervisorRunDir ?? args.input;
951
+ if (target !== void 0) return cmdWatchRunTarget(target, args);
914
952
  const all = args.all || !args.harnessExplicit && !args.cwd;
915
953
  const controller = new AbortController();
916
954
  process.once("SIGINT", () => controller.abort());
@@ -939,6 +977,26 @@ async function cmdWatch(args) {
939
977
  }
940
978
  });
941
979
  }
980
+ async function cmdWatchRunTarget(dir, args) {
981
+ const target = await resolveRunWatchTarget(resolve(dir));
982
+ const controller = new AbortController();
983
+ if (!args.once) {
984
+ process.once("SIGINT", () => controller.abort());
985
+ process.stderr.write(
986
+ `traces watch: tailing ${target.requested} every ${args.interval}s; read-only, ${target.runDir === null ? "span source only \u2014 Ctrl-C to stop" : "stops when result.json lands. Ctrl-C to stop"}.
987
+ `
988
+ );
989
+ }
990
+ const snapshot = await watchRunTarget(target, {
991
+ once: args.once,
992
+ // A tree view wants a tighter poll than the session observer's 5s default:
993
+ // a blocking question is worth surfacing the moment it lands.
994
+ intervalMs: args.intervalExplicit ? Math.max(250, args.interval * 1e3) : 2e3,
995
+ signal: controller.signal
996
+ });
997
+ const result = snapshot.journal?.result ?? null;
998
+ if (result !== null && result.errorMessage !== null) process.exitCode = 1;
999
+ }
942
1000
  async function cmdUpload(args) {
943
1001
  const sinceMs = args.since ? parseSince(args.since) : Date.now() - 24 * 60 * 60 * 1e3;
944
1002
  const all = args.all || !args.harnessExplicit;
@@ -1057,6 +1115,7 @@ Commands:
1057
1115
  evidence Emit compact session-evidence JSONL for downstream policy miners
1058
1116
  stream Emit JSONL trace stream events for live visualizers or replay
1059
1117
  watch Online observer: tail active sessions, notify on loops + semantic findings
1118
+ (watch <target> tails ONE run tree instead: a run directory or a span file)
1060
1119
  upload Redact + upload sessions in a time window to the Tangle Intelligence Platform
1061
1120
 
1062
1121
  Options:
@@ -1074,6 +1133,8 @@ Options:
1074
1133
  analyze: report a SUPERVISION TREE instead of harness sessions \u2014
1075
1134
  steers, spawn waves, concurrency, idle wall, cost by role,
1076
1135
  accepted vs rejected. Rolls up when the dir holds many runs.
1136
+ watch: same directory, live. Reads the loops layout, the
1137
+ agent-runtime createFileRunContext journal, and OTLP span files.
1077
1138
  --since <t> upload: window, 30m / 2h / 7d or an ISO date (default 24h); analyze: ISO cutoff
1078
1139
  --out <path> Write report to a file
1079
1140
  --dir <path> improve: write artifacts to this directory
@@ -1083,6 +1144,7 @@ Options:
1083
1144
  --attr <k=v> analyze/export file: attach one span attribute (repeatable)
1084
1145
  --mode <kind> stream: visualizer | findings | agent (default visualizer)
1085
1146
  --replay, --once stream: scan once and exit (default for positional input / --session)
1147
+ --once watch <target>: print ONE snapshot and exit, for scripts and agents
1086
1148
  --no-spans stream: omit per-span pulse events
1087
1149
  --no-findings stream: omit semantic live-finding events
1088
1150
  --llm Enable agentic RLM analysts. Runs on the Tangle router by
@@ -1096,7 +1158,7 @@ Options:
1096
1158
  --budget <usd> USD cap for agentic analysts
1097
1159
  --analyzer <id> analyze: also run halo, hodoscope, or an installed command (repeatable)
1098
1160
  --analyzer-prompt <p> analyze: prompt passed to external analyzers (default: diagnose)
1099
- --interval <s> watch/stream: poll interval seconds (default 5)
1161
+ --interval <s> watch/stream: poll interval seconds (sessions 5, run tree 2)
1100
1162
  --window <m> watch/stream: only sessions active in the last N minutes (default 30)
1101
1163
  --min-loop <n> Min identical repeated calls to flag a loop (default 3)
1102
1164
  --dry-run upload: redact + dedup + preview, write OTLP, but do NOT send
@@ -1106,6 +1168,13 @@ Options:
1106
1168
  --version, -v Print the installed traces version
1107
1169
  --help, -h Show help (use \`traces export --help\` or \`traces import-codetracebench --help\`)
1108
1170
 
1171
+ Watch a run tree (any depth; driver spend and child spend stay separate,
1172
+ and a cost the harness never priced reads "unknown", never $0):
1173
+ traces watch runs/my-run live tree: status, budget, driver vs child spend
1174
+ traces watch runs/my-run --once one snapshot, then exit
1175
+ traces watch traces.otlp.jsonl OTLP spans only \u2014 works for ANY emitter
1176
+ traces analyze --supervisor-run-dir runs/my-run the full tree report
1177
+
1109
1178
  Upload env: TANGLE_INGEST_URL (or TANGLE_ORCHESTRATOR_URL), TANGLE_INGEST_API_KEY (or TANGLE_API_KEY), TANGLE_TENANT_ID`);
1110
1179
  }
1111
1180
  async function main() {