@oh-my-pi/omp-stats 18.16.0 → 18.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/client/index.css +1 -1
  3. package/dist/client/index.js +102 -99
  4. package/dist/types/client/api.d.ts +4 -1
  5. package/dist/types/client/app/nav.d.ts +1 -1
  6. package/dist/types/client/charts/Chart.d.ts +16 -8
  7. package/dist/types/client/charts/DotWhisker.d.ts +50 -0
  8. package/dist/types/client/charts/Sparkline.d.ts +1 -1
  9. package/dist/types/client/charts/Waterfall.d.ts +26 -0
  10. package/dist/types/client/charts/index.d.ts +2 -0
  11. package/dist/types/client/charts/types.d.ts +8 -2
  12. package/dist/types/client/routes/SpotlightRoute.d.ts +7 -0
  13. package/dist/types/client/routes/index.d.ts +1 -0
  14. package/dist/types/client/spotlight/Compounding.d.ts +8 -0
  15. package/dist/types/client/spotlight/Coverage.d.ts +6 -0
  16. package/dist/types/client/spotlight/Economics.d.ts +10 -0
  17. package/dist/types/client/spotlight/FetchBack.d.ts +9 -0
  18. package/dist/types/client/spotlight/Hero.d.ts +12 -0
  19. package/dist/types/client/spotlight/Overhead.d.ts +6 -0
  20. package/dist/types/client/spotlight/Ranking.d.ts +6 -0
  21. package/dist/types/client/spotlight/ResultsFeed.d.ts +6 -0
  22. package/dist/types/client/spotlight/Savings.d.ts +10 -0
  23. package/dist/types/client/spotlight/ShareTrend.d.ts +8 -0
  24. package/dist/types/client/spotlight/Steps.d.ts +6 -0
  25. package/dist/types/client/spotlight/TimeCost.d.ts +6 -0
  26. package/dist/types/client/spotlight/chips.d.ts +16 -0
  27. package/dist/types/client/spotlight/meta.d.ts +64 -0
  28. package/dist/types/db.d.ts +26 -0
  29. package/dist/types/index.d.ts +2 -1
  30. package/dist/types/parser.d.ts +4 -0
  31. package/dist/types/rollup.d.ts +22 -1
  32. package/dist/types/shared-types.d.ts +419 -0
  33. package/dist/types/spotlight-aggregator.d.ts +189 -0
  34. package/dist/types/spotlight-bootstrap.d.ts +32 -0
  35. package/dist/types/spotlight-ingest.d.ts +258 -0
  36. package/dist/types/spotlight-measures.d.ts +51 -0
  37. package/package.json +5 -5
  38. package/src/aggregator.ts +3 -1
  39. package/src/client/App.tsx +3 -0
  40. package/src/client/api.ts +21 -0
  41. package/src/client/app/nav.ts +4 -1
  42. package/src/client/charts/Chart.tsx +105 -22
  43. package/src/client/charts/DotWhisker.tsx +149 -0
  44. package/src/client/charts/Sparkline.tsx +3 -2
  45. package/src/client/charts/Waterfall.tsx +86 -0
  46. package/src/client/charts/index.ts +2 -0
  47. package/src/client/charts/types.ts +9 -2
  48. package/src/client/react-css.d.ts +1 -1
  49. package/src/client/routes/SpotlightRoute.tsx +138 -0
  50. package/src/client/routes/index.ts +1 -0
  51. package/src/client/spotlight/Compounding.tsx +222 -0
  52. package/src/client/spotlight/Coverage.tsx +96 -0
  53. package/src/client/spotlight/Economics.tsx +167 -0
  54. package/src/client/spotlight/FetchBack.tsx +222 -0
  55. package/src/client/spotlight/Hero.tsx +177 -0
  56. package/src/client/spotlight/Overhead.tsx +135 -0
  57. package/src/client/spotlight/Ranking.tsx +248 -0
  58. package/src/client/spotlight/ResultsFeed.tsx +354 -0
  59. package/src/client/spotlight/Savings.tsx +355 -0
  60. package/src/client/spotlight/ShareTrend.tsx +103 -0
  61. package/src/client/spotlight/Steps.tsx +225 -0
  62. package/src/client/spotlight/TimeCost.tsx +64 -0
  63. package/src/client/spotlight/chips.tsx +63 -0
  64. package/src/client/spotlight/meta.ts +206 -0
  65. package/src/client/spotlight/spotlight.css +1387 -0
  66. package/src/client/styles.css +289 -1
  67. package/src/db.ts +480 -2
  68. package/src/index.ts +10 -1
  69. package/src/live.ts +21 -9
  70. package/src/parser.ts +44 -8
  71. package/src/rollup.ts +203 -10
  72. package/src/server.ts +42 -0
  73. package/src/shared-types.ts +453 -0
  74. package/src/spotlight-aggregator.ts +1738 -0
  75. package/src/spotlight-bootstrap.ts +110 -0
  76. package/src/spotlight-ingest.ts +981 -0
  77. package/src/spotlight-measures.ts +667 -0
@@ -1,4 +1,4 @@
1
- import type { CostDashboardStats, FolderStats, FrustrationDashboardStats, FrustrationEstimate, FrustrationJobStatus, GainDashboardStats, LiveStatus, MessageStats, ModelDashboardStats, OverviewStats, ProviderDashboardStats, ProviderWindowStats, RequestDetails, SessionSummary, SessionTrace, TimeRange, ToolDashboardStats } from "./types.js";
1
+ import type { CostDashboardStats, FolderStats, FrustrationDashboardStats, FrustrationEstimate, FrustrationJobStatus, GainDashboardStats, LiveStatus, MessageStats, ModelDashboardStats, OverviewStats, ProviderDashboardStats, ProviderWindowStats, RequestDetails, SessionSummary, SessionTrace, SpotlightAgentScope, SpotlightDashboardStats, SpotlightSessionContext, TimeRange, ToolDashboardStats } from "./types.js";
2
2
  export declare class ApiError extends Error {
3
3
  status: number;
4
4
  endpoint: string;
@@ -24,6 +24,9 @@ export declare function startFrustrationRun(range: TimeRange): Promise<Frustrati
24
24
  export declare function cancelFrustrationRun(): Promise<FrustrationJobStatus>;
25
25
  export declare function getFolderStats(range?: TimeRange, signal?: AbortSignal): Promise<FolderStats[]>;
26
26
  export declare function getGainDashboardStats(range?: TimeRange, project?: string | null, signal?: AbortSignal): Promise<GainDashboardStats>;
27
+ export declare function getSpotlightDashboardStats(range?: TimeRange, agent?: SpotlightAgentScope, signal?: AbortSignal): Promise<SpotlightDashboardStats>;
28
+ /** One experiment session's context per request, with and without shaping. */
29
+ export declare function getSpotlightSessionContext(file: string, signal?: AbortSignal): Promise<SpotlightSessionContext>;
27
30
  export declare function getToolDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<ToolDashboardStats>;
28
31
  export declare function getProviderDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<ProviderDashboardStats>;
29
32
  /** Subscription-window insights (all providers) plus utilization series for `provider` only. */
@@ -1,5 +1,5 @@
1
1
  import { type LucideIcon } from "lucide-react";
2
- export type DashboardSection = "overview" | "models" | "providers" | "costs" | "requests" | "errors" | "traces" | "tools" | "frustration" | "projects" | "gain";
2
+ export type DashboardSection = "overview" | "models" | "providers" | "costs" | "requests" | "errors" | "traces" | "tools" | "frustration" | "projects" | "gain" | "spotlight";
3
3
  export interface NavItem {
4
4
  id: DashboardSection;
5
5
  label: string;
@@ -1,13 +1,14 @@
1
1
  /**
2
- * Core SVG chart: categorical x slots, stacked or grouped bars, stacked areas
3
- * and lines, an optional right axis, a hover cursor and a floating tooltip.
4
- * Marks are crisp and unsmoothed — square bars, straight segments.
2
+ * Core SVG chart: categorical x slots, stacked or grouped bars, stacked areas,
3
+ * lines and dots, an optional right axis, a hover cursor and a floating tooltip.
4
+ * Marks are crisp and unsmoothed — square bars, straight segments. Negative
5
+ * values extend the axis below zero (bars hang down from the baseline).
5
6
  *
6
7
  * `TimeChart` wraps this for bucketed time series; use `Chart` directly for
7
8
  * categorical axes (hour of day, model names).
8
9
  */
9
10
  import { type ReactNode } from "react";
10
- import type { ChartKind, ChartSeries, ReferenceLine } from "./types.js";
11
+ import type { ChartKind, ChartSeries, ReferenceLine, SlotMarker } from "./types.js";
11
12
  export interface ChartProps {
12
13
  /** Number of x positions; every series' `values` has this length. */
13
14
  slots: number;
@@ -35,15 +36,22 @@ export interface ChartProps {
35
36
  /** Show a total row in the tooltip. Default: stacked with 2+ series. */
36
37
  showTotal?: boolean;
37
38
  references?: readonly ReferenceLine[];
39
+ /** Vertical guides at x slots, labelled along the top edge. */
40
+ markers?: readonly SlotMarker[];
38
41
  onSelect?: (index: number) => void;
39
42
  /** Shown over empty axes when every visible value is zero. */
40
43
  emptyLabel?: ReactNode;
41
44
  /** Extra tooltip rows for a slot (below the series rows). */
42
45
  tooltipExtra?: (index: number) => ReactNode;
43
46
  }
44
- export declare function Chart({ slots, tickLabel, tooltipTitle, series, kind, stacked, height, format, formatRight, formatTooltip, yMax, yMaxRight, hidden, showTotal, references, onSelect, emptyLabel, tooltipExtra, }: ChartProps): import("react").JSX.Element;
45
- /** Round an axis maximum up to 1/2/2.5/5 × 10ⁿ and return evenly spaced ticks from 0. */
46
- export declare function niceScale(max: number): {
47
+ export declare function Chart({ slots, tickLabel, tooltipTitle, series, kind, stacked, height, format, formatRight, formatTooltip, yMax, yMaxRight, hidden, showTotal, references, markers, onSelect, emptyLabel, tooltipExtra, }: ChartProps): import("react").JSX.Element;
48
+ export interface AxisScale {
49
+ min: number;
47
50
  max: number;
48
51
  ticks: number[];
49
- };
52
+ }
53
+ /**
54
+ * Round an axis span out to 1/2/2.5/5 × 10ⁿ steps and return evenly spaced
55
+ * ticks. The span always includes zero; `min` (default 0) extends it below.
56
+ */
57
+ export declare function niceScale(max: number, min?: number): AxisScale;
@@ -0,0 +1,50 @@
1
+ import type { ReactNode } from "react";
2
+ /** One estimate on a row: a point and its interval. */
3
+ export interface DotWhiskerMark {
4
+ key: string;
5
+ value: number | null;
6
+ lo: number | null;
7
+ hi: number | null;
8
+ color: string;
9
+ /** `dot` (default) filled; `ring` hollow (a counterfactual); `diamond` a reference level; `square` a variant. */
10
+ shape?: "dot" | "ring" | "diamond" | "square";
11
+ /** Vertical offset from the row's center in px, to keep several marks of one row apart. */
12
+ offset?: number;
13
+ /** Hover text naming the mark. */
14
+ title?: string;
15
+ }
16
+ export interface DotWhiskerRow {
17
+ key: string;
18
+ label: ReactNode;
19
+ marks: readonly DotWhiskerMark[];
20
+ /** Right-column figure; defaults to the first mark's value. */
21
+ figure?: ReactNode;
22
+ /** Small print under the figure; defaults to the first mark's interval. */
23
+ detail?: ReactNode;
24
+ }
25
+ export interface DotWhiskerGuide {
26
+ key: string;
27
+ value: number;
28
+ color: string;
29
+ }
30
+ /** A shaded span through every row (e.g. a reference's interval). */
31
+ export interface DotWhiskerBand {
32
+ lo: number;
33
+ hi: number;
34
+ color: string;
35
+ }
36
+ export interface DotWhiskerProps {
37
+ rows: readonly DotWhiskerRow[];
38
+ /** Vertical guides through every row (e.g. chance levels). */
39
+ guides?: readonly DotWhiskerGuide[];
40
+ band?: DotWhiskerBand;
41
+ format: (value: number) => string;
42
+ /** Axis tick formatter; defaults to `format`. */
43
+ formatTick?: (value: number) => string;
44
+ }
45
+ /**
46
+ * Point estimates with their intervals on one shared axis that always spans
47
+ * zero (and extends below it for signed values), one row per group. Layout is
48
+ * percentage-based, so it never measures the DOM.
49
+ */
50
+ export declare function DotWhisker({ rows, guides, band, format, formatTick }: DotWhiskerProps): import("react").JSX.Element;
@@ -7,5 +7,5 @@ export interface SparklineProps {
7
7
  /** Fill under the line. Default true. */
8
8
  area?: boolean;
9
9
  }
10
- /** Axis-free trend line for stat tiles and table cells. */
10
+ /** Axis-free trend line for stat tiles and table cells; negative values dip below the zero line. */
11
11
  export declare function Sparkline({ values, color, height, width, area }: SparklineProps): import("react").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import type { ReactNode } from "react";
2
+ export interface WaterfallStep {
3
+ key: string;
4
+ label: ReactNode;
5
+ /** `total` bars start at zero and reset the running total; `delta` bars float from it. */
6
+ kind: "total" | "delta";
7
+ /** A total's level, or a delta's signed change. */
8
+ value: number;
9
+ /** Any CSS background (solid color or gradient). */
10
+ color: string;
11
+ /** Dim figure after the value (e.g. share of the first total). */
12
+ note?: ReactNode;
13
+ title?: string;
14
+ }
15
+ export interface WaterfallProps {
16
+ steps: readonly WaterfallStep[];
17
+ /** Formats magnitudes; deltas get their sign from the component. */
18
+ format: (value: number) => string;
19
+ }
20
+ /**
21
+ * Horizontal bridge chart: a total, the changes that eat into it, and the
22
+ * total left at the end. Rows read top to bottom; dashed connectors carry the
23
+ * running total from one bar to the next. Pure layout (percentages), so it
24
+ * never measures the DOM and reflows with its column.
25
+ */
26
+ export declare function Waterfall({ steps, format }: WaterfallProps): import("react").JSX.Element;
@@ -1,7 +1,9 @@
1
1
  export * from "./BarList.js";
2
2
  export * from "./Chart.js";
3
+ export * from "./DotWhisker.js";
3
4
  export * from "./Legend.js";
4
5
  export * from "./ShareBar.js";
5
6
  export * from "./Sparkline.js";
6
7
  export * from "./TimeChart.js";
7
8
  export * from "./types.js";
9
+ export * from "./Waterfall.js";
@@ -11,12 +11,18 @@ export interface ChartSeries {
11
11
  axis?: "left" | "right";
12
12
  /** Diagonal hatching instead of a solid fill (bars/areas). */
13
13
  pattern?: "hatch";
14
- /** Dashed stroke (lines). */
14
+ /** Dashed stroke (lines, area outlines). */
15
15
  dashed?: boolean;
16
16
  /** Leave this series out of the tooltip (e.g. a trend line that repeats a bar). */
17
17
  tooltip?: false;
18
18
  }
19
- export type ChartKind = "bars" | "area" | "line";
19
+ /** `dots` marks each value with a point and no connecting segment (raw samples under a trend line). */
20
+ export type ChartKind = "bars" | "area" | "line" | "dots";
21
+ /** Vertical guide at an x slot (e.g. an experiment start or a compaction). */
22
+ export interface SlotMarker {
23
+ index: number;
24
+ label?: string;
25
+ }
20
26
  /** Horizontal guide drawn across the plot (e.g. a 100% capacity line). */
21
27
  export interface ReferenceLine {
22
28
  value: number;
@@ -0,0 +1,7 @@
1
+ import type { TimeRange } from "../types.js";
2
+ import "../spotlight/spotlight.css";
3
+ export interface SpotlightRouteProps {
4
+ active: boolean;
5
+ range: TimeRange;
6
+ }
7
+ export declare function SpotlightRoute({ active, range }: SpotlightRouteProps): import("react").JSX.Element;
@@ -7,5 +7,6 @@ export * from "./OverviewRoute.js";
7
7
  export * from "./ProjectsRoute.js";
8
8
  export * from "./ProvidersRoute.js";
9
9
  export * from "./RequestsRoute.js";
10
+ export * from "./SpotlightRoute.js";
10
11
  export * from "./ToolsRoute.js";
11
12
  export * from "./TracesRoute.js";
@@ -0,0 +1,8 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ export interface CompoundingProps {
3
+ stats: SpotlightDashboardStats;
4
+ active: boolean;
5
+ stale: boolean;
6
+ }
7
+ /** A cut keeps paying: every later request would have re-read it. One session's context with and without shaping. */
8
+ export declare function Compounding({ stats, active, stale }: CompoundingProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ /** Which tools' output the models of experiment sessions saw, shaped and not: where shaping could reach next. */
3
+ export declare function Coverage({ stats, stale }: {
4
+ stats: SpotlightDashboardStats;
5
+ stale: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ export interface EconomicsProps {
3
+ stats: SpotlightDashboardStats;
4
+ stale: boolean;
5
+ }
6
+ /**
7
+ * Per tool: what a hundred cuts earn after fetch-backs, extra turns and Spotlight's bill. Tools with cuts, the
8
+ * largest saving first; past the top ones the rest sum into one `other` column.
9
+ */
10
+ export declare function Economics({ stats, stale }: EconomicsProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ export interface FetchBackProps {
3
+ stats: SpotlightDashboardStats;
4
+ stale: boolean;
5
+ }
6
+ /** Fetch-back rate per tool: the scored cut against the score-free one, the random holdout and the unchanged results. */
7
+ export declare function FetchBack({ stats, stale }: FetchBackProps): import("react").JSX.Element;
8
+ /** How many calls after the cut the agent fetched back, per tool, shortened against held out. */
9
+ export declare function FetchBackGaps({ stats, stale }: FetchBackProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ export interface SpotlightHeroProps {
3
+ stats: SpotlightDashboardStats;
4
+ /** Prose window ("the last 7 days"). */
5
+ windowLabel: string;
6
+ stale: boolean;
7
+ }
8
+ /**
9
+ * Headline: the holdout-adjusted net (tokens and $, with intervals) against what `plain` would have shown, the old
10
+ * full-output figure struck through as the baseline note, then gross, the excess fetch-back and the sample.
11
+ */
12
+ export declare function SpotlightHero({ stats, windowLabel, stale }: SpotlightHeroProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ /** What shaping costs in latency, reliability and Spotlight's bill. */
3
+ export declare function Overhead({ stats, stale }: {
4
+ stats: SpotlightDashboardStats;
5
+ stale: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ /** Per-line ranking quality: Spotlight's heat and the cut against the lines the agent needed later. */
3
+ export declare function Ranking({ stats, stale }: {
4
+ stats: SpotlightDashboardStats;
5
+ stale: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { SpotlightResultRow } from "../types.js";
2
+ /** The 60 newest shortened results; a row opens its recovery timeline. */
3
+ export declare function ResultsFeed({ rows, stale }: {
4
+ rows: readonly SpotlightResultRow[];
5
+ stale: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import type { SpotlightDashboardStats, TimeRange } from "../types.js";
2
+ export interface SavingsProps {
3
+ stats: SpotlightDashboardStats;
4
+ range: TimeRange;
5
+ stale: boolean;
6
+ }
7
+ /** Cumulative gross vs net per bucket, with what recoveries took back hanging below zero. */
8
+ export declare function SavingsOverTime({ stats, range, stale }: SavingsProps): import("react").JSX.Element;
9
+ /** Bridge from gross to the holdout-adjusted net: every way the saving was undone, and what would have come back anyway. */
10
+ export declare function WhereSavingsWent({ stats, stale }: Omit<SavingsProps, "range">): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import type { SpotlightDashboardStats, TimeRange } from "../types.js";
2
+ export interface ShareTrendProps {
3
+ stats: SpotlightDashboardStats;
4
+ range: TimeRange;
5
+ stale: boolean;
6
+ }
7
+ /** Share of context that is tool output, per session group, raw per bucket and as a rolling ratio. */
8
+ export declare function ShareTrend({ stats, range, stale }: ShareTrendProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ /** Tool × shaping steps × cut size: how much of each kind of cut's saving stays saved after fetch-backs. */
3
+ export declare function Steps({ stats, stale }: {
4
+ stats: SpotlightDashboardStats;
5
+ stale: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { SpotlightDashboardStats } from "../types.js";
2
+ /** Share of the experiment's agent time spent on requests that only fetched cut output back, and on shaping. */
3
+ export declare function TimeCost({ stats, stale }: {
4
+ stats: SpotlightDashboardStats;
5
+ stale: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import type { SpotlightCutGroup, SpotlightRecoveryKind } from "../types.js";
2
+ /** Key to the fetch-back groups: each group's mark shape and color, its rule on hover. */
3
+ export declare function GroupLegend({ groups }: {
4
+ groups: readonly SpotlightCutGroup[];
5
+ }): import("react").JSX.Element;
6
+ /** Shows or hides the tools a card folded away (see `foldTools`). */
7
+ export declare function MoreTools({ hidden, expanded, onToggle, }: {
8
+ hidden: readonly string[];
9
+ expanded: boolean;
10
+ onToggle: () => void;
11
+ }): import("react").JSX.Element;
12
+ /** Recovery kind pill: icon, label (or a count) in the kind's color. */
13
+ export declare function KindBadge({ kind, count }: {
14
+ kind: SpotlightRecoveryKind;
15
+ count?: number;
16
+ }): import("react").JSX.Element;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Spotlight vocabulary shared by the page's sections: recovery-kind and
3
+ * tool labels, their colors (CSS variables from `spotlight.css`, so both
4
+ * themes resolve them) and signed number formatting.
5
+ */
6
+ import { type LucideIcon } from "lucide-react";
7
+ import type { SpotlightCutGroup, SpotlightDashboardStats, SpotlightEstimate, SpotlightGapBin, SpotlightRecoveryKind, SpotlightSizeBin, SpotlightTool } from "../types.js";
8
+ export declare const RECOVERY_KINDS: readonly SpotlightRecoveryKind[];
9
+ export interface RecoveryKindMeta {
10
+ label: string;
11
+ /** Plural, for waterfall steps and totals. */
12
+ plural: string;
13
+ icon: LucideIcon;
14
+ color: string;
15
+ /** One-line rule, for tooltips. */
16
+ rule: string;
17
+ }
18
+ export declare const RECOVERY_KIND: Record<SpotlightRecoveryKind, RecoveryKindMeta>;
19
+ /** The range's evaluated tools, the largest saving first (the order of `gross.byTool`). */
20
+ export declare function toolsBySaving(stats: SpotlightDashboardStats): SpotlightTool[];
21
+ /** Tools a card lists by name before the rest fold into `other` (or behind a "more tools" toggle). */
22
+ export declare const TOP_TOOLS = 6;
23
+ /** The folded rest's label where tools are rows or columns. */
24
+ export declare const OTHER_TOOLS = "other";
25
+ /**
26
+ * Split tools (ordered) into the first `limit` a card lists and the rest it folds; a lone leftover is listed
27
+ * instead.
28
+ */
29
+ export declare function foldTools<T>(items: readonly T[], limit?: number): {
30
+ listed: readonly T[];
31
+ rest: readonly T[];
32
+ };
33
+ export interface CutGroupMeta {
34
+ label: string;
35
+ color: string;
36
+ /** Its mark in dot-whisker charts. */
37
+ shape: "dot" | "ring" | "diamond" | "square";
38
+ /** One-line definition, for tooltips and legends. */
39
+ rule: string;
40
+ }
41
+ /**
42
+ * The fetch-back comparison's groups. The cut is vivid; the score-free cut
43
+ * (the same shaping without Spotlight's scores) takes its own hue; the two
44
+ * baselines are neutral inks, the held-out one (the true counterfactual) the
45
+ * stronger.
46
+ */
47
+ export declare const CUT_GROUP: Record<SpotlightCutGroup, CutGroupMeta>;
48
+ export declare const CUT_GROUPS: readonly SpotlightCutGroup[];
49
+ export declare const SIZE_BINS: readonly SpotlightSizeBin[];
50
+ export declare const GAP_BINS: readonly SpotlightGapBin[];
51
+ /** A tool's icon; tools without one of their own (MCP and extension tools) get a generic wrench. */
52
+ export declare function toolIcon(tool: SpotlightTool): LucideIcon;
53
+ /** What one time bucket of the range is called in prose ("hour", "day"). */
54
+ export declare function bucketNoun(bucketMs: number): string;
55
+ /** Compact token count with a real minus sign. */
56
+ export declare function formatSignedCompact(value: number): string;
57
+ /** Dollar amount with a real minus sign (`formatCost` alone prints `$-0.12`). */
58
+ export declare function formatSignedCost(value: number): string;
59
+ /** A relative change as a signed percentage (`+12%`, `−3.5%`), `–` when undefined. */
60
+ export declare function formatSignedShare(value: number | null): string;
61
+ /** An estimate's 90% interval as `lo–hi`, empty when it has none. */
62
+ export declare function formatInterval(estimate: SpotlightEstimate, format: (value: number) => string): string;
63
+ /** Share as a whole or one-decimal percentage, `–` when undefined. */
64
+ export declare function formatShare(value: number | null): string;
@@ -1,5 +1,6 @@
1
1
  import { Database } from "bun:sqlite";
2
2
  import { type ParseSessionResult, type SessionParserState } from "./parser.js";
3
+ import { type SpotlightCallResultLink, type SpotlightCallRow, type SpotlightNeedRow, type SpotlightRequestRow, type SpotlightSessionRow, type SpotlightShapeRow } from "./spotlight-ingest.js";
3
4
  import type { DailyActivityPoint, FrustrationCounts, MessageStats, MessageStatsInput, ToolCallStats, ToolResultLink, UserMessageLink, UserMessageStats } from "./types.js";
4
5
  /**
5
6
  * Predicate counting one stored request as "unpriced" — the public rate card
@@ -188,3 +189,28 @@ export declare function insertToolCalls(calls: Iterable<ToolCallStats>): number;
188
189
  * never match.
189
190
  */
190
191
  export declare function updateToolResults(links: Iterable<ToolResultLink>): number;
192
+ /** Record each experiment session's first Spotlight marker; a later one (a resumed session) never replaces it. */
193
+ export declare function insertSpotlightSessions(rows: Iterable<SpotlightSessionRow>): number;
194
+ export declare function updateSpotlightTitles(rows: Iterable<{
195
+ sessionFile: string;
196
+ title: string;
197
+ }>): number;
198
+ /**
199
+ * Upsert evaluated results. The shape entry and the result message can land in
200
+ * different tail parses: the shape entry brings Spotlight's usage and timing,
201
+ * the result's details the hidden lines and named artifacts, and either may
202
+ * come first. Fork copies of a call (same tool call id under another
203
+ * transcript) are skipped, first writer wins.
204
+ */
205
+ export declare function upsertSpotlightShapes(rows: Iterable<SpotlightShapeRow>): number;
206
+ /**
207
+ * Merge needed lines of shaped reads: ranges add to the stored ones (a tail parse brings only its own calls'),
208
+ * `open` takes the latest. A fork's copy of another transcript's read is skipped, first writer wins.
209
+ */
210
+ export declare function upsertSpotlightNeeds(rows: Iterable<SpotlightNeedRow>): number;
211
+ /** Insert experiment-session tool calls; fork copies are skipped as for `tool_calls`. */
212
+ export declare function insertSpotlightCalls(rows: Iterable<SpotlightCallRow>): number;
213
+ /** Attach result size and named artifacts to recorded calls (results can land in a later tail parse). */
214
+ export declare function updateSpotlightCallResults(links: Iterable<SpotlightCallResultLink>): number;
215
+ /** Insert experiment-session main-loop requests; fork copies are skipped as for `messages`. */
216
+ export declare function insertSpotlightRequests(rows: Iterable<SpotlightRequestRow>): number;
@@ -5,7 +5,8 @@ export { refreshRollups } from "./rollup.js";
5
5
  export type { StatsJudge, StatsJudgeProvider } from "./frustration.js";
6
6
  export { getGainDashboardStats } from "./gain-aggregator.js";
7
7
  export { formatStatsDashboardUrl, type StartServerOptions, setStatsCloseHandler, startServer } from "./server.js";
8
- export type { GainDashboardStats, GainSource, GainSourceTotals, GainTimeSeriesPoint } from "./shared-types.js";
8
+ export type { GainDashboardStats, GainSource, GainSourceTotals, GainTimeSeriesPoint, SpotlightAgentScope, SpotlightDashboardStats, SpotlightSessionContext, } from "./shared-types.js";
9
+ export { getSpotlightDashboardStats, getSpotlightSessionContext } from "./spotlight-aggregator.js";
9
10
  export type { AggregatedStats, DashboardStats, FolderStats, MessageStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, TimeSeriesPoint, ToolDashboardStats, ToolModelStats, ToolTimeSeriesPoint, ToolUsageStats, } from "./types.js";
10
11
  /**
11
12
  * Print the dashboard summary to the console. Shared by `omp stats --summary`
@@ -1,6 +1,7 @@
1
1
  import type * as nodeFs from "node:fs";
2
2
  import { type ServiceTierByFamily } from "@oh-my-pi/pi-ai";
3
3
  import type { AgentType, MessageStatsInput, SessionEntry, ToolCallStats, ToolResultLink, UserMessageLink, UserMessageStats } from "./types.js";
4
+ import { type SpotlightParseRows, type SpotlightParserState } from "./spotlight-ingest.js";
4
5
  /**
5
6
  * Classify which agent produced a transcript from its path within the sessions
6
7
  * directory. Layout: `<sessionsDir>/<project>/<file>.jsonl` is the `main`
@@ -56,6 +57,8 @@ export interface SessionParserState {
56
57
  mtimeMs: number;
57
58
  checkpoint: string;
58
59
  serviceTier: ServiceTierByFamily | null;
60
+ /** Absent in cursors persisted before the Spotlight tables; such a tail parse starts from an empty state. */
61
+ spotlight?: SpotlightParserState;
59
62
  }
60
63
  export interface ParseSessionResult {
61
64
  stats: MessageStatsInput[];
@@ -63,6 +66,7 @@ export interface ParseSessionResult {
63
66
  userLinks: UserMessageLink[];
64
67
  toolCalls: ToolCallStats[];
65
68
  toolResults: ToolResultLink[];
69
+ spotlight: SpotlightParseRows;
66
70
  newOffset: number;
67
71
  parserState?: SessionParserState;
68
72
  reset?: boolean;
@@ -25,7 +25,7 @@
25
25
  * (an hour of data is small and indexed by timestamp).
26
26
  */
27
27
  import type { Database } from "bun:sqlite";
28
- import type { AgentTypeStats, AggregatedStats, CostTimeSeriesPoint, DailyActivityPoint, FolderStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, ProviderAggregate, ProviderHourlyPoint, ProviderTimeSeriesPoint, TimeSeriesPoint, ToolModelStats, ToolTimeSeriesPoint, ToolUsageStats } from "./types.js";
28
+ import type { AgentType, AgentTypeStats, AggregatedStats, CostTimeSeriesPoint, DailyActivityPoint, FolderStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, ProviderAggregate, ProviderHourlyPoint, ProviderTimeSeriesPoint, TimeSeriesPoint, ToolModelStats, ToolTimeSeriesPoint, ToolUsageStats } from "./types.js";
29
29
  /**
30
30
  * Create (or rebuild after a version bump) the rollup tables and the triggers
31
31
  * that mark hours dirty. Called from `initDb` after the raw tables exist.
@@ -121,3 +121,24 @@ export declare function getToolStats(cutoff?: number | null): ToolUsageStats[];
121
121
  export declare function getToolStatsByModel(cutoff?: number | null): ToolModelStats[];
122
122
  /** Calls and errors per bucket per tool. */
123
123
  export declare function getToolTimeSeries({ cutoff, bucketMs }: RangeWindow): ToolTimeSeriesPoint[];
124
+ /** Per-bucket context facts of every transcript of one agent type: tool-result characters and output tokens. */
125
+ export interface ContextFactPoint {
126
+ bucket: number;
127
+ agentType: AgentType;
128
+ resultChars: number;
129
+ outputTokens: number;
130
+ }
131
+ /** {@link ContextFactPoint}s over a window, from the rollups (exact while few hours are dirty). */
132
+ export declare function getContextFactSeries(database: Database, { cutoff, bucketMs }: RangeWindow): ContextFactPoint[];
133
+ /** A transcript's request span and its first request's prompt (input + cache read + cache write). */
134
+ export interface SessionSpan {
135
+ sessionFile: string;
136
+ startedAt: number;
137
+ endedAt: number;
138
+ firstPrompt: number;
139
+ }
140
+ /**
141
+ * Spans of the transcripts with a request at or after `endedAfter` (all when null), from `session_rollup` with
142
+ * the same exactness rule as {@link getSessionRollups}.
143
+ */
144
+ export declare function getSessionSpans(database: Database, endedAfter: number | null): SessionSpan[];