@oh-my-pi-zen/omp-stats 16.3.6-zen.1

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 (120) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/README.md +82 -0
  3. package/build.ts +95 -0
  4. package/dist/client/index.css +1 -0
  5. package/dist/client/index.html +24 -0
  6. package/dist/client/index.js +257 -0
  7. package/dist/client/styles.css +1656 -0
  8. package/dist/types/aggregator.d.ts +87 -0
  9. package/dist/types/client/App.d.ts +1 -0
  10. package/dist/types/client/api.d.ts +21 -0
  11. package/dist/types/client/app/AppLayout.d.ts +16 -0
  12. package/dist/types/client/app/NavRail.d.ts +7 -0
  13. package/dist/types/client/app/RangeControl.d.ts +7 -0
  14. package/dist/types/client/app/SyncButton.d.ts +14 -0
  15. package/dist/types/client/app/ThemeToggle.d.ts +1 -0
  16. package/dist/types/client/app/TopBar.d.ts +15 -0
  17. package/dist/types/client/app/routes.d.ts +12 -0
  18. package/dist/types/client/components/AgentTokenShare.d.ts +5 -0
  19. package/dist/types/client/components/chart-shared.d.ts +173 -0
  20. package/dist/types/client/components/models-table-shared.d.ts +175 -0
  21. package/dist/types/client/components/range-meta.d.ts +21 -0
  22. package/dist/types/client/data/charts.d.ts +1 -0
  23. package/dist/types/client/data/formatters.d.ts +8 -0
  24. package/dist/types/client/data/useHashRoute.d.ts +8 -0
  25. package/dist/types/client/data/useResource.d.ts +13 -0
  26. package/dist/types/client/data/view-models.d.ts +67 -0
  27. package/dist/types/client/index.d.ts +2 -0
  28. package/dist/types/client/routes/BehaviorRoute.d.ts +7 -0
  29. package/dist/types/client/routes/CostsRoute.d.ts +7 -0
  30. package/dist/types/client/routes/ErrorsRoute.d.ts +8 -0
  31. package/dist/types/client/routes/GainRoute.d.ts +7 -0
  32. package/dist/types/client/routes/ModelsRoute.d.ts +7 -0
  33. package/dist/types/client/routes/OverviewRoute.d.ts +8 -0
  34. package/dist/types/client/routes/ProjectsRoute.d.ts +7 -0
  35. package/dist/types/client/routes/RequestsRoute.d.ts +8 -0
  36. package/dist/types/client/routes/ToolsRoute.d.ts +7 -0
  37. package/dist/types/client/routes/index.d.ts +9 -0
  38. package/dist/types/client/types.d.ts +63 -0
  39. package/dist/types/client/ui/AsyncBoundary.d.ts +12 -0
  40. package/dist/types/client/ui/DataTable.d.ts +17 -0
  41. package/dist/types/client/ui/EmptyState.d.ts +7 -0
  42. package/dist/types/client/ui/ErrorState.d.ts +6 -0
  43. package/dist/types/client/ui/JsonBlock.d.ts +7 -0
  44. package/dist/types/client/ui/MetricCluster.d.ts +5 -0
  45. package/dist/types/client/ui/Panel.d.ts +7 -0
  46. package/dist/types/client/ui/RequestDrawer.d.ts +5 -0
  47. package/dist/types/client/ui/SegmentedControl.d.ts +12 -0
  48. package/dist/types/client/ui/Skeleton.d.ts +8 -0
  49. package/dist/types/client/ui/StatusPill.d.ts +7 -0
  50. package/dist/types/client/ui/index.d.ts +11 -0
  51. package/dist/types/client/useSystemTheme.d.ts +11 -0
  52. package/dist/types/db.d.ts +144 -0
  53. package/dist/types/embedded-client.d.ts +18 -0
  54. package/dist/types/gain-aggregator.d.ts +26 -0
  55. package/dist/types/index.d.ts +7 -0
  56. package/dist/types/parser.d.ts +53 -0
  57. package/dist/types/server.d.ts +7 -0
  58. package/dist/types/shared-types.d.ts +301 -0
  59. package/dist/types/sync-worker.d.ts +31 -0
  60. package/dist/types/types.d.ts +164 -0
  61. package/dist/types/user-metrics.d.ts +72 -0
  62. package/package.json +95 -0
  63. package/src/aggregator.ts +501 -0
  64. package/src/client/App.tsx +109 -0
  65. package/src/client/api.ts +102 -0
  66. package/src/client/app/AppLayout.tsx +93 -0
  67. package/src/client/app/NavRail.tsx +44 -0
  68. package/src/client/app/RangeControl.tsx +39 -0
  69. package/src/client/app/SyncButton.tsx +75 -0
  70. package/src/client/app/ThemeToggle.tsx +37 -0
  71. package/src/client/app/TopBar.tsx +73 -0
  72. package/src/client/app/routes.ts +69 -0
  73. package/src/client/components/AgentTokenShare.tsx +68 -0
  74. package/src/client/components/chart-shared.tsx +257 -0
  75. package/src/client/components/models-table-shared.tsx +255 -0
  76. package/src/client/components/range-meta.ts +73 -0
  77. package/src/client/css.d.ts +1 -0
  78. package/src/client/data/charts.ts +14 -0
  79. package/src/client/data/formatters.ts +45 -0
  80. package/src/client/data/useHashRoute.ts +87 -0
  81. package/src/client/data/useResource.ts +154 -0
  82. package/src/client/data/view-models.ts +251 -0
  83. package/src/client/index.tsx +10 -0
  84. package/src/client/routes/BehaviorRoute.tsx +623 -0
  85. package/src/client/routes/CostsRoute.tsx +234 -0
  86. package/src/client/routes/ErrorsRoute.tsx +118 -0
  87. package/src/client/routes/GainRoute.tsx +226 -0
  88. package/src/client/routes/ModelsRoute.tsx +430 -0
  89. package/src/client/routes/OverviewRoute.tsx +342 -0
  90. package/src/client/routes/ProjectsRoute.tsx +163 -0
  91. package/src/client/routes/RequestsRoute.tsx +123 -0
  92. package/src/client/routes/ToolsRoute.tsx +463 -0
  93. package/src/client/routes/index.ts +9 -0
  94. package/src/client/styles.css +1330 -0
  95. package/src/client/types.ts +80 -0
  96. package/src/client/ui/AsyncBoundary.tsx +54 -0
  97. package/src/client/ui/DataTable.tsx +122 -0
  98. package/src/client/ui/EmptyState.tsx +16 -0
  99. package/src/client/ui/ErrorState.tsx +25 -0
  100. package/src/client/ui/JsonBlock.tsx +75 -0
  101. package/src/client/ui/MetricCluster.tsx +67 -0
  102. package/src/client/ui/Panel.tsx +24 -0
  103. package/src/client/ui/RequestDrawer.tsx +208 -0
  104. package/src/client/ui/SegmentedControl.tsx +36 -0
  105. package/src/client/ui/Skeleton.tsx +17 -0
  106. package/src/client/ui/StatusPill.tsx +15 -0
  107. package/src/client/ui/index.ts +11 -0
  108. package/src/client/useSystemTheme.ts +87 -0
  109. package/src/db.ts +1530 -0
  110. package/src/embedded-client.generated.txt +0 -0
  111. package/src/embedded-client.ts +26 -0
  112. package/src/gain-aggregator.ts +281 -0
  113. package/src/index.ts +194 -0
  114. package/src/parser.ts +450 -0
  115. package/src/server.ts +352 -0
  116. package/src/shared-types.ts +323 -0
  117. package/src/sync-worker.ts +40 -0
  118. package/src/types.ts +171 -0
  119. package/src/user-metrics.ts +685 -0
  120. package/tailwind.config.js +40 -0
@@ -0,0 +1,87 @@
1
+ import type { BehaviorDashboardStats, DashboardStats, MessageStats, RequestDetails, ToolDashboardStats } from "./types";
2
+ /**
3
+ * Progress event emitted after each session file is fully processed.
4
+ * `current` is the number of files completed (skipped + parsed),
5
+ * `total` is the size of the work set. `processed` is the running total
6
+ * of inserted rows.
7
+ */
8
+ export interface SyncProgress {
9
+ current: number;
10
+ total: number;
11
+ processed: number;
12
+ sessionFile: string;
13
+ }
14
+ export interface SyncOptions {
15
+ /** Called after each file completes. Synchronous; keep it cheap. */
16
+ onProgress?: (event: SyncProgress) => void;
17
+ /**
18
+ * Worker pool size. Defaults to a sensible value derived from the host
19
+ * (capped to avoid drowning a small machine in workers). Set to `1` to
20
+ * force serial parsing without spawning workers.
21
+ */
22
+ workers?: number;
23
+ }
24
+ /**
25
+ * Smoke test: spawns one sync worker, pings it, asserts the pong response,
26
+ * then terminates. Used by `omp --smoke-test` so the install-method CI jobs
27
+ * catch the silent worker-load failure that hit compiled binaries in #1011
28
+ * and #1027 — neither `--version` nor `stats --summary` exercises the worker
29
+ * spawn path on a fresh install (no session files = early return), so a
30
+ * dedicated probe is the only reliable signal.
31
+ *
32
+ * No-op on darwin: `syncAllSessions` keeps macOS on the serial parser path
33
+ * (see {@link defaultWorkerCount}) so the worker spawn surface is unreachable
34
+ * from the CLI, and probing it under the hardened runtime in
35
+ * `scripts/ci-macos-sign.sh` would re-enter the Bun-worker abort surface that
36
+ * motivated the darwin serial default in the first place.
37
+ *
38
+ * Rejects on transport error, error response, or timeout.
39
+ */
40
+ export declare function smokeTestSyncWorker({ timeoutMs }?: {
41
+ timeoutMs?: number;
42
+ }): Promise<void>;
43
+ /**
44
+ * Sync all session files to the database.
45
+ *
46
+ * `workers: 1` parses inline. Larger pools fan parsing out across workers
47
+ * (one in-flight job per worker) while DB writes and offset bookkeeping stay on
48
+ * the calling thread so the single SQLite handle stays uncontended.
49
+ * `onProgress` fires once per completed file (skipped files included so the
50
+ * bar walks at a steady rate).
51
+ */
52
+ export declare function syncAllSessions(opts?: SyncOptions): Promise<{
53
+ processed: number;
54
+ files: number;
55
+ }>;
56
+ interface TimeRangeConfig {
57
+ timeSeriesHours: number;
58
+ timeSeriesBucketMs: number;
59
+ modelSeriesDays: number;
60
+ modelSeriesBucketMs: number;
61
+ modelPerformanceDays: number;
62
+ modelPerformanceBucketMs: number;
63
+ costSeriesDays: number;
64
+ cutoff: number | null;
65
+ }
66
+ export declare function getTimeRangeConfig(range?: string | null): TimeRangeConfig;
67
+ /**
68
+ * Get all dashboard stats.
69
+ */
70
+ export declare function getDashboardStats(range?: string | null): Promise<DashboardStats>;
71
+ export declare function getOverviewStats(range?: string | null): Promise<Pick<DashboardStats, "overall" | "byAgentType" | "timeSeries">>;
72
+ export declare function getModelDashboardStats(range?: string | null): Promise<Pick<DashboardStats, "byModel" | "modelSeries" | "modelPerformanceSeries">>;
73
+ export declare function getCostDashboardStats(range?: string | null): Promise<Pick<DashboardStats, "costSeries">>;
74
+ export declare function getRecentRequests(limit?: number): Promise<MessageStats[]>;
75
+ export declare function getRecentErrors(limit?: number): Promise<MessageStats[]>;
76
+ export declare function getRequestDetails(id: number): Promise<RequestDetails | null>;
77
+ /**
78
+ * Get the current message count in the database.
79
+ */
80
+ export declare function getTotalMessageCount(): Promise<number>;
81
+ export declare function getBehaviorDashboardStats(range?: string | null): Promise<BehaviorDashboardStats>;
82
+ /**
83
+ * Get the tools dashboard payload: per-tool totals, per-(tool, model)
84
+ * breakdown, and the call time series (bucketed like the model series).
85
+ */
86
+ export declare function getToolDashboardStats(range?: string | null): Promise<ToolDashboardStats>;
87
+ export {};
@@ -0,0 +1 @@
1
+ export default function App(): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import type { BehaviorDashboardStats, CostDashboardStats, FolderStats, GainDashboardStats, MessageStats, ModelDashboardStats, OverviewStats, RequestDetails, TimeRange, ToolDashboardStats } from "./types";
2
+ export declare class ApiError extends Error {
3
+ status: number;
4
+ endpoint: string;
5
+ constructor(status: number, endpoint: string, message: string);
6
+ }
7
+ export declare function getOverviewStats(range?: TimeRange, signal?: AbortSignal): Promise<OverviewStats>;
8
+ export declare function getModelDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<ModelDashboardStats>;
9
+ export declare function getCostDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<CostDashboardStats>;
10
+ export declare function getRecentRequests(limit?: number, signal?: AbortSignal): Promise<MessageStats[]>;
11
+ export declare function getRecentErrors(limit?: number, signal?: AbortSignal): Promise<MessageStats[]>;
12
+ export declare function getRequestDetails(id: number, signal?: AbortSignal): Promise<RequestDetails>;
13
+ export declare function sync(signal?: AbortSignal): Promise<{
14
+ processed: number;
15
+ files: number;
16
+ totalMessages: number;
17
+ }>;
18
+ export declare function getBehaviorDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<BehaviorDashboardStats>;
19
+ export declare function getFolderStats(range?: TimeRange, signal?: AbortSignal): Promise<FolderStats[]>;
20
+ export declare function getGainDashboardStats(range?: TimeRange, project?: string | null, signal?: AbortSignal): Promise<GainDashboardStats>;
21
+ export declare function getToolDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<ToolDashboardStats>;
@@ -0,0 +1,16 @@
1
+ import type React from "react";
2
+ import type { TimeRange } from "../types";
3
+ import type { DashboardSection } from "./routes";
4
+ export interface AppLayoutProps {
5
+ activeSection: DashboardSection;
6
+ onSectionChange: (section: DashboardSection) => void;
7
+ range: TimeRange;
8
+ onRangeChange: (range: TimeRange) => void;
9
+ updatedAt: number | null;
10
+ onSyncStart?: () => void;
11
+ onSyncComplete?: (result: {
12
+ success: boolean;
13
+ }) => void;
14
+ children: React.ReactNode;
15
+ }
16
+ export declare function AppLayout({ activeSection, onSectionChange, range, onRangeChange, updatedAt, onSyncStart, onSyncComplete, children, }: AppLayoutProps): React.JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { type DashboardSection } from "./routes";
2
+ export interface NavRailProps {
3
+ activeSection: DashboardSection;
4
+ onSectionChange: (section: DashboardSection) => void;
5
+ className?: string;
6
+ }
7
+ export declare function NavRail({ activeSection, onSectionChange, className }: NavRailProps): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import type { TimeRange } from "../types";
2
+ export interface RangeControlProps {
3
+ value: TimeRange;
4
+ onChange: (value: TimeRange) => void;
5
+ className?: string;
6
+ }
7
+ export declare function RangeControl({ value, onChange, className }: RangeControlProps): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ export interface SyncButtonProps {
2
+ onSyncStart?: () => void;
3
+ onSyncComplete?: (result: {
4
+ success: boolean;
5
+ data?: {
6
+ processed: number;
7
+ files: number;
8
+ totalMessages: number;
9
+ };
10
+ error?: string;
11
+ }) => void;
12
+ className?: string;
13
+ }
14
+ export declare function SyncButton({ onSyncStart, onSyncComplete, className }: SyncButtonProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function ThemeToggle(): import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ import type { TimeRange } from "../types";
2
+ import type { DashboardSection } from "./routes";
3
+ export interface TopBarProps {
4
+ activeSection: DashboardSection;
5
+ range: TimeRange;
6
+ onRangeChange: (range: TimeRange) => void;
7
+ updatedAt: number | null;
8
+ onSyncStart?: () => void;
9
+ onSyncComplete?: (result: {
10
+ success: boolean;
11
+ }) => void;
12
+ onMenuToggle?: () => void;
13
+ className?: string;
14
+ }
15
+ export declare function TopBar({ activeSection, range, onRangeChange, updatedAt, onSyncStart, onSyncComplete, onMenuToggle, className, }: TopBarProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type React from "react";
2
+ export type DashboardSection = "overview" | "requests" | "errors" | "models" | "tools" | "costs" | "behavior" | "projects" | "gain";
3
+ export interface DashboardRoute {
4
+ id: DashboardSection;
5
+ label: string;
6
+ shortLabel?: string;
7
+ icon: React.ComponentType<{
8
+ size?: number;
9
+ className?: string;
10
+ }>;
11
+ }
12
+ export declare const routes: DashboardRoute[];
@@ -0,0 +1,5 @@
1
+ import type { AgentTypeStats } from "../types";
2
+ export interface AgentTokenShareProps {
3
+ stats: AgentTypeStats[];
4
+ }
5
+ export declare function AgentTokenShare({ stats }: AgentTokenShareProps): import("react").JSX.Element;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Shared chart primitives for the dashboard timeline charts: the OMP color
3
+ * palette, light/dark chart chrome, legend/tooltip + scale plumbing, dataset
4
+ * styling, and the top-N-by-model / aggregate bucketing used by the cost and
5
+ * behavior series.
6
+ */
7
+ export declare const MODEL_COLORS: string[];
8
+ export declare const CHART_THEMES: {
9
+ readonly dark: {
10
+ readonly legendLabel: "#a89fb3";
11
+ readonly tooltipBackground: "#241a2e";
12
+ readonly tooltipTitle: "#eae5ef";
13
+ readonly tooltipBody: "#a89fb3";
14
+ readonly tooltipBorder: "rgba(255, 255, 255, 0.12)";
15
+ readonly grid: "rgba(255, 255, 255, 0.06)";
16
+ readonly tick: "#867a93";
17
+ };
18
+ readonly light: {
19
+ readonly legendLabel: "#5a5462";
20
+ readonly tooltipBackground: "#ffffff";
21
+ readonly tooltipTitle: "#241a2e";
22
+ readonly tooltipBody: "#5a5462";
23
+ readonly tooltipBorder: "rgba(20, 12, 28, 0.15)";
24
+ readonly grid: "rgba(20, 12, 28, 0.08)";
25
+ readonly tick: "#6a6275";
26
+ };
27
+ };
28
+ export type ChartTheme = (typeof CHART_THEMES)[keyof typeof CHART_THEMES];
29
+ export interface ChartSeries {
30
+ labels: string[];
31
+ datasets: Array<{
32
+ label: string;
33
+ data: number[];
34
+ }>;
35
+ }
36
+ interface TooltipItem {
37
+ parsed: {
38
+ y: number | null;
39
+ };
40
+ }
41
+ /** Tooltip + legend config common to bar and line variants of the time charts. */
42
+ export declare function buildSharedPlugins(opts: {
43
+ chartTheme: ChartTheme;
44
+ showLegend: boolean;
45
+ defaultLabel: string;
46
+ formatValue: (n: number) => string;
47
+ footer?: (items: TooltipItem[]) => string | undefined;
48
+ }): {
49
+ legend: {
50
+ display: boolean;
51
+ position: "top";
52
+ align: "start";
53
+ labels: {
54
+ color: "#5a5462" | "#a89fb3";
55
+ usePointStyle: boolean;
56
+ padding: number;
57
+ font: {
58
+ size: number;
59
+ };
60
+ boxWidth: number;
61
+ };
62
+ };
63
+ tooltip: {
64
+ backgroundColor: "#241a2e" | "#ffffff";
65
+ titleColor: "#241a2e" | "#eae5ef";
66
+ bodyColor: "#5a5462" | "#a89fb3";
67
+ borderColor: "rgba(20, 12, 28, 0.15)" | "rgba(255, 255, 255, 0.12)";
68
+ borderWidth: number;
69
+ padding: number;
70
+ cornerRadius: number;
71
+ callbacks: {
72
+ label: (ctx: {
73
+ dataset: {
74
+ label?: string;
75
+ };
76
+ parsed: {
77
+ y: number | null;
78
+ };
79
+ }) => string;
80
+ footer?: ((items: TooltipItem[]) => string | undefined) | undefined;
81
+ };
82
+ };
83
+ };
84
+ /** Y-axis tick formatter + grid/tick styling shared by both charts. */
85
+ export declare function buildSharedScales(opts: {
86
+ chartTheme: ChartTheme;
87
+ formatY: (n: number) => string;
88
+ }): {
89
+ sharedScaleBase: {
90
+ grid: {
91
+ color: "rgba(20, 12, 28, 0.08)" | "rgba(255, 255, 255, 0.06)";
92
+ drawBorder: boolean;
93
+ };
94
+ ticks: {
95
+ color: "#6a6275" | "#867a93";
96
+ font: {
97
+ size: number;
98
+ };
99
+ };
100
+ };
101
+ yScale: {
102
+ grid: {
103
+ color: "rgba(20, 12, 28, 0.08)" | "rgba(255, 255, 255, 0.06)";
104
+ drawBorder: boolean;
105
+ };
106
+ ticks: {
107
+ color: "#6a6275" | "#867a93";
108
+ font: {
109
+ size: number;
110
+ };
111
+ callback: (value: number | string) => string;
112
+ };
113
+ min: number;
114
+ };
115
+ };
116
+ /** Stylistic defaults for a single line dataset in a stacked/by-model chart. */
117
+ export declare function lineDatasetStyle(color: string): {
118
+ borderColor: string;
119
+ backgroundColor: string;
120
+ fill: boolean;
121
+ tension: number;
122
+ pointRadius: number;
123
+ pointHoverRadius: number;
124
+ borderWidth: number;
125
+ };
126
+ /** Stylistic defaults for a single bar dataset in a stacked chart. */
127
+ export declare function barDatasetStyle(color: string): {
128
+ backgroundColor: string;
129
+ borderColor: string;
130
+ borderWidth: number;
131
+ borderRadius: number;
132
+ maxBarThickness: number;
133
+ };
134
+ /**
135
+ * Map a generic ChartSeries' datasets through a per-index style function so
136
+ * callers can supply line or bar styling without repeating the label/data
137
+ * spread at every chart site.
138
+ */
139
+ export declare function styleDatasets(series: ChartSeries, styleFor: (index: number) => Record<string, unknown>): {
140
+ label: string;
141
+ data: number[];
142
+ }[];
143
+ /**
144
+ * Bucket points by day into a single aggregate series. Caller supplies the
145
+ * per-bucket accumulator + final value extractor; mirrors the shape of
146
+ * `buildTopNByModelSeries` for the non-by-model variant of each time chart.
147
+ */
148
+ export declare function buildAggregateTimeSeries<T extends {
149
+ timestamp: number;
150
+ }, B>(points: T[], label: string, opts: {
151
+ initBucket: () => B;
152
+ accumulate: (bucket: B, point: T) => void;
153
+ bucketToValue: (bucket: B) => number;
154
+ }): ChartSeries;
155
+ interface ModelKeyedPoint {
156
+ timestamp: number;
157
+ model: string;
158
+ provider: string;
159
+ }
160
+ /**
161
+ * Bucket points by day and by top-N model (with an "Other" rollup), producing
162
+ * a ChartSeries. Caller controls how points contribute to ranking and to each
163
+ * day-bucket value via the `rankWeight`/`accumulate`/`bucketToValue` callbacks
164
+ * — keeps the behavior chart's rate math separate from the cost chart's sum.
165
+ */
166
+ export declare function buildTopNByModelSeries<T extends ModelKeyedPoint, B>(points: T[], opts: {
167
+ topN?: number;
168
+ rankWeight: (point: T) => number;
169
+ initBucket: () => B;
170
+ accumulate: (bucket: B, point: T) => void;
171
+ bucketToValue: (bucket: B) => number;
172
+ }): ChartSeries;
173
+ export {};
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Shared primitives for the per-model breakdown tables. Each table owns its
3
+ * column definitions, sort order, and chart type — this module owns the
4
+ * surface chrome, expand-row plumbing, theme palette, the mini-sparkline, and
5
+ * the shared plugin/scale config consumed by multi-line detail charts.
6
+ */
7
+ import type { ChartTheme } from "./chart-shared";
8
+ export { CHART_THEMES as TABLE_CHART_THEMES, MODEL_COLORS } from "./chart-shared";
9
+ export type TableChartTheme = ChartTheme;
10
+ /** Style defaults for one line in a non-stacked detail chart. */
11
+ export declare function lineSeriesStyle(color: string): {
12
+ borderColor: string;
13
+ backgroundColor: string;
14
+ tension: number;
15
+ pointRadius: number;
16
+ borderWidth: number;
17
+ };
18
+ /**
19
+ * No-axis, no-legend single-series sparkline used in the trend cell of every
20
+ * model row. Caller supplies the already-extracted numeric series so this
21
+ * stays agnostic of the row's underlying data shape.
22
+ */
23
+ export declare function MiniSparkline({ timestamps, values, color, }: {
24
+ timestamps: number[];
25
+ values: number[];
26
+ color: string;
27
+ }): import("react").JSX.Element;
28
+ /**
29
+ * Plugin block (legend + tooltip) shared by every multi-series detail chart
30
+ * in the table expanded views.
31
+ */
32
+ export declare function detailChartPlugins(chartTheme: TableChartTheme): {
33
+ legend: {
34
+ display: boolean;
35
+ position: "top";
36
+ labels: {
37
+ color: "#5a5462" | "#a89fb3";
38
+ usePointStyle: boolean;
39
+ padding: number;
40
+ font: {
41
+ size: number;
42
+ };
43
+ };
44
+ };
45
+ tooltip: {
46
+ backgroundColor: "#241a2e" | "#ffffff";
47
+ titleColor: "#241a2e" | "#eae5ef";
48
+ bodyColor: "#5a5462" | "#a89fb3";
49
+ borderColor: "rgba(20, 12, 28, 0.15)" | "rgba(255, 255, 255, 0.12)";
50
+ borderWidth: number;
51
+ cornerRadius: number;
52
+ };
53
+ };
54
+ /**
55
+ * Single-Y-axis scales for a detail chart (used when every series shares a
56
+ * unit, e.g. behavior counts). Min anchored at 0.
57
+ */
58
+ export declare function detailChartScalesSingleAxis(chartTheme: TableChartTheme): {
59
+ x: {
60
+ grid: {
61
+ color: "rgba(20, 12, 28, 0.08)" | "rgba(255, 255, 255, 0.06)";
62
+ };
63
+ ticks: {
64
+ color: "#6a6275" | "#867a93";
65
+ font: {
66
+ size: number;
67
+ };
68
+ };
69
+ };
70
+ y: {
71
+ grid: {
72
+ color: "rgba(20, 12, 28, 0.08)" | "rgba(255, 255, 255, 0.06)";
73
+ };
74
+ ticks: {
75
+ color: "#6a6275" | "#867a93";
76
+ font: {
77
+ size: number;
78
+ };
79
+ };
80
+ min: number;
81
+ };
82
+ };
83
+ /**
84
+ * Dual-Y-axis scales for a detail chart with mixed units (e.g. TTFT seconds
85
+ * on left, tokens/s on right). Right-axis grid is suppressed so it doesn't
86
+ * collide with the left.
87
+ */
88
+ export declare function detailChartScalesDualAxis(chartTheme: TableChartTheme): {
89
+ x: {
90
+ grid: {
91
+ color: "rgba(20, 12, 28, 0.08)" | "rgba(255, 255, 255, 0.06)";
92
+ };
93
+ ticks: {
94
+ color: "#6a6275" | "#867a93";
95
+ font: {
96
+ size: number;
97
+ };
98
+ };
99
+ };
100
+ y: {
101
+ type: "linear";
102
+ display: boolean;
103
+ position: "left";
104
+ grid: {
105
+ color: "rgba(20, 12, 28, 0.08)" | "rgba(255, 255, 255, 0.06)";
106
+ };
107
+ ticks: {
108
+ color: "#6a6275" | "#867a93";
109
+ font: {
110
+ size: number;
111
+ };
112
+ };
113
+ };
114
+ y1: {
115
+ type: "linear";
116
+ display: boolean;
117
+ position: "right";
118
+ grid: {
119
+ drawOnChartArea: boolean;
120
+ };
121
+ ticks: {
122
+ color: "#6a6275" | "#867a93";
123
+ font: {
124
+ size: number;
125
+ };
126
+ };
127
+ };
128
+ };
129
+ export interface TableColumn {
130
+ label: string;
131
+ align?: "left" | "right" | "center";
132
+ }
133
+ /** Outer card + section title used by every model table. */
134
+ export declare function ModelTableShell({ title, subtitle, children, }: {
135
+ title: string;
136
+ subtitle?: string;
137
+ children: React.ReactNode;
138
+ }): import("react").JSX.Element;
139
+ /** Sticky column-header row for a model table. */
140
+ export declare function ModelTableHeader({ columns, gridTemplate }: {
141
+ columns: TableColumn[];
142
+ gridTemplate: string;
143
+ }): import("react").JSX.Element;
144
+ /** Scroll wrapper for the row stack — capped to fit the dashboard viewport. */
145
+ export declare function ModelTableBody({ children }: {
146
+ children: React.ReactNode;
147
+ }): import("react").JSX.Element;
148
+ /**
149
+ * Two-line model identity cell (model name + provider) shared by every
150
+ * per-model table. Kept as a stable named contract so callers don't restate
151
+ * the same two divs and font-utility classes.
152
+ */
153
+ export declare function ModelNameCell({ model, provider }: {
154
+ model: string;
155
+ provider: string;
156
+ }): import("react").JSX.Element;
157
+ /**
158
+ * One expandable model row. `cells` matches the column order from
159
+ * `ModelTableHeader` plus the trend cell at the end (caller controls the
160
+ * sparkline / placeholder). `expandedContent` is the panel revealed on toggle.
161
+ */
162
+ export declare function ExpandableModelRow({ gridTemplate, cells, trendCell, isExpanded, onToggle, expandedContent, }: {
163
+ gridTemplate: string;
164
+ cells: React.ReactNode[];
165
+ trendCell: React.ReactNode;
166
+ isExpanded: boolean;
167
+ onToggle: () => void;
168
+ expandedContent: React.ReactNode;
169
+ }): import("react").JSX.Element;
170
+ /** Placeholder shown in the trend cell when a model has no time-series data. */
171
+ export declare function TrendEmpty(): import("react").JSX.Element;
172
+ /** Placeholder shown in the expanded detail-chart slot when data is missing. */
173
+ export declare function DetailChartEmpty({ message }: {
174
+ message?: string;
175
+ }): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Display metadata for a `TimeRange` — keeps chart labels, sparkline bucket
3
+ * counts, and x-axis date formatting in sync with the server-side bucketing
4
+ * defined in `aggregator.ts`.
5
+ */
6
+ import type { TimeRange } from "../types";
7
+ export interface RangeMeta {
8
+ /** Human label used in chart subtitles ("the last 24 hours"). */
9
+ windowLabel: string;
10
+ /** Short prefix used in compact column headers ("24h Trend"). */
11
+ trendLabel: string;
12
+ /** Bucket size matching the server query for this range. */
13
+ bucketMs: number;
14
+ /** Number of buckets the server is expected to return for this range. */
15
+ bucketCount: number;
16
+ /** date-fns format string for x-axis labels and tooltip headings. */
17
+ tickFormat: string;
18
+ }
19
+ export declare function rangeMeta(range: TimeRange): RangeMeta;
20
+ /** Format a bucket timestamp using the active range's tick format. */
21
+ export declare function formatRangeTick(timestamp: number, range: TimeRange): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export declare function formatInteger(value: number): string;
2
+ export declare function formatCompact(value: number): string;
3
+ export declare function formatCost(value: number, digits?: number): string;
4
+ export declare function formatPercent(value: number, digits?: number): string;
5
+ export declare function formatDurationMs(value: number | null, digits?: number): string;
6
+ export declare function formatTokensPerSecond(value: number | null): string;
7
+ export declare function formatRelativeTime(timestamp: number): string;
8
+ export declare function formatBytes(value: number): string;
@@ -0,0 +1,8 @@
1
+ import type { DashboardSection } from "../app/routes";
2
+ import type { TimeRange } from "../types";
3
+ export declare function useHashRoute(): {
4
+ section: DashboardSection;
5
+ setSection: (newSection: DashboardSection) => void;
6
+ range: TimeRange;
7
+ setRange: (newRange: string) => void;
8
+ };
@@ -0,0 +1,13 @@
1
+ export interface ResourceResult<T> {
2
+ data: T | null;
3
+ error: Error | null;
4
+ loading: boolean;
5
+ refreshing: boolean;
6
+ refetch: () => Promise<void>;
7
+ updatedAt: number | null;
8
+ }
9
+ export interface ResourceOptions {
10
+ pollMs?: number;
11
+ enabled?: boolean;
12
+ }
13
+ export declare function useResource<T>(key: readonly unknown[], fetcher: (signal: AbortSignal) => Promise<T>, options?: ResourceOptions): ResourceResult<T>;
@@ -0,0 +1,67 @@
1
+ import type { AgentType, AgentTypeStats, BehaviorOverallStats, BehaviorTimeSeriesPoint, CostTimeSeriesPoint, FolderStats, ModelPerformancePoint, TimeRange, ToolUsageStats } from "../types";
2
+ export interface AgentTokenSegment {
3
+ agentType: AgentType;
4
+ /** input + output + cache read + cache write — the displayed denominator. */
5
+ tokens: number;
6
+ requests: number;
7
+ cost: number;
8
+ /** Fraction (0-1) of total tokens across all present agent types. */
9
+ share: number;
10
+ }
11
+ export interface AgentTokenShareView {
12
+ totalTokens: number;
13
+ totalCost: number;
14
+ segments: AgentTokenSegment[];
15
+ }
16
+ /**
17
+ * Build the "token usage by agent" breakdown: one segment per agent type that
18
+ * appears in the data, ordered main -> subagents -> advisor, each carrying its
19
+ * token total and share of the grand total. Token counts sum the same four
20
+ * columns the overview renders (input + output + cache read + cache write) so a
21
+ * segment's share never disagrees with the count beside it.
22
+ */
23
+ export declare function buildAgentTokenShare(stats: AgentTypeStats[]): AgentTokenShareView;
24
+ export interface CostSummaryView {
25
+ totalCost: number;
26
+ avgDailyCost: number;
27
+ topModelName: string;
28
+ topModelCost: number;
29
+ }
30
+ export interface ModelPerformanceDataPoint {
31
+ timestamp: number;
32
+ avgTtftSeconds: number | null;
33
+ avgTokensPerSecond: number | null;
34
+ requests: number;
35
+ }
36
+ export interface ModelPerformanceSeries {
37
+ label: string;
38
+ data: ModelPerformanceDataPoint[];
39
+ }
40
+ export interface BehaviorSummaryView {
41
+ totalMessages: number;
42
+ totalYelling: number;
43
+ totalProfanity: number;
44
+ totalAnguish: number;
45
+ totalFrustration: number;
46
+ highestFrictionModel: {
47
+ model: string;
48
+ provider: string;
49
+ score: number;
50
+ } | null;
51
+ }
52
+ export interface FolderRowView extends FolderStats {
53
+ costPercentage: number;
54
+ requestsPercentage: number;
55
+ }
56
+ export declare function buildCostSummary(costSeries: CostTimeSeriesPoint[]): CostSummaryView;
57
+ export declare function buildModelPerformanceLookup(points: ModelPerformancePoint[], range: TimeRange): Map<string, ModelPerformanceSeries>;
58
+ export declare function buildBehaviorSummary(overall: BehaviorOverallStats, series: BehaviorTimeSeriesPoint[]): BehaviorSummaryView;
59
+ export declare function buildFolderRows(folders: FolderStats[]): FolderRowView[];
60
+ /** Table row for the Tools route: usage stats plus derived rates/shares. */
61
+ export interface ToolRowView extends ToolUsageStats {
62
+ /** errors / calls (0 for zero calls). */
63
+ errorRate: number;
64
+ /** Calls relative to the busiest tool, 0-100, for the share bar. */
65
+ callsPercentage: number;
66
+ }
67
+ export declare function buildToolRows(tools: ToolUsageStats[]): ToolRowView[];