@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.
- package/CHANGELOG.md +197 -0
- package/README.md +82 -0
- package/build.ts +95 -0
- package/dist/client/index.css +1 -0
- package/dist/client/index.html +24 -0
- package/dist/client/index.js +257 -0
- package/dist/client/styles.css +1656 -0
- package/dist/types/aggregator.d.ts +87 -0
- package/dist/types/client/App.d.ts +1 -0
- package/dist/types/client/api.d.ts +21 -0
- package/dist/types/client/app/AppLayout.d.ts +16 -0
- package/dist/types/client/app/NavRail.d.ts +7 -0
- package/dist/types/client/app/RangeControl.d.ts +7 -0
- package/dist/types/client/app/SyncButton.d.ts +14 -0
- package/dist/types/client/app/ThemeToggle.d.ts +1 -0
- package/dist/types/client/app/TopBar.d.ts +15 -0
- package/dist/types/client/app/routes.d.ts +12 -0
- package/dist/types/client/components/AgentTokenShare.d.ts +5 -0
- package/dist/types/client/components/chart-shared.d.ts +173 -0
- package/dist/types/client/components/models-table-shared.d.ts +175 -0
- package/dist/types/client/components/range-meta.d.ts +21 -0
- package/dist/types/client/data/charts.d.ts +1 -0
- package/dist/types/client/data/formatters.d.ts +8 -0
- package/dist/types/client/data/useHashRoute.d.ts +8 -0
- package/dist/types/client/data/useResource.d.ts +13 -0
- package/dist/types/client/data/view-models.d.ts +67 -0
- package/dist/types/client/index.d.ts +2 -0
- package/dist/types/client/routes/BehaviorRoute.d.ts +7 -0
- package/dist/types/client/routes/CostsRoute.d.ts +7 -0
- package/dist/types/client/routes/ErrorsRoute.d.ts +8 -0
- package/dist/types/client/routes/GainRoute.d.ts +7 -0
- package/dist/types/client/routes/ModelsRoute.d.ts +7 -0
- package/dist/types/client/routes/OverviewRoute.d.ts +8 -0
- package/dist/types/client/routes/ProjectsRoute.d.ts +7 -0
- package/dist/types/client/routes/RequestsRoute.d.ts +8 -0
- package/dist/types/client/routes/ToolsRoute.d.ts +7 -0
- package/dist/types/client/routes/index.d.ts +9 -0
- package/dist/types/client/types.d.ts +63 -0
- package/dist/types/client/ui/AsyncBoundary.d.ts +12 -0
- package/dist/types/client/ui/DataTable.d.ts +17 -0
- package/dist/types/client/ui/EmptyState.d.ts +7 -0
- package/dist/types/client/ui/ErrorState.d.ts +6 -0
- package/dist/types/client/ui/JsonBlock.d.ts +7 -0
- package/dist/types/client/ui/MetricCluster.d.ts +5 -0
- package/dist/types/client/ui/Panel.d.ts +7 -0
- package/dist/types/client/ui/RequestDrawer.d.ts +5 -0
- package/dist/types/client/ui/SegmentedControl.d.ts +12 -0
- package/dist/types/client/ui/Skeleton.d.ts +8 -0
- package/dist/types/client/ui/StatusPill.d.ts +7 -0
- package/dist/types/client/ui/index.d.ts +11 -0
- package/dist/types/client/useSystemTheme.d.ts +11 -0
- package/dist/types/db.d.ts +144 -0
- package/dist/types/embedded-client.d.ts +18 -0
- package/dist/types/gain-aggregator.d.ts +26 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/parser.d.ts +53 -0
- package/dist/types/server.d.ts +7 -0
- package/dist/types/shared-types.d.ts +301 -0
- package/dist/types/sync-worker.d.ts +31 -0
- package/dist/types/types.d.ts +164 -0
- package/dist/types/user-metrics.d.ts +72 -0
- package/package.json +95 -0
- package/src/aggregator.ts +501 -0
- package/src/client/App.tsx +109 -0
- package/src/client/api.ts +102 -0
- package/src/client/app/AppLayout.tsx +93 -0
- package/src/client/app/NavRail.tsx +44 -0
- package/src/client/app/RangeControl.tsx +39 -0
- package/src/client/app/SyncButton.tsx +75 -0
- package/src/client/app/ThemeToggle.tsx +37 -0
- package/src/client/app/TopBar.tsx +73 -0
- package/src/client/app/routes.ts +69 -0
- package/src/client/components/AgentTokenShare.tsx +68 -0
- package/src/client/components/chart-shared.tsx +257 -0
- package/src/client/components/models-table-shared.tsx +255 -0
- package/src/client/components/range-meta.ts +73 -0
- package/src/client/css.d.ts +1 -0
- package/src/client/data/charts.ts +14 -0
- package/src/client/data/formatters.ts +45 -0
- package/src/client/data/useHashRoute.ts +87 -0
- package/src/client/data/useResource.ts +154 -0
- package/src/client/data/view-models.ts +251 -0
- package/src/client/index.tsx +10 -0
- package/src/client/routes/BehaviorRoute.tsx +623 -0
- package/src/client/routes/CostsRoute.tsx +234 -0
- package/src/client/routes/ErrorsRoute.tsx +118 -0
- package/src/client/routes/GainRoute.tsx +226 -0
- package/src/client/routes/ModelsRoute.tsx +430 -0
- package/src/client/routes/OverviewRoute.tsx +342 -0
- package/src/client/routes/ProjectsRoute.tsx +163 -0
- package/src/client/routes/RequestsRoute.tsx +123 -0
- package/src/client/routes/ToolsRoute.tsx +463 -0
- package/src/client/routes/index.ts +9 -0
- package/src/client/styles.css +1330 -0
- package/src/client/types.ts +80 -0
- package/src/client/ui/AsyncBoundary.tsx +54 -0
- package/src/client/ui/DataTable.tsx +122 -0
- package/src/client/ui/EmptyState.tsx +16 -0
- package/src/client/ui/ErrorState.tsx +25 -0
- package/src/client/ui/JsonBlock.tsx +75 -0
- package/src/client/ui/MetricCluster.tsx +67 -0
- package/src/client/ui/Panel.tsx +24 -0
- package/src/client/ui/RequestDrawer.tsx +208 -0
- package/src/client/ui/SegmentedControl.tsx +36 -0
- package/src/client/ui/Skeleton.tsx +17 -0
- package/src/client/ui/StatusPill.tsx +15 -0
- package/src/client/ui/index.ts +11 -0
- package/src/client/useSystemTheme.ts +87 -0
- package/src/db.ts +1530 -0
- package/src/embedded-client.generated.txt +0 -0
- package/src/embedded-client.ts +26 -0
- package/src/gain-aggregator.ts +281 -0
- package/src/index.ts +194 -0
- package/src/parser.ts +450 -0
- package/src/server.ts +352 -0
- package/src/shared-types.ts +323 -0
- package/src/sync-worker.ts +40 -0
- package/src/types.ts +171 -0
- package/src/user-metrics.ts +685 -0
- package/tailwind.config.js +40 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TimeRange } from "../types";
|
|
2
|
+
export interface BehaviorRouteProps {
|
|
3
|
+
active: boolean;
|
|
4
|
+
range: TimeRange;
|
|
5
|
+
refreshTrigger: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function BehaviorRoute({ active, range, refreshTrigger }: BehaviorRouteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TimeRange } from "../types";
|
|
2
|
+
export interface ErrorsRouteProps {
|
|
3
|
+
active: boolean;
|
|
4
|
+
range: TimeRange;
|
|
5
|
+
refreshTrigger: number;
|
|
6
|
+
onRequestClick: (id: number) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function ErrorsRoute({ active, refreshTrigger, onRequestClick }: ErrorsRouteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TimeRange } from "../types";
|
|
2
|
+
export interface ModelsRouteProps {
|
|
3
|
+
active: boolean;
|
|
4
|
+
range: TimeRange;
|
|
5
|
+
refreshTrigger: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function ModelsRoute({ active, range, refreshTrigger }: ModelsRouteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TimeRange } from "../types";
|
|
2
|
+
export interface OverviewRouteProps {
|
|
3
|
+
active: boolean;
|
|
4
|
+
range: TimeRange;
|
|
5
|
+
refreshTrigger: number;
|
|
6
|
+
onRequestClick: (id: number) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function OverviewRoute({ active, range, refreshTrigger, onRequestClick }: OverviewRouteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TimeRange } from "../types";
|
|
2
|
+
export interface ProjectsRouteProps {
|
|
3
|
+
active: boolean;
|
|
4
|
+
range: TimeRange;
|
|
5
|
+
refreshTrigger: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function ProjectsRoute({ active, range, refreshTrigger }: ProjectsRouteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TimeRange } from "../types";
|
|
2
|
+
export interface RequestsRouteProps {
|
|
3
|
+
active: boolean;
|
|
4
|
+
range: TimeRange;
|
|
5
|
+
refreshTrigger: number;
|
|
6
|
+
onRequestClick: (id: number) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function RequestsRoute({ active, refreshTrigger, onRequestClick }: RequestsRouteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./BehaviorRoute";
|
|
2
|
+
export * from "./CostsRoute";
|
|
3
|
+
export * from "./ErrorsRoute";
|
|
4
|
+
export * from "./GainRoute";
|
|
5
|
+
export * from "./ModelsRoute";
|
|
6
|
+
export * from "./OverviewRoute";
|
|
7
|
+
export * from "./ProjectsRoute";
|
|
8
|
+
export * from "./RequestsRoute";
|
|
9
|
+
export * from "./ToolsRoute";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side type definitions.
|
|
3
|
+
*
|
|
4
|
+
* Shared shapes (aggregations, time-series, dashboard payloads) live in
|
|
5
|
+
* `../shared-types` and are re-exported here. The types declared inline below
|
|
6
|
+
* are deliberately client-only because:
|
|
7
|
+
* - `Usage` is redeclared locally so the client bundle avoids importing
|
|
8
|
+
* `@oh-my-pi-zen/pi-ai` (the server-side AI types package).
|
|
9
|
+
* - `MessageStats.stopReason` is widened from the server's `StopReason`
|
|
10
|
+
* enum to `string`, again to keep the client free of pi-ai types.
|
|
11
|
+
* - `TimeRange`, `OverviewStats`, `ModelDashboardStats`,
|
|
12
|
+
* `CostDashboardStats` are UI-only view shapes the server never produces.
|
|
13
|
+
*/
|
|
14
|
+
import type { AgentTypeStats, AggregatedStats, CostTimeSeriesPoint, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, TimeSeriesPoint } from "../shared-types";
|
|
15
|
+
export * from "../shared-types";
|
|
16
|
+
export interface Usage {
|
|
17
|
+
input: number;
|
|
18
|
+
output: number;
|
|
19
|
+
cacheRead: number;
|
|
20
|
+
cacheWrite: number;
|
|
21
|
+
totalTokens: number;
|
|
22
|
+
premiumRequests?: number;
|
|
23
|
+
cost: {
|
|
24
|
+
input: number;
|
|
25
|
+
output: number;
|
|
26
|
+
cacheRead: number;
|
|
27
|
+
cacheWrite: number;
|
|
28
|
+
total: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export interface MessageStats {
|
|
32
|
+
id?: number;
|
|
33
|
+
sessionFile: string;
|
|
34
|
+
entryId: string;
|
|
35
|
+
folder: string;
|
|
36
|
+
model: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
api: string;
|
|
39
|
+
timestamp: number;
|
|
40
|
+
duration: number | null;
|
|
41
|
+
ttft: number | null;
|
|
42
|
+
stopReason: string;
|
|
43
|
+
errorMessage: string | null;
|
|
44
|
+
usage: Usage;
|
|
45
|
+
}
|
|
46
|
+
export interface RequestDetails extends MessageStats {
|
|
47
|
+
messages: unknown[];
|
|
48
|
+
output: unknown;
|
|
49
|
+
}
|
|
50
|
+
export type TimeRange = "1h" | "24h" | "7d" | "30d" | "90d" | "all";
|
|
51
|
+
export interface OverviewStats {
|
|
52
|
+
overall: AggregatedStats;
|
|
53
|
+
byAgentType: AgentTypeStats[];
|
|
54
|
+
timeSeries: TimeSeriesPoint[];
|
|
55
|
+
}
|
|
56
|
+
export interface ModelDashboardStats {
|
|
57
|
+
byModel: ModelStats[];
|
|
58
|
+
modelSeries: ModelTimeSeriesPoint[];
|
|
59
|
+
modelPerformanceSeries: ModelPerformancePoint[];
|
|
60
|
+
}
|
|
61
|
+
export interface CostDashboardStats {
|
|
62
|
+
costSeries: CostTimeSeriesPoint[];
|
|
63
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export interface AsyncBoundaryProps {
|
|
3
|
+
loading: boolean;
|
|
4
|
+
error: Error | null;
|
|
5
|
+
data: unknown | null;
|
|
6
|
+
empty?: boolean;
|
|
7
|
+
emptyText?: string;
|
|
8
|
+
fallback?: React.ReactNode;
|
|
9
|
+
onRetry?: () => void;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export declare function AsyncBoundary({ loading, error, data, empty, emptyText, fallback, onRetry, children, }: AsyncBoundaryProps): React.JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export interface DataTableColumn<T> {
|
|
3
|
+
key: string;
|
|
4
|
+
header: React.ReactNode;
|
|
5
|
+
render?: (item: T) => React.ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
numeric?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface DataTableProps<T> {
|
|
10
|
+
columns: DataTableColumn<T>[];
|
|
11
|
+
data: T[];
|
|
12
|
+
keyExtractor: (item: T) => string | number;
|
|
13
|
+
onRowClick?: (item: T) => void;
|
|
14
|
+
renderMobileCard?: (item: T, onClick?: () => void) => React.ReactNode;
|
|
15
|
+
emptyText?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function DataTable<T>({ columns, data, keyExtractor, onRowClick, renderMobileCard, emptyText, }: DataTableProps<T>): React.JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type LucideIcon } from "lucide-react";
|
|
2
|
+
export interface EmptyStateProps {
|
|
3
|
+
message?: string;
|
|
4
|
+
icon?: LucideIcon;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function EmptyState({ message, icon: Icon, className }: EmptyStateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export interface PanelProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
3
|
+
title?: React.ReactNode;
|
|
4
|
+
subtitle?: React.ReactNode;
|
|
5
|
+
actions?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function Panel({ title, subtitle, actions, children, className, ...props }: PanelProps): React.JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface SegmentedControlOption<T> {
|
|
2
|
+
value: T;
|
|
3
|
+
label: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SegmentedControlProps<T> {
|
|
7
|
+
options: SegmentedControlOption<T>[];
|
|
8
|
+
value: T;
|
|
9
|
+
onChange: (value: T) => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function SegmentedControl<T>({ options, value, onChange, className }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export interface SkeletonProps {
|
|
3
|
+
variant?: "text" | "rect" | "circle";
|
|
4
|
+
width?: string | number;
|
|
5
|
+
height?: string | number;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function Skeleton({ variant, width, height, className }: SkeletonProps): React.JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export interface StatusPillProps {
|
|
3
|
+
variant: "success" | "danger" | "warning" | "info" | "default";
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function StatusPill({ variant, children, className }: StatusPillProps): React.JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./AsyncBoundary";
|
|
2
|
+
export * from "./DataTable";
|
|
3
|
+
export * from "./EmptyState";
|
|
4
|
+
export * from "./ErrorState";
|
|
5
|
+
export * from "./JsonBlock";
|
|
6
|
+
export * from "./MetricCluster";
|
|
7
|
+
export * from "./Panel";
|
|
8
|
+
export * from "./RequestDrawer";
|
|
9
|
+
export * from "./SegmentedControl";
|
|
10
|
+
export * from "./Skeleton";
|
|
11
|
+
export * from "./StatusPill";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type SystemTheme = "light" | "dark";
|
|
2
|
+
export type ThemePreference = "system" | "light" | "dark";
|
|
3
|
+
export declare function setThemePreference(next: ThemePreference): void;
|
|
4
|
+
/** Reader for the active resolved theme. Reflects system default and overrides. */
|
|
5
|
+
export declare function useSystemTheme(): SystemTheme;
|
|
6
|
+
/** Reader + writer for the theme preference (powers the toggle). */
|
|
7
|
+
export declare function useThemePreference(): {
|
|
8
|
+
preference: ThemePreference;
|
|
9
|
+
resolved: SystemTheme;
|
|
10
|
+
setPreference: (next: ThemePreference) => void;
|
|
11
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import type { AgentTypeStats, AggregatedStats, BehaviorModelStats, BehaviorOverallStats, BehaviorTimeSeriesPoint, CostTimeSeriesPoint, FolderStats, MessageStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, TimeSeriesPoint, ToolCallStats, ToolModelStats, ToolResultLink, ToolTimeSeriesPoint, ToolUsageStats, UserMessageLink, UserMessageStats } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Initialize the database and create tables.
|
|
5
|
+
*/
|
|
6
|
+
export declare function initDb(): Promise<Database>;
|
|
7
|
+
/**
|
|
8
|
+
* Get the stored offset for a session file.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getFileOffset(sessionFile: string): {
|
|
11
|
+
offset: number;
|
|
12
|
+
lastModified: number;
|
|
13
|
+
} | null;
|
|
14
|
+
/**
|
|
15
|
+
* Update the stored offset for a session file.
|
|
16
|
+
*/
|
|
17
|
+
export declare function setFileOffset(sessionFile: string, offset: number, lastModified: number): void;
|
|
18
|
+
/**
|
|
19
|
+
* Insert message stats into the database.
|
|
20
|
+
*
|
|
21
|
+
* Forked / branched sessions (see `SessionManager.fork()` and
|
|
22
|
+
* `createBranchedSession()` in `@oh-my-pi-zen/pi-coding-agent`) deep-copy a parent
|
|
23
|
+
* session's entries into a new JSONL — same `entry_id`, `timestamp`, `model`,
|
|
24
|
+
* `provider`, token counts, and `responseId`. The `UNIQUE(session_file,
|
|
25
|
+
* entry_id)` constraint alone keys each row by file, so without the guard
|
|
26
|
+
* below the same provider request would land twice and inflate every
|
|
27
|
+
* aggregate. The `WHERE NOT EXISTS` clause skips inserts whose
|
|
28
|
+
* `(entry_id, timestamp)` already exists under a different `session_file` —
|
|
29
|
+
* first-write-wins across the lineage. Same-file re-syncs still hit the
|
|
30
|
+
* `ON CONFLICT(session_file, entry_id)` upsert below so historical
|
|
31
|
+
* `premium_requests` fix-ups continue to work.
|
|
32
|
+
*/
|
|
33
|
+
export declare function insertMessageStats(stats: MessageStats[]): number;
|
|
34
|
+
/**
|
|
35
|
+
* Get overall aggregated stats.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getOverallStats(cutoff?: number): AggregatedStats;
|
|
38
|
+
/**
|
|
39
|
+
* Get stats grouped by model.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getStatsByModel(cutoff?: number): ModelStats[];
|
|
42
|
+
/**
|
|
43
|
+
* Get stats grouped by folder.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getStatsByFolder(cutoff?: number): FolderStats[];
|
|
46
|
+
/**
|
|
47
|
+
* Get token usage grouped by agent type (main agent, task subagents, advisor).
|
|
48
|
+
* Token columns are explicit so the dashboard's share denominator matches the
|
|
49
|
+
* counts it renders. Rows missing `agent_type` (defensive) fall back to "main".
|
|
50
|
+
*/
|
|
51
|
+
export declare function getStatsByAgentType(cutoff?: number): AgentTypeStats[];
|
|
52
|
+
/**
|
|
53
|
+
* Get time series data.
|
|
54
|
+
*/
|
|
55
|
+
export declare function getTimeSeries(hours?: number, cutoff?: number | null, bucketMs?: number): TimeSeriesPoint[];
|
|
56
|
+
/**
|
|
57
|
+
* Get daily performance time series data for the last N days.
|
|
58
|
+
*/
|
|
59
|
+
/**
|
|
60
|
+
* Get daily model usage time series data for the last N days.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getModelTimeSeries(days?: number, cutoff?: number | null, bucketMs?: number): ModelTimeSeriesPoint[];
|
|
63
|
+
/**
|
|
64
|
+
* Get daily model performance time series data for the last N days.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getModelPerformanceSeries(days?: number, cutoff?: number | null, bucketMs?: number): ModelPerformancePoint[];
|
|
67
|
+
/**
|
|
68
|
+
* Get total message count.
|
|
69
|
+
*/
|
|
70
|
+
export declare function getMessageCount(): number;
|
|
71
|
+
/**
|
|
72
|
+
* Close the database connection.
|
|
73
|
+
*/
|
|
74
|
+
export declare function closeDb(): void;
|
|
75
|
+
export declare function getRecentRequests(limit?: number): MessageStats[];
|
|
76
|
+
export declare function getRecentErrors(limit?: number): MessageStats[];
|
|
77
|
+
export declare function getMessageById(id: number): MessageStats | null;
|
|
78
|
+
/**
|
|
79
|
+
* Get daily cost time series data for the last N days, broken down by model.
|
|
80
|
+
*/
|
|
81
|
+
export declare function getCostTimeSeries(days?: number, cutoff?: number | null): CostTimeSeriesPoint[];
|
|
82
|
+
export declare function markPriorityPremiumRequestsBackfillComplete(): void;
|
|
83
|
+
export declare function markUserMessagesBackfillComplete(): void;
|
|
84
|
+
export declare function markUserMessageLinksRepairComplete(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Insert user-message stats. Idempotent via UNIQUE(session_file, entry_id).
|
|
87
|
+
* The `WHERE NOT EXISTS` clause matches {@link insertMessageStats}: forks
|
|
88
|
+
* copy user entries verbatim into the child JSONL, so the same
|
|
89
|
+
* `(entry_id, timestamp)` must not land twice across different session files.
|
|
90
|
+
*/
|
|
91
|
+
export declare function insertUserMessageStats(stats: UserMessageStats[]): number;
|
|
92
|
+
/**
|
|
93
|
+
* Backfill the responding `model`/`provider` on user-message rows that were
|
|
94
|
+
* persisted before their assistant reply was parsed (a side effect of
|
|
95
|
+
* incremental `fromOffset` syncing: the `userByEntryId` map in
|
|
96
|
+
* `parseSessionFile` only spans a single pass). Each row is updated at most
|
|
97
|
+
* once because the `model IS NULL` guard short-circuits subsequent passes.
|
|
98
|
+
*
|
|
99
|
+
* Returns the number of rows actually updated.
|
|
100
|
+
*/
|
|
101
|
+
export declare function updateUserMessageLinks(links: UserMessageLink[]): number;
|
|
102
|
+
/**
|
|
103
|
+
* Daily behavioral time series, grouped by responding model+provider.
|
|
104
|
+
*/
|
|
105
|
+
export declare function getBehaviorTimeSeries(cutoff?: number | null): BehaviorTimeSeriesPoint[];
|
|
106
|
+
/**
|
|
107
|
+
* Overall behavioral totals across the cutoff window.
|
|
108
|
+
*/
|
|
109
|
+
export declare function getBehaviorOverall(cutoff?: number | null): BehaviorOverallStats;
|
|
110
|
+
/**
|
|
111
|
+
* Per-model behavioral totals over the cutoff window. "Unknown" represents
|
|
112
|
+
* user messages that never received an assistant reply.
|
|
113
|
+
*/
|
|
114
|
+
export declare function getBehaviorByModel(cutoff?: number | null): BehaviorModelStats[];
|
|
115
|
+
/**
|
|
116
|
+
* Insert tool-call rows. Idempotent via UNIQUE(session_file, tool_call_id);
|
|
117
|
+
* the `WHERE NOT EXISTS` guard mirrors {@link insertMessageStats}: forked
|
|
118
|
+
* sessions deep-copy assistant entries (same `entry_id`, `timestamp`, and
|
|
119
|
+
* tool-call ids under a new file), so first-write-wins across the lineage
|
|
120
|
+
* keeps aggregates from double counting. Keyed on the assistant entry
|
|
121
|
+
* identity, not the call id alone — provider call ids are not a global
|
|
122
|
+
* namespace across unrelated sessions.
|
|
123
|
+
*/
|
|
124
|
+
export declare function insertToolCalls(calls: ToolCallStats[]): number;
|
|
125
|
+
/**
|
|
126
|
+
* Attach result size / error flag to persisted tool-call rows. Results can
|
|
127
|
+
* land in a later incremental sync pass than the call that produced them, so
|
|
128
|
+
* this is an UPDATE keyed by (session_file, tool_call_id). The `IS NULL`
|
|
129
|
+
* guard makes re-syncs idempotent; rows skipped by the fork guard simply
|
|
130
|
+
* never match.
|
|
131
|
+
*/
|
|
132
|
+
export declare function updateToolResults(links: ToolResultLink[]): number;
|
|
133
|
+
/**
|
|
134
|
+
* Get tool usage aggregated by tool name.
|
|
135
|
+
*/
|
|
136
|
+
export declare function getToolStats(cutoff?: number): ToolUsageStats[];
|
|
137
|
+
/**
|
|
138
|
+
* Get tool usage aggregated by (tool, model, provider).
|
|
139
|
+
*/
|
|
140
|
+
export declare function getToolStatsByModel(cutoff?: number): ToolModelStats[];
|
|
141
|
+
/**
|
|
142
|
+
* Get tool-call time series (one point per bucket per tool).
|
|
143
|
+
*/
|
|
144
|
+
export declare function getToolTimeSeries(days?: number, cutoff?: number | null, bucketMs?: number): ToolTimeSeriesPoint[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded stats dashboard archive handling.
|
|
3
|
+
*
|
|
4
|
+
* `embedded-client.generated.txt` holds the base64 of a gzipped tar of the
|
|
5
|
+
* built dashboard (`dist/client`). It is populated by
|
|
6
|
+
* `gen:stats` for compiled binaries and the
|
|
7
|
+
* prepacked npm bundle, and reset to an empty file afterwards so the dev tree
|
|
8
|
+
* keeps building the dashboard from source.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Decode the generated archive text.
|
|
12
|
+
*
|
|
13
|
+
* Returns `null` when the content is blank or not a raw gzip archive encoded as
|
|
14
|
+
* base64 — notably the legacy placeholder that contained a TypeScript
|
|
15
|
+
* `export const … = "";` stub, which must be treated as "no archive embedded"
|
|
16
|
+
* rather than decoded into garbage bytes.
|
|
17
|
+
*/
|
|
18
|
+
export declare function decodeEmbeddedClientArchive(txt: string): Buffer | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregates token-savings data for the Gain dashboard.
|
|
3
|
+
*
|
|
4
|
+
* Source:
|
|
5
|
+
* 1. Snapcompact: colocated with stats.db as snapcompact-savings.jsonl
|
|
6
|
+
*
|
|
7
|
+
* Missing files are treated as zero records — never an error.
|
|
8
|
+
*/
|
|
9
|
+
import type { GainDashboardStats } from "./shared-types";
|
|
10
|
+
/**
|
|
11
|
+
* Collapse conventional worktree sub-paths to their logical project root.
|
|
12
|
+
*
|
|
13
|
+
* Rules are generic: omp internal wt paths are dropped; conventional worktree
|
|
14
|
+
* suffixes (`.wt/`, `-wt/`, `.worktrees/`, `-worktrees/`) are stripped. No
|
|
15
|
+
* author-specific IDE or tool paths are baked in.
|
|
16
|
+
*
|
|
17
|
+
* Returns null to drop temp/internal paths entirely.
|
|
18
|
+
*/
|
|
19
|
+
export declare function normalizeProjectPath(p: string): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Given a raw set of paths, normalize worktree paths and remove sub-paths
|
|
22
|
+
* that are already covered by a shorter parent at depth ≥ 4.
|
|
23
|
+
* Returns a sorted, deduped list of meaningful project roots.
|
|
24
|
+
*/
|
|
25
|
+
export declare function dedupeProjects(rawPaths: Set<string>): string[];
|
|
26
|
+
export declare function getGainDashboardStats(range?: string | null, project?: string | null): Promise<GainDashboardStats>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
export { getDashboardStats, getToolDashboardStats, getTotalMessageCount, type SyncOptions, type SyncProgress, smokeTestSyncWorker, syncAllSessions, } from "./aggregator";
|
|
3
|
+
export { closeDb } from "./db";
|
|
4
|
+
export { getGainDashboardStats } from "./gain-aggregator";
|
|
5
|
+
export { startServer } from "./server";
|
|
6
|
+
export type { GainDashboardStats, GainSource, GainSourceTotals, GainTimeSeriesPoint, } from "./shared-types";
|
|
7
|
+
export type { AggregatedStats, DashboardStats, FolderStats, MessageStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, TimeSeriesPoint, ToolDashboardStats, ToolModelStats, ToolTimeSeriesPoint, ToolUsageStats, } from "./types";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AgentType, MessageStats, SessionEntry, ToolCallStats, ToolResultLink, UserMessageLink, UserMessageStats } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Classify which agent produced a transcript from its path within the sessions
|
|
4
|
+
* directory. Layout: `<sessionsDir>/<project>/<file>.jsonl` is the `main`
|
|
5
|
+
* agent; subagent and advisor transcripts live nested one level deeper inside
|
|
6
|
+
* the session's artifacts dir (`<project>/<session>/<id>.jsonl`,
|
|
7
|
+
* `<project>/<session>/__advisor.jsonl`). Any advisor transcript
|
|
8
|
+
* (`__advisor.jsonl` or `__advisor.<slug>.jsonl`) — at any depth, including a
|
|
9
|
+
* subagent's own advisor — counts as `advisor`; every other nested transcript
|
|
10
|
+
* is a task `subagent`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function classifyAgentType(sessionPath: string): AgentType;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a session file and extract all assistant message stats.
|
|
15
|
+
* Uses incremental reading with offset tracking.
|
|
16
|
+
*
|
|
17
|
+
* Service-tier carry-over: `currentServiceTier` is a session-scoped piece of
|
|
18
|
+
* state derived from `service_tier_change` entries that affects whether
|
|
19
|
+
* subsequent OpenAI assistant replies count as premium requests. Incremental
|
|
20
|
+
* syncs that resume past the most-recent tier change would otherwise lose
|
|
21
|
+
* that state and silently record `premiumRequests = 0` for priority traffic
|
|
22
|
+
* (the coding-agent stopped folding the tier into `usage.premiumRequests`
|
|
23
|
+
* after 13f59162e — the parser is now the sole source of truth). When
|
|
24
|
+
* `fromOffset > 0` we therefore scan the bytes preceding `fromOffset`
|
|
25
|
+
* for the latest service-tier value before parsing the unprocessed tail.
|
|
26
|
+
* The scan only keeps the current tier and does not materialize prefix
|
|
27
|
+
* entries, preserving offset-based memory behavior for large sessions.
|
|
28
|
+
*/
|
|
29
|
+
export interface ParseSessionResult {
|
|
30
|
+
stats: MessageStats[];
|
|
31
|
+
userStats: UserMessageStats[];
|
|
32
|
+
userLinks: UserMessageLink[];
|
|
33
|
+
toolCalls: ToolCallStats[];
|
|
34
|
+
toolResults: ToolResultLink[];
|
|
35
|
+
newOffset: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function parseSessionFile(sessionPath: string, fromOffset?: number): Promise<ParseSessionResult>;
|
|
38
|
+
/**
|
|
39
|
+
* List all session directories (folders).
|
|
40
|
+
*/
|
|
41
|
+
export declare function listSessionFolders(): Promise<string[]>;
|
|
42
|
+
/**
|
|
43
|
+
* List all session files in a folder.
|
|
44
|
+
*/
|
|
45
|
+
export declare function listSessionFiles(folderPath: string): Promise<string[]>;
|
|
46
|
+
/**
|
|
47
|
+
* List all session files across all folders.
|
|
48
|
+
*/
|
|
49
|
+
export declare function listAllSessionFiles(): Promise<string[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Find a specific entry in a session file.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getSessionEntry(sessionPath: string, entryId: string): Promise<SessionEntry | null>;
|