jeopi-stats 16.2.13 → 16.2.14
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.
- package/CHANGELOG.md +2 -0
- package/README.md +3 -3
- package/package.json +16 -16
- package/src/gain-aggregator.ts +2 -2
- package/dist/types/aggregator.d.ts +0 -82
- package/dist/types/client/App.d.ts +0 -1
- package/dist/types/client/api.d.ts +0 -20
- package/dist/types/client/app/AppLayout.d.ts +0 -16
- package/dist/types/client/app/NavRail.d.ts +0 -7
- package/dist/types/client/app/RangeControl.d.ts +0 -7
- package/dist/types/client/app/SyncButton.d.ts +0 -14
- package/dist/types/client/app/ThemeToggle.d.ts +0 -1
- package/dist/types/client/app/TopBar.d.ts +0 -15
- package/dist/types/client/app/routes.d.ts +0 -12
- package/dist/types/client/components/AgentTokenShare.d.ts +0 -5
- package/dist/types/client/components/chart-shared.d.ts +0 -173
- package/dist/types/client/components/models-table-shared.d.ts +0 -175
- package/dist/types/client/components/range-meta.d.ts +0 -21
- package/dist/types/client/data/charts.d.ts +0 -1
- package/dist/types/client/data/formatters.d.ts +0 -8
- package/dist/types/client/data/useHashRoute.d.ts +0 -8
- package/dist/types/client/data/useResource.d.ts +0 -13
- package/dist/types/client/data/view-models.d.ts +0 -59
- package/dist/types/client/index.d.ts +0 -2
- package/dist/types/client/routes/BehaviorRoute.d.ts +0 -7
- package/dist/types/client/routes/CostsRoute.d.ts +0 -7
- package/dist/types/client/routes/ErrorsRoute.d.ts +0 -8
- package/dist/types/client/routes/GainRoute.d.ts +0 -7
- package/dist/types/client/routes/ModelsRoute.d.ts +0 -7
- package/dist/types/client/routes/OverviewRoute.d.ts +0 -8
- package/dist/types/client/routes/ProjectsRoute.d.ts +0 -7
- package/dist/types/client/routes/RequestsRoute.d.ts +0 -8
- package/dist/types/client/routes/index.d.ts +0 -8
- package/dist/types/client/types.d.ts +0 -63
- package/dist/types/client/ui/AsyncBoundary.d.ts +0 -12
- package/dist/types/client/ui/DataTable.d.ts +0 -17
- package/dist/types/client/ui/EmptyState.d.ts +0 -7
- package/dist/types/client/ui/ErrorState.d.ts +0 -6
- package/dist/types/client/ui/JsonBlock.d.ts +0 -7
- package/dist/types/client/ui/MetricCluster.d.ts +0 -5
- package/dist/types/client/ui/Panel.d.ts +0 -7
- package/dist/types/client/ui/RequestDrawer.d.ts +0 -5
- package/dist/types/client/ui/SegmentedControl.d.ts +0 -12
- package/dist/types/client/ui/Skeleton.d.ts +0 -8
- package/dist/types/client/ui/StatusPill.d.ts +0 -7
- package/dist/types/client/ui/index.d.ts +0 -11
- package/dist/types/client/useSystemTheme.d.ts +0 -11
- package/dist/types/db.d.ts +0 -114
- package/dist/types/embedded-client.d.ts +0 -18
- package/dist/types/gain-aggregator.d.ts +0 -26
- package/dist/types/index.d.ts +0 -7
- package/dist/types/parser.d.ts +0 -51
- package/dist/types/server.d.ts +0 -7
- package/dist/types/shared-types.d.ts +0 -253
- package/dist/types/sync-worker.d.ts +0 -31
- package/dist/types/types.d.ts +0 -123
- package/dist/types/user-metrics.d.ts +0 -72
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.2.14] - 2026-07-02
|
|
6
|
+
|
|
5
7
|
### Changed
|
|
6
8
|
|
|
7
9
|
- Rebranded the dashboard for jeopi: page title is now `jeopi · stats`, the nav-rail/mobile-drawer logo reads "JEOPI" with the persona tagline "Encode intention. Decode software." and a synthwave gradient, and the CLI summary/help headers carry the jeopi name.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Local observability dashboard for AI usage statistics.
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Session log parsing**: Reads JSONL session logs from `~/.
|
|
7
|
+
- **Session log parsing**: Reads JSONL session logs from `~/.jeopi/agent/sessions/`
|
|
8
8
|
- **SQLite aggregation**: Efficient stats storage and querying using `bun:sqlite`
|
|
9
9
|
- **Web dashboard**: Real-time metrics visualization with Chart.js
|
|
10
10
|
- **Incremental sync**: Only processes new/modified log entries
|
|
@@ -64,8 +64,8 @@ console.log(stats.byModel[0].avgTokensPerSecond);
|
|
|
64
64
|
|
|
65
65
|
## Data Storage
|
|
66
66
|
|
|
67
|
-
- **Session logs**: `~/.
|
|
68
|
-
- **Stats database**: `~/.
|
|
67
|
+
- **Session logs**: `~/.jeopi/agent/sessions/` (JSONL files)
|
|
68
|
+
- **Stats database**: `~/.jeopi/stats.db` (SQLite)
|
|
69
69
|
|
|
70
70
|
## Dashboard
|
|
71
71
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "jeopi-stats",
|
|
4
|
-
"version": "16.2.
|
|
4
|
+
"version": "16.2.14",
|
|
5
5
|
"description": "Local observability dashboard for pi AI usage statistics",
|
|
6
6
|
"homepage": "https://github.com/akillness/jeopi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -39,23 +39,23 @@
|
|
|
39
39
|
"fmt": "biome format --write ."
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"jeopi-ai": "
|
|
43
|
-
"jeopi-catalog": "
|
|
44
|
-
"jeopi-utils": "
|
|
45
|
-
"@tailwindcss/node": "
|
|
46
|
-
"chart.js": "
|
|
47
|
-
"date-fns": "
|
|
48
|
-
"lucide-react": "
|
|
49
|
-
"react": "
|
|
50
|
-
"react-chartjs-2": "
|
|
51
|
-
"react-dom": "
|
|
52
|
-
"tailwindcss": "
|
|
42
|
+
"jeopi-ai": "catalog:",
|
|
43
|
+
"jeopi-catalog": "catalog:",
|
|
44
|
+
"jeopi-utils": "catalog:",
|
|
45
|
+
"@tailwindcss/node": "catalog:",
|
|
46
|
+
"chart.js": "catalog:",
|
|
47
|
+
"date-fns": "catalog:",
|
|
48
|
+
"lucide-react": "catalog:",
|
|
49
|
+
"react": "catalog:",
|
|
50
|
+
"react-chartjs-2": "catalog:",
|
|
51
|
+
"react-dom": "catalog:",
|
|
52
|
+
"tailwindcss": "catalog:"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@types/bun": "
|
|
56
|
-
"@types/react": "
|
|
57
|
-
"@types/react-dom": "
|
|
58
|
-
"postcss": "
|
|
55
|
+
"@types/bun": "catalog:",
|
|
56
|
+
"@types/react": "catalog:",
|
|
57
|
+
"@types/react-dom": "catalog:",
|
|
58
|
+
"postcss": "catalog:"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
61
61
|
"bun": ">=1.3.14"
|
package/src/gain-aggregator.ts
CHANGED
|
@@ -57,7 +57,7 @@ function matchesProject(cwd: string | undefined, project: string): boolean {
|
|
|
57
57
|
/**
|
|
58
58
|
* Collapse conventional worktree sub-paths to their logical project root.
|
|
59
59
|
*
|
|
60
|
-
* Rules are generic:
|
|
60
|
+
* Rules are generic: jeopi internal wt paths are dropped; conventional worktree
|
|
61
61
|
* suffixes (`.wt/`, `-wt/`, `.worktrees/`, `-worktrees/`) are stripped. No
|
|
62
62
|
* author-specific IDE or tool paths are baked in.
|
|
63
63
|
*
|
|
@@ -66,7 +66,7 @@ function matchesProject(cwd: string | undefined, project: string): boolean {
|
|
|
66
66
|
export function normalizeProjectPath(p: string): string | null {
|
|
67
67
|
const clean = canonicalProjectPath(p);
|
|
68
68
|
if (TEMP_PATH_RE.test(clean)) return null;
|
|
69
|
-
if (/\/\.omp\/wt\//u.test(clean)) return null;
|
|
69
|
+
if (/\/\.(?:omp|jeopi)\/wt\//u.test(clean)) return null;
|
|
70
70
|
|
|
71
71
|
const worktreePatterns = [
|
|
72
72
|
/^(.+)\/\.wt\/[^/]+(?:\/.*)?$/u,
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { BehaviorDashboardStats, DashboardStats, MessageStats, RequestDetails } 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
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function App(): import("react").JSX.Element;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { BehaviorDashboardStats, CostDashboardStats, FolderStats, GainDashboardStats, MessageStats, ModelDashboardStats, OverviewStats, RequestDetails, TimeRange } 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>;
|
|
@@ -1,16 +0,0 @@
|
|
|
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;
|
|
@@ -1,7 +0,0 @@
|
|
|
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;
|
|
@@ -1,7 +0,0 @@
|
|
|
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;
|
|
@@ -1,14 +0,0 @@
|
|
|
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;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function ThemeToggle(): import("react").JSX.Element;
|
|
@@ -1,15 +0,0 @@
|
|
|
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;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type React from "react";
|
|
2
|
-
export type DashboardSection = "overview" | "requests" | "errors" | "models" | "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[];
|
|
@@ -1,173 +0,0 @@
|
|
|
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 {};
|
|
@@ -1,175 +0,0 @@
|
|
|
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;
|
|
@@ -1,21 +0,0 @@
|
|
|
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;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|