agent-inspect 6.7.3 → 6.7.4

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +1 -1
  3. package/packages/cli/dist/{chunk-EMYDJREA.mjs → chunk-FVEQ7JFF.mjs} +227 -201
  4. package/packages/cli/dist/chunk-FVEQ7JFF.mjs.map +1 -0
  5. package/packages/cli/dist/index.cjs +247 -209
  6. package/packages/cli/dist/index.cjs.map +1 -1
  7. package/packages/cli/dist/index.mjs +16 -5
  8. package/packages/cli/dist/index.mjs.map +1 -1
  9. package/packages/cli/dist/{src-IPJNFV37.mjs → src-I5NA7BLK.mjs} +3 -3
  10. package/packages/cli/dist/{src-IPJNFV37.mjs.map → src-I5NA7BLK.mjs.map} +1 -1
  11. package/packages/core/dist/advanced.cjs +225 -199
  12. package/packages/core/dist/advanced.cjs.map +1 -1
  13. package/packages/core/dist/advanced.mjs +26 -241
  14. package/packages/core/dist/advanced.mjs.map +1 -1
  15. package/packages/core/dist/{chunk-X2FLDF7M.mjs → chunk-CTA6XNDP.mjs} +3 -3
  16. package/packages/core/dist/{chunk-X2FLDF7M.mjs.map → chunk-CTA6XNDP.mjs.map} +1 -1
  17. package/packages/core/dist/{chunk-3USJVBLA.mjs → chunk-KDDU2R5P.mjs} +236 -5
  18. package/packages/core/dist/chunk-KDDU2R5P.mjs.map +1 -0
  19. package/packages/core/dist/{chunk-E5F2LQCX.mjs → chunk-T5MASTIW.mjs} +15 -4
  20. package/packages/core/dist/chunk-T5MASTIW.mjs.map +1 -0
  21. package/packages/core/dist/{chunk-KNYL56KZ.mjs → chunk-UOPVGCOB.mjs} +3 -3
  22. package/packages/core/dist/{chunk-KNYL56KZ.mjs.map → chunk-UOPVGCOB.mjs.map} +1 -1
  23. package/packages/core/dist/exporters.cjs +136 -129
  24. package/packages/core/dist/exporters.cjs.map +1 -1
  25. package/packages/core/dist/exporters.mjs +1 -1
  26. package/packages/core/dist/logs.cjs +13 -2
  27. package/packages/core/dist/logs.cjs.map +1 -1
  28. package/packages/core/dist/logs.mjs +2 -2
  29. package/packages/core/dist/persisted.cjs +13 -2
  30. package/packages/core/dist/persisted.cjs.map +1 -1
  31. package/packages/core/dist/persisted.mjs +3 -3
  32. package/packages/core/dist/readers.cjs +13 -2
  33. package/packages/core/dist/readers.cjs.map +1 -1
  34. package/packages/core/dist/readers.mjs +3 -3
  35. package/packages/cli/dist/chunk-EMYDJREA.mjs.map +0 -1
  36. package/packages/core/dist/chunk-3USJVBLA.mjs.map +0 -1
  37. package/packages/core/dist/chunk-E5F2LQCX.mjs.map +0 -1
@@ -3394,6 +3394,202 @@ function filterTraces(traces, options) {
3394
3394
  return out;
3395
3395
  }
3396
3396
 
3397
+ // packages/core/src/stats.ts
3398
+ function percentile(sorted, p) {
3399
+ if (sorted.length === 0) return void 0;
3400
+ const idx = Math.min(
3401
+ sorted.length - 1,
3402
+ Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
3403
+ );
3404
+ return sorted[idx];
3405
+ }
3406
+ async function readRunStartedMetadata(filePath) {
3407
+ try {
3408
+ const events = await readTraceEventsFromFile(filePath);
3409
+ for (const event of events) {
3410
+ if (event.event !== "run_started") continue;
3411
+ const rs = event;
3412
+ if (rs.metadata && typeof rs.metadata === "object") {
3413
+ return rs.metadata;
3414
+ }
3415
+ return void 0;
3416
+ }
3417
+ } catch {
3418
+ }
3419
+ return void 0;
3420
+ }
3421
+ function metaMatchesCorrelation(metadata, correlationId, groupId) {
3422
+ if (correlationId) {
3423
+ const v = metadata?.correlationId;
3424
+ if (typeof v !== "string" || v !== correlationId) return false;
3425
+ }
3426
+ if (groupId) {
3427
+ const v = metadata?.groupId;
3428
+ if (typeof v !== "string" || v !== groupId) return false;
3429
+ }
3430
+ return true;
3431
+ }
3432
+ async function buildTraceStats(metas, options) {
3433
+ let filtered = filterTraces(metas, { since: options.since });
3434
+ if (options.correlationId || options.groupId) {
3435
+ const next = [];
3436
+ for (const m of filtered) {
3437
+ const md = await readRunStartedMetadata(m.filePath);
3438
+ if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
3439
+ next.push(m);
3440
+ }
3441
+ }
3442
+ filtered = next;
3443
+ }
3444
+ let successCount = 0;
3445
+ let errorCount = 0;
3446
+ let runningCount = 0;
3447
+ let unknownCount = 0;
3448
+ const durations = [];
3449
+ let totalSteps = 0;
3450
+ let totalLlmSteps = 0;
3451
+ let totalToolSteps = 0;
3452
+ let totalErrorSteps = 0;
3453
+ const slowestRuns = [];
3454
+ const slowestSteps = [];
3455
+ for (const m of filtered) {
3456
+ if (m.status === "success") successCount += 1;
3457
+ else if (m.status === "error") errorCount += 1;
3458
+ else if (m.status === "running") runningCount += 1;
3459
+ else unknownCount += 1;
3460
+ if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
3461
+ durations.push(m.durationMs);
3462
+ slowestRuns.push({
3463
+ runId: m.runId,
3464
+ name: m.name,
3465
+ durationMs: m.durationMs,
3466
+ status: m.status
3467
+ });
3468
+ }
3469
+ try {
3470
+ const events = await readTraceEventsFromFile(m.filePath);
3471
+ if (events.length === 0) continue;
3472
+ const summary = buildRunSummary(events);
3473
+ totalSteps += summary.totalSteps;
3474
+ totalLlmSteps += summary.llmSteps;
3475
+ totalToolSteps += summary.toolSteps;
3476
+ totalErrorSteps += summary.errorSteps;
3477
+ const steps = collectCompletedSteps(events, m.runId);
3478
+ for (const s of steps) {
3479
+ slowestSteps.push(s);
3480
+ }
3481
+ } catch {
3482
+ }
3483
+ }
3484
+ slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
3485
+ slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
3486
+ const runLimit = options.slowRunLimit ?? 5;
3487
+ const stepLimit = options.slowStepLimit ?? 5;
3488
+ const sortedDur = [...durations].sort((a, b) => a - b);
3489
+ const totalRuns = filtered.length;
3490
+ const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
3491
+ const sumDur = durations.reduce((a, b) => a + b, 0);
3492
+ return {
3493
+ traceDir: options.traceDir,
3494
+ ...options.since ? { since: options.since } : {},
3495
+ ...options.correlationId ? { correlationId: options.correlationId } : {},
3496
+ ...options.groupId ? { groupId: options.groupId } : {},
3497
+ totalRuns,
3498
+ successCount,
3499
+ errorCount,
3500
+ runningCount,
3501
+ unknownCount,
3502
+ errorRate,
3503
+ duration: {
3504
+ ...sortedDur.length > 0 ? {
3505
+ minMs: sortedDur[0],
3506
+ maxMs: sortedDur[sortedDur.length - 1],
3507
+ avgMs: sumDur / sortedDur.length,
3508
+ p50Ms: percentile(sortedDur, 50),
3509
+ p95Ms: percentile(sortedDur, 95)
3510
+ } : {}
3511
+ },
3512
+ totalSteps,
3513
+ avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
3514
+ totalLlmSteps,
3515
+ totalToolSteps,
3516
+ totalErrorSteps,
3517
+ slowestRuns: slowestRuns.slice(0, runLimit),
3518
+ slowestSteps: slowestSteps.slice(0, stepLimit)
3519
+ };
3520
+ }
3521
+ function collectCompletedSteps(events, runId) {
3522
+ const started = /* @__PURE__ */ new Map();
3523
+ const out = [];
3524
+ for (const e of events) {
3525
+ if (e.event === "step_started") {
3526
+ const s = e;
3527
+ started.set(s.stepId, { name: s.name, type: s.type });
3528
+ }
3529
+ if (e.event === "step_completed") {
3530
+ const c = e;
3531
+ if (c.status !== "success" && c.status !== "error") continue;
3532
+ if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
3533
+ continue;
3534
+ }
3535
+ const meta = started.get(c.stepId);
3536
+ out.push({
3537
+ runId,
3538
+ stepName: meta?.name ?? c.stepId,
3539
+ stepType: meta?.type ?? "logic",
3540
+ durationMs: c.durationMs
3541
+ });
3542
+ }
3543
+ }
3544
+ return out;
3545
+ }
3546
+ function formatStepLabel(stepType, stepName) {
3547
+ return stepName.startsWith(`${stepType}:`) ? stepName : `${stepType}:${stepName}`;
3548
+ }
3549
+ function renderTraceStats(stats) {
3550
+ const lines = [];
3551
+ lines.push("Trace stats (local)");
3552
+ lines.push(`Directory: ${stats.traceDir}`);
3553
+ if (stats.since) lines.push(`Since: ${stats.since}`);
3554
+ if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
3555
+ if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
3556
+ lines.push("");
3557
+ lines.push(`Runs: ${stats.totalRuns}`);
3558
+ lines.push(
3559
+ ` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
3560
+ );
3561
+ lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
3562
+ if (stats.duration.avgMs !== void 0) {
3563
+ lines.push(
3564
+ `Duration: min ${formatDuration2(stats.duration.minMs ?? 0)} | avg ${formatDuration2(stats.duration.avgMs)} | p50 ${formatDuration2(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration2(stats.duration.p95Ms ?? 0)} | max ${formatDuration2(stats.duration.maxMs ?? 0)}`
3565
+ );
3566
+ }
3567
+ lines.push("");
3568
+ lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
3569
+ lines.push(
3570
+ ` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
3571
+ );
3572
+ if (stats.slowestRuns.length > 0) {
3573
+ lines.push("");
3574
+ lines.push("Slowest runs:");
3575
+ for (const r of stats.slowestRuns) {
3576
+ lines.push(
3577
+ ` ${r.runId} | ${r.name ?? "-"} | ${formatDuration2(r.durationMs ?? 0)} | ${r.status}`
3578
+ );
3579
+ }
3580
+ }
3581
+ if (stats.slowestSteps.length > 0) {
3582
+ lines.push("");
3583
+ lines.push("Slowest steps:");
3584
+ for (const s of stats.slowestSteps) {
3585
+ lines.push(
3586
+ ` ${s.runId} | ${formatStepLabel(s.stepType, s.stepName)} | ${formatDuration2(s.durationMs)}`
3587
+ );
3588
+ }
3589
+ }
3590
+ return lines.join("\n");
3591
+ }
3592
+
3397
3593
  // packages/core/src/timeline.ts
3398
3594
  function finite(n) {
3399
3595
  return typeof n === "number" && Number.isFinite(n);
@@ -3551,7 +3747,7 @@ function renderTimeline(timeline, options = {}) {
3551
3747
  const dur = e.durationMs !== void 0 ? formatDuration2(e.durationMs) : "-";
3552
3748
  const err = e.isError ? " error" : "";
3553
3749
  const off = formatDuration2(e.offsetMs);
3554
- let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
3750
+ let line = `${prefix}+${off} ${formatStepLabel(typeTag, e.name)} (${dur})${err}`;
3555
3751
  if (e.streaming?.chunkCount !== void 0) {
3556
3752
  line += ` chunks=${e.streaming.chunkCount}`;
3557
3753
  }
@@ -3703,6 +3899,12 @@ function renderRunWhat(summary, options = {}) {
3703
3899
  }
3704
3900
 
3705
3901
  // packages/core/src/explain.ts
3902
+ function toDisplayStatus(status) {
3903
+ if (status === "ok") return "success";
3904
+ if (status === "error") return "error";
3905
+ if (status === "running") return "running";
3906
+ return "unknown";
3907
+ }
3706
3908
  function flatten(nodes, out = []) {
3707
3909
  for (const node of nodes) {
3708
3910
  out.push({ node, index: out.length + 1 });
@@ -3760,7 +3962,7 @@ function buildFacts(run, redactor) {
3760
3962
  const facts = [
3761
3963
  fact("run.id", "Run id", run.runId, redactor),
3762
3964
  fact("run.name", "Run name", run.name ?? run.runId, redactor),
3763
- fact("run.status", "Run status", run.status ?? "unknown", redactor),
3965
+ fact("run.status", "Run status", toDisplayStatus(run.status), redactor),
3764
3966
  fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
3765
3967
  fact("run.stepCount", "Top-level step count", run.children.length, redactor),
3766
3968
  fact("run.nodeCount", "Total node count", nodes.length, redactor),
@@ -3836,7 +4038,7 @@ function buildLocalExplanation(run, options = {}) {
3836
4038
  mode,
3837
4039
  runId: String(redactValue(redactor, "runId", run.runId)),
3838
4040
  ...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
3839
- ...run.status !== void 0 ? { status: run.status } : {},
4041
+ ...run.status !== void 0 ? { status: toDisplayStatus(run.status) } : {},
3840
4042
  redactionProfile,
3841
4043
  facts,
3842
4044
  inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
@@ -3847,199 +4049,6 @@ function buildLocalExplanation(run, options = {}) {
3847
4049
  };
3848
4050
  }
3849
4051
 
3850
- // packages/core/src/stats.ts
3851
- function percentile(sorted, p) {
3852
- if (sorted.length === 0) return void 0;
3853
- const idx = Math.min(
3854
- sorted.length - 1,
3855
- Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
3856
- );
3857
- return sorted[idx];
3858
- }
3859
- async function readRunStartedMetadata(filePath) {
3860
- try {
3861
- const events = await readTraceEventsFromFile(filePath);
3862
- for (const event of events) {
3863
- if (event.event !== "run_started") continue;
3864
- const rs = event;
3865
- if (rs.metadata && typeof rs.metadata === "object") {
3866
- return rs.metadata;
3867
- }
3868
- return void 0;
3869
- }
3870
- } catch {
3871
- }
3872
- return void 0;
3873
- }
3874
- function metaMatchesCorrelation(metadata, correlationId, groupId) {
3875
- if (correlationId) {
3876
- const v = metadata?.correlationId;
3877
- if (typeof v !== "string" || v !== correlationId) return false;
3878
- }
3879
- if (groupId) {
3880
- const v = metadata?.groupId;
3881
- if (typeof v !== "string" || v !== groupId) return false;
3882
- }
3883
- return true;
3884
- }
3885
- async function buildTraceStats(metas, options) {
3886
- let filtered = filterTraces(metas, { since: options.since });
3887
- if (options.correlationId || options.groupId) {
3888
- const next = [];
3889
- for (const m of filtered) {
3890
- const md = await readRunStartedMetadata(m.filePath);
3891
- if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
3892
- next.push(m);
3893
- }
3894
- }
3895
- filtered = next;
3896
- }
3897
- let successCount = 0;
3898
- let errorCount = 0;
3899
- let runningCount = 0;
3900
- let unknownCount = 0;
3901
- const durations = [];
3902
- let totalSteps = 0;
3903
- let totalLlmSteps = 0;
3904
- let totalToolSteps = 0;
3905
- let totalErrorSteps = 0;
3906
- const slowestRuns = [];
3907
- const slowestSteps = [];
3908
- for (const m of filtered) {
3909
- if (m.status === "success") successCount += 1;
3910
- else if (m.status === "error") errorCount += 1;
3911
- else if (m.status === "running") runningCount += 1;
3912
- else unknownCount += 1;
3913
- if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
3914
- durations.push(m.durationMs);
3915
- slowestRuns.push({
3916
- runId: m.runId,
3917
- name: m.name,
3918
- durationMs: m.durationMs,
3919
- status: m.status
3920
- });
3921
- }
3922
- try {
3923
- const events = await readTraceEventsFromFile(m.filePath);
3924
- if (events.length === 0) continue;
3925
- const summary = buildRunSummary(events);
3926
- totalSteps += summary.totalSteps;
3927
- totalLlmSteps += summary.llmSteps;
3928
- totalToolSteps += summary.toolSteps;
3929
- totalErrorSteps += summary.errorSteps;
3930
- const steps = collectCompletedSteps(events, m.runId);
3931
- for (const s of steps) {
3932
- slowestSteps.push(s);
3933
- }
3934
- } catch {
3935
- }
3936
- }
3937
- slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
3938
- slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
3939
- const runLimit = options.slowRunLimit ?? 5;
3940
- const stepLimit = options.slowStepLimit ?? 5;
3941
- const sortedDur = [...durations].sort((a, b) => a - b);
3942
- const totalRuns = filtered.length;
3943
- const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
3944
- const sumDur = durations.reduce((a, b) => a + b, 0);
3945
- return {
3946
- traceDir: options.traceDir,
3947
- ...options.since ? { since: options.since } : {},
3948
- ...options.correlationId ? { correlationId: options.correlationId } : {},
3949
- ...options.groupId ? { groupId: options.groupId } : {},
3950
- totalRuns,
3951
- successCount,
3952
- errorCount,
3953
- runningCount,
3954
- unknownCount,
3955
- errorRate,
3956
- duration: {
3957
- ...sortedDur.length > 0 ? {
3958
- minMs: sortedDur[0],
3959
- maxMs: sortedDur[sortedDur.length - 1],
3960
- avgMs: sumDur / sortedDur.length,
3961
- p50Ms: percentile(sortedDur, 50),
3962
- p95Ms: percentile(sortedDur, 95)
3963
- } : {}
3964
- },
3965
- totalSteps,
3966
- avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
3967
- totalLlmSteps,
3968
- totalToolSteps,
3969
- totalErrorSteps,
3970
- slowestRuns: slowestRuns.slice(0, runLimit),
3971
- slowestSteps: slowestSteps.slice(0, stepLimit)
3972
- };
3973
- }
3974
- function collectCompletedSteps(events, runId) {
3975
- const started = /* @__PURE__ */ new Map();
3976
- const out = [];
3977
- for (const e of events) {
3978
- if (e.event === "step_started") {
3979
- const s = e;
3980
- started.set(s.stepId, { name: s.name, type: s.type });
3981
- }
3982
- if (e.event === "step_completed") {
3983
- const c = e;
3984
- if (c.status !== "success" && c.status !== "error") continue;
3985
- if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
3986
- continue;
3987
- }
3988
- const meta = started.get(c.stepId);
3989
- out.push({
3990
- runId,
3991
- stepName: meta?.name ?? c.stepId,
3992
- stepType: meta?.type ?? "logic",
3993
- durationMs: c.durationMs
3994
- });
3995
- }
3996
- }
3997
- return out;
3998
- }
3999
- function renderTraceStats(stats) {
4000
- const lines = [];
4001
- lines.push("Trace stats (local)");
4002
- lines.push(`Directory: ${stats.traceDir}`);
4003
- if (stats.since) lines.push(`Since: ${stats.since}`);
4004
- if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
4005
- if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
4006
- lines.push("");
4007
- lines.push(`Runs: ${stats.totalRuns}`);
4008
- lines.push(
4009
- ` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
4010
- );
4011
- lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
4012
- if (stats.duration.avgMs !== void 0) {
4013
- lines.push(
4014
- `Duration: min ${formatDuration2(stats.duration.minMs ?? 0)} | avg ${formatDuration2(stats.duration.avgMs)} | p50 ${formatDuration2(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration2(stats.duration.p95Ms ?? 0)} | max ${formatDuration2(stats.duration.maxMs ?? 0)}`
4015
- );
4016
- }
4017
- lines.push("");
4018
- lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
4019
- lines.push(
4020
- ` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
4021
- );
4022
- if (stats.slowestRuns.length > 0) {
4023
- lines.push("");
4024
- lines.push("Slowest runs:");
4025
- for (const r of stats.slowestRuns) {
4026
- lines.push(
4027
- ` ${r.runId} | ${r.name ?? "-"} | ${formatDuration2(r.durationMs ?? 0)} | ${r.status}`
4028
- );
4029
- }
4030
- }
4031
- if (stats.slowestSteps.length > 0) {
4032
- lines.push("");
4033
- lines.push("Slowest steps:");
4034
- for (const s of stats.slowestSteps) {
4035
- lines.push(
4036
- ` ${s.runId} | ${s.stepType}:${s.stepName} | ${formatDuration2(s.durationMs)}`
4037
- );
4038
- }
4039
- }
4040
- return lines.join("\n");
4041
- }
4042
-
4043
4052
  // packages/core/src/search.ts
4044
4053
  function parseDurationFilter(expr) {
4045
4054
  const raw = expr.trim();
@@ -4106,6 +4115,12 @@ async function searchTraces(metas, options) {
4106
4115
  ...sessionLabel ? { sessionId: sessionLabel } : {}
4107
4116
  });
4108
4117
  }
4118
+ results.sort((a, b) => {
4119
+ const ta = a.timestamp ?? 0;
4120
+ const tb = b.timestamp ?? 0;
4121
+ if (ta !== tb) return tb - ta;
4122
+ return a.runId.localeCompare(b.runId);
4123
+ });
4109
4124
  return results.slice(0, limit);
4110
4125
  }
4111
4126
  for (const m of filtered) {
@@ -4153,7 +4168,7 @@ async function searchTraces(metas, options) {
4153
4168
  results.sort((a, b) => {
4154
4169
  const ta = a.timestamp ?? 0;
4155
4170
  const tb = b.timestamp ?? 0;
4156
- if (ta !== tb) return ta - tb;
4171
+ if (ta !== tb) return tb - ta;
4157
4172
  const runCmp = a.runId.localeCompare(b.runId);
4158
4173
  if (runCmp !== 0) return runCmp;
4159
4174
  return (a.stepName ?? "").localeCompare(b.stepName ?? "");
@@ -6421,13 +6436,24 @@ function inc(map, key) {
6421
6436
  map[key] = (map[key] ?? 0) + 1;
6422
6437
  }
6423
6438
  function computeRunStatus(events) {
6439
+ let runTerminal;
6440
+ let sawRunEvent = false;
6441
+ for (const e of events) {
6442
+ if (e.kind !== "RUN") continue;
6443
+ sawRunEvent = true;
6444
+ if (e.status === "ok" || e.status === "error") {
6445
+ runTerminal = e.status;
6446
+ }
6447
+ }
6448
+ if (sawRunEvent) {
6449
+ return runTerminal ?? "running";
6450
+ }
6424
6451
  let hasRunning = false;
6425
6452
  for (const e of events) {
6426
6453
  if (e.status === "error") return "error";
6427
6454
  if (e.status === "running") hasRunning = true;
6428
6455
  }
6429
- if (hasRunning) return "running";
6430
- return "ok";
6456
+ return hasRunning ? "running" : "ok";
6431
6457
  }
6432
6458
  var TreeBuilder = class {
6433
6459
  constructor(options) {