@tangle-network/charts 2.0.4 → 2.0.6

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.
@@ -177,7 +177,7 @@
177
177
  .fw-root .fw-agent-dot { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; background: var(--tone, var(--fw-muted)); }
178
178
  .fw-root .fw-agent-dot:not([data-outcome]) { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fw-muted); }
179
179
  .fw-root :is(.fw-agent-dot, .fw-legend .fw-swatch)[data-ring] { background: transparent; box-shadow: inset 0 0 0 1.5px var(--tone, var(--fw-muted)); }
180
- .fw-root :is(.fw-agent-dot, .fw-legend .fw-swatch)[data-outcome="live"]:not([data-ring]) { animation: tangle-breathe var(--motion-ambient) infinite; }
180
+ .fw-root .fw-agent-dot[data-outcome="live"]:not([data-ring]) { animation: tangle-breathe var(--motion-ambient) infinite; }
181
181
 
182
182
  .fw-root .fw-lane { position: relative; overflow: hidden; min-width: 0; }
183
183
  .fw-root .fw-invalid { position: absolute; left: var(--fw-pad); top: 50%; transform: translateY(-50%); color: var(--fw-muted); }
@@ -221,7 +221,7 @@
221
221
  .fw-root [data-outcome], .fw-root [data-outcome] [data-tone] { --tone: var(--outcome-tone); }
222
222
  .fw-root.fw-root .fw-agent-dot[data-outcome] { --tone: var(--outcome-tone); }
223
223
  .fw-root .fw-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 0; padding: 0; list-style: none; color: var(--fw-muted); font-size: 14px; line-height: 18px; }
224
- .fw-root .fw-legend li { display: inline-flex; align-items: center; gap: 8px; }
224
+ .fw-root .fw-legend li { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; max-width: 100%; overflow-wrap: anywhere; }
225
225
  .fw-root .fw-legends { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 24px; margin-top: 8px; }
226
226
  .fw-root .fw-legends .fw-legend { margin: 0; }
227
227
  .fw-root .fw-kinds { margin: 0; padding: 0; justify-content: flex-start; color: var(--fw-muted); }
@@ -270,6 +270,7 @@
270
270
  .fw-root .fw-end { z-index: 2; display: inline-flex; align-items: center; gap: 8px; top: calc(50% + var(--fw-bar-shift) - var(--fw-bar-h) / 2); height: var(--fw-bar-h);
271
271
  left: min(calc(var(--x0) + max(var(--w), 3px) + 4px), calc(100% - var(--fw-end-w, 0px) - 4px)); padding: 0 4px; border-radius: var(--radius-tag);
272
272
  background: linear-gradient(var(--fw-tint, transparent) 0 0), var(--fw-surface); white-space: nowrap; pointer-events: none; }
273
+ .fw-root .fw-outcome-end { display: inline-flex; pointer-events: auto; }
273
274
  .fw-root .fw-duration { font-size: 14px; color: var(--fw-muted); font-variant-numeric: tabular-nums; }
274
275
  .fw-root .fw-k-failed ~ .fw-end .fw-duration { color: var(--fw-failed); }
275
276
  .fw-root .fw-badge { display: inline-flex; flex: none; height: 18px; padding: 0 6px; border-radius: var(--radius-pill); font-size: 12px; line-height: 18px; font-weight: 500; color: var(--fw-muted); background: transparent; box-shadow: inset 0 0 0 1px var(--fw-border); }
@@ -374,37 +375,48 @@
374
375
  .fw-root .fw-key > summary { display: none; }
375
376
  .fw-root .fw-key > summary svg { width: 12px; height: 12px; margin-left: 6px; }
376
377
  .fw-root .fw-key[open] > summary svg { transform: rotate(90deg); }
377
- .fw-root .fw-row-state { display: none; font-size: 12px; font-weight: 600; }
378
+ .fw-root .fw-row-state { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600; }
378
379
  .fw-root .fw-error-rug { position: relative; height: 10px; margin-left: var(--fw-label-col); overflow: hidden; }
379
380
  .fw-root .fw-error-tick { position: absolute; width: 2px; height: 8px; background: var(--fw-failed); left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); }
380
381
  .fw-root .fw-error-tick[data-unlocated] { left: auto; right: calc(var(--error-index) * 3px); }
381
- .fw-root .fw-quiet { color: var(--fw-amber); font-size: 12px; font-weight: 500; white-space: nowrap; }
382
+ .fw-root .fw-quiet { display: inline-flex; align-items: center; gap: 4px; color: var(--fw-amber); font-size: 13px; font-weight: 500; white-space: nowrap; }
383
+ .fw-root .fw-quiet::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
384
+ .fw-root [data-activity="quiet"] :is(.fw-agent-dot[data-outcome="live"], .fw-spinner) { display: none; }
382
385
  .fw-root [data-activity="quiet"] :is(.fw-agent-dot, .fw-spinner) { animation: none !important; }
383
386
  .fw-root .fw-quiet-tail { position: absolute; top: calc(50% + var(--fw-bar-shift) - var(--fw-bar-h) / 2); height: var(--fw-bar-h); left: calc(var(--fw-pad) + (var(--s) - var(--fw-v0)) * var(--fw-k) * 1px); width: calc(max(0, var(--fw-t) - var(--s)) * var(--fw-k) * 1px); background: repeating-linear-gradient(-45deg, var(--fw-hatch) 0 1px, transparent 1px 5px); pointer-events: none; }
384
387
  .fw-root .fw-now { background: color-mix(in oklab, var(--fw-text) 28%, transparent); }
385
388
  .fw-root .fw-card-error { margin-top: 8px; color: var(--fw-failed); font-size: 13px; line-height: 18px; }
386
389
  .fw-root .fw-card .fw-agent-dot:not([data-outcome]) { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fw-muted); }
387
390
  @container flow-waterfall (max-width: 599px) {
388
- .fw-root > * { --fw-label-col: 0px; --fw-bar-shift: 8px; --fw-bar-h: 8px; --fw-row-h: 44px; }
389
- .fw-root .fw-summary > div:nth-child(-n+2) { flex-basis: 50%; padding: 6px 8px; }
391
+ .fw-root > * { --fw-label-col: 0px; --fw-bar-shift: 18px; --fw-bar-h: 8px; --fw-row-h: 52px; }
392
+ .fw-root .fw-summary > div:nth-child(-n+2) { flex: 1 0 auto; display: flex; align-items: baseline; gap: 8px; padding: 6px 8px; }
393
+ .fw-root .fw-summary > div:nth-child(-n+2) .fw-value { margin: 0; font-size: 20px; line-height: 28px; }
394
+ .fw-root .fw-summary::after { content: ""; flex-basis: 100%; }
395
+ .fw-root .fw-summary > div:nth-child(n+3) { order: 1; }
390
396
  .fw-root :is(.fw-zoom, .fw-branch-controls, .fw-resize, .fw-links, .fw-gridlayer, .fw-marker-layer, .fw-subtitle, .fw-badge, .fw-icon-tile) { display: none; }
391
- .fw-root .fw-row-state { display: inline; }
392
- .fw-root .fw-key > summary { display: flex; align-items: center; min-height: 32px; cursor: pointer; }
397
+ .fw-root .fw-key > summary { display: flex; align-items: center; min-height: 32px; cursor: pointer; grid-area: 2 / 2; }
393
398
  .fw-root .fw-key:not([open]) .fw-legends { display: none; }
394
- .fw-root .fw-heading { padding: 12px 8px; }
395
- .fw-root .fw-title-line { flex-wrap: wrap; }
399
+ .fw-root .fw-heading { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 8px; padding: 8px; }
400
+ .fw-root .fw-title-block, .fw-root .fw-key { display: contents; }
401
+ .fw-root .fw-title-line { grid-column: 1 / -1; flex-wrap: wrap; }
402
+ .fw-root .fw-legends { grid-area: 3 / 1 / auto / -1; margin: 4px 0; }
403
+ .fw-root .fw-tools { grid-area: 2 / 1; flex-wrap: wrap; }
404
+ .fw-root .fw-segmented { padding: 2px; }
405
+ .fw-root .fw-segmented button { min-width: 28px; padding: 0 6px; }
406
+ .fw-root.fw-root-agents .fw-playback { padding: 8px; }
407
+ .fw-root.fw-root-agents .fw-overview { margin-top: 0; }
396
408
  .fw-root .fw-search-input { width: 120px; }
397
409
  .fw-root .fw-axis-label { border: 0; padding: 0; }
398
410
  .fw-root .fw-tick:is(:nth-child(2), :nth-child(3)) { transform: translate(-50%, -50%); }
399
411
  .fw-root .fw-tick:nth-child(4) { transform: translate(calc(-100% - 4px), -50%); }
400
412
  .fw-root .fw-row { transform: none; top: var(--row-y); contain: style; }
401
- .fw-root .fw-label { position: absolute; z-index: 3; height: 20px; top: 0; left: 0; right: 0; padding: 0 calc(var(--fw-end-w, 0px) + 8px) 0 calc(8px + var(--depth) * 12px); border: 0; gap: 4px; background: transparent; pointer-events: none; }
413
+ .fw-root .fw-label { position: absolute; z-index: 3; height: 20px; top: 0; left: 0; right: 0; padding: 0 8px 0 calc(8px + var(--depth) * 12px); border: 0; gap: 4px; background: transparent; pointer-events: none; }
414
+ .fw-root .fw-row :is(.fw-row-state, .fw-quiet) { position: absolute; top: 20px; left: calc(28px + var(--depth) * 12px); height: 18px; }
402
415
  .fw-root .fw-view-agents .fw-names { flex-direction: row; font-size: 14px; line-height: 20px; }
403
416
  .fw-root .fw-view-agents :is(.fw-subtitle, .fw-seg-label) { display: none; }
404
417
  .fw-root .fw-view-agents .fw-label { padding-left: calc(8px + var(--depth) * 12px); }
405
418
  .fw-root .fw-lane { grid-column: 2; }
406
- .fw-root .fw-end { top: 0; height: 20px; left: auto; right: 4px; }
407
- .fw-root .fw-duration { font-size: 12px; }
419
+ .fw-root .fw-end { top: 20px; height: 18px; left: auto; right: 4px; }
408
420
  .fw-root .fw-time { display: block; grid-column: 2; position: absolute; top: -12px; left: var(--fw-progress); transform: translateX(calc(-1 * var(--fw-progress))); width: max-content; max-width: 100%; background: var(--fw-surface); }
409
421
  .fw-root .fw-playback { position: relative; padding: 12px 8px 8px; }
410
422
  .fw-root .fw-overview { margin-top: 12px; grid-template-columns: 0 minmax(0, 1fr); column-gap: 0; }
@@ -482,7 +482,7 @@ interface FlowWaterfallProps {
482
482
  defaultView?: FlowView;
483
483
  /** Host graph rendered by the same view control, retaining the trace clock and selection. */
484
484
  graph?: ReactNode;
485
- /** Shared header feed, kept mounted across Agents, Steps and Graph. */
485
+ /** Shared feed after the active view, kept mounted across Agents, Steps and Graph. */
486
486
  latestEvents?: ReactNode;
487
487
  /** Host brand marks by span; the inspector draws kind glyphs without it. */
488
488
  renderIcon?: (span: FlowSpan) => ReactNode;
@@ -6494,6 +6494,7 @@ function RunStatusIcon({ status, className, style, ...props }) {
6494
6494
  }
6495
6495
  //#endregion
6496
6496
  //#region src/react/flow-waterfall-model.ts
6497
+ const workKind = (mark) => mark.kind === "model" || mark.modelCall ? "model" : "tool";
6497
6498
  const toolOf = (name) => name?.split(" · ")[0];
6498
6499
  /** The CSS hue slot: 0 is the root agent's neutral, then five agent hues cycle. */
6499
6500
  const toneKey = (tone) => tone > 0 && tone <= 5 ? tone : 0;
@@ -7085,15 +7086,8 @@ function stepRuns(steps) {
7085
7086
  ...stepStats(run),
7086
7087
  tokens: sumTokens(run),
7087
7088
  own: run.map((step) => ({
7088
- startMs: step.span.startMs,
7089
- endMs: step.span.endMs,
7090
- kind: step.ok ? step.kind === "model" ? "model" : "tool" : "failed",
7091
- tone: first.tone,
7092
- id: step.id,
7093
- count: 1,
7094
- retry: step.retry,
7095
- name: step.name,
7096
- tool: toolOf(step.name)
7089
+ ...segmentOf(step),
7090
+ tone: first.tone
7097
7091
  })),
7098
7092
  ...costs.length ? { rollupCostUsd: costs.reduce((sum, cost) => sum + cost, 0) } : {},
7099
7093
  span: {
@@ -7523,7 +7517,7 @@ const at = (startMs, endMs) => ({
7523
7517
  const endLabelWidth = (label) => label.length * 7 + 8;
7524
7518
  function Segment({ mark, events, agentView }) {
7525
7519
  const glyph = mark.kind === "failed" ? "fail" : mark.retry ? "retry" : null;
7526
- const model = mark.kind === "model" || mark.modelCall;
7520
+ const model = workKind(mark) === "model";
7527
7521
  const name = model ? void 0 : mark.count === 1 ? mark.name : mark.tool;
7528
7522
  const duration = Number.isFinite(mark.endMs) ? formatSpanDuration(mark.endMs - mark.startMs) : "";
7529
7523
  const meta = [duration, mark.costUsd ? formatCost(mark.costUsd) : ""].filter(Boolean).join(" · ");
@@ -7599,12 +7593,13 @@ const FlowRow = memo(function FlowRow(props) {
7599
7593
  const marks = isAgent || row.hasChildren || row.id.startsWith("run:") ? folded && !agentView ? row.segments : row.own : [];
7600
7594
  const label = endLabel(row, clockMs);
7601
7595
  const activity = quietActivity(row, clockMs);
7602
- const summary = [...span.detail && span.detail !== props.sharedDetail ? [span.detail] : [], ...agentSummary(row).filter((part) => part !== props.sharedOutcome)];
7596
+ const summary = [...span.detail && span.detail !== props.sharedDetail ? [span.detail] : [], ...agentSummary(row).filter((part) => part !== props.sharedOutcome && (state === "unknown" || part !== meta.label))];
7603
7597
  const inspect = (event) => props.onInspect(row.id, event.currentTarget, event.clientX);
7604
7598
  const family = agentView && row.id.startsWith("family:");
7605
7599
  const step = agentView && row.stepOf !== void 0;
7606
7600
  const opens = family || agentView && isAgent && row.own.length > 0;
7607
7601
  const outcomes = row.outcomes ?? (span.outcome ? [span.outcome] : []);
7602
+ const failedEnd = isAgent && !family && state === "failed" && Number.isFinite(span.endMs) && span.endMs <= clockMs;
7608
7603
  const callouts = /* @__PURE__ */ jsxs(Fragment, { children: [slowest && /* @__PURE__ */ jsx("span", {
7609
7604
  className: "fw-badge",
7610
7605
  title: agentView ? "Longest elapsed leaf agent" : "Longest elapsed leaf step",
@@ -7633,7 +7628,7 @@ const FlowRow = memo(function FlowRow(props) {
7633
7628
  style: {
7634
7629
  "--row-y": `${top}px`,
7635
7630
  "--fw-enter-delay": `${motion?.enter ?? 0}ms`,
7636
- "--fw-end-w": `${endLabelWidth(label)}px`
7631
+ "--fw-end-w": `${endLabelWidth(label) + (failedEnd ? 20 : 0)}px`
7637
7632
  },
7638
7633
  onFocus: (event) => {
7639
7634
  if (event.target === event.currentTarget) props.onActivate(row);
@@ -7725,13 +7720,19 @@ const FlowRow = memo(function FlowRow(props) {
7725
7720
  children: row.name
7726
7721
  }),
7727
7722
  !agentView && callouts,
7728
- state !== "unknown" && !activity.quiet && /* @__PURE__ */ jsx("span", {
7723
+ state !== "unknown" && !activity.quiet && /* @__PURE__ */ jsxs("span", {
7729
7724
  className: "fw-row-state",
7730
7725
  style: { color: `var(${meta.token})` },
7731
- children: meta.label
7726
+ children: [state !== "running" && /* @__PURE__ */ jsx(RunStatusIcon, {
7727
+ status: state,
7728
+ size: 16,
7729
+ "aria-hidden": true
7730
+ }), meta.label]
7732
7731
  }),
7733
7732
  activity.quiet && /* @__PURE__ */ jsxs("span", {
7734
7733
  className: "fw-quiet",
7734
+ title: "Running; no recorded activity during this interval",
7735
+ "aria-label": `Running; Quiet ${formatSpanDuration(activity.quietMs)} since last recorded activity`,
7735
7736
  children: ["Quiet ", formatSpanDuration(activity.quietMs)]
7736
7737
  })
7737
7738
  ]
@@ -7813,13 +7814,20 @@ const FlowRow = memo(function FlowRow(props) {
7813
7814
  events: props,
7814
7815
  agentView
7815
7816
  }, `${mark.id}-${i}`)),
7816
- /* @__PURE__ */ jsx("span", {
7817
+ /* @__PURE__ */ jsxs("span", {
7817
7818
  className: "fw-end",
7818
7819
  style: at(span.startMs, running ? OPEN_END : span.endMs),
7819
- children: /* @__PURE__ */ jsx("span", {
7820
+ children: [failedEnd && /* @__PURE__ */ jsx("span", {
7821
+ className: "fw-outcome-end",
7822
+ title: "Recorded end of failed agent; failure instant not reported",
7823
+ children: /* @__PURE__ */ jsx(RunStatusIcon, {
7824
+ status: "failed",
7825
+ size: 12
7826
+ })
7827
+ }), /* @__PURE__ */ jsx("span", {
7820
7828
  className: "fw-duration",
7821
7829
  children: label
7822
- })
7830
+ })]
7823
7831
  })
7824
7832
  ] })
7825
7833
  })]
@@ -8032,7 +8040,7 @@ function linksFor(rows, byId, view) {
8032
8040
  function FlowBody(props) {
8033
8041
  const { rows, view, maxHeight, collapsed, searching, slowestId, activeId, selectedId, clockMs, window: win, trackPx, showCursor, zoomed } = props;
8034
8042
  const [narrow, setNarrow] = useState(false);
8035
- const rowHeight = narrow ? 44 : ROW_HEIGHT[view];
8043
+ const rowHeight = narrow ? 52 : ROW_HEIGHT[view];
8036
8044
  const scroller = useRef(null);
8037
8045
  const surface = useRef(null);
8038
8046
  useEffect(() => {
@@ -8327,17 +8335,17 @@ function FlowBody(props) {
8327
8335
  ref: surface,
8328
8336
  children: [
8329
8337
  axis,
8330
- Boolean(props.errorTimes?.length) && /* @__PURE__ */ jsx("div", {
8338
+ Boolean(props.errorEnds?.length) && /* @__PURE__ */ jsx("div", {
8331
8339
  className: "fw-error-rug",
8332
- "aria-label": `${props.errorTimes.length} errors`,
8333
- children: props.errorTimes.map((at, index) => /* @__PURE__ */ jsx("span", {
8340
+ "aria-label": `${props.errorEnds.length} errors`,
8341
+ children: props.errorEnds.map((at, index) => /* @__PURE__ */ jsx("span", {
8334
8342
  className: "fw-error-tick",
8335
8343
  "data-unlocated": at === void 0 || void 0,
8336
8344
  style: {
8337
8345
  "--s": at,
8338
8346
  "--error-index": index
8339
8347
  },
8340
- title: at === void 0 ? "Error time not reported" : `Error at ${formatClock(at)}`
8348
+ title: at === void 0 ? "Error time not reported" : `Recorded end of failed span at ${formatClock(at)}; failure instant not reported`
8341
8349
  }, index))
8342
8350
  }),
8343
8351
  /* @__PURE__ */ jsxs("div", {
@@ -8776,7 +8784,6 @@ function summaryCells(trace, at, durationMs) {
8776
8784
  ]
8777
8785
  };
8778
8786
  }
8779
- /** One legend item per outcome label the agents carry, with its count; nothing when no agent has an outcome. */
8780
8787
  const TONE_ORDER = [
8781
8788
  "failed",
8782
8789
  "warn",
@@ -8784,32 +8791,46 @@ const TONE_ORDER = [
8784
8791
  "neutral",
8785
8792
  "ok"
8786
8793
  ];
8787
- /** What each mark means, as the agent view draws it; a key only for kinds the run has. */
8788
8794
  function KindLegend({ rows, fill }) {
8789
- const has = (kind) => rows.some((row) => row.own.some((mark) => mark.kind === kind) || row.span.kind === kind);
8795
+ const has = (kind) => rows.some((row) => row.own.some((mark) => workKind(mark) === kind) || row.span.kind === kind);
8790
8796
  const shown = [
8791
8797
  ["model", "Model call"],
8792
8798
  ["tool", "Tool call"],
8793
- ["waiting", "Waiting"],
8799
+ ["waiting", "No recorded work"],
8794
8800
  ["handoff", "Handoff"]
8795
8801
  ].filter(([kind]) => kind === "waiting" ? rows.some((row) => row.kind === "pipeline") : kind === "handoff" ? rows.some((row) => row.span.handoffTo || row.hasAgents) : has(kind));
8796
8802
  if (shown.length === 0) return null;
8797
- const example = rows.find((row) => toneKey(row.tone) > 0 && row.own.some((mark) => mark.kind === "model")) ?? rows.find((row) => row.own.length);
8798
8803
  return /* @__PURE__ */ jsxs("ul", {
8799
8804
  className: "fw-legend fw-kinds",
8800
8805
  "aria-label": "Key",
8801
- "data-tone": fill === "agent" ? toneKey(example?.tone ?? 0) : void 0,
8802
- "data-example": example?.id,
8803
- children: [shown.map(([kind, name]) => /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsx("span", {
8804
- className: `fw-swatch-${kind === "waiting" ? "wait" : kind}`,
8805
- "aria-hidden": true
8806
- }), name] }, kind)), /* @__PURE__ */ jsx("li", {
8806
+ children: [shown.map(([kind, name]) => {
8807
+ const examples = rows.flatMap((owner) => owner.own.flatMap((mark) => workKind(mark) === kind ? [{
8808
+ owner,
8809
+ mark
8810
+ }] : []));
8811
+ const example = examples.find(({ mark }) => toneKey(mark.tone) > 0) ?? examples[0];
8812
+ return /* @__PURE__ */ jsxs("li", {
8813
+ "data-tone": fill === "agent" ? toneKey(example?.mark.tone ?? 0) : void 0,
8814
+ "data-example": example?.owner.id,
8815
+ children: [
8816
+ /* @__PURE__ */ jsx("span", {
8817
+ className: `fw-swatch-${kind === "waiting" ? "wait" : kind}`,
8818
+ "aria-hidden": true
8819
+ }),
8820
+ name,
8821
+ example && /* @__PURE__ */ jsxs("span", { children: [
8822
+ "(",
8823
+ example.owner.name,
8824
+ ")"
8825
+ ] })
8826
+ ]
8827
+ }, kind);
8828
+ }), /* @__PURE__ */ jsx("li", {
8807
8829
  className: "fw-kind-rule",
8808
- children: fill === "agent" ? "Bar color identifies family; shade identifies work." : "Shade identifies work."
8830
+ children: fill === "agent" ? "Hue identifies family; shade identifies work. Rail: recorded elapsed time." : "Shade identifies work. Rail: recorded elapsed time."
8809
8831
  })]
8810
8832
  });
8811
8833
  }
8812
- /** The axis dots and the dashed lines they drop: one key naming what they mark (a release, or the kinds the host gave). */
8813
8834
  function MarkerLegend({ markers }) {
8814
8835
  if (!markers?.length) return null;
8815
8836
  const kinds = [...new Set(markers.map((marker) => marker.kind ?? "event"))];
@@ -9277,7 +9298,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
9277
9298
  const quietAgents = agents.filter((row) => quietActivity(row, clockMs).quiet).length;
9278
9299
  const recordedErrors = trace.spans.filter((span) => spanFailed(span) && span.kind !== "pipeline");
9279
9300
  const errorSpans = recordedErrors.length ? recordedErrors : trace.spans.filter(spanFailed);
9280
- const errorTimes = Array.from({ length: errors ?? 0 }, (_, index) => errorSpans[index]?.endMs);
9301
+ const errorEnds = Array.from({ length: errors ?? 0 }, (_, index) => Number.isFinite(errorSpans[index]?.endMs) ? errorSpans[index].endMs : void 0);
9281
9302
  const done = !isLive && !trace.spans.some(spanRunning);
9282
9303
  const shown = (row) => row && drawnRow(row, visible);
9283
9304
  const cardRow = shown(card ? byId.get(card.target) : void 0);
@@ -9455,7 +9476,6 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
9455
9476
  })]
9456
9477
  })]
9457
9478
  }),
9458
- latestEvents,
9459
9479
  view === "graph" ? graph : /* @__PURE__ */ jsxs(Fragment, { children: [
9460
9480
  showSummary && /* @__PURE__ */ jsx("dl", {
9461
9481
  className: "fw-summary",
@@ -9485,7 +9505,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
9485
9505
  query,
9486
9506
  matchSpan,
9487
9507
  pauses: trace.pauses,
9488
- errorTimes,
9508
+ errorEnds,
9489
9509
  cursorLine: isLive || position !== null || playing,
9490
9510
  sharedDetail,
9491
9511
  sharedOutcome,
@@ -9542,7 +9562,8 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
9542
9562
  })
9543
9563
  }),
9544
9564
  view === "spans" && playback
9545
- ] })
9565
+ ] }),
9566
+ latestEvents
9546
9567
  ]
9547
9568
  });
9548
9569
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/charts",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Static SVG and HTML figures for benchmarks and operational timing. Draws from producer data and refuses what it cannot draw honestly.",
5
5
  "type": "module",
6
6
  "license": "MIT",