claude-session-dashboard 0.4.1 → 0.4.2
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/server/assets/_tanstack-start-manifest_v-RaGuPsWw.js +4 -0
- package/dist/server/assets/{project-analytics.server-aftsdOgf.js → project-analytics.server-BsmZ4xil.js} +2 -2
- package/dist/server/assets/{session-detail.server-4Cp5Zyo1.js → session-detail.server-BDup9xb0.js} +1 -1
- package/dist/server/assets/{session-parser-Bq8g2LOP.js → session-parser-75iTexM0.js} +2 -2
- package/dist/server/assets/{session-scanner-BzGf0Bqs.js → session-scanner-CPud4KGP.js} +13 -5
- package/dist/server/assets/{sessions.server-XaGOdz4f.js → sessions.server-60puUvjv.js} +2 -2
- package/dist/server/assets/stats.server-qTOvID9-.js +261 -10
- package/dist/server/server.js +16 -16
- package/package.json +1 -1
- package/dist/server/assets/_tanstack-start-manifest_v-JNF_5-F_.js +0 -4
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/__root.tsx", "children": ["/", "/_dashboard"], "preloads": ["/assets/main-CV28H4XG.js"], "assets": [] }, "/": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/index.tsx" }, "/_dashboard": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard.tsx", "children": ["/_dashboard/settings", "/_dashboard/stats", "/_dashboard/sessions/$sessionId", "/_dashboard/sessions/"], "assets": [], "preloads": ["/assets/_dashboard-t702m22X.js", "/assets/createServerFn-BYTDoNe-.js", "/assets/sessions.queries-tzrs5GhP.js"] }, "/_dashboard/settings": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/settings.tsx", "assets": [], "preloads": ["/assets/settings-D8yv1q93.js", "/assets/settings.types-CMYAW0cQ.js"] }, "/_dashboard/stats": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/stats.tsx", "assets": [], "preloads": ["/assets/stats-C_6E4jyb.js", "/assets/format-Bsprb3az.js", "/assets/useSessionCost-BBu3AmcX.js", "/assets/settings.types-CMYAW0cQ.js"] }, "/_dashboard/sessions/$sessionId": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/sessions/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-D4Tpmmb5.js", "/assets/format-Bsprb3az.js", "/assets/useSessionCost-BBu3AmcX.js", "/assets/settings.types-CMYAW0cQ.js"] }, "/_dashboard/sessions/": { "filePath": "/Users/dmytro.lupiak/Documents/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/sessions/index.tsx", "assets": [], "preloads": ["/assets/index-DnK_zh3s.js", "/assets/format-Bsprb3az.js"] } }, "clientEntry": "/assets/main-CV28H4XG.js" });
|
|
2
|
+
export {
|
|
3
|
+
tsrStartManifest
|
|
4
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
2
|
-
import { s as scanAllSessions } from "./session-scanner-
|
|
2
|
+
import { s as scanAllSessions } from "./session-scanner-CPud4KGP.js";
|
|
3
3
|
import { c as createServerFn } from "../server.js";
|
|
4
4
|
import "node:fs";
|
|
5
5
|
import "node:path";
|
|
6
6
|
import "./claude-path-BdwflgZ1.js";
|
|
7
7
|
import "node:os";
|
|
8
|
-
import "./session-parser-
|
|
8
|
+
import "./session-parser-75iTexM0.js";
|
|
9
9
|
import "node:readline";
|
|
10
10
|
import "@tanstack/history";
|
|
11
11
|
import "@tanstack/router-core/ssr/client";
|
package/dist/server/assets/{session-detail.server-4Cp5Zyo1.js → session-detail.server-BDup9xb0.js}
RENAMED
|
@@ -2,7 +2,7 @@ import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { e as extractProjectName, a as getProjectsDir, d as decodeProjectDirName } from "./claude-path-BdwflgZ1.js";
|
|
5
|
-
import {
|
|
5
|
+
import { a as parseDetail } from "./session-parser-75iTexM0.js";
|
|
6
6
|
import { c as createServerFn } from "../server.js";
|
|
7
7
|
import "node:os";
|
|
8
8
|
import "node:readline";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { a as getProjectsDir, d as decodeProjectDirName, e as extractProjectName, b as extractSessionId } from "./claude-path-BdwflgZ1.js";
|
|
4
|
-
import {
|
|
4
|
+
import { p as parseSummary } from "./session-parser-75iTexM0.js";
|
|
5
5
|
async function scanProjects() {
|
|
6
6
|
const projectsDir = getProjectsDir();
|
|
7
7
|
let entries;
|
|
@@ -41,7 +41,7 @@ async function isSessionActive(projectDirName, sessionId) {
|
|
|
41
41
|
return lockStat?.isDirectory() ?? false;
|
|
42
42
|
}
|
|
43
43
|
const summaryCache = /* @__PURE__ */ new Map();
|
|
44
|
-
async function
|
|
44
|
+
async function scanSessionsInternal() {
|
|
45
45
|
const projects = await scanProjects();
|
|
46
46
|
const summaries = [];
|
|
47
47
|
for (const project of projects) {
|
|
@@ -57,7 +57,7 @@ async function scanAllSessions() {
|
|
|
57
57
|
const cached = summaryCache.get(sessionId);
|
|
58
58
|
if (cached && cached.mtimeMs === stat.mtimeMs) {
|
|
59
59
|
const active = await isSessionActive(project.dirName, sessionId);
|
|
60
|
-
summaries.push({ ...cached.summary, isActive: active });
|
|
60
|
+
summaries.push({ ...cached.summary, isActive: active, filePath });
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
63
|
const summary = await parseSummary(
|
|
@@ -74,7 +74,7 @@ async function scanAllSessions() {
|
|
|
74
74
|
mtimeMs: stat.mtimeMs,
|
|
75
75
|
summary
|
|
76
76
|
});
|
|
77
|
-
summaries.push(summary);
|
|
77
|
+
summaries.push({ ...summary, filePath });
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}
|
|
@@ -83,11 +83,19 @@ async function scanAllSessions() {
|
|
|
83
83
|
);
|
|
84
84
|
return summaries;
|
|
85
85
|
}
|
|
86
|
+
async function scanAllSessions() {
|
|
87
|
+
const results = await scanSessionsInternal();
|
|
88
|
+
return results.map(({ filePath: _fp, ...rest }) => rest);
|
|
89
|
+
}
|
|
90
|
+
async function scanAllSessionsWithPaths() {
|
|
91
|
+
return scanSessionsInternal();
|
|
92
|
+
}
|
|
86
93
|
async function getActiveSessions() {
|
|
87
94
|
const all = await scanAllSessions();
|
|
88
95
|
return all.filter((s) => s.isActive);
|
|
89
96
|
}
|
|
90
97
|
export {
|
|
91
98
|
getActiveSessions as g,
|
|
92
|
-
scanAllSessions as s
|
|
99
|
+
scanAllSessions as s,
|
|
100
|
+
scanAllSessionsWithPaths as w
|
|
93
101
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { s as scanAllSessions, g as getActiveSessions } from "./session-scanner-
|
|
3
|
+
import { s as scanAllSessions, g as getActiveSessions } from "./session-scanner-CPud4KGP.js";
|
|
4
4
|
import { c as createServerFn } from "../server.js";
|
|
5
5
|
import "node:fs";
|
|
6
6
|
import "node:path";
|
|
7
7
|
import "./claude-path-BdwflgZ1.js";
|
|
8
8
|
import "node:os";
|
|
9
|
-
import "./session-parser-
|
|
9
|
+
import "./session-parser-75iTexM0.js";
|
|
10
10
|
import "node:readline";
|
|
11
11
|
import "@tanstack/history";
|
|
12
12
|
import "@tanstack/router-core/ssr/client";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import { g as getStatsPath } from "./claude-path-BdwflgZ1.js";
|
|
4
|
+
import { s as scanAllSessions, w as scanAllSessionsWithPaths } from "./session-scanner-CPud4KGP.js";
|
|
5
|
+
import { a as parseDetail } from "./session-parser-75iTexM0.js";
|
|
4
6
|
import * as path from "node:path";
|
|
5
7
|
import * as os from "node:os";
|
|
6
8
|
import { z } from "zod";
|
|
@@ -110,24 +112,273 @@ const StatsCacheSchema = z.object({
|
|
|
110
112
|
totalSpeculationTimeSavedMs: z.number().optional()
|
|
111
113
|
});
|
|
112
114
|
let cachedStats = null;
|
|
115
|
+
let mergedCache = null;
|
|
116
|
+
const MERGE_STALENESS_MS = 60000;
|
|
117
|
+
function getTodayDateString() {
|
|
118
|
+
return new Date().toISOString().split("T")[0];
|
|
119
|
+
}
|
|
120
|
+
function extractDateString(isoOrDate) {
|
|
121
|
+
return isoOrDate.split("T")[0];
|
|
122
|
+
}
|
|
123
|
+
function updateHourCounts(hourCounts, session) {
|
|
124
|
+
const startedAt = session.startedAt;
|
|
125
|
+
if (!startedAt) return;
|
|
126
|
+
try {
|
|
127
|
+
const date = new Date(startedAt);
|
|
128
|
+
const hour = date.getHours().toString();
|
|
129
|
+
hourCounts[hour] = (hourCounts[hour] ?? 0) + 1;
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function parseDetailsInBatches(sessions, batchSize = 10) {
|
|
134
|
+
const results = new Map();
|
|
135
|
+
for (let i = 0; i < sessions.length; i += batchSize) {
|
|
136
|
+
const batch = sessions.slice(i, i + batchSize);
|
|
137
|
+
const details = await Promise.all(
|
|
138
|
+
batch.map(async (s) => {
|
|
139
|
+
try {
|
|
140
|
+
return {
|
|
141
|
+
sessionId: s.sessionId,
|
|
142
|
+
detail: await parseDetail(s.filePath, s.sessionId, s.projectPath, s.projectName),
|
|
143
|
+
};
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
for (const result of details) {
|
|
150
|
+
if (result) results.set(result.sessionId, result.detail);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return results;
|
|
154
|
+
}
|
|
155
|
+
async function maybeEnrichWithRecentSessions(stats, mtimeMs) {
|
|
156
|
+
const today = getTodayDateString();
|
|
157
|
+
const lastComputed = extractDateString(stats.lastComputedDate);
|
|
158
|
+
if (lastComputed >= today) {
|
|
159
|
+
return stats;
|
|
160
|
+
}
|
|
161
|
+
if (mergedCache && mergedCache.mtimeMs === mtimeMs && Date.now() - mergedCache.mergedAt < MERGE_STALENESS_MS) {
|
|
162
|
+
return mergedCache.data;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const merged = await mergeRecentSessions(stats);
|
|
166
|
+
mergedCache = { mtimeMs, mergedAt: Date.now(), data: merged };
|
|
167
|
+
return merged;
|
|
168
|
+
} catch {
|
|
169
|
+
return stats;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function mergeRecentSessions(stats) {
|
|
173
|
+
const summaries = await scanAllSessionsWithPaths();
|
|
174
|
+
const cutoffDate = extractDateString(stats.lastComputedDate);
|
|
175
|
+
const recentSessions = summaries.filter((s) => {
|
|
176
|
+
const sessionDate = extractDateString(s.lastActiveAt ?? s.startedAt);
|
|
177
|
+
return sessionDate > cutoffDate;
|
|
178
|
+
});
|
|
179
|
+
if (recentSessions.length === 0) {
|
|
180
|
+
return stats;
|
|
181
|
+
}
|
|
182
|
+
const detailMap = await parseDetailsInBatches(recentSessions);
|
|
183
|
+
const activityMap = new Map();
|
|
184
|
+
for (const entry of stats.dailyActivity) {
|
|
185
|
+
activityMap.set(entry.date, {
|
|
186
|
+
messageCount: entry.messageCount,
|
|
187
|
+
sessionCount: entry.sessionCount,
|
|
188
|
+
toolCallCount: entry.toolCallCount
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const modelTokensMap = new Map();
|
|
192
|
+
for (const entry of stats.dailyModelTokens) {
|
|
193
|
+
modelTokensMap.set(entry.date, { ...entry.tokensByModel });
|
|
194
|
+
}
|
|
195
|
+
const hourCounts = { ...stats.hourCounts };
|
|
196
|
+
const modelUsage = {};
|
|
197
|
+
for (const [model, usage] of Object.entries(stats.modelUsage)) {
|
|
198
|
+
modelUsage[model] = { ...usage };
|
|
199
|
+
}
|
|
200
|
+
let additionalMessages = 0;
|
|
201
|
+
const additionalSessions = recentSessions.length;
|
|
202
|
+
let longestSession = { ...stats.longestSession };
|
|
203
|
+
const existingSessionCount = stats.totalSessions;
|
|
204
|
+
for (const s of recentSessions) {
|
|
205
|
+
const date = extractDateString(s.lastActiveAt ?? s.startedAt);
|
|
206
|
+
const detail = detailMap.get(s.sessionId);
|
|
207
|
+
const cur = activityMap.get(date) ?? { messageCount: 0, sessionCount: 0, toolCallCount: 0 };
|
|
208
|
+
cur.sessionCount += 1;
|
|
209
|
+
if (detail) {
|
|
210
|
+
cur.messageCount += detail.turns.length;
|
|
211
|
+
cur.toolCallCount += Object.values(detail.toolFrequency)
|
|
212
|
+
.reduce((sum, n) => sum + n, 0);
|
|
213
|
+
const dayTokens = modelTokensMap.get(date) ?? {};
|
|
214
|
+
for (const [model, usage] of Object.entries(detail.tokensByModel)) {
|
|
215
|
+
const total = usage.inputTokens + usage.outputTokens;
|
|
216
|
+
dayTokens[model] = (dayTokens[model] ?? 0) + total;
|
|
217
|
+
}
|
|
218
|
+
modelTokensMap.set(date, dayTokens);
|
|
219
|
+
for (const [model, usage] of Object.entries(detail.tokensByModel)) {
|
|
220
|
+
const existing = modelUsage[model] ?? {
|
|
221
|
+
inputTokens: 0, outputTokens: 0,
|
|
222
|
+
cacheReadInputTokens: 0, cacheCreationInputTokens: 0,
|
|
223
|
+
};
|
|
224
|
+
existing.inputTokens += usage.inputTokens;
|
|
225
|
+
existing.outputTokens += usage.outputTokens;
|
|
226
|
+
existing.cacheReadInputTokens += usage.cacheReadInputTokens;
|
|
227
|
+
existing.cacheCreationInputTokens += usage.cacheCreationInputTokens;
|
|
228
|
+
modelUsage[model] = existing;
|
|
229
|
+
}
|
|
230
|
+
additionalMessages += detail.turns.length;
|
|
231
|
+
} else {
|
|
232
|
+
cur.messageCount += s.messageCount;
|
|
233
|
+
additionalMessages += s.messageCount;
|
|
234
|
+
if (!modelTokensMap.has(date)) {
|
|
235
|
+
modelTokensMap.set(date, {});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
activityMap.set(date, cur);
|
|
239
|
+
updateHourCounts(hourCounts, s);
|
|
240
|
+
if (s.durationMs > longestSession.duration) {
|
|
241
|
+
longestSession = {
|
|
242
|
+
sessionId: s.sessionId,
|
|
243
|
+
duration: s.durationMs,
|
|
244
|
+
messageCount: detail?.turns.length ?? s.messageCount,
|
|
245
|
+
timestamp: s.lastActiveAt ?? s.startedAt
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const dailyActivity = Array.from(activityMap.entries()).map(([date, v]) => ({
|
|
250
|
+
date,
|
|
251
|
+
messageCount: v.messageCount,
|
|
252
|
+
sessionCount: v.sessionCount,
|
|
253
|
+
toolCallCount: v.toolCallCount
|
|
254
|
+
})).sort((a, b) => a.date < b.date ? -1 : 1);
|
|
255
|
+
const dailyModelTokens = Array.from(modelTokensMap.entries()).map(([date, tokensByModel]) => ({ date, tokensByModel })).sort((a, b) => a.date < b.date ? -1 : 1);
|
|
256
|
+
return {
|
|
257
|
+
...stats,
|
|
258
|
+
dailyActivity,
|
|
259
|
+
dailyModelTokens,
|
|
260
|
+
modelUsage,
|
|
261
|
+
totalSessions: existingSessionCount + additionalSessions,
|
|
262
|
+
totalMessages: stats.totalMessages + additionalMessages,
|
|
263
|
+
longestSession,
|
|
264
|
+
hourCounts
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
async function computeStatsFromSessions() {
|
|
268
|
+
try {
|
|
269
|
+
const summaries = await scanAllSessionsWithPaths();
|
|
270
|
+
const detailMap = await parseDetailsInBatches(summaries);
|
|
271
|
+
const activityMap = new Map();
|
|
272
|
+
const modelTokensMap = new Map();
|
|
273
|
+
const modelUsage = {};
|
|
274
|
+
const hourCounts = {};
|
|
275
|
+
let totalMessages = 0;
|
|
276
|
+
let longestSession = { sessionId: "", duration: 0, messageCount: 0, timestamp: "" };
|
|
277
|
+
let firstSessionDate = null;
|
|
278
|
+
for (const s of summaries) {
|
|
279
|
+
const d = (s.lastActiveAt ?? s.startedAt).split("T")[0];
|
|
280
|
+
const detail = detailMap.get(s.sessionId);
|
|
281
|
+
const cur = activityMap.get(d) ?? { messageCount: 0, sessionCount: 0, toolCallCount: 0 };
|
|
282
|
+
cur.sessionCount += 1;
|
|
283
|
+
if (detail) {
|
|
284
|
+
cur.messageCount += detail.turns.length;
|
|
285
|
+
cur.toolCallCount += Object.values(detail.toolFrequency)
|
|
286
|
+
.reduce((sum, n) => sum + n, 0);
|
|
287
|
+
totalMessages += detail.turns.length;
|
|
288
|
+
const dayTokens = modelTokensMap.get(d) ?? {};
|
|
289
|
+
for (const [model, usage] of Object.entries(detail.tokensByModel)) {
|
|
290
|
+
const total = usage.inputTokens + usage.outputTokens;
|
|
291
|
+
dayTokens[model] = (dayTokens[model] ?? 0) + total;
|
|
292
|
+
}
|
|
293
|
+
modelTokensMap.set(d, dayTokens);
|
|
294
|
+
for (const [model, usage] of Object.entries(detail.tokensByModel)) {
|
|
295
|
+
const existing = modelUsage[model] ?? {
|
|
296
|
+
inputTokens: 0, outputTokens: 0,
|
|
297
|
+
cacheReadInputTokens: 0, cacheCreationInputTokens: 0,
|
|
298
|
+
};
|
|
299
|
+
existing.inputTokens += usage.inputTokens;
|
|
300
|
+
existing.outputTokens += usage.outputTokens;
|
|
301
|
+
existing.cacheReadInputTokens += usage.cacheReadInputTokens;
|
|
302
|
+
existing.cacheCreationInputTokens += usage.cacheCreationInputTokens;
|
|
303
|
+
modelUsage[model] = existing;
|
|
304
|
+
}
|
|
305
|
+
} else {
|
|
306
|
+
cur.messageCount += s.messageCount;
|
|
307
|
+
totalMessages += s.messageCount;
|
|
308
|
+
if (!modelTokensMap.has(d)) modelTokensMap.set(d, {});
|
|
309
|
+
}
|
|
310
|
+
activityMap.set(d, cur);
|
|
311
|
+
updateHourCounts(hourCounts, s);
|
|
312
|
+
const msgCount = detail?.turns.length ?? s.messageCount;
|
|
313
|
+
if (s.durationMs > longestSession.duration) {
|
|
314
|
+
longestSession = {
|
|
315
|
+
sessionId: s.sessionId,
|
|
316
|
+
duration: s.durationMs,
|
|
317
|
+
messageCount: msgCount,
|
|
318
|
+
timestamp: s.lastActiveAt ?? s.startedAt
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
if (!firstSessionDate || s.startedAt < firstSessionDate) {
|
|
322
|
+
firstSessionDate = s.startedAt;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const dailyActivity = Array.from(activityMap.entries())
|
|
326
|
+
.map(([date, v]) => ({ date, ...v }))
|
|
327
|
+
.sort((a, b) => a.date < b.date ? -1 : 1);
|
|
328
|
+
const dailyModelTokens = Array.from(modelTokensMap.entries())
|
|
329
|
+
.map(([date, tokensByModel]) => ({ date, tokensByModel }))
|
|
330
|
+
.sort((a, b) => a.date < b.date ? -1 : 1);
|
|
331
|
+
return {
|
|
332
|
+
version: 1,
|
|
333
|
+
lastComputedDate: new Date().toISOString(),
|
|
334
|
+
dailyActivity,
|
|
335
|
+
dailyModelTokens,
|
|
336
|
+
modelUsage,
|
|
337
|
+
totalSessions: summaries.length,
|
|
338
|
+
totalMessages,
|
|
339
|
+
longestSession: {
|
|
340
|
+
sessionId: longestSession.sessionId,
|
|
341
|
+
duration: longestSession.duration,
|
|
342
|
+
messageCount: longestSession.messageCount,
|
|
343
|
+
timestamp: longestSession.timestamp || new Date().toISOString()
|
|
344
|
+
},
|
|
345
|
+
firstSessionDate: firstSessionDate ?? new Date().toISOString(),
|
|
346
|
+
hourCounts
|
|
347
|
+
};
|
|
348
|
+
} catch (error) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
113
352
|
async function parseStats() {
|
|
114
353
|
const statsPath = getStatsPath();
|
|
115
354
|
const stat = await fs.promises.stat(statsPath).catch(() => null);
|
|
116
|
-
if (!stat)
|
|
355
|
+
if (!stat) {
|
|
356
|
+
try {
|
|
357
|
+
const computed = await computeStatsFromSessions();
|
|
358
|
+
return computed;
|
|
359
|
+
} catch {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
117
363
|
if (cachedStats && cachedStats.mtimeMs === stat.mtimeMs) {
|
|
118
|
-
return cachedStats.data;
|
|
364
|
+
return maybeEnrichWithRecentSessions(cachedStats.data, stat.mtimeMs);
|
|
119
365
|
}
|
|
120
366
|
const diskResult = readDiskCache("stats", stat.mtimeMs, StatsCacheSchema);
|
|
121
367
|
if (diskResult) {
|
|
122
368
|
cachedStats = { mtimeMs: stat.mtimeMs, data: diskResult };
|
|
123
|
-
return diskResult;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
369
|
+
return maybeEnrichWithRecentSessions(diskResult, stat.mtimeMs);
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
const raw = await fs.promises.readFile(statsPath, "utf-8");
|
|
373
|
+
const parsed = JSON.parse(raw);
|
|
374
|
+
const result = StatsCacheSchema.parse(parsed);
|
|
375
|
+
writeDiskCache("stats", statsPath, stat.mtimeMs, result);
|
|
376
|
+
cachedStats = { mtimeMs: stat.mtimeMs, data: result };
|
|
377
|
+
return maybeEnrichWithRecentSessions(result, stat.mtimeMs);
|
|
378
|
+
} catch {
|
|
379
|
+
const computed = await computeStatsFromSessions();
|
|
380
|
+
return computed;
|
|
381
|
+
}
|
|
131
382
|
}
|
|
132
383
|
const getStats_createServerFn_handler = createServerRpc({
|
|
133
384
|
id: "4b9a58c176f487b49800a372100037cdf33cf048f3592a449f115c7e3f5ea799",
|
package/dist/server/server.js
CHANGED
|
@@ -423,7 +423,7 @@ function getResponse() {
|
|
|
423
423
|
return event.res;
|
|
424
424
|
}
|
|
425
425
|
async function getStartManifest(matchedRoutes) {
|
|
426
|
-
const { tsrStartManifest } = await import("./assets/_tanstack-start-manifest_v-
|
|
426
|
+
const { tsrStartManifest } = await import("./assets/_tanstack-start-manifest_v-RaGuPsWw.js");
|
|
427
427
|
const startManifest = tsrStartManifest();
|
|
428
428
|
const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
|
|
429
429
|
rootRoute.assets = rootRoute.assets || [];
|
|
@@ -580,27 +580,27 @@ function createMultiplexedStream(jsonStream, rawStreams) {
|
|
|
580
580
|
const manifest = { "4b9a58c176f487b49800a372100037cdf33cf048f3592a449f115c7e3f5ea799": {
|
|
581
581
|
functionName: "getStats_createServerFn_handler",
|
|
582
582
|
importer: () => import("./assets/stats.server-qTOvID9-.js")
|
|
583
|
-
}, "
|
|
584
|
-
functionName: "
|
|
585
|
-
importer: () => import("./assets/
|
|
586
|
-
}, "bf8e4a7901f1843bdc9c46be1ad5ad59c615b8bbe611b73eb3ff28f20e43ee0d": {
|
|
587
|
-
functionName: "getSessionList_createServerFn_handler",
|
|
588
|
-
importer: () => import("./assets/sessions.server-XaGOdz4f.js")
|
|
589
|
-
}, "839d29fe93dfa2a6d506af7b48ca25197190a5ff4c796e970ddfdc6e8c98827f": {
|
|
590
|
-
functionName: "getActiveSessionList_createServerFn_handler",
|
|
591
|
-
importer: () => import("./assets/sessions.server-XaGOdz4f.js")
|
|
592
|
-
}, "a3f42f9012fd83586787da8f7cb90649da739dd947d867eb67572f68735ff495": {
|
|
593
|
-
functionName: "getPaginatedSessions_createServerFn_handler",
|
|
594
|
-
importer: () => import("./assets/sessions.server-XaGOdz4f.js")
|
|
583
|
+
}, "64052f224a1d6696436e5d3deeee2b798f0742e1292ffabd038c3a7bf75e6fcb": {
|
|
584
|
+
functionName: "getProjectAnalytics_createServerFn_handler",
|
|
585
|
+
importer: () => import("./assets/project-analytics.server-BsmZ4xil.js")
|
|
595
586
|
}, "810657681a273df5b4e58f0d8fcc6a5451598b489431b9bcaa98eea0ad815da8": {
|
|
596
587
|
functionName: "getSettings_createServerFn_handler",
|
|
597
588
|
importer: () => import("./assets/settings.server-6B2PvLgf.js")
|
|
598
589
|
}, "3050115d92ca91ab1fd8fd698e33076328aae80dc64ca27c088eee16cebccc1a": {
|
|
599
590
|
functionName: "saveSettings_createServerFn_handler",
|
|
600
591
|
importer: () => import("./assets/settings.server-6B2PvLgf.js")
|
|
601
|
-
}, "
|
|
602
|
-
functionName: "
|
|
603
|
-
importer: () => import("./assets/
|
|
592
|
+
}, "bf8e4a7901f1843bdc9c46be1ad5ad59c615b8bbe611b73eb3ff28f20e43ee0d": {
|
|
593
|
+
functionName: "getSessionList_createServerFn_handler",
|
|
594
|
+
importer: () => import("./assets/sessions.server-60puUvjv.js")
|
|
595
|
+
}, "839d29fe93dfa2a6d506af7b48ca25197190a5ff4c796e970ddfdc6e8c98827f": {
|
|
596
|
+
functionName: "getActiveSessionList_createServerFn_handler",
|
|
597
|
+
importer: () => import("./assets/sessions.server-60puUvjv.js")
|
|
598
|
+
}, "a3f42f9012fd83586787da8f7cb90649da739dd947d867eb67572f68735ff495": {
|
|
599
|
+
functionName: "getPaginatedSessions_createServerFn_handler",
|
|
600
|
+
importer: () => import("./assets/sessions.server-60puUvjv.js")
|
|
601
|
+
}, "ff8a3161afdfa175e9c519e4146a56ab5bce6e80745e99cfc2191ebbb7a859bb": {
|
|
602
|
+
functionName: "getSessionDetail_createServerFn_handler",
|
|
603
|
+
importer: () => import("./assets/session-detail.server-BDup9xb0.js")
|
|
604
604
|
} };
|
|
605
605
|
async function getServerFnById(id) {
|
|
606
606
|
const serverFnInfo = manifest[id];
|
package/package.json
CHANGED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/__root.tsx", "children": ["/", "/_dashboard"], "preloads": ["/assets/main-CV28H4XG.js"], "assets": [] }, "/": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/index.tsx" }, "/_dashboard": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/_dashboard.tsx", "children": ["/_dashboard/settings", "/_dashboard/stats", "/_dashboard/sessions/$sessionId", "/_dashboard/sessions/"], "assets": [], "preloads": ["/assets/_dashboard-t702m22X.js", "/assets/createServerFn-BYTDoNe-.js", "/assets/sessions.queries-tzrs5GhP.js"] }, "/_dashboard/settings": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/_dashboard/settings.tsx", "assets": [], "preloads": ["/assets/settings-D8yv1q93.js", "/assets/settings.types-CMYAW0cQ.js"] }, "/_dashboard/stats": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/_dashboard/stats.tsx", "assets": [], "preloads": ["/assets/stats-C_6E4jyb.js", "/assets/format-Bsprb3az.js", "/assets/useSessionCost-BBu3AmcX.js", "/assets/settings.types-CMYAW0cQ.js"] }, "/_dashboard/sessions/$sessionId": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/_dashboard/sessions/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-D4Tpmmb5.js", "/assets/format-Bsprb3az.js", "/assets/useSessionCost-BBu3AmcX.js", "/assets/settings.types-CMYAW0cQ.js"] }, "/_dashboard/sessions/": { "filePath": "/home/runner/work/claude-session-dashboard/claude-session-dashboard/apps/web/src/routes/_dashboard/sessions/index.tsx", "assets": [], "preloads": ["/assets/index-DnK_zh3s.js", "/assets/format-Bsprb3az.js"] } }, "clientEntry": "/assets/main-CV28H4XG.js" });
|
|
2
|
-
export {
|
|
3
|
-
tsrStartManifest
|
|
4
|
-
};
|