claude-session-dashboard 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/_dashboard-ChSI7O-o.js +1 -0
- package/dist/client/assets/_sessionId-DxfkocLt.js +12 -0
- package/dist/client/assets/app-BAZLXX_G.css +1 -0
- package/dist/client/assets/createServerFn-DJjqV8Yc.js +1 -0
- package/dist/client/assets/index-BHwOAB5a.js +1 -0
- package/dist/client/assets/main-DMwMzWYr.js +69 -0
- package/dist/client/assets/sessions.queries-D7WObk5d.js +1 -0
- package/dist/client/assets/settings-BM0TBEkW.js +1 -0
- package/dist/client/assets/settings.types-BNSfIfFX.js +1 -0
- package/dist/client/assets/stats-wLUGXFpZ.js +4 -0
- package/dist/client/assets/useSessionCost-BPqnyONZ.js +37 -0
- package/dist/server/assets/{_dashboard-smfIqyQC.js → _dashboard-DZJZ9oYy.js} +13 -12
- package/dist/server/assets/{_sessionId-DIUMcrWR.js → _sessionId-znGcd1Dj.js} +53 -24
- package/dist/server/assets/_tanstack-start-manifest_v-BNorjuP4.js +4 -0
- package/dist/server/assets/{app-info.server-CXcS0a5s.js → app-info.api-CrHplh0q.js} +33 -18
- package/dist/server/assets/{createServerRpc-Bd3B-Ah9.js → createServerRpc-D_-6bKnO.js} +1 -1
- package/dist/server/assets/{createSsrRpc-CVg2UDl0.js → createSsrRpc-OFLSk08e.js} +2 -3
- package/dist/server/assets/{index-hFrIPkke.js → index-BnvjnlZM.js} +31 -14
- package/dist/server/assets/{project-analytics.server-Bxk8-NnT.js → project-analytics.api-6b5TIBNn.js} +12 -10
- package/dist/server/assets/{router-5hznwWqr.js → router-DAepjaOj.js} +80 -12
- package/dist/server/assets/{session-detail.server-BIoOQwSE.js → session-detail.api-BQts3iQn.js} +38 -33
- package/dist/server/assets/{session-parser-B0pdBvgT.js → session-parser-DKZZMuh6.js} +123 -31
- package/dist/server/assets/{session-scanner-CpgOq5m1.js → session-scanner-CECpfGFh.js} +4 -4
- package/dist/server/assets/{sessions.server-Biq8gbAJ.js → sessions.api-CQ-Lrk5S.js} +16 -14
- package/dist/server/assets/{sessions.queries-B5ZBiVJy.js → sessions.queries-MfPgj6cK.js} +4 -4
- package/dist/server/assets/{settings-D0FgLIR5.js → settings-DsLaw8yg.js} +42 -13
- package/dist/server/assets/{settings.server-6B2PvLgf.js → settings.api-Cq5KPUxN.js} +12 -11
- package/dist/server/assets/{settings.queries-DSQd324O.js → settings.queries-CMWxUDF-.js} +4 -4
- package/dist/server/assets/{settings.types-DntadCHo.js → settings.types-CphWe-HW.js} +10 -1
- package/dist/server/assets/{stats-Ae6umrPI.js → stats-DKbhSePW.js} +57 -43
- package/dist/server/assets/{stats.server-DhzOihwM.js → stats.api-tIZqhk4B.js} +12 -10
- package/dist/server/assets/{useSessionCost-CYs5UOX-.js → useSessionCost-iQEg4FRM.js} +2 -2
- package/dist/server/server.js +458 -808
- package/package.json +6 -2
- package/LICENSE +0 -21
- package/README.md +0 -194
- package/dist/client/assets/_dashboard-DLFGahko.js +0 -1
- package/dist/client/assets/_sessionId-xiPzwrlf.js +0 -12
- package/dist/client/assets/app-DREGBD44.css +0 -1
- package/dist/client/assets/createServerFn-BLR4iNR3.js +0 -1
- package/dist/client/assets/index-D_9sS4oJ.js +0 -1
- package/dist/client/assets/main-BcKPK-4E.js +0 -56
- package/dist/client/assets/sessions.queries-CHKiZnLm.js +0 -1
- package/dist/client/assets/settings-B2tG1vy0.js +0 -1
- package/dist/client/assets/settings.types-DHC6rkil.js +0 -1
- package/dist/client/assets/stats-BlA0NIHc.js +0 -4
- package/dist/client/assets/useSessionCost-BikgEmWy.js +0 -37
- package/dist/server/assets/_tanstack-start-manifest_v-Dmhlhehg.js +0 -4
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
|
-
import { s as settingsQuery, u as useSettingsMutation } from "./settings.queries-
|
|
5
|
-
import { a as SUBSCRIPTION_TIERS, b as DEFAULT_PRICING, D as DEFAULT_SETTINGS } from "./settings.types-
|
|
6
|
-
import { u as usePrivacy } from "./router-
|
|
7
|
-
import "./createSsrRpc-
|
|
4
|
+
import { s as settingsQuery, u as useSettingsMutation } from "./settings.queries-CMWxUDF-.js";
|
|
5
|
+
import { a as SUBSCRIPTION_TIERS, b as DEFAULT_PRICING, D as DEFAULT_SETTINGS } from "./settings.types-CphWe-HW.js";
|
|
6
|
+
import { u as usePrivacy, a as useTheme } from "./router-DAepjaOj.js";
|
|
7
|
+
import "./createSsrRpc-OFLSk08e.js";
|
|
8
8
|
import "../server.js";
|
|
9
|
-
import "@tanstack/history";
|
|
10
|
-
import "@tanstack/router-core/ssr/client";
|
|
11
|
-
import "@tanstack/router-core";
|
|
12
9
|
import "node:async_hooks";
|
|
13
|
-
import "@tanstack/router-core/ssr/server";
|
|
14
10
|
import "h3-v2";
|
|
11
|
+
import "@tanstack/router-core";
|
|
15
12
|
import "tiny-invariant";
|
|
16
13
|
import "seroval";
|
|
17
|
-
import "@tanstack/
|
|
14
|
+
import "@tanstack/history";
|
|
15
|
+
import "@tanstack/router-core/ssr/client";
|
|
16
|
+
import "@tanstack/router-core/ssr/server";
|
|
18
17
|
import "@tanstack/react-router";
|
|
18
|
+
import "@tanstack/react-router/ssr/server";
|
|
19
19
|
import "zod";
|
|
20
20
|
function TierSelector({ value, onChange }) {
|
|
21
21
|
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-4", children: SUBSCRIPTION_TIERS.map((tier) => {
|
|
@@ -25,7 +25,7 @@ function TierSelector({ value, onChange }) {
|
|
|
25
25
|
{
|
|
26
26
|
type: "button",
|
|
27
27
|
onClick: () => onChange(tier.id),
|
|
28
|
-
className: `rounded-lg border px-3 py-2 text-left transition-colors ${isSelected ? "border-brand-500 bg-brand-500/10 text-
|
|
28
|
+
className: `rounded-lg border px-3 py-2 text-left transition-colors ${isSelected ? "border-brand-500 bg-brand-500/10 text-gray-100" : "border-gray-800 bg-gray-900/50 text-gray-400 hover:border-gray-700 hover:text-gray-300"}`,
|
|
29
29
|
children: [
|
|
30
30
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: tier.displayName }),
|
|
31
31
|
/* @__PURE__ */ jsx("div", { className: "mt-0.5 font-mono text-[10px] text-gray-500", children: tier.monthlyUSD !== null ? `$${tier.monthlyUSD}/mo` : "Custom" })
|
|
@@ -115,6 +115,8 @@ function SettingsPage() {
|
|
|
115
115
|
function SettingsForm({ settings }) {
|
|
116
116
|
const mutation = useSettingsMutation();
|
|
117
117
|
const { privacyMode, togglePrivacyMode } = usePrivacy();
|
|
118
|
+
const { theme, toggleTheme } = useTheme();
|
|
119
|
+
const isDark = theme === "dark";
|
|
118
120
|
const [tier, setTier] = useState(settings.subscriptionTier);
|
|
119
121
|
const [overrides, setOverrides] = useState(settings.pricingOverrides);
|
|
120
122
|
const [isDirty, setIsDirty] = useState(false);
|
|
@@ -135,7 +137,8 @@ function SettingsForm({ settings }) {
|
|
|
135
137
|
const updated = {
|
|
136
138
|
version: 1,
|
|
137
139
|
subscriptionTier: tier,
|
|
138
|
-
pricingOverrides: overrides
|
|
140
|
+
pricingOverrides: overrides,
|
|
141
|
+
dataSources: []
|
|
139
142
|
};
|
|
140
143
|
mutation.mutate(updated, {
|
|
141
144
|
onSuccess: () => {
|
|
@@ -144,7 +147,7 @@ function SettingsForm({ settings }) {
|
|
|
144
147
|
});
|
|
145
148
|
}
|
|
146
149
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
147
|
-
/* @__PURE__ */ jsx("h1", { className: "text-xl font-bold text-
|
|
150
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-bold text-gray-100", children: "Settings" }),
|
|
148
151
|
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Configure your subscription tier and API pricing for cost estimation." }),
|
|
149
152
|
/* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
150
153
|
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-300", children: "Privacy Mode" }),
|
|
@@ -194,6 +197,32 @@ function SettingsForm({ settings }) {
|
|
|
194
197
|
] })
|
|
195
198
|
] })
|
|
196
199
|
] }),
|
|
200
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
201
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-300", children: "Theme" }),
|
|
202
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-gray-500", children: "Switch between dark and light mode. Defaults to your system preference." }),
|
|
203
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 rounded-xl border border-gray-800 bg-gray-900/50 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
204
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-300", children: isDark ? "Dark mode" : "Light mode" }),
|
|
205
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
206
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500", children: isDark ? "🌙" : "☀️" }),
|
|
207
|
+
/* @__PURE__ */ jsx(
|
|
208
|
+
"button",
|
|
209
|
+
{
|
|
210
|
+
type: "button",
|
|
211
|
+
role: "switch",
|
|
212
|
+
"aria-checked": !isDark,
|
|
213
|
+
onClick: toggleTheme,
|
|
214
|
+
className: `relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors ${!isDark ? "bg-brand-600" : "bg-gray-800"}`,
|
|
215
|
+
children: /* @__PURE__ */ jsx(
|
|
216
|
+
"span",
|
|
217
|
+
{
|
|
218
|
+
className: `inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform ${!isDark ? "translate-x-[18px]" : "translate-x-[3px]"}`
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
] })
|
|
224
|
+
] }) })
|
|
225
|
+
] }),
|
|
197
226
|
/* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
198
227
|
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-300", children: "Subscription Tier" }),
|
|
199
228
|
/* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-gray-500", children: "Select your Claude subscription plan. This is informational only and does not affect cost calculations." }),
|
|
@@ -232,7 +261,7 @@ function SettingsForm({ settings }) {
|
|
|
232
261
|
type: "button",
|
|
233
262
|
onClick: handleSave,
|
|
234
263
|
disabled: !isDirty || mutation.isPending,
|
|
235
|
-
className: `rounded-lg px-4 py-1.5 text-xs font-medium transition-colors ${isDirty && !mutation.isPending ? "bg-brand-600 text-
|
|
264
|
+
className: `rounded-lg px-4 py-1.5 text-xs font-medium transition-colors ${isDirty && !mutation.isPending ? "bg-brand-600 text-gray-100 hover:bg-brand-500" : "cursor-not-allowed bg-gray-800 text-gray-500"}`,
|
|
236
265
|
children: mutation.isPending ? "Saving..." : "Save"
|
|
237
266
|
}
|
|
238
267
|
)
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { c as createServerRpc } from "./createServerRpc-
|
|
1
|
+
import { c as createServerRpc } from "./createServerRpc-D_-6bKnO.js";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as os from "node:os";
|
|
5
|
-
import { S as SettingsSchema, D as DEFAULT_SETTINGS } from "./settings.types-
|
|
5
|
+
import { S as SettingsSchema, D as DEFAULT_SETTINGS } from "./settings.types-CphWe-HW.js";
|
|
6
6
|
import { c as createServerFn } from "../server.js";
|
|
7
7
|
import "zod";
|
|
8
|
-
import "@tanstack/history";
|
|
9
|
-
import "@tanstack/router-core/ssr/client";
|
|
10
|
-
import "@tanstack/router-core";
|
|
11
8
|
import "node:async_hooks";
|
|
12
|
-
import "@tanstack/router-core/ssr/server";
|
|
13
9
|
import "h3-v2";
|
|
10
|
+
import "@tanstack/router-core";
|
|
14
11
|
import "tiny-invariant";
|
|
15
12
|
import "seroval";
|
|
13
|
+
import "@tanstack/history";
|
|
14
|
+
import "@tanstack/router-core/ssr/client";
|
|
15
|
+
import "@tanstack/router-core/ssr/server";
|
|
16
|
+
import "react";
|
|
17
|
+
import "@tanstack/react-router";
|
|
16
18
|
import "react/jsx-runtime";
|
|
17
19
|
import "@tanstack/react-router/ssr/server";
|
|
18
|
-
import "@tanstack/react-router";
|
|
19
20
|
const SETTINGS_DIR = ".claude-dashboard";
|
|
20
21
|
const SETTINGS_FILE = "settings.json";
|
|
21
22
|
function getSettingsPath() {
|
|
@@ -25,9 +26,9 @@ function getSettingsDir() {
|
|
|
25
26
|
return path.join(os.homedir(), SETTINGS_DIR);
|
|
26
27
|
}
|
|
27
28
|
const getSettings_createServerFn_handler = createServerRpc({
|
|
28
|
-
id: "
|
|
29
|
+
id: "72f81ef9e8fa751bab60a8bdabd7e77816e2a6723a5e6e26e03712c01b3a249c",
|
|
29
30
|
name: "getSettings",
|
|
30
|
-
filename: "src/features/settings/settings.
|
|
31
|
+
filename: "src/features/settings/settings.api.ts"
|
|
31
32
|
}, (opts) => getSettings.__executeServer(opts));
|
|
32
33
|
const getSettings = createServerFn({
|
|
33
34
|
method: "GET"
|
|
@@ -47,9 +48,9 @@ const getSettings = createServerFn({
|
|
|
47
48
|
}
|
|
48
49
|
});
|
|
49
50
|
const saveSettings_createServerFn_handler = createServerRpc({
|
|
50
|
-
id: "
|
|
51
|
+
id: "7fe8c2b131c4fc81aa9a2570aec79640ff84603fe0060d13c24928b7329cb236",
|
|
51
52
|
name: "saveSettings",
|
|
52
|
-
filename: "src/features/settings/settings.
|
|
53
|
+
filename: "src/features/settings/settings.api.ts"
|
|
53
54
|
}, (opts) => saveSettings.__executeServer(opts));
|
|
54
55
|
const saveSettings = createServerFn({
|
|
55
56
|
method: "POST"
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { queryOptions, useQueryClient, useMutation } from "@tanstack/react-query";
|
|
2
|
-
import { c as createSsrRpc } from "./createSsrRpc-
|
|
3
|
-
import { S as SettingsSchema } from "./settings.types-
|
|
2
|
+
import { c as createSsrRpc } from "./createSsrRpc-OFLSk08e.js";
|
|
3
|
+
import { S as SettingsSchema } from "./settings.types-CphWe-HW.js";
|
|
4
4
|
import { c as createServerFn } from "../server.js";
|
|
5
5
|
const getSettings = createServerFn({
|
|
6
6
|
method: "GET"
|
|
7
|
-
}).handler(createSsrRpc("
|
|
7
|
+
}).handler(createSsrRpc("72f81ef9e8fa751bab60a8bdabd7e77816e2a6723a5e6e26e03712c01b3a249c"));
|
|
8
8
|
const saveSettings = createServerFn({
|
|
9
9
|
method: "POST"
|
|
10
10
|
}).inputValidator((input) => {
|
|
11
11
|
const result = SettingsSchema.parse(input);
|
|
12
12
|
return result;
|
|
13
|
-
}).handler(createSsrRpc("
|
|
13
|
+
}).handler(createSsrRpc("7fe8c2b131c4fc81aa9a2570aec79640ff84603fe0060d13c24928b7329cb236"));
|
|
14
14
|
const settingsQuery = queryOptions({
|
|
15
15
|
queryKey: ["settings"],
|
|
16
16
|
queryFn: () => getSettings(),
|
|
@@ -9,6 +9,14 @@ const SettingsSchema = z.object({
|
|
|
9
9
|
version: z.literal(1),
|
|
10
10
|
subscriptionTier: z.enum(["free", "pro", "max-5x", "max-20x", "teams", "enterprise", "api"]).default("pro"),
|
|
11
11
|
pricingOverrides: z.record(z.string(), ModelPricingOverrideSchema).default({}),
|
|
12
|
+
dataSources: z.array(
|
|
13
|
+
z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
label: z.string(),
|
|
16
|
+
path: z.string(),
|
|
17
|
+
enabled: z.boolean().default(true)
|
|
18
|
+
})
|
|
19
|
+
).default([]),
|
|
12
20
|
updatedAt: z.string().datetime().optional()
|
|
13
21
|
});
|
|
14
22
|
const DEFAULT_PRICING = [
|
|
@@ -97,7 +105,8 @@ const SUBSCRIPTION_TIERS = [
|
|
|
97
105
|
const DEFAULT_SETTINGS = {
|
|
98
106
|
version: 1,
|
|
99
107
|
subscriptionTier: "pro",
|
|
100
|
-
pricingOverrides: {}
|
|
108
|
+
pricingOverrides: {},
|
|
109
|
+
dataSources: []
|
|
101
110
|
};
|
|
102
111
|
function normalizeModelId(raw) {
|
|
103
112
|
return raw.replace(/-\d{8}$/, "");
|
|
@@ -1,35 +1,43 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useMemo } from "react";
|
|
3
3
|
import { queryOptions, useQuery } from "@tanstack/react-query";
|
|
4
|
-
import { c as createSsrRpc } from "./createSsrRpc-
|
|
4
|
+
import { c as createSsrRpc } from "./createSsrRpc-OFLSk08e.js";
|
|
5
5
|
import { c as createServerFn } from "../server.js";
|
|
6
6
|
import { ResponsiveContainer, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, Bar, AreaChart, Area, PieChart, Pie, Cell, Legend } from "recharts";
|
|
7
7
|
import { format, addDays, getDay, parseISO, startOfISOWeek } from "date-fns";
|
|
8
8
|
import { createPortal } from "react-dom";
|
|
9
9
|
import { f as formatTokenCount, a as formatDuration, b as formatRelativeTime, c as formatUSD } from "./format-DIZHV7IJ.js";
|
|
10
10
|
import { Link } from "@tanstack/react-router";
|
|
11
|
-
import { u as usePrivacy, R as Route } from "./router-
|
|
12
|
-
import { u as useSessionCost, E as ExportDropdown, d as downloadFile, a as dailyActivityToCSV, b as dailyTokensToCSV, m as modelUsageToCSV, s as statsToJSON } from "./useSessionCost-
|
|
13
|
-
import "@tanstack/history";
|
|
14
|
-
import "@tanstack/router-core/ssr/client";
|
|
15
|
-
import "@tanstack/router-core";
|
|
11
|
+
import { u as usePrivacy, R as Route } from "./router-DAepjaOj.js";
|
|
12
|
+
import { u as useSessionCost, E as ExportDropdown, d as downloadFile, a as dailyActivityToCSV, b as dailyTokensToCSV, m as modelUsageToCSV, s as statsToJSON } from "./useSessionCost-iQEg4FRM.js";
|
|
16
13
|
import "node:async_hooks";
|
|
17
|
-
import "@tanstack/router-core/ssr/server";
|
|
18
14
|
import "h3-v2";
|
|
15
|
+
import "@tanstack/router-core";
|
|
19
16
|
import "tiny-invariant";
|
|
20
17
|
import "seroval";
|
|
18
|
+
import "@tanstack/history";
|
|
19
|
+
import "@tanstack/router-core/ssr/client";
|
|
20
|
+
import "@tanstack/router-core/ssr/server";
|
|
21
21
|
import "@tanstack/react-router/ssr/server";
|
|
22
22
|
import "zod";
|
|
23
|
-
import "./settings.queries-
|
|
24
|
-
import "./settings.types-
|
|
23
|
+
import "./settings.queries-CMWxUDF-.js";
|
|
24
|
+
import "./settings.types-CphWe-HW.js";
|
|
25
25
|
const getStats = createServerFn({
|
|
26
26
|
method: "GET"
|
|
27
|
-
}).handler(createSsrRpc("
|
|
27
|
+
}).handler(createSsrRpc("44af69d3bfcf3ec46fffb3f297d2b12cd7fe4db36c654b8a322df34d549c6493"));
|
|
28
28
|
const statsQuery = queryOptions({
|
|
29
29
|
queryKey: ["stats"],
|
|
30
30
|
queryFn: () => getStats(),
|
|
31
31
|
refetchInterval: 6e4
|
|
32
32
|
});
|
|
33
|
+
const getProjectAnalytics = createServerFn({
|
|
34
|
+
method: "GET"
|
|
35
|
+
}).handler(createSsrRpc("39e65590d2bc41f653f54a9b6a9e0a72f185da275304c0a4a595d811cf185572"));
|
|
36
|
+
const projectAnalyticsQuery = queryOptions({
|
|
37
|
+
queryKey: ["projects", "analytics"],
|
|
38
|
+
queryFn: () => getProjectAnalytics(),
|
|
39
|
+
refetchInterval: 6e4
|
|
40
|
+
});
|
|
33
41
|
function ActivityChart({ data }) {
|
|
34
42
|
const chartData = data.map((d) => ({
|
|
35
43
|
...d,
|
|
@@ -39,19 +47,19 @@ function ActivityChart({ data }) {
|
|
|
39
47
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-300", children: "Daily Activity" }),
|
|
40
48
|
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Messages, sessions, and tool calls per day" }),
|
|
41
49
|
/* @__PURE__ */ jsx("div", { className: "mt-4 h-64", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(BarChart, { data: chartData, children: [
|
|
42
|
-
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "
|
|
50
|
+
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--color-gray-800)" }),
|
|
43
51
|
/* @__PURE__ */ jsx(
|
|
44
52
|
XAxis,
|
|
45
53
|
{
|
|
46
54
|
dataKey: "dateLabel",
|
|
47
|
-
tick: { fill: "
|
|
55
|
+
tick: { fill: "var(--color-gray-500)", fontSize: 10 },
|
|
48
56
|
tickLine: false
|
|
49
57
|
}
|
|
50
58
|
),
|
|
51
59
|
/* @__PURE__ */ jsx(
|
|
52
60
|
YAxis,
|
|
53
61
|
{
|
|
54
|
-
tick: { fill: "
|
|
62
|
+
tick: { fill: "var(--color-gray-500)", fontSize: 10 },
|
|
55
63
|
tickLine: false,
|
|
56
64
|
axisLine: false
|
|
57
65
|
}
|
|
@@ -60,8 +68,8 @@ function ActivityChart({ data }) {
|
|
|
60
68
|
Tooltip,
|
|
61
69
|
{
|
|
62
70
|
contentStyle: {
|
|
63
|
-
backgroundColor: "
|
|
64
|
-
border: "1px solid
|
|
71
|
+
backgroundColor: "var(--color-gray-900)",
|
|
72
|
+
border: "1px solid var(--color-gray-700)",
|
|
65
73
|
borderRadius: "8px",
|
|
66
74
|
fontSize: "12px"
|
|
67
75
|
}
|
|
@@ -98,7 +106,7 @@ function ActivityChart({ data }) {
|
|
|
98
106
|
] });
|
|
99
107
|
}
|
|
100
108
|
const INTENSITY_COLORS = [
|
|
101
|
-
"
|
|
109
|
+
"var(--color-gray-800)",
|
|
102
110
|
// Level 0: warm gray-800 (no activity)
|
|
103
111
|
"#3d2a1e",
|
|
104
112
|
// Level 1: dark terracotta
|
|
@@ -422,7 +430,7 @@ function CustomTooltip({ active, payload, label }) {
|
|
|
422
430
|
] }, entry.name)),
|
|
423
431
|
/* @__PURE__ */ jsxs("div", { className: "mt-1.5 border-t border-gray-700 pt-1.5 flex justify-between", children: [
|
|
424
432
|
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "Total" }),
|
|
425
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium text-
|
|
433
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium text-gray-100", children: formatTokenCount(total) })
|
|
426
434
|
] })
|
|
427
435
|
] });
|
|
428
436
|
}
|
|
@@ -462,7 +470,7 @@ function TokenTrendChart({ data }) {
|
|
|
462
470
|
{
|
|
463
471
|
type: "button",
|
|
464
472
|
onClick: () => setGranularity("daily"),
|
|
465
|
-
className: `rounded-l-lg px-3 py-1 ${granularity === "daily" ? "bg-gray-700 text-
|
|
473
|
+
className: `rounded-l-lg px-3 py-1 ${granularity === "daily" ? "bg-gray-700 text-gray-100" : "text-gray-400 hover:text-gray-300"}`,
|
|
466
474
|
children: "Daily"
|
|
467
475
|
}
|
|
468
476
|
),
|
|
@@ -471,26 +479,26 @@ function TokenTrendChart({ data }) {
|
|
|
471
479
|
{
|
|
472
480
|
type: "button",
|
|
473
481
|
onClick: () => setGranularity("weekly"),
|
|
474
|
-
className: `rounded-r-lg px-3 py-1 ${granularity === "weekly" ? "bg-gray-700 text-
|
|
482
|
+
className: `rounded-r-lg px-3 py-1 ${granularity === "weekly" ? "bg-gray-700 text-gray-100" : "text-gray-400 hover:text-gray-300"}`,
|
|
475
483
|
children: "Weekly"
|
|
476
484
|
}
|
|
477
485
|
)
|
|
478
486
|
] })
|
|
479
487
|
] }),
|
|
480
488
|
/* @__PURE__ */ jsx("div", { className: "mt-4 h-72", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(AreaChart, { data: chartData, children: [
|
|
481
|
-
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "
|
|
489
|
+
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--color-gray-800)" }),
|
|
482
490
|
/* @__PURE__ */ jsx(
|
|
483
491
|
XAxis,
|
|
484
492
|
{
|
|
485
493
|
dataKey: "dateLabel",
|
|
486
|
-
tick: { fill: "
|
|
494
|
+
tick: { fill: "var(--color-gray-500)", fontSize: 10 },
|
|
487
495
|
tickLine: false
|
|
488
496
|
}
|
|
489
497
|
),
|
|
490
498
|
/* @__PURE__ */ jsx(
|
|
491
499
|
YAxis,
|
|
492
500
|
{
|
|
493
|
-
tick: { fill: "
|
|
501
|
+
tick: { fill: "var(--color-gray-500)", fontSize: 10 },
|
|
494
502
|
tickLine: false,
|
|
495
503
|
axisLine: false,
|
|
496
504
|
tickFormatter: (value) => formatTokenCount(value)
|
|
@@ -544,8 +552,8 @@ function ModelUsageChart({ data }) {
|
|
|
544
552
|
{
|
|
545
553
|
formatter: (value) => formatTokenCount(value),
|
|
546
554
|
contentStyle: {
|
|
547
|
-
backgroundColor: "
|
|
548
|
-
border: "1px solid
|
|
555
|
+
backgroundColor: "var(--color-gray-900)",
|
|
556
|
+
border: "1px solid var(--color-gray-700)",
|
|
549
557
|
borderRadius: "8px",
|
|
550
558
|
fontSize: "12px"
|
|
551
559
|
}
|
|
@@ -610,14 +618,6 @@ function HourlyDistribution({
|
|
|
610
618
|
] })
|
|
611
619
|
] });
|
|
612
620
|
}
|
|
613
|
-
const getProjectAnalytics = createServerFn({
|
|
614
|
-
method: "GET"
|
|
615
|
-
}).handler(createSsrRpc("64052f224a1d6696436e5d3deeee2b798f0742e1292ffabd038c3a7bf75e6fcb"));
|
|
616
|
-
const projectAnalyticsQuery = queryOptions({
|
|
617
|
-
queryKey: ["projects", "analytics"],
|
|
618
|
-
queryFn: () => getProjectAnalytics(),
|
|
619
|
-
refetchInterval: 6e4
|
|
620
|
-
});
|
|
621
621
|
const COLUMNS = [
|
|
622
622
|
{ key: "projectName", label: "Project" },
|
|
623
623
|
{ key: "totalSessions", label: "Sessions", align: "right" },
|
|
@@ -690,7 +690,7 @@ function ProjectTable({ projects }) {
|
|
|
690
690
|
{
|
|
691
691
|
to: "/sessions",
|
|
692
692
|
search: { project: project.projectName },
|
|
693
|
-
className: "text-sm text-brand-
|
|
693
|
+
className: "text-sm text-brand-500 hover:underline",
|
|
694
694
|
children: anonymizeProjectName(project.projectName)
|
|
695
695
|
}
|
|
696
696
|
),
|
|
@@ -769,7 +769,7 @@ function SummaryCard({
|
|
|
769
769
|
}) {
|
|
770
770
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-gray-800 bg-gray-900/50 p-4", children: [
|
|
771
771
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400", children: label }),
|
|
772
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 truncate text-xl font-bold text-
|
|
772
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 truncate text-xl font-bold text-gray-100", children: value }),
|
|
773
773
|
sub && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-gray-500", children: sub })
|
|
774
774
|
] });
|
|
775
775
|
}
|
|
@@ -802,7 +802,7 @@ function StatsPage() {
|
|
|
802
802
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
803
803
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
804
804
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
805
|
-
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-
|
|
805
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-gray-100", children: "Stats" }),
|
|
806
806
|
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-400", children: "Usage analytics and project insights" })
|
|
807
807
|
] }),
|
|
808
808
|
tab === "overview" && stats && /* @__PURE__ */ jsx(ExportDropdown, { options: [{
|
|
@@ -824,12 +824,12 @@ function StatsPage() {
|
|
|
824
824
|
search: {
|
|
825
825
|
tab: "overview"
|
|
826
826
|
}
|
|
827
|
-
}), className: `px-4 py-2 text-sm border-b-2 transition-colors ${tab === "overview" ? "border-brand-500 text-
|
|
827
|
+
}), className: `px-4 py-2 text-sm border-b-2 transition-colors ${tab === "overview" ? "border-brand-500 text-gray-100" : "border-transparent text-gray-400 hover:text-gray-200"}`, children: "Overview" }),
|
|
828
828
|
/* @__PURE__ */ jsx("button", { onClick: () => navigate({
|
|
829
829
|
search: {
|
|
830
830
|
tab: "projects"
|
|
831
831
|
}
|
|
832
|
-
}), className: `px-4 py-2 text-sm border-b-2 transition-colors ${tab === "projects" ? "border-brand-500 text-
|
|
832
|
+
}), className: `px-4 py-2 text-sm border-b-2 transition-colors ${tab === "projects" ? "border-brand-500 text-gray-100" : "border-transparent text-gray-400 hover:text-gray-200"}`, children: "Projects" })
|
|
833
833
|
] }),
|
|
834
834
|
tab === "overview" ? /* @__PURE__ */ jsx(StatsOverview, { stats, isLoading, cost }) : /* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsx(ProjectAnalytics, {}) })
|
|
835
835
|
] });
|
|
@@ -839,10 +839,16 @@ function StatsOverview({
|
|
|
839
839
|
isLoading,
|
|
840
840
|
cost
|
|
841
841
|
}) {
|
|
842
|
+
const {
|
|
843
|
+
data: projectData
|
|
844
|
+
} = useQuery(projectAnalyticsQuery);
|
|
842
845
|
if (isLoading) {
|
|
843
846
|
return /* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-4", children: [
|
|
844
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 md:grid-cols-
|
|
845
|
-
length:
|
|
847
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 md:grid-cols-4", children: Array.from({
|
|
848
|
+
length: 4
|
|
849
|
+
}).map((_, i) => /* @__PURE__ */ jsx("div", { className: "h-20 animate-pulse rounded-xl bg-gray-900/50" }, i)) }),
|
|
850
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 md:grid-cols-4", children: Array.from({
|
|
851
|
+
length: 4
|
|
846
852
|
}).map((_, i) => /* @__PURE__ */ jsx("div", { className: "h-20 animate-pulse rounded-xl bg-gray-900/50" }, i)) }),
|
|
847
853
|
Array.from({
|
|
848
854
|
length: 3
|
|
@@ -853,12 +859,20 @@ function StatsOverview({
|
|
|
853
859
|
return /* @__PURE__ */ jsx("div", { className: "py-12 text-center text-sm text-gray-500", children: "No stats data found. Check ~/.claude/stats-cache.json" });
|
|
854
860
|
}
|
|
855
861
|
const totalTokens = Object.values(stats.modelUsage).reduce((sum, m) => sum + m.inputTokens + m.outputTokens, 0);
|
|
862
|
+
const totalToolCalls = stats.dailyActivity.reduce((sum, d) => sum + d.toolCallCount, 0);
|
|
863
|
+
const totalDurationMs = projectData?.projects.reduce((sum, p) => sum + p.totalDurationMs, 0) ?? 0;
|
|
864
|
+
const projectCount = projectData?.projects.length ?? 0;
|
|
856
865
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
857
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-6 grid grid-cols-2 gap-3 md:grid-cols-
|
|
866
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-6 grid grid-cols-2 gap-3 md:grid-cols-4", children: [
|
|
858
867
|
/* @__PURE__ */ jsx(StatCard, { label: "Total Sessions", value: String(stats.totalSessions) }),
|
|
859
868
|
/* @__PURE__ */ jsx(StatCard, { label: "Total Messages", value: stats.totalMessages.toLocaleString() }),
|
|
860
|
-
/* @__PURE__ */ jsx(StatCard, { label: "Total
|
|
861
|
-
/* @__PURE__ */ jsx(StatCard, { label: "
|
|
869
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Total Time", value: formatDuration(totalDurationMs) }),
|
|
870
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Projects", value: String(projectCount) })
|
|
871
|
+
] }),
|
|
872
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-2 gap-3 md:grid-cols-4", children: [
|
|
873
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Total Tokens", value: formatTokenCount(totalTokens) }),
|
|
874
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Estimated Cost", value: cost ? `~${formatUSD(cost.totalUSD)}` : "N/A" }),
|
|
875
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Tool Calls", value: totalToolCalls.toLocaleString() }),
|
|
862
876
|
/* @__PURE__ */ jsx(StatCard, { label: "Longest Session", value: formatDuration(stats.longestSession.duration), sub: `${stats.longestSession.messageCount} messages` })
|
|
863
877
|
] }),
|
|
864
878
|
/* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsx(ContributionHeatmap, { dailyActivity: stats.dailyActivity, dailyModelTokens: stats.dailyModelTokens }) }),
|
|
@@ -877,7 +891,7 @@ function StatCard({
|
|
|
877
891
|
}) {
|
|
878
892
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-gray-800 bg-gray-900/50 p-4", children: [
|
|
879
893
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400", children: label }),
|
|
880
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xl font-bold text-
|
|
894
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xl font-bold text-gray-100", children: value }),
|
|
881
895
|
sub && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-gray-500", children: sub })
|
|
882
896
|
] });
|
|
883
897
|
}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { c as createServerRpc } from "./createServerRpc-
|
|
1
|
+
import { c as createServerRpc } from "./createServerRpc-D_-6bKnO.js";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { g as getStatsPath, p as parseDetail } from "./session-parser-DKZZMuh6.js";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import * as os from "node:os";
|
|
6
6
|
import { z } from "zod";
|
|
7
|
-
import {
|
|
7
|
+
import { a as scanAllSessionsWithPaths } from "./session-scanner-CECpfGFh.js";
|
|
8
8
|
import { c as createServerFn } from "../server.js";
|
|
9
|
+
import "node:fs/promises";
|
|
9
10
|
import "node:readline";
|
|
10
|
-
import "@tanstack/history";
|
|
11
|
-
import "@tanstack/router-core/ssr/client";
|
|
12
|
-
import "@tanstack/router-core";
|
|
13
11
|
import "node:async_hooks";
|
|
14
|
-
import "@tanstack/router-core/ssr/server";
|
|
15
12
|
import "h3-v2";
|
|
13
|
+
import "@tanstack/router-core";
|
|
16
14
|
import "tiny-invariant";
|
|
17
15
|
import "seroval";
|
|
16
|
+
import "@tanstack/history";
|
|
17
|
+
import "@tanstack/router-core/ssr/client";
|
|
18
|
+
import "@tanstack/router-core/ssr/server";
|
|
19
|
+
import "react";
|
|
20
|
+
import "@tanstack/react-router";
|
|
18
21
|
import "react/jsx-runtime";
|
|
19
22
|
import "@tanstack/react-router/ssr/server";
|
|
20
|
-
import "@tanstack/react-router";
|
|
21
23
|
const CACHE_VERSION = 1;
|
|
22
24
|
function getCacheDir() {
|
|
23
25
|
return path.join(os.homedir(), ".claude-dashboard", "cache");
|
|
@@ -384,9 +386,9 @@ async function computeStatsFromSessions() {
|
|
|
384
386
|
}
|
|
385
387
|
}
|
|
386
388
|
const getStats_createServerFn_handler = createServerRpc({
|
|
387
|
-
id: "
|
|
389
|
+
id: "44af69d3bfcf3ec46fffb3f297d2b12cd7fe4db36c654b8a322df34d549c6493",
|
|
388
390
|
name: "getStats",
|
|
389
|
-
filename: "src/features/stats/stats.
|
|
391
|
+
filename: "src/features/stats/stats.api.ts"
|
|
390
392
|
}, (opts) => getStats.__executeServer(opts));
|
|
391
393
|
const getStats = createServerFn({
|
|
392
394
|
method: "GET"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useRef, useEffect, useMemo } from "react";
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
|
-
import { s as settingsQuery } from "./settings.queries-
|
|
5
|
-
import { b as DEFAULT_PRICING, n as normalizeModelId } from "./settings.types-
|
|
4
|
+
import { s as settingsQuery } from "./settings.queries-CMWxUDF-.js";
|
|
5
|
+
import { b as DEFAULT_PRICING, n as normalizeModelId } from "./settings.types-CphWe-HW.js";
|
|
6
6
|
function escapeCSVField(value) {
|
|
7
7
|
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
8
8
|
return `"${value.replace(/"/g, '""')}"`;
|