@tangle-network/traces 0.9.11 → 0.9.13
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 +62 -19
- package/dist/{chunk-ELWOJS65.js → chunk-H47X6QWV.js} +4016 -750
- package/dist/cli.js +162 -68
- package/dist/index.d.ts +325 -30
- package/dist/index.js +23 -1
- package/docs/demo.gif +0 -0
- package/docs/trace-analysts.md +222 -0
- package/examples/custom-analyst.ts +179 -0
- package/examples/custom-backend.ts +21 -0
- package/examples/external-engines.ts +49 -0
- package/examples/improvement-config.mjs +63 -0
- package/examples/observe-and-alert.ts +19 -0
- package/examples/register-harness.ts +26 -0
- package/package.json +9 -8
package/dist/cli.js
CHANGED
|
@@ -6,11 +6,14 @@ import {
|
|
|
6
6
|
appendAll,
|
|
7
7
|
buildPolicyEvidenceRecord,
|
|
8
8
|
buildSessionIndexFromRows,
|
|
9
|
+
collectSessionSelection,
|
|
9
10
|
commandAnalyzer,
|
|
10
11
|
commandRedactor,
|
|
12
|
+
describeSessionRelationship,
|
|
11
13
|
executeUpload,
|
|
12
14
|
exportTraceEvidenceFile,
|
|
13
15
|
haloAnalyzer,
|
|
16
|
+
hodoscopeAnalyzer,
|
|
14
17
|
indexSessionIdsByTrace,
|
|
15
18
|
inspectSessionIndex,
|
|
16
19
|
knownHarnesses,
|
|
@@ -40,11 +43,10 @@ import {
|
|
|
40
43
|
writePolicyEvidenceFile,
|
|
41
44
|
writeSessionIndexFile,
|
|
42
45
|
writeTraceEvidenceExportFile
|
|
43
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-H47X6QWV.js";
|
|
44
47
|
|
|
45
48
|
// src/cli.ts
|
|
46
|
-
import {
|
|
47
|
-
import { createReadStream, readFileSync } from "fs";
|
|
49
|
+
import { readFileSync } from "fs";
|
|
48
50
|
import { readFile, stat } from "fs/promises";
|
|
49
51
|
import { basename, resolve } from "path";
|
|
50
52
|
import {
|
|
@@ -55,6 +57,8 @@ import {
|
|
|
55
57
|
renderSupervisorRunMarkdown,
|
|
56
58
|
rollupSupervisorRuns
|
|
57
59
|
} from "@tangle-network/agent-eval/supervisor-run";
|
|
60
|
+
import { createAnalystAi } from "@tangle-network/agent-eval/analyst";
|
|
61
|
+
var DEFAULT_ANALYST_MODEL = "gpt-5-mini";
|
|
58
62
|
function packageVersion() {
|
|
59
63
|
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
60
64
|
if (typeof pkg.version !== "string" || !pkg.version) throw new Error("package.json is missing version");
|
|
@@ -68,6 +72,10 @@ function parseArgs(argv) {
|
|
|
68
72
|
harnessExplicit: false,
|
|
69
73
|
all: false,
|
|
70
74
|
last: 0,
|
|
75
|
+
current: false,
|
|
76
|
+
latestTurn: false,
|
|
77
|
+
workflow: false,
|
|
78
|
+
maxWorkflowSessions: 100,
|
|
71
79
|
llm: false,
|
|
72
80
|
interval: 5,
|
|
73
81
|
window: 30,
|
|
@@ -95,6 +103,18 @@ function parseArgs(argv) {
|
|
|
95
103
|
case "--last":
|
|
96
104
|
a.last = Number(next());
|
|
97
105
|
break;
|
|
106
|
+
case "--current":
|
|
107
|
+
a.current = true;
|
|
108
|
+
break;
|
|
109
|
+
case "--latest-turn":
|
|
110
|
+
a.latestTurn = true;
|
|
111
|
+
break;
|
|
112
|
+
case "--workflow":
|
|
113
|
+
a.workflow = true;
|
|
114
|
+
break;
|
|
115
|
+
case "--max-workflow-sessions":
|
|
116
|
+
a.maxWorkflowSessions = Number(next());
|
|
117
|
+
break;
|
|
98
118
|
case "--session":
|
|
99
119
|
a.session = next();
|
|
100
120
|
break;
|
|
@@ -194,6 +214,57 @@ function parseArgs(argv) {
|
|
|
194
214
|
}
|
|
195
215
|
return a;
|
|
196
216
|
}
|
|
217
|
+
var CURRENT_SESSION_COMMANDS = /* @__PURE__ */ new Set([
|
|
218
|
+
"analyze",
|
|
219
|
+
"investigate",
|
|
220
|
+
"improve",
|
|
221
|
+
"convert",
|
|
222
|
+
"index",
|
|
223
|
+
"evidence",
|
|
224
|
+
"stream"
|
|
225
|
+
]);
|
|
226
|
+
var WORKFLOW_COMMANDS = /* @__PURE__ */ new Set([
|
|
227
|
+
"analyze",
|
|
228
|
+
"investigate",
|
|
229
|
+
"improve",
|
|
230
|
+
"convert",
|
|
231
|
+
"index",
|
|
232
|
+
"evidence"
|
|
233
|
+
]);
|
|
234
|
+
function applyCurrentSessionSelection(args) {
|
|
235
|
+
if (!args.current) return args;
|
|
236
|
+
if (!CURRENT_SESSION_COMMANDS.has(args.command)) {
|
|
237
|
+
throw new Error(`--current is not supported by ${args.command}`);
|
|
238
|
+
}
|
|
239
|
+
if (args.input) throw new Error("--current cannot be combined with an input file");
|
|
240
|
+
if (args.supervisorRunDir) throw new Error("--current cannot be combined with --supervisor-run-dir");
|
|
241
|
+
if (args.session) throw new Error("--current cannot be combined with --session");
|
|
242
|
+
if (args.last > 0) throw new Error("--current cannot be combined with --last");
|
|
243
|
+
if (args.all) throw new Error("--current cannot be combined with --all");
|
|
244
|
+
const adapter = resolveAdapter(args.harness);
|
|
245
|
+
if (adapter?.harness !== "codex") {
|
|
246
|
+
throw new Error("--current uses CODEX_THREAD_ID and requires --harness codex");
|
|
247
|
+
}
|
|
248
|
+
const sessionId = process.env.CODEX_THREAD_ID?.trim();
|
|
249
|
+
if (!sessionId) throw new Error("--current requires CODEX_THREAD_ID from the active Codex session");
|
|
250
|
+
return { ...args, session: sessionId };
|
|
251
|
+
}
|
|
252
|
+
function validateWorkflowSelection(args) {
|
|
253
|
+
if (!args.workflow && !args.latestTurn) return args;
|
|
254
|
+
if (!WORKFLOW_COMMANDS.has(args.command)) {
|
|
255
|
+
throw new Error(`${args.workflow ? "--workflow" : "--latest-turn"} is not supported by ${args.command}`);
|
|
256
|
+
}
|
|
257
|
+
if (args.input) throw new Error("--workflow and --latest-turn cannot be combined with an input file");
|
|
258
|
+
if (args.supervisorRunDir) {
|
|
259
|
+
throw new Error("--workflow and --latest-turn cannot be combined with --supervisor-run-dir");
|
|
260
|
+
}
|
|
261
|
+
const selected = resolveAdapter(args.harness);
|
|
262
|
+
const supportsTaskTurns = selected?.harness === "codex" || selected?.harness === "claude-code";
|
|
263
|
+
if (args.latestTurn && (args.all || !supportsTaskTurns)) {
|
|
264
|
+
throw new Error("--latest-turn requires --harness codex or claude-code");
|
|
265
|
+
}
|
|
266
|
+
return args;
|
|
267
|
+
}
|
|
197
268
|
async function confirm(question) {
|
|
198
269
|
if (!process.stdin.isTTY) return false;
|
|
199
270
|
const rl = (await import("readline/promises")).createInterface({
|
|
@@ -239,7 +310,7 @@ async function resolveSelectedSession(args) {
|
|
|
239
310
|
sessionId: args.session,
|
|
240
311
|
path: args.session,
|
|
241
312
|
// --session is an explicit file; honor --cwd so adoption can find the
|
|
242
|
-
// project's
|
|
313
|
+
// project's current or legacy skill-run log (locate() infers cwd in the scan path).
|
|
243
314
|
cwd: args.cwd ?? null,
|
|
244
315
|
mtimeMs: st.mtimeMs
|
|
245
316
|
}
|
|
@@ -264,7 +335,7 @@ async function resolveSelectedSession(args) {
|
|
|
264
335
|
`session ID "${args.session}" is ambiguous across ${matches.length} files; select one harness or pass its explicit session path`
|
|
265
336
|
);
|
|
266
337
|
}
|
|
267
|
-
async function buildAxService() {
|
|
338
|
+
async function buildAxService(model) {
|
|
268
339
|
const apiKey = process.env.OPENAI_API_KEY;
|
|
269
340
|
if (!apiKey) {
|
|
270
341
|
throw new Error(
|
|
@@ -272,8 +343,7 @@ async function buildAxService() {
|
|
|
272
343
|
);
|
|
273
344
|
}
|
|
274
345
|
const apiURL = process.env.OPENAI_BASE_URL || void 0;
|
|
275
|
-
|
|
276
|
-
return AxAI.create({ name: "openai", apiKey, ...apiURL ? { apiURL } : {} });
|
|
346
|
+
return createAnalystAi({ apiKey, baseUrl: apiURL, model });
|
|
277
347
|
}
|
|
278
348
|
async function cmdList(args) {
|
|
279
349
|
const groups = await discover({ ...args, last: args.last || 20 });
|
|
@@ -297,6 +367,7 @@ function selectedSessionSource(ref, spans, sessionIdOverride) {
|
|
|
297
367
|
const subject = firstLine.length > 240 ? `${firstLine.slice(0, 240)}\u2026 [+${firstLine.length - 240} chars]` : firstLine;
|
|
298
368
|
const role = root?.attributes["traces.session.role"];
|
|
299
369
|
const parentSessionId = root?.attributes["traces.parent_session_id"];
|
|
370
|
+
const relationship = describeSessionRelationship(ref, spans);
|
|
300
371
|
const corruptionDigest = root?.attributes[ATTR.CORRUPTION_DIGEST];
|
|
301
372
|
const sessionId = [
|
|
302
373
|
sessionIdOverride,
|
|
@@ -310,6 +381,13 @@ function selectedSessionSource(ref, spans, sessionIdOverride) {
|
|
|
310
381
|
subject,
|
|
311
382
|
role: role === "operator" || role === "child" ? role : "unknown",
|
|
312
383
|
...typeof parentSessionId === "string" ? { parentSessionId } : {},
|
|
384
|
+
childSessionIds: relationship.childSessionIds,
|
|
385
|
+
...relationship.depth !== void 0 ? { depth: relationship.depth } : {},
|
|
386
|
+
...relationship.agentNickname ? { agentNickname: relationship.agentNickname } : {},
|
|
387
|
+
...relationship.agentRole ? { agentRole: relationship.agentRole } : {},
|
|
388
|
+
...relationship.agentPath ? { agentPath: relationship.agentPath } : {},
|
|
389
|
+
...relationship.taskScope ? { taskScope: relationship.taskScope } : {},
|
|
390
|
+
...relationship.turnId ? { turnId: relationship.turnId } : {},
|
|
313
391
|
integrity: ref.integrity?.status ?? "complete",
|
|
314
392
|
...ref.integrity ? {
|
|
315
393
|
corruptionCount: ref.integrity.corruptions.length,
|
|
@@ -319,66 +397,67 @@ function selectedSessionSource(ref, spans, sessionIdOverride) {
|
|
|
319
397
|
};
|
|
320
398
|
}
|
|
321
399
|
async function collectSpans(args) {
|
|
322
|
-
if (args.input)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const spans2 = await parseSession(adapter, ref);
|
|
326
|
-
return {
|
|
327
|
-
spans: spans2,
|
|
328
|
-
harness: adapter.harness,
|
|
329
|
-
cwds: ref.cwd ? [ref.cwd] : [],
|
|
330
|
-
sources: [selectedSessionSource(ref, spans2)]
|
|
331
|
-
};
|
|
400
|
+
if (args.input) {
|
|
401
|
+
if (args.workflow) throw new Error("--workflow reads discovered sessions and cannot be combined with an input file");
|
|
402
|
+
return collectImportedSpans(args);
|
|
332
403
|
}
|
|
333
|
-
const
|
|
404
|
+
const selection = await collectSessionRows(args, false, args.last || 1);
|
|
334
405
|
const spans = [];
|
|
335
|
-
const harnesses =
|
|
406
|
+
const harnesses = /* @__PURE__ */ new Set();
|
|
336
407
|
const cwds = [];
|
|
337
408
|
const sources = [];
|
|
338
|
-
for (const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
sources.push(selectedSessionSource(ref, parsed));
|
|
344
|
-
if (ref.cwd) cwds.push(ref.cwd);
|
|
345
|
-
}
|
|
409
|
+
for (const row of selection.rows) {
|
|
410
|
+
harnesses.add(row.adapter.harness);
|
|
411
|
+
appendAll(spans, row.spans);
|
|
412
|
+
sources.push(selectedSessionSource(row.ref, row.spans));
|
|
413
|
+
if (row.ref.cwd) cwds.push(row.ref.cwd);
|
|
346
414
|
}
|
|
347
|
-
return {
|
|
415
|
+
return {
|
|
416
|
+
spans,
|
|
417
|
+
harness: [...harnesses].join("+") || args.harness,
|
|
418
|
+
cwds,
|
|
419
|
+
sources,
|
|
420
|
+
...selection.workflow ? { workflow: selection.workflow } : {}
|
|
421
|
+
};
|
|
348
422
|
}
|
|
349
423
|
async function cmdConvert(args) {
|
|
350
|
-
const { spans } = await collectSpans(args);
|
|
424
|
+
const { spans, workflow } = await collectSpans(args);
|
|
351
425
|
if (spans.length === 0) throw new Error("no spans found for the given selection");
|
|
426
|
+
warnIncompleteWorkflow(workflow);
|
|
352
427
|
const path = await writeOtlpFile(spans, args.otlp);
|
|
353
428
|
console.log(`wrote ${spans.length} spans \u2192 ${path}`);
|
|
354
429
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
async function collectSessionRows(args, bindExplicitSource = false) {
|
|
361
|
-
if (args.session) {
|
|
362
|
-
const { adapter, ref } = await resolveSelectedSession(args);
|
|
363
|
-
if (!bindExplicitSource) return [{ ref, spans: await parseSession(adapter, ref) }];
|
|
364
|
-
const before = await sourceSha256(ref.path);
|
|
365
|
-
const spans = await parseSession(adapter, ref);
|
|
366
|
-
const after = await sourceSha256(ref.path);
|
|
367
|
-
if (before !== after) {
|
|
368
|
-
throw new Error(`session source changed while parsing; refusing unbound evidence: ${ref.path}`);
|
|
369
|
-
}
|
|
370
|
-
return [{ ref, spans, sourceSha256: after }];
|
|
430
|
+
function workflowIssueText(issue) {
|
|
431
|
+
if (issue.kind === "cycle") return `cycle: ${issue.sessionIds.join(" -> ")}`;
|
|
432
|
+
if (issue.kind === "unresolved-parent-task") {
|
|
433
|
+
return `cannot resolve parent task for child ${issue.childSessionId} in ${issue.parentSessionId}: ${issue.reason}`;
|
|
371
434
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
for (const { adapter, refs } of groups) {
|
|
375
|
-
for (const ref of refs) rows.push({ ref, spans: await parseSession(adapter, ref) });
|
|
435
|
+
if (issue.kind === "parent-conflict") {
|
|
436
|
+
return `parent conflict for ${issue.sessionId}: declared ${issue.declaredParentSessionId ?? "none"}, referenced by ${issue.referencedParentSessionIds.join(", ") || "none"}`;
|
|
376
437
|
}
|
|
377
|
-
return
|
|
438
|
+
return `${issue.kind} ${issue.sessionId}, referenced as ${issue.relation} by ${issue.referencedBySessionId}`;
|
|
439
|
+
}
|
|
440
|
+
function warnIncompleteWorkflow(workflow) {
|
|
441
|
+
if (!workflow || workflow.complete) return;
|
|
442
|
+
process.stderr.write(
|
|
443
|
+
`warning: session workflow is incomplete (${workflow.issues.length} issue(s)): ${workflow.issues.map(workflowIssueText).join("; ")}
|
|
444
|
+
`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
async function collectSessionRows(args, bindExplicitSource = false, defaultLast = 20) {
|
|
448
|
+
const groups = args.session ? [await resolveSelectedSession(args).then(({ adapter, ref }) => ({ adapter, refs: [ref] }))] : await discover({ ...args, last: args.last || defaultLast });
|
|
449
|
+
return collectSessionSelection(groups, {
|
|
450
|
+
workflow: args.workflow,
|
|
451
|
+
maxWorkflowSessions: args.maxWorkflowSessions,
|
|
452
|
+
taskScope: args.latestTurn ? "latest" : "all",
|
|
453
|
+
bindSources: bindExplicitSource && Boolean(args.session)
|
|
454
|
+
});
|
|
378
455
|
}
|
|
379
456
|
async function cmdEvidence(args) {
|
|
380
|
-
const
|
|
457
|
+
const selection = await collectSessionRows(args, true);
|
|
458
|
+
const rows = selection.rows.filter((row) => row.spans.length > 0);
|
|
381
459
|
if (rows.length === 0) throw new Error("no spans found for the given selection");
|
|
460
|
+
warnIncompleteWorkflow(selection.workflow);
|
|
382
461
|
const otlpPath = args.otlp ? await writeOtlpFile(rows.flatMap((row) => row.spans), args.otlp) : void 0;
|
|
383
462
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
384
463
|
const records = await Promise.all(rows.map(
|
|
@@ -398,8 +477,10 @@ async function cmdEvidence(args) {
|
|
|
398
477
|
}
|
|
399
478
|
}
|
|
400
479
|
async function cmdIndex(args) {
|
|
401
|
-
const
|
|
480
|
+
const selection = await collectSessionRows(args);
|
|
481
|
+
const rows = selection.rows.filter((row) => row.spans.length > 0);
|
|
402
482
|
if (rows.length === 0) throw new Error("no spans found for the given selection");
|
|
483
|
+
warnIncompleteWorkflow(selection.workflow);
|
|
403
484
|
const index = await buildSessionIndexFromRows(rows, {
|
|
404
485
|
minLoopOccurrences: args.minLoop,
|
|
405
486
|
selection: {
|
|
@@ -409,7 +490,9 @@ async function cmdIndex(args) {
|
|
|
409
490
|
last: args.last || void 0,
|
|
410
491
|
session: args.session,
|
|
411
492
|
cwd: args.cwd,
|
|
412
|
-
since: args.since
|
|
493
|
+
since: args.since,
|
|
494
|
+
latestTurn: args.latestTurn || void 0,
|
|
495
|
+
...selection.workflow ? { workflow: selection.workflow } : {}
|
|
413
496
|
}
|
|
414
497
|
});
|
|
415
498
|
if (args.out) {
|
|
@@ -447,8 +530,8 @@ async function cmdExport(args) {
|
|
|
447
530
|
}
|
|
448
531
|
function traceEvidenceFormat(raw) {
|
|
449
532
|
const format = raw ?? "auto";
|
|
450
|
-
if (format !== "auto" && format !== "policy-evidence" && format !== "sandbox-events" && format !== "openinference" && format !== "intelligence-spans") {
|
|
451
|
-
throw new Error("--format must be auto, policy-evidence, sandbox-events, openinference, or
|
|
533
|
+
if (format !== "auto" && format !== "policy-evidence" && format !== "sandbox-events" && format !== "openinference" && format !== "intelligence-spans" && format !== "chat-trajectory") {
|
|
534
|
+
throw new Error("--format must be auto, policy-evidence, sandbox-events, openinference, intelligence-spans, or chat-trajectory");
|
|
452
535
|
}
|
|
453
536
|
return format;
|
|
454
537
|
}
|
|
@@ -546,7 +629,7 @@ async function collectImportedSpans(args) {
|
|
|
546
629
|
}
|
|
547
630
|
function externalAnalyzersFromArgs(args) {
|
|
548
631
|
return args.analyzers.map(
|
|
549
|
-
(spec) => spec === "halo" ? haloAnalyzer({ defaultPrompt: args.analyzerPrompt, model: args.model }) : commandAnalyzer({ name: spec, command: spec, args: (p, prompt) => prompt ? [p, prompt] : [p] })
|
|
632
|
+
(spec) => spec === "halo" ? haloAnalyzer({ defaultPrompt: args.analyzerPrompt, model: args.model }) : spec === "hodoscope" ? hodoscopeAnalyzer({ summarizeModel: args.model }) : commandAnalyzer({ name: spec, command: spec, args: (p, prompt) => prompt ? [p, prompt] : [p] })
|
|
550
633
|
);
|
|
551
634
|
}
|
|
552
635
|
async function cmdInvestigate(args) {
|
|
@@ -559,18 +642,20 @@ async function cmdInvestigate(args) {
|
|
|
559
642
|
}
|
|
560
643
|
}
|
|
561
644
|
async function investigate(args, options = {}) {
|
|
562
|
-
const { spans, harness, cwds, sources } = await collectSpans(args);
|
|
645
|
+
const { spans, harness, cwds, sources, workflow } = await collectSpans(args);
|
|
563
646
|
if (spans.length === 0) throw new Error("no spans found for the given selection");
|
|
564
647
|
const config = args.config !== void 0 || options.loadDefaultConfig !== false ? await loadTracesConfig(args.config) : void 0;
|
|
565
|
-
const
|
|
648
|
+
const analystModel = args.model ?? process.env.TRACES_ANALYST_MODEL ?? DEFAULT_ANALYST_MODEL;
|
|
649
|
+
const ai = args.llm ? await buildAxService(analystModel) : void 0;
|
|
566
650
|
return runTraceInvestigation(mergeTracesConfig({
|
|
567
651
|
spans,
|
|
568
652
|
harness,
|
|
569
653
|
sources,
|
|
654
|
+
workflow,
|
|
570
655
|
cwds,
|
|
571
656
|
minLoopOccurrences: args.minLoop,
|
|
572
657
|
ai,
|
|
573
|
-
model: args.model,
|
|
658
|
+
model: args.llm ? analystModel : args.model,
|
|
574
659
|
budgetUsd: args.budget,
|
|
575
660
|
otlpOutPath: args.otlp,
|
|
576
661
|
externalAnalyzers: externalAnalyzersFromArgs(args),
|
|
@@ -580,19 +665,21 @@ async function investigate(args, options = {}) {
|
|
|
580
665
|
}, config));
|
|
581
666
|
}
|
|
582
667
|
async function cmdImprove(args) {
|
|
583
|
-
const { spans, harness, cwds, sources } = await collectSpans(args);
|
|
668
|
+
const { spans, harness, cwds, sources, workflow } = await collectSpans(args);
|
|
584
669
|
if (spans.length === 0) throw new Error("no spans found for the given selection");
|
|
585
670
|
const config = await loadTracesConfig(args.config);
|
|
586
|
-
const
|
|
671
|
+
const analystModel = args.model ?? process.env.TRACES_ANALYST_MODEL ?? DEFAULT_ANALYST_MODEL;
|
|
672
|
+
const ai = args.llm ? await buildAxService(analystModel) : void 0;
|
|
587
673
|
const result = await runTraceImprovement({
|
|
588
674
|
...mergeTracesConfig({
|
|
589
675
|
spans,
|
|
590
676
|
harness,
|
|
591
677
|
sources,
|
|
678
|
+
workflow,
|
|
592
679
|
cwds,
|
|
593
680
|
minLoopOccurrences: args.minLoop,
|
|
594
681
|
ai,
|
|
595
|
-
model: args.model,
|
|
682
|
+
model: args.llm ? analystModel : args.model,
|
|
596
683
|
budgetUsd: args.budget,
|
|
597
684
|
otlpOutPath: args.otlp,
|
|
598
685
|
externalAnalyzers: externalAnalyzersFromArgs(args),
|
|
@@ -819,6 +906,7 @@ Input formats:
|
|
|
819
906
|
sandbox-events JSON arrays with start/raw/result/done/error events
|
|
820
907
|
openinference Existing OpenInference JSONL; rewrites through traces redaction
|
|
821
908
|
intelligence-spans JSONL rows exported from Tangle Intelligence trace spans
|
|
909
|
+
chat-trajectory A message array or objects with a messages array
|
|
822
910
|
auto Detect the format from the file contents (default)
|
|
823
911
|
|
|
824
912
|
Examples:
|
|
@@ -855,7 +943,12 @@ Options:
|
|
|
855
943
|
--harness <id> Harness or alias (default: claude-code). Known: ${knownHarnesses().join(", ")}
|
|
856
944
|
--all Sweep every known harness
|
|
857
945
|
--last <n> Most-recent N sessions
|
|
946
|
+
--current Analyze the active Codex session named by CODEX_THREAD_ID
|
|
947
|
+
--latest-turn Limit a resumed Codex or Claude Code session to its latest task turn
|
|
858
948
|
--session <id|path> Analyze one listed session ID or one explicit harness session file
|
|
949
|
+
--workflow Expand selected sessions through stable parent/child session IDs
|
|
950
|
+
--max-workflow-sessions <n>
|
|
951
|
+
Stop workflow expansion before parsing more than N files (default 100)
|
|
859
952
|
--cwd <dir> Filter sessions by working directory
|
|
860
953
|
--supervisor-run-dir <dir>
|
|
861
954
|
analyze: report a SUPERVISION TREE instead of harness sessions \u2014
|
|
@@ -865,7 +958,7 @@ Options:
|
|
|
865
958
|
--out <path> Write report to a file
|
|
866
959
|
--dir <path> improve: write artifacts to this directory
|
|
867
960
|
--otlp <path> OTLP artifact path (also evidence provenance / dry-run upload preview)
|
|
868
|
-
--format <kind> analyze/export
|
|
961
|
+
--format <kind> analyze/export: auto | policy-evidence | sandbox-events | openinference | intelligence-spans | chat-trajectory
|
|
869
962
|
--metadata <json> analyze/export file: attach JSON object fields as span attributes
|
|
870
963
|
--attr <k=v> analyze/export file: attach one span attribute (repeatable)
|
|
871
964
|
--mode <kind> stream: visualizer | findings | agent (default visualizer)
|
|
@@ -873,10 +966,10 @@ Options:
|
|
|
873
966
|
--no-spans stream: omit per-span pulse events
|
|
874
967
|
--no-findings stream: omit semantic live-finding events
|
|
875
968
|
--llm Enable agentic RLM analysts (needs OPENAI_API_KEY / OPENAI_BASE_URL)
|
|
876
|
-
--model <id> --llm
|
|
969
|
+
--model <id> Model for --llm, HALO, and Hodoscope (default for --llm: ${DEFAULT_ANALYST_MODEL})
|
|
877
970
|
--config <path> investigate/improve/stream: JS config with analysts, liveAnalysts, or external analyzers
|
|
878
971
|
--budget <usd> USD cap for agentic analysts
|
|
879
|
-
--analyzer <
|
|
972
|
+
--analyzer <id> analyze: also run halo, hodoscope, or an installed command (repeatable)
|
|
880
973
|
--analyzer-prompt <p> analyze: prompt passed to external analyzers (default: diagnose)
|
|
881
974
|
--interval <s> watch/stream: poll interval seconds (default 5)
|
|
882
975
|
--window <m> watch/stream: only sessions active in the last N minutes (default 30)
|
|
@@ -896,12 +989,13 @@ async function main() {
|
|
|
896
989
|
console.log(`traces ${packageVersion()}`);
|
|
897
990
|
return;
|
|
898
991
|
}
|
|
899
|
-
const
|
|
900
|
-
if (
|
|
901
|
-
if (
|
|
992
|
+
const parsedArgs = parseArgs(rawArgs);
|
|
993
|
+
if (parsedArgs.help) {
|
|
994
|
+
if (parsedArgs.command === "export" || parsedArgs.command === "help" && parsedArgs.input === "export") usageExport();
|
|
902
995
|
else usage();
|
|
903
996
|
return;
|
|
904
997
|
}
|
|
998
|
+
const args = validateWorkflowSelection(applyCurrentSessionSelection(parsedArgs));
|
|
905
999
|
switch (args.command) {
|
|
906
1000
|
case "help":
|
|
907
1001
|
if (args.input === "export") usageExport();
|