@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.
- package/README.md +59 -2
- package/dist/{chunk-LC66I5TE.js → chunk-JCI5YXNT.js} +1162 -47
- package/dist/cli.js +79 -10
- package/dist/index.d.ts +509 -1
- package/dist/index.js +77 -3
- package/package.json +4 -2
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-
|
|
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
|
|
683
|
+
const runContextDirs = await findFileRunContextDirs(runDir);
|
|
684
|
+
const nested = runContextDirs.length > 0 ? [] : await findSupervisorRunDirs(runDir);
|
|
672
685
|
let markdown;
|
|
673
|
-
if (
|
|
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 (
|
|
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() {
|