@tangle-network/charts 1.0.1 → 1.0.2
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.
|
@@ -368,7 +368,7 @@ interface FlowPause {
|
|
|
368
368
|
/** The full reason, shown on hover and focus of the label rather than printed across the rows. */
|
|
369
369
|
detail?: string;
|
|
370
370
|
}
|
|
371
|
-
/**
|
|
371
|
+
/** An optional host outcome; absent outcomes use the canonical lifecycle status. */
|
|
372
372
|
interface FlowOutcome {
|
|
373
373
|
/** `live` is a running agent: the one running hue the host uses for every live mark. */
|
|
374
374
|
tone: 'ok' | 'live' | 'neutral' | 'failed' | 'warn';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as BreakdownInput, B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, H as Tier, I as Interval, L as IntervalMethod, M as CostBasis, N as Estimate, O as YTarget, P as Exclusion, R as MatrixCell, S as ChartMark, T as MarkerShape, U as TierCounts, V as Setup, W as isRefusal, _ as checkerColor, a as TimelineLane, b as BandKind, c as TimelineTick, d as ENDING_COLORS, f as ENDING_ORDER, g as TickOutcome, h as RunEnding, i as FlowTrace, j as ComparisonRow, k as YTick, l as timeline, m as OUTCOME_ORDER, n as FlowOutcome, o as TimelineOptions, p as OUTCOME_COLORS, r as FlowSpan, s as TimelineSpan, t as FlowMarker, u as CHECKER_HUES, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph, z as RateRow } from "./flow-trace-
|
|
1
|
+
import { A as BreakdownInput, B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, H as Tier, I as Interval, L as IntervalMethod, M as CostBasis, N as Estimate, O as YTarget, P as Exclusion, R as MatrixCell, S as ChartMark, T as MarkerShape, U as TierCounts, V as Setup, W as isRefusal, _ as checkerColor, a as TimelineLane, b as BandKind, c as TimelineTick, d as ENDING_COLORS, f as ENDING_ORDER, g as TickOutcome, h as RunEnding, i as FlowTrace, j as ComparisonRow, k as YTick, l as timeline, m as OUTCOME_ORDER, n as FlowOutcome, o as TimelineOptions, p as OUTCOME_COLORS, r as FlowSpan, s as TimelineSpan, t as FlowMarker, u as CHECKER_HUES, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph, z as RateRow } from "./flow-trace-CKk85dAV.js";
|
|
2
2
|
//#region src/block.d.ts
|
|
3
3
|
interface RenderFigureOptions {
|
|
4
4
|
/** Chart uses a closed data disclosure; plot keeps only the SVG and accessible data. */
|
package/dist/index.js
CHANGED
|
@@ -1138,7 +1138,7 @@ function plot$1(costed, unplaced, drawLine, o) {
|
|
|
1138
1138
|
/** The figure block and mark styles (src/figure.css), for documents that inline their CSS. */
|
|
1139
1139
|
const figureCss = "/* @tangle-network/charts — figure block and mark styles.\n *\n * Every colour is a --chart-* token from @tangle-network/brand tokens.css, so a\n * figure follows the page theme. A standalone document without brand tokens\n * embeds `chartTokensCss` first. Fonts fall back to Inter and JetBrains Mono.\n *\n * Each figure carries a 720 px and a 358 px render. The swap follows the\n * figure's own width (a container query), so a narrow column shows the phone\n * render even on a wide screen. */\n\n.tgc-figure {\n margin: 32px 0 0;\n padding: 0;\n max-width: 720px;\n color: var(--chart-ink);\n font-family: var(--font-sans, Inter, ui-sans-serif, system-ui, sans-serif);\n}\n\n.tgc-finding {\n margin: 0 0 8px;\n font-size: 18px;\n line-height: 24px;\n font-weight: 600;\n color: var(--chart-ink);\n}\n\n.tgc-noteref {\n margin-left: 2px;\n font-size: 14px;\n font-weight: 400;\n color: var(--chart-ink-muted);\n text-decoration: none;\n font-family: var(--font-mono, \"JetBrains Mono\", ui-monospace, monospace);\n}\n.tgc-noteref:hover,\n.tgc-noteref:focus-visible {\n color: var(--chart-accent);\n text-decoration: underline;\n}\n\n.tgc-lede {\n margin: 0 0 16px;\n font-size: 14px;\n line-height: 20px;\n color: var(--text-secondary, var(--chart-ink));\n}\n\n.tgc-plot {\n container-type: inline-size;\n}\n.tgc-wide svg,\n.tgc-narrow svg {\n display: block;\n overflow: visible;\n}\n.tgc-narrow {\n display: none;\n}\n.tgc-narrow svg {\n max-width: 100%;\n height: auto;\n}\n@container (max-width: 719.98px) {\n .tgc-wide {\n display: none;\n }\n .tgc-narrow {\n display: block;\n }\n}\n\n.tgc-read {\n margin: 8px 0 0;\n font-size: 14px;\n line-height: 20px;\n color: var(--chart-ink-muted);\n}\n\n.tgc-data {\n margin: 8px 0 0;\n font-size: 14px;\n line-height: 20px;\n}\n.tgc-data > summary {\n cursor: pointer;\n color: var(--chart-ink-muted);\n width: fit-content;\n}\n.tgc-data > summary:hover {\n color: var(--chart-ink);\n}\n.tgc-data[open] > summary {\n margin-bottom: 8px;\n}\n\n.tgc-scroll {\n overflow-x: auto;\n}\n.tgc-scroll:focus-visible {\n outline: 2px solid var(--chart-accent);\n outline-offset: 2px;\n}\n\n.tgc-table {\n border-collapse: collapse;\n min-width: 100%;\n font-size: 14px;\n line-height: 20px;\n color: var(--chart-ink);\n /* A host page's table rules must not restyle the figure's table. */\n border: 0;\n border-radius: 0;\n background: none;\n}\n.tgc-table caption {\n text-align: left;\n padding: 0 0 8px;\n color: var(--chart-ink-muted);\n}\n.tgc-table th,\n.tgc-table td {\n padding: 8px 12px 8px 0;\n border-bottom: 1px solid var(--chart-rule);\n text-align: left;\n vertical-align: top;\n font-weight: 400;\n font-size: inherit;\n color: inherit;\n background: none;\n text-transform: none;\n letter-spacing: normal;\n}\n.tgc-table thead th {\n color: var(--chart-ink-muted);\n white-space: nowrap;\n}\n.tgc-table tbody th {\n position: sticky;\n left: 0;\n background: var(--chart-canvas, var(--depth-1, transparent));\n}\n.tgc-table .tgc-n {\n font-family: var(--font-mono, \"JetBrains Mono\", ui-monospace, monospace);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n.tgc-table thead .tgc-n {\n font-family: inherit;\n}\n.tgc-table tbody tr:hover {\n background: var(--chart-shade);\n}\n.tgc-narrow-table .tgc-table {\n display: block;\n overflow-x: auto;\n}\n\n.tgc-notes {\n margin: 16px 0 0;\n padding-left: 20px;\n font-size: 14px;\n line-height: 20px;\n color: var(--chart-ink-muted);\n}\n.tgc-notes li {\n margin: 0 0 8px;\n padding-left: 4px;\n}\n.tgc-notes li:target {\n color: var(--chart-ink);\n}\n.tgc-backlink {\n color: var(--chart-ink-muted);\n text-decoration: none;\n}\n\n.tgc-refusals {\n margin: 8px 0 0;\n padding-left: 20px;\n font-size: 14px;\n line-height: 22px;\n color: var(--chart-ink-muted);\n}\n\n/* Marks */\n.tgc-svg {\n font-family: var(--font-sans, Inter, ui-sans-serif, system-ui, sans-serif);\n}\n.tgc-svg .tgc-num {\n font-family: var(--font-mono, \"JetBrains Mono\", ui-monospace, monospace);\n font-variant-numeric: tabular-nums;\n}\n.tgc-ink {\n fill: var(--chart-ink);\n}\n.tgc-ink-muted {\n fill: var(--chart-ink-muted);\n}\n.tgc-bar,\n.tgc-ci,\n.tgc-pt-front {\n fill: var(--chart-accent);\n}\n.tgc-gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n}\n.tgc-rule {\n stroke: var(--chart-rule);\n stroke-width: 1;\n}\n.tgc-axis,\n.tgc-zero {\n stroke: var(--chart-muted);\n stroke-width: 1;\n}\n.tgc-whisker,\n.tgc-tick {\n stroke: var(--chart-ink);\n stroke-width: 2;\n stroke-linecap: round;\n}\n.tgc-threshold {\n stroke: var(--chart-ink);\n stroke-width: 1.5;\n stroke-dasharray: 3 3;\n}\n.tgc-front-line {\n fill: none;\n stroke: var(--chart-ink);\n stroke-width: 1.5;\n stroke-linejoin: round;\n}\n.tgc-pt,\n.tgc-open {\n fill: none;\n stroke: var(--chart-muted);\n stroke-width: 1.5;\n}\n.tgc-pt-est {\n fill: none;\n stroke: var(--chart-accent);\n stroke-width: 2;\n}\n.tgc-pt-ci,\n.tgc-strike {\n stroke: var(--chart-muted);\n stroke-width: 1.5;\n}\n.tgc-leader {\n stroke: var(--chart-muted);\n stroke-width: 1;\n}\n.tgc-ci-exact,\n.tgc-dot {\n fill: var(--chart-muted);\n}\n.tgc-dashed {\n stroke-dasharray: 2 2;\n}\n.tgc-tier-c {\n fill: var(--chart-tier-c);\n}\n.tgc-tier-b {\n fill: var(--chart-tier-b);\n}\n.tgc-tier-a {\n fill: var(--chart-tier-a);\n}\n.tgc-tier-s {\n fill: var(--chart-tier-s);\n}\n/* Neutral tint for counts: never the accent, capped at half strength so ink keeps 6:1. */\n.tgc-tint {\n fill: color-mix(in srgb, var(--chart-muted) calc(var(--s, 0) * 50%), transparent);\n}\n\n@media print {\n .tgc-plot {\n container-type: normal;\n }\n .tgc-wide {\n display: block;\n }\n .tgc-narrow {\n display: none;\n }\n .tgc-wide svg {\n width: 100%;\n height: auto;\n }\n .tgc-figure {\n break-inside: avoid;\n }\n}\n\n/* Chart-led surfaces keep supporting text in the native disclosure. */\n.tgc-figure-chart { max-width: none; margin: 0; }\n.tgc-figure-chart .tgc-wide svg { width: 100%; height: auto; }\n.tgc-wide:has(.tgc-vertical), .tgc-narrow:has(.tgc-vertical) { overflow-x: auto; }\n.tgc-vertical { width: 100%; }\n.tgc-narrow .tgc-vertical { max-width: none; }\n.tgc-column-hit { fill: transparent; stroke: transparent; stroke-width: 2; }\n.tgc-column:focus-visible { outline: none; }\n.tgc-column:focus-visible .tgc-column-hit { stroke: var(--chart-accent); }\n.tgc-vertical-bar { fill: var(--chart-accent); }\n/* Identity assets keep their approved colors on a white plate in either theme. */\n.tgc-logo-plate { fill: #fff; stroke: var(--chart-rule); }\n.tgc-column-tip { opacity: 0; pointer-events: none; }\n.tgc-tip-bg { fill: var(--chart-ink); }\n.tgc-tip-ink { fill: var(--chart-canvas); }\n\n.tgc-series-line { fill: none; stroke: var(--tgc-series, var(--chart-accent)); stroke-width: 2; stroke-linejoin: round; }\n.tgc-series-point, .tgc-series-key { fill: var(--tgc-series, var(--chart-accent)); stroke: var(--chart-canvas); stroke-width: 2; }\n\n/* Semantic states stay tied to Brand status tokens. No-data has its own neutral mark. */\n.tgc-heat-pass { fill: color-mix(in srgb, var(--chart-pass, var(--status-running)) 19%, var(--chart-canvas)); stroke: var(--chart-pass, var(--status-running)); stroke-width: .8; }\n.tgc-heat-breach { fill: color-mix(in srgb, var(--chart-breach, var(--status-error)) 17%, var(--chart-canvas)); stroke: var(--chart-breach, var(--status-error)); stroke-width: .8; }\n.tgc-heat-no-data { fill: var(--chart-grid); stroke: var(--chart-rule); stroke-width: .8; }\n.tgc-heat-label { fill: var(--chart-ink); }\n.tgc-heat-missing { fill: var(--chart-ink-muted); }\n.tgc-wide:has(.tgc-heat-pass), .tgc-wide:has(.tgc-heat-breach) { overflow-x: auto; }\n.tgc-range-pass { fill: var(--chart-pass, var(--status-running)); }\n.tgc-range-breach { fill: var(--chart-breach, var(--status-error)); }\n.tgc-range-dot-pass { fill: var(--chart-canvas); stroke: var(--chart-pass, var(--status-running)); stroke-width: 3; }\n.tgc-range-dot-breach { fill: var(--chart-canvas); stroke: var(--chart-breach, var(--status-error)); stroke-width: 3; }\n.tgc-waterfall-bar { fill: var(--chart-accent); }\n.tgc-series-hit { fill: transparent; stroke: transparent; }\n.tgc-series-observation:focus-visible { outline: none; }\n.tgc-series-observation:focus-visible .tgc-series-hit { stroke: var(--chart-ink); stroke-width: 2; }\n.tgc-series-tip { opacity: 0; pointer-events: none; }\n\n.tgc-scalar-table { min-width: 620px; }\n.tgc-scalar-table tbody th { min-width: 180px; max-width: 260px; }\n\n/* Plot presentation keeps the same complete data available to assistive technology. */\n.tgc-accessible-data { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }\n.tgc-figure-plot .tgc-wide svg { box-sizing: content-box; width: calc(100% - 48px); padding: 0 24px; }\n/* One plot text size on the 12/14/18/32 scale; numbers differ by tabular figures, not size. */\n.tgc-figure-plot svg text { font-size: 14px; }\n/* Larger tooltip text needs padding outside the original report backdrop. */\n.tgc-figure-plot .tgc-tip-bg { stroke: var(--chart-ink); stroke-width: 24px; }\n.tgc-figure-plot .tgc-phone-plot svg { min-width: var(--tgc-phone-width); }\n.tgc-figure-plot .tgc-wide, .tgc-figure-plot .tgc-narrow { overflow-x: auto; }\n\n.tgc-figure-plot .tgc-wide-fallback svg { min-width: var(--tgc-fallback-width); }\n.tgc-phone-plot:focus-visible, .tgc-wide-fallback:focus-visible { outline: 2px solid var(--chart-accent); outline-offset: 2px; }\n\n/* Recorded events and spans. Kinds differ by stroke pattern as well as token, so they read without colour. */\n.tgc-mark { stroke-width: 1.5; }\n.tgc-mark-pass { stroke: var(--chart-pass, var(--status-running)); }\n.tgc-mark-deadline { stroke: var(--chart-ink); stroke-dasharray: 5 3; }\n.tgc-mark-died { stroke: var(--chart-breach, var(--status-error)); stroke-width: 2; }\n.tgc-mark-event { stroke: var(--chart-ink-muted); stroke-dasharray: 1 3; stroke-linecap: round; }\n.tgc-mark-release { stroke: var(--chart-ink-muted); }\n.tgc-mark-steer { stroke: var(--chart-accent); stroke-dasharray: 1 3; stroke-linecap: round; }\n.tgc-mark-ruling { stroke: var(--chart-ink); stroke-dasharray: 6 2 1 2; }\n.tgc-mark-wake { stroke: var(--chart-ink-muted); stroke-dasharray: 1 3; stroke-linecap: round; }\n.tgc-mark-head { fill: var(--chart-ink-muted); stroke: var(--chart-canvas); stroke-width: 1; }\n[data-mark=\"steer\"] .tgc-mark-head { fill: var(--chart-accent); }\n[data-mark=\"ruling\"] .tgc-mark-head { fill: var(--chart-ink); }\n/* A recorded verdict colours the rule and head: pass and fail take the status tones, unknown the muted tone. */\n.tgc-verdict-pass .tgc-mark { stroke: var(--chart-pass, var(--status-running)); }\n.tgc-verdict-pass .tgc-mark-head { fill: var(--chart-pass, var(--status-running)); }\n.tgc-verdict-fail .tgc-mark { stroke: var(--chart-breach, var(--status-error)); }\n.tgc-verdict-fail .tgc-mark-head { fill: var(--chart-breach, var(--status-error)); }\n.tgc-verdict-unknown .tgc-mark { stroke: var(--chart-muted); }\n.tgc-verdict-unknown .tgc-mark-head { fill: var(--chart-muted); }\n.tgc-mark-label { fill: var(--chart-ink); paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }\n.tgc-mark-edge { fill: var(--chart-ink-muted); }\n.tgc-band-after-pass { fill: color-mix(in srgb, var(--chart-pass, var(--status-running)) 12%, transparent); }\n.tgc-band-idle { fill: var(--chart-shade); }\n/* A system-wide wall, such as a quota window: a breach wash across every lane, topped by a solid edge. */\n.tgc-band-blocked { fill: color-mix(in srgb, var(--chart-breach, var(--status-error)) 9%, transparent); }\n.tgc-band-wall { stroke: var(--chart-breach, var(--status-error)); stroke-width: 2; }\n/* Missing data: a neutral wash under hatch lines, never a zero-height mark. */\n.tgc-hatch-bg { fill: color-mix(in srgb, var(--chart-muted) 10%, transparent); }\n.tgc-hatch { fill: none; stroke: var(--chart-muted); stroke-width: 1; }\n.tgc-span { fill: var(--chart-accent); }\n.tgc-span-muted { fill: var(--chart-muted); }\n.tgc-span-open { stroke: var(--chart-ink); stroke-width: 1.5; stroke-dasharray: 3 2; }\n.tgc-now { stroke: var(--chart-ink); stroke-width: 1.5; }\n/* Timeline trees and attempts. Ok ticks rise above the bar and failed ticks drop below it, so they read without colour. */\n.tgc-tree { fill: none; stroke: var(--chart-muted); stroke-width: 1; }\n.tgc-caret { fill: var(--chart-ink-muted); }\n.tgc-lane-toggle { cursor: pointer; }\n.tgc-lane-toggle:focus-visible { outline: none; }\n.tgc-lane-hit { fill: transparent; stroke: transparent; stroke-width: 2; }\n.tgc-lane-toggle:hover .tgc-lane-hit { fill: var(--chart-shade); }\n.tgc-lane-toggle:focus-visible .tgc-lane-hit { stroke: var(--chart-accent); }\n.tgc-tick { stroke-width: 1.5; }\n.tgc-tick-ok { stroke: var(--chart-outcome-ok); }\n.tgc-tick-quota { stroke: var(--chart-outcome-quota); }\n.tgc-tick-lost { stroke: var(--chart-outcome-lost); }\n.tgc-tick-rate-limit { stroke: var(--chart-outcome-rate-limit); }\n.tgc-tick-oom { stroke: var(--chart-outcome-oom); }\n.tgc-tick-refused { stroke: var(--chart-outcome-refused); }\n.tgc-tick-aborted { stroke: var(--chart-outcome-neutral); }\n.tgc-tick-other { stroke: var(--chart-outcome-other); }\n/* Lane labels and counts keep a canvas halo, so rules and ticks under them never strike through the text. */\n.tgc-lane-label, .tgc-count { paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }\n.tgc-count { fill: var(--chart-ink); }\n.tgc-count-ok { fill: var(--chart-pass, var(--status-running)); }\n.tgc-count-failed { fill: var(--chart-breach, var(--status-error)); }\n\n/* FigureView (React) picks the render by measured width; the wide plot fills its container. */\n.tgc-figure-view { max-width: none; margin: 0; }\n.tgc-view-plot svg { display: block; overflow: visible; }\n.tgc-view-wide svg { width: 100%; height: auto; }\n.tgc-view-narrow svg { max-width: 100%; height: auto; }\n\n/*\n * One fixed palette in every view (src/outcomes.ts names them), each a light-dark() pair picked by the page's\n * color-scheme. Green, red and amber are status colours and mean one thing everywhere: green is a turn or run that\n * worked (an `ok` attempt, a solved run), red a run that died, amber a run stalled or a turn rate-limited. Outcomes\n * pass the dataviz colour-vision checks as adjacent pairs in stack order (ok, quota, lost, rate-limit, oom, refused) on\n * the light surface and on #161616; `aborted` and `other` are two distinct greys. Checkers take hues no status uses\n * (blue for the current checker, then magenta, cyan and violet for older ones) and pass as adjacent series; their\n * marks also carry a vN label. Run endings reuse those colours. `scripts/palette-check.mjs` re-runs the validator. A\n * page may override any of these properties; :where() keeps them at zero specificity.\n */\n:where(:root) {\n --chart-outcome-ok: light-dark(#1baf7a, #199e70);\n --chart-outcome-quota: light-dark(#eb6834, #d95926);\n --chart-outcome-lost: light-dark(#0f9fb8, #1a9cb3);\n --chart-outcome-rate-limit: light-dark(#eda100, #c98500);\n --chart-outcome-oom: light-dark(#e87ba4, #d55181);\n --chart-outcome-refused: light-dark(#6250d6, #9085e9);\n --chart-outcome-neutral: #898781;\n --chart-outcome-other: #b5b3ac;\n --chart-checker-0: light-dark(#2a78d6, #3987e5);\n --chart-checker-1: light-dark(#b8478f, #c2408f);\n --chart-checker-2: light-dark(#0f9fb8, #1a9cb3);\n --chart-checker-3: light-dark(#6250d6, #8c7ce6);\n /* How a run ended: solved green, died red, stalled amber, live blue; not solved and cancelled are neutral. */\n --chart-ending-solved: var(--chart-outcome-ok);\n --chart-ending-died: light-dark(#d03b3b, #e05252);\n --chart-ending-stalled: var(--chart-outcome-rate-limit);\n --chart-ending-live: var(--chart-checker-0);\n --chart-ending-not-solved: light-dark(#6b7a90, #8494ab);\n --chart-ending-cancelled: var(--chart-outcome-neutral);\n --chart-ending-never-started: color-mix(in srgb, var(--chart-outcome-other) 45%, transparent);\n}\n/* A series drawn in a checker's hue; past the fourth hue it is muted and named by its label. */\n.tgc-checker-0 { --tgc-series: var(--chart-checker-0); }\n.tgc-checker-1 { --tgc-series: var(--chart-checker-1); }\n.tgc-checker-2 { --tgc-series: var(--chart-checker-2); }\n.tgc-checker-3 { --tgc-series: var(--chart-checker-3); }\n.tgc-checker-other { --tgc-series: var(--chart-muted); }\n/* Recorded verdicts: a pass is filled, a fail or an incomparable value is an outline, an undecided one dashed. */\n.tgc-series-point.tgc-point-outline { fill: var(--chart-canvas); stroke: var(--tgc-series, var(--chart-accent)); stroke-width: 1.75; }\n.tgc-series-point.tgc-point-undecided { fill: var(--chart-canvas); stroke: var(--tgc-series, var(--chart-accent)); stroke-width: 1.5; stroke-dasharray: 2 1.5; }\n.tgc-strip-hatch .tgc-hatch { stroke: var(--tgc-series, var(--chart-muted)); }\n/* A failing verdict without a value is a neutral ring: in its checker's hue it read as that checker passing. */\n.tgc-series-point.tgc-point-outline.tgc-strip-fail { stroke: var(--chart-ink-muted); }\n.tgc-strip-edge { fill: none; stroke: var(--tgc-series, var(--chart-muted)); stroke-width: 1.25; }\n.tgc-strip-observation:focus-visible { outline: none; }\n.tgc-strip-observation:focus-visible .tgc-series-hit { stroke: var(--chart-ink); stroke-width: 2; }\n.tgc-point-badge { paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; font-family: var(--font-mono, \"JetBrains Mono\", ui-monospace, monospace); }\n.tgc-point-label { fill: var(--chart-ink-muted); }\n.tgc-glyph-note { fill: var(--chart-ink); font-weight: 600; }\n/* Status colours appear only on these glyphs. */\n.tgc-glyph-check { fill: var(--chart-pass, var(--status-running)); font-weight: 600; }\n.tgc-glyph-cross { fill: var(--chart-breach, var(--status-error)); font-weight: 600; }\n/* Recorded targets sit under the data: a target is a soft band between solid edges, a stretch a dashed outline. */\n.tgc-target-target { fill: color-mix(in srgb, var(--chart-ink) 7%, transparent); }\n.tgc-target-stretch { fill: none; }\n.tgc-target-target-edge, .tgc-target-target.tgc-target-line { stroke: var(--chart-ink-muted); stroke-width: 1; }\n.tgc-target-stretch-edge, .tgc-target-stretch.tgc-target-line { stroke: var(--chart-ink-muted); stroke-width: 1; stroke-dasharray: 4 3; }\n.tgc-target-label { fill: var(--chart-ink-muted); paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }\n/* Group headers: a labelled bracket above the plot and a light rule at each inner edge. */\n.tgc-group-rule { stroke: var(--chart-ink-muted); stroke-width: 1.5; }\n.tgc-group-edge { stroke: var(--chart-rule); stroke-width: 1; }\n.tgc-group-label { fill: var(--chart-ink); paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }\n/* The verdict key: glyphs in the neutral ink, so they describe a mark's form, not a series. */\n.tgc-key-mark { stroke-width: 1.5; }\n.tgc-key-filled { fill: var(--chart-ink-muted); stroke: none; }\n.tgc-key-outline { fill: none; stroke: var(--chart-ink-muted); }\n.tgc-key-dashed { fill: none; stroke: var(--chart-ink-muted); stroke-dasharray: 2 1.5; }\n";
|
|
1140
1140
|
/** --chart-* resolved per theme, for documents without brand tokens: light, dark by preference or [data-theme="dark"], light in print. */
|
|
1141
|
-
const chartTokensCss = ":root{--chart-ink:hsl(0 0%
|
|
1141
|
+
const chartTokensCss = ":root{--chart-ink:hsl(0 0% 24.7059%);--chart-ink-muted:hsl(0 0% 41.9608%);--chart-muted:hsl(0 0% 36.4706%);--chart-grid:hsl(225 28.5714% 94.5098%);--chart-rule:hsl(222.8571 6.6667% 79.4118%);--chart-shade:color-mix(in srgb, hsl(246.2264 92.1739% 54.902%) 7%, transparent);--chart-accent:hsl(245.9504 54.2601% 56.2745%);--chart-tier-c:hsl(246.2687 54.4715% 75.8824%);--chart-tier-b:hsl(246.055 54.7739% 60.9804%);--chart-tier-a:hsl(246.0465 54.8936% 46.0784%);--chart-tier-s:hsl(245.5172 54.717% 31.1765%);--chart-pass:hsl(154.8148 64.8% 24.5098%);--chart-breach:hsl(0 75.1244% 39.4118%);--chart-canvas:hsl(0 0% 100%);color-scheme:light}\n@media (prefers-color-scheme: dark){:root:not([data-theme=\"light\"]){--chart-ink:hsl(0 0% 84.3137%);--chart-ink-muted:hsl(0 0% 60.3922%);--chart-muted:hsl(0 0% 67.0588%);--chart-grid:hsl(243.3333 20.4545% 17.2549%);--chart-rule:hsl(245 18.4615% 25.4902%);--chart-shade:color-mix(in srgb, hsl(245.5556 93.1034% 88.6275%) 7%, transparent);--chart-accent:hsl(246.0465 85.4305% 70.3922%);--chart-tier-c:hsl(246.1017 55.1402% 41.9608%);--chart-tier-b:hsl(246.1905 54.7826% 54.902%);--chart-tier-a:hsl(245.3933 54.6012% 68.0392%);--chart-tier-s:hsl(245.6604 54.6392% 80.9804%);--chart-pass:hsl(155.1429 64.8148% 78.8235%);--chart-breach:hsl(0 74.4681% 90.7843%);--chart-canvas:hsl(246.6667 31.0345% 5.6863%);color-scheme:dark}}\n:root[data-theme=\"dark\"]{--chart-ink:hsl(0 0% 84.3137%);--chart-ink-muted:hsl(0 0% 60.3922%);--chart-muted:hsl(0 0% 67.0588%);--chart-grid:hsl(243.3333 20.4545% 17.2549%);--chart-rule:hsl(245 18.4615% 25.4902%);--chart-shade:color-mix(in srgb, hsl(245.5556 93.1034% 88.6275%) 7%, transparent);--chart-accent:hsl(246.0465 85.4305% 70.3922%);--chart-tier-c:hsl(246.1017 55.1402% 41.9608%);--chart-tier-b:hsl(246.1905 54.7826% 54.902%);--chart-tier-a:hsl(245.3933 54.6012% 68.0392%);--chart-tier-s:hsl(245.6604 54.6392% 80.9804%);--chart-pass:hsl(155.1429 64.8148% 78.8235%);--chart-breach:hsl(0 74.4681% 90.7843%);--chart-canvas:hsl(246.6667 31.0345% 5.6863%);color-scheme:dark}\n@media print{:root,:root:not([data-theme=\"light\"]),:root[data-theme=\"dark\"]{--chart-ink:hsl(0 0% 24.7059%);--chart-ink-muted:hsl(0 0% 41.9608%);--chart-muted:hsl(0 0% 36.4706%);--chart-grid:hsl(225 28.5714% 94.5098%);--chart-rule:hsl(222.8571 6.6667% 79.4118%);--chart-shade:color-mix(in srgb, hsl(246.2264 92.1739% 54.902%) 7%, transparent);--chart-accent:hsl(245.9504 54.2601% 56.2745%);--chart-tier-c:hsl(246.2687 54.4715% 75.8824%);--chart-tier-b:hsl(246.055 54.7739% 60.9804%);--chart-tier-a:hsl(246.0465 54.8936% 46.0784%);--chart-tier-s:hsl(245.5172 54.717% 31.1765%);--chart-pass:hsl(154.8148 64.8% 24.5098%);--chart-breach:hsl(0 75.1244% 39.4118%);--chart-canvas:hsl(0 0% 100%);color-scheme:light}}";
|
|
1142
1142
|
//#endregion
|
|
1143
1143
|
//#region src/vertical-columns.ts
|
|
1144
1144
|
function image(mark, x, y, size) {
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
--fw-ok: var(--surface-success-text);
|
|
14
14
|
--fw-amber: var(--surface-warning-text);
|
|
15
15
|
--fw-live: var(--fw-accent);
|
|
16
|
-
--fw-kind-model: var(--chart-accent);
|
|
17
|
-
--fw-kind-tool: var(--tone-cyan-icon);
|
|
16
|
+
--fw-kind-model: light-dark(oklch(from var(--chart-accent) .50 min(c, .10) h), oklch(from var(--chart-accent) .72 min(c, .10) h));
|
|
17
|
+
--fw-kind-tool: light-dark(oklch(from var(--tone-cyan-icon) .80 min(c, .10) h), oklch(from var(--tone-cyan-icon) .46 min(c, .10) h));
|
|
18
18
|
--fw-neutral-bar: color-mix(in oklab, var(--fw-text) 15%, var(--fw-surface));
|
|
19
19
|
--fw-hatch: color-mix(in oklab, var(--fw-text) 22%, transparent);
|
|
20
20
|
--fw-h0: var(--chart-muted);
|
|
21
21
|
--fw-h1: light-dark(oklch(from var(--tone-blue-icon) .58 .11 calc(h + 39)), oklch(from var(--tone-blue-icon) .67 .11 calc(h + 39)));
|
|
22
22
|
--fw-h2: light-dark(oklch(from var(--tone-violet-icon) .55 .11 h), oklch(from var(--tone-violet-icon) .70 .11 h));
|
|
23
23
|
--fw-h3: light-dark(oklch(from var(--tone-pink-icon) .55 .11 h), oklch(from var(--tone-pink-icon) .67 .11 calc(h - 16)));
|
|
24
|
-
--fw-h4: light-dark(oklch(from var(--tone-cyan-icon) .
|
|
24
|
+
--fw-h4: light-dark(oklch(from var(--tone-cyan-icon) .60 .11 calc(h - 16.256)), oklch(from var(--tone-cyan-icon) .67 .11 calc(h - 26.148)));
|
|
25
25
|
--fw-h5: light-dark(oklch(from var(--tone-blue-icon) .58 .03 calc(h + 37.6)), oklch(from var(--tone-blue-icon) .67 .03 calc(h + 29.5)));
|
|
26
26
|
--fw-ease: var(--ease-standard, cubic-bezier(.2,.8,.2,1));
|
|
27
27
|
--fw-bar-h: 20px;
|
|
@@ -260,9 +260,8 @@
|
|
|
260
260
|
.fw-root .fw-view-agents .fw-seg .fw-glyph { flex: none; margin-left: 0; display: grid; place-items: center; width: min(14px, 100%); height: 14px; border-radius: 50%; background: var(--fw-failed); color: light-dark(var(--fw-surface), var(--bg-root)); }
|
|
261
261
|
.fw-root .fw-view-agents .fw-seg .fw-glyph[data-glyph="retry"] { background: var(--fw-muted); }
|
|
262
262
|
.fw-root .fw-view-agents .fw-seg .fw-glyph svg { width: min(9px, 100%); height: 9px; stroke-width: 2.5; }
|
|
263
|
-
.fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents :is(.fw-seg-alt.fw-seg-model, .fw-seg-alt.fw-seg-tool) { filter: brightness(.88); }
|
|
264
263
|
.fw-root .fw-seg-failed { background: color-mix(in oklab, var(--fw-failed) 18%, var(--fw-surface)); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fw-failed) 70%, transparent); color: var(--fw-failed); }
|
|
265
|
-
.fw-root .fw-view-agents .fw-seg-failed { background: var(--
|
|
264
|
+
.fw-root .fw-view-agents .fw-seg-failed { background: var(--tool-fill); box-shadow: inset 0 0 0 1px var(--dim-line); }
|
|
266
265
|
.fw-root .fw-glyph { display: inline-flex; color: currentColor; }
|
|
267
266
|
.fw-root .fw-glyph svg { width: 11px; height: 11px; stroke-width: 2; }
|
|
268
267
|
.fw-root .fw-seg-model .fw-glyph, .fw-root .fw-k-model .fw-glyph { color: light-dark(var(--tone), var(--fw-text)); }
|
|
@@ -371,6 +370,9 @@
|
|
|
371
370
|
.fw-root .fw-legend button[aria-pressed="true"] { color: var(--fw-text); text-decoration: underline; text-underline-offset: 4px; }
|
|
372
371
|
.fw-root .fw-summary button { appearance: none; background: transparent; border: 0; padding: 0; cursor: pointer; color: inherit; }
|
|
373
372
|
.fw-root .fw-key > summary { display: none; }
|
|
373
|
+
.fw-root .fw-key > summary svg { width: 12px; height: 12px; margin-left: 6px; }
|
|
374
|
+
.fw-root .fw-key[open] > summary svg { transform: rotate(90deg); }
|
|
375
|
+
.fw-root .fw-row-state { display: none; font-size: 12px; font-weight: 600; }
|
|
374
376
|
.fw-root .fw-error-rug { position: relative; height: 10px; margin-left: var(--fw-label-col); overflow: hidden; }
|
|
375
377
|
.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); }
|
|
376
378
|
.fw-root .fw-error-tick[data-unlocated] { left: auto; right: calc(var(--error-index) * 3px); }
|
|
@@ -387,6 +389,7 @@
|
|
|
387
389
|
.fw-root .fw-summary > div:nth-child(4) { border-left: 0; }
|
|
388
390
|
.fw-root .fw-summary > div:nth-child(n+4) { border-top: 1px solid var(--fw-border); }
|
|
389
391
|
.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; }
|
|
392
|
+
.fw-root .fw-row-state { display: inline; }
|
|
390
393
|
.fw-root .fw-key > summary { display: flex; align-items: center; min-height: 32px; cursor: pointer; }
|
|
391
394
|
.fw-root .fw-key:not([open]) .fw-legends { display: none; }
|
|
392
395
|
.fw-root .fw-heading { padding: 12px 8px; }
|
|
@@ -411,5 +414,3 @@
|
|
|
411
414
|
.fw-root.fw-fill-agent .fw-view-agents .fw-seg-failed[data-model] { background: var(--model-fill); --fw-seg-ink: light-dark(var(--fw-surface), var(--bg-root)); }
|
|
412
415
|
|
|
413
416
|
.fw-root.fw-root.fw-root-agents[data-selection] .fw-row:not([aria-selected="true"]) .fw-seg { opacity: var(--on); background: color-mix(in oklab, var(--fw-surface) 80%, var(--tone)); --fw-seg-ink: var(--fw-text); }
|
|
414
|
-
|
|
415
|
-
.fw-root:is(.fw-fill-muted, .fw-fill-outcome) .fw-view-agents .fw-seg-tool { --fw-seg-ink: light-dark(var(--fw-surface), var(--bg-root)); }
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, n as FlowOutcome, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-
|
|
1
|
+
import { B as Refusal, C as MarkKind, D as YScale, E as XCategory, F as Figure, O as YTarget, S as ChartMark, T as MarkerShape, a as TimelineLane, b as BandKind, c as TimelineTick, g as TickOutcome, i as FlowTrace, k as YTick, n as FlowOutcome, o as TimelineOptions, r as FlowSpan, s as TimelineSpan, t as FlowMarker, v as PointFields, w as MarkVerdict, x as ChartBand, y as PointGlyph } from "../flow-trace-CKk85dAV.js";
|
|
2
2
|
import { CSSProperties, ReactElement, ReactNode } from "react";
|
|
3
3
|
//#region src/react/sparkline.d.ts
|
|
4
4
|
type SparklineDirection = "rising" | "falling" | "flat";
|
package/dist/react/index.js
CHANGED
|
@@ -6560,10 +6560,22 @@ function mergeSegments(marks, gapMs, cap = 240) {
|
|
|
6560
6560
|
* Orphaned parents become roots; cycles are broken without dropping any span. */
|
|
6561
6561
|
function flowWaterfallRows(trace, resolutionMs) {
|
|
6562
6562
|
const ids = /* @__PURE__ */ new Set();
|
|
6563
|
-
const rows = [...trace.spans].map((
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6563
|
+
const rows = [...trace.spans].map((recorded, i) => {
|
|
6564
|
+
const state = runStatus(recorded.status ?? "unknown");
|
|
6565
|
+
const outcome = {
|
|
6566
|
+
label: statusMeta(state).label,
|
|
6567
|
+
tone: state === "running" ? "live" : state === "done" ? "ok" : state === "needs-you" ? "warn" : state === "failed" ? "failed" : "neutral",
|
|
6568
|
+
...state === "unknown" ? { ring: true } : {}
|
|
6569
|
+
};
|
|
6570
|
+
const span = recorded.outcome ? recorded : {
|
|
6571
|
+
...recorded,
|
|
6572
|
+
outcome
|
|
6573
|
+
};
|
|
6574
|
+
return {
|
|
6575
|
+
span,
|
|
6576
|
+
key: span.id ?? `span-${i}`
|
|
6577
|
+
};
|
|
6578
|
+
}).sort((a, b) => a.span.startMs - b.span.startMs).map(({ span, key }, index) => {
|
|
6567
6579
|
let id = key;
|
|
6568
6580
|
let suffix = index;
|
|
6569
6581
|
while (ids.has(id)) id = `${key}:${suffix++}`;
|
|
@@ -7106,17 +7118,17 @@ const rowCostText = (row, cost) => `${row.costFloor ? "≥" : ""}${formatCost(co
|
|
|
7106
7118
|
/** Quiet is elapsed silence beyond both five minutes and three median event gaps. */
|
|
7107
7119
|
function quietActivity(row, now) {
|
|
7108
7120
|
const times = [...row.span.activityAt ?? row.own.flatMap((mark) => [mark.startMs, mark.endMs])].filter(Number.isFinite).sort((a, b) => a - b);
|
|
7109
|
-
const last = times.at(-1) ??
|
|
7110
|
-
const gaps = times.slice(1).map((at, i) => at - times[i]).
|
|
7121
|
+
const last = times.at(-1) ?? NaN;
|
|
7122
|
+
const gaps = times.slice(1).map((at, i) => at - times[i]).sort((a, b) => a - b);
|
|
7111
7123
|
const middle = Math.floor(gaps.length / 2);
|
|
7112
7124
|
const observedMedian = gaps.length ? gaps.length % 2 ? gaps[middle] : (gaps[middle - 1] + gaps[middle]) / 2 : 0;
|
|
7113
7125
|
const supplied = row.span.medianEventGapMs;
|
|
7114
7126
|
const median = typeof supplied === "number" && Number.isFinite(supplied) && supplied >= 0 ? supplied : observedMedian;
|
|
7115
|
-
const quietMs = Math.max(0, now - last);
|
|
7127
|
+
const quietMs = Number.isFinite(last) ? Math.max(0, now - last) : 0;
|
|
7116
7128
|
return {
|
|
7117
7129
|
last,
|
|
7118
7130
|
quietMs,
|
|
7119
|
-
quiet: spanRunning(row.span) && quietMs > Math.max(3e5, 3 * median)
|
|
7131
|
+
quiet: spanRunning(row.span) && Number.isFinite(last) && quietMs > Math.max(3e5, 3 * median)
|
|
7120
7132
|
};
|
|
7121
7133
|
}
|
|
7122
7134
|
//#endregion
|
|
@@ -7561,6 +7573,8 @@ function endLabel(row, clockMs) {
|
|
|
7561
7573
|
const FlowRow = memo(function FlowRow(props) {
|
|
7562
7574
|
const { row, view, top, collapsed, searching, slowest, costliest, critical, matched, active, focusable, selected, sticky, clockMs, renderIcon, fillByAgent, motion } = props;
|
|
7563
7575
|
const span = row.span;
|
|
7576
|
+
const state = runStatus(span.status ?? "unknown");
|
|
7577
|
+
const meta = statusMeta(state);
|
|
7564
7578
|
const running = spanRunning(span);
|
|
7565
7579
|
const agentView = view === "agents";
|
|
7566
7580
|
const folded = row.hasChildren && collapsed && !searching;
|
|
@@ -7687,6 +7701,11 @@ const FlowRow = memo(function FlowRow(props) {
|
|
|
7687
7701
|
className: "fw-name-text",
|
|
7688
7702
|
children: row.name
|
|
7689
7703
|
}),
|
|
7704
|
+
(state === "failed" || state === "needs-you") && /* @__PURE__ */ jsx("span", {
|
|
7705
|
+
className: "fw-row-state",
|
|
7706
|
+
style: { color: `var(${meta.token})` },
|
|
7707
|
+
children: meta.label
|
|
7708
|
+
}),
|
|
7690
7709
|
activity.quiet && /* @__PURE__ */ jsxs("span", {
|
|
7691
7710
|
className: "fw-quiet",
|
|
7692
7711
|
children: ["Quiet ", formatSpanDuration(activity.quietMs)]
|
|
@@ -9322,7 +9341,7 @@ function FlowWaterfall({ trace, live, startedAt, label = "Trace waterfall", defa
|
|
|
9322
9341
|
}), /* @__PURE__ */ jsxs("details", {
|
|
9323
9342
|
className: "fw-key",
|
|
9324
9343
|
open: root.current ? root.current.clientWidth >= 600 : true,
|
|
9325
|
-
children: [/* @__PURE__ */
|
|
9344
|
+
children: [/* @__PURE__ */ jsxs("summary", { children: ["Key", /* @__PURE__ */ jsx(ChevronGlyph, {})] }), /* @__PURE__ */ jsxs("div", {
|
|
9326
9345
|
className: "fw-legends",
|
|
9327
9346
|
children: [
|
|
9328
9347
|
/* @__PURE__ */ jsx(OutcomeLegend, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/charts",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"check:run-tokens": "node scripts/check-run-tokens.mjs"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@tangle-network/brand": "1.31.
|
|
55
|
+
"@tangle-network/brand": "1.31.1",
|
|
56
56
|
"@testing-library/react": "^16.3.3",
|
|
57
57
|
"@testing-library/user-event": "^14.6.7",
|
|
58
58
|
"@types/node": "^26.6.3",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"tsdown": "^0.23.0",
|
|
67
67
|
"typescript": "^7.0.2",
|
|
68
68
|
"vitest": "^5.0.2",
|
|
69
|
-
"@tangle-network/ui": "11.
|
|
69
|
+
"@tangle-network/ui": "11.51.1"
|
|
70
70
|
},
|
|
71
71
|
"keywords": [
|
|
72
72
|
"tangle",
|