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,7 +1,7 @@
|
|
|
1
1
|
import { createRootRoute, Outlet, HeadContent, Scripts, createFileRoute, lazyRouteComponent, redirect, createRouter } from "@tanstack/react-router";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { useState, useRef, useCallback, createContext, useContext } from "react";
|
|
4
|
+
import { useState, useRef, useCallback, createContext, useContext, useEffect, useMemo } from "react";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
const OS_USERNAME_PATTERN = /^(\/(?:Users|home))\/[^/]+/;
|
|
7
7
|
function anonymizePath(path, anonymizedProjectName) {
|
|
@@ -96,7 +96,57 @@ function usePrivacy() {
|
|
|
96
96
|
}
|
|
97
97
|
return ctx;
|
|
98
98
|
}
|
|
99
|
-
const
|
|
99
|
+
const THEME_STORAGE_KEY = "csd-theme";
|
|
100
|
+
const ThemeContext = createContext(null);
|
|
101
|
+
function getInitialTheme() {
|
|
102
|
+
if (typeof window === "undefined") return "dark";
|
|
103
|
+
const stored = window.localStorage.getItem(THEME_STORAGE_KEY);
|
|
104
|
+
if (stored === "light" || stored === "dark") {
|
|
105
|
+
return stored;
|
|
106
|
+
}
|
|
107
|
+
const prefersDark = window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
108
|
+
return prefersDark ? "dark" : "light";
|
|
109
|
+
}
|
|
110
|
+
function ThemeProvider({ children }) {
|
|
111
|
+
const [theme, setTheme] = useState(getInitialTheme);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const root = document.documentElement;
|
|
114
|
+
root.setAttribute("data-theme", theme);
|
|
115
|
+
window.localStorage.setItem(THEME_STORAGE_KEY, theme);
|
|
116
|
+
const metaTheme = document.querySelector('meta[name="theme-color"]');
|
|
117
|
+
if (metaTheme) {
|
|
118
|
+
metaTheme.setAttribute("content", theme === "dark" ? "#141413" : "#f5f3ec");
|
|
119
|
+
}
|
|
120
|
+
}, [theme]);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
123
|
+
const listener = (event) => {
|
|
124
|
+
const stored = window.localStorage.getItem(THEME_STORAGE_KEY);
|
|
125
|
+
if (stored !== "light" && stored !== "dark") {
|
|
126
|
+
setTheme(event.matches ? "dark" : "light");
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
media.addEventListener("change", listener);
|
|
130
|
+
return () => media.removeEventListener("change", listener);
|
|
131
|
+
}, []);
|
|
132
|
+
const value = useMemo(
|
|
133
|
+
() => ({
|
|
134
|
+
theme,
|
|
135
|
+
toggleTheme: () => setTheme((prev) => prev === "dark" ? "light" : "dark"),
|
|
136
|
+
setTheme
|
|
137
|
+
}),
|
|
138
|
+
[theme]
|
|
139
|
+
);
|
|
140
|
+
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
|
|
141
|
+
}
|
|
142
|
+
function useTheme() {
|
|
143
|
+
const ctx = useContext(ThemeContext);
|
|
144
|
+
if (!ctx) {
|
|
145
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
146
|
+
}
|
|
147
|
+
return ctx;
|
|
148
|
+
}
|
|
149
|
+
const appCss = "/assets/app-BAZLXX_G.css";
|
|
100
150
|
const queryClient = new QueryClient({
|
|
101
151
|
defaultOptions: {
|
|
102
152
|
queries: {
|
|
@@ -125,18 +175,35 @@ const Route$6 = createRootRoute({
|
|
|
125
175
|
component: RootComponent
|
|
126
176
|
});
|
|
127
177
|
function RootComponent() {
|
|
128
|
-
return /* @__PURE__ */ jsx(RootDocument, { children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(PrivacyProvider, { children: /* @__PURE__ */ jsx(Outlet, {}) }) }) });
|
|
178
|
+
return /* @__PURE__ */ jsx(RootDocument, { children: /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(PrivacyProvider, { children: /* @__PURE__ */ jsx(Outlet, {}) }) }) }) });
|
|
129
179
|
}
|
|
180
|
+
const themeInitScript = `
|
|
181
|
+
(() => {
|
|
182
|
+
try {
|
|
183
|
+
const stored = localStorage.getItem('csd-theme');
|
|
184
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
185
|
+
const theme = stored === 'light' || stored === 'dark' ? stored : (prefersDark ? 'dark' : 'light');
|
|
186
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
187
|
+
const meta = document.querySelector('meta[name="theme-color"]');
|
|
188
|
+
if (meta) meta.setAttribute('content', theme === 'dark' ? '#141413' : '#f5f3ec');
|
|
189
|
+
} catch (e) {
|
|
190
|
+
document.documentElement.setAttribute('data-theme', 'dark');
|
|
191
|
+
}
|
|
192
|
+
})();
|
|
193
|
+
`;
|
|
130
194
|
function RootDocument({ children }) {
|
|
131
195
|
return /* @__PURE__ */ jsxs("html", { lang: "en", children: [
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
|
|
196
|
+
/* @__PURE__ */ jsxs("head", { children: [
|
|
197
|
+
/* @__PURE__ */ jsx(HeadContent, {}),
|
|
198
|
+
/* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: themeInitScript } })
|
|
199
|
+
] }),
|
|
200
|
+
/* @__PURE__ */ jsxs("body", { className: "antialiased", children: [
|
|
134
201
|
children,
|
|
135
202
|
/* @__PURE__ */ jsx(Scripts, {})
|
|
136
203
|
] })
|
|
137
204
|
] });
|
|
138
205
|
}
|
|
139
|
-
const $$splitComponentImporter$4 = () => import("./_dashboard-
|
|
206
|
+
const $$splitComponentImporter$4 = () => import("./_dashboard-DZJZ9oYy.js");
|
|
140
207
|
const Route$5 = createFileRoute("/_dashboard")({
|
|
141
208
|
component: lazyRouteComponent($$splitComponentImporter$4, "component")
|
|
142
209
|
});
|
|
@@ -145,7 +212,7 @@ const Route$4 = createFileRoute("/")({
|
|
|
145
212
|
throw redirect({ to: "/sessions" });
|
|
146
213
|
}
|
|
147
214
|
});
|
|
148
|
-
const $$splitComponentImporter$3 = () => import("./stats-
|
|
215
|
+
const $$splitComponentImporter$3 = () => import("./stats-DKbhSePW.js");
|
|
149
216
|
const statsSearchSchema = z.object({
|
|
150
217
|
tab: z.enum(["overview", "projects"]).default("overview").catch("overview")
|
|
151
218
|
});
|
|
@@ -153,11 +220,11 @@ const Route$3 = createFileRoute("/_dashboard/stats")({
|
|
|
153
220
|
validateSearch: statsSearchSchema,
|
|
154
221
|
component: lazyRouteComponent($$splitComponentImporter$3, "component")
|
|
155
222
|
});
|
|
156
|
-
const $$splitComponentImporter$2 = () => import("./settings-
|
|
223
|
+
const $$splitComponentImporter$2 = () => import("./settings-DsLaw8yg.js");
|
|
157
224
|
const Route$2 = createFileRoute("/_dashboard/settings")({
|
|
158
225
|
component: lazyRouteComponent($$splitComponentImporter$2, "component")
|
|
159
226
|
});
|
|
160
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
227
|
+
const $$splitComponentImporter$1 = () => import("./index-BnvjnlZM.js");
|
|
161
228
|
const sessionsSearchSchema = z.object({
|
|
162
229
|
page: z.number().int().min(1).default(1).catch(1),
|
|
163
230
|
pageSize: z.number().int().min(5).max(100).default(5).catch(5),
|
|
@@ -169,7 +236,7 @@ const Route$1 = createFileRoute("/_dashboard/sessions/")({
|
|
|
169
236
|
validateSearch: sessionsSearchSchema,
|
|
170
237
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
171
238
|
});
|
|
172
|
-
const $$splitComponentImporter = () => import("./_sessionId-
|
|
239
|
+
const $$splitComponentImporter = () => import("./_sessionId-znGcd1Dj.js");
|
|
173
240
|
const searchSchema = z.object({
|
|
174
241
|
project: z.string().optional()
|
|
175
242
|
});
|
|
@@ -233,8 +300,9 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
233
300
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
234
301
|
export {
|
|
235
302
|
Route$3 as R,
|
|
236
|
-
|
|
237
|
-
Route as b,
|
|
303
|
+
useTheme as a,
|
|
304
|
+
Route$1 as b,
|
|
305
|
+
Route as c,
|
|
238
306
|
router as r,
|
|
239
307
|
usePrivacy as u
|
|
240
308
|
};
|
package/dist/server/assets/{session-detail.server-BIoOQwSE.js → session-detail.api-BQts3iQn.js}
RENAMED
|
@@ -1,40 +1,34 @@
|
|
|
1
|
-
import { c as createServerRpc } from "./createServerRpc-
|
|
1
|
+
import { c as createServerRpc } from "./createServerRpc-D_-6bKnO.js";
|
|
2
|
+
import { a as getDataSources, b as getProjectsDirFor, d as decodeProjectDirName, e as extractProjectName, p as parseDetail } from "./session-parser-DKZZMuh6.js";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
|
-
import { e as extractProjectName, p as parseDetail, g as getProjectsDir, d as decodeProjectDirName } from "./session-parser-B0pdBvgT.js";
|
|
5
5
|
import { c as createServerFn } from "../server.js";
|
|
6
6
|
import "node:os";
|
|
7
|
+
import "node:fs/promises";
|
|
7
8
|
import "node:readline";
|
|
8
|
-
import "@tanstack/history";
|
|
9
|
-
import "@tanstack/router-core/ssr/client";
|
|
10
|
-
import "@tanstack/router-core";
|
|
11
9
|
import "node:async_hooks";
|
|
12
|
-
import "@tanstack/router-core/ssr/server";
|
|
13
10
|
import "h3-v2";
|
|
11
|
+
import "@tanstack/router-core";
|
|
14
12
|
import "tiny-invariant";
|
|
15
13
|
import "seroval";
|
|
14
|
+
import "@tanstack/history";
|
|
15
|
+
import "@tanstack/router-core/ssr/client";
|
|
16
|
+
import "@tanstack/router-core/ssr/server";
|
|
17
|
+
import "react";
|
|
18
|
+
import "@tanstack/react-router";
|
|
16
19
|
import "react/jsx-runtime";
|
|
17
20
|
import "@tanstack/react-router/ssr/server";
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const getSessionDetail = createServerFn({
|
|
25
|
-
method: "GET"
|
|
26
|
-
}).inputValidator((input) => input).handler(getSessionDetail_createServerFn_handler, async ({
|
|
27
|
-
data
|
|
28
|
-
}) => {
|
|
29
|
-
const filePath = findSessionFile(data.sessionId, data.projectPath);
|
|
30
|
-
if (!filePath) {
|
|
31
|
-
throw new Error(`Session not found: ${data.sessionId}`);
|
|
21
|
+
async function findSessionFile(sessionId, projectPath) {
|
|
22
|
+
const sources = await getDataSources();
|
|
23
|
+
for (const source of sources) {
|
|
24
|
+
if (!source.available) continue;
|
|
25
|
+
const result = findInSource(sessionId, projectPath, source);
|
|
26
|
+
if (result) return result;
|
|
32
27
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const projectsDir = getProjectsDir();
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function findInSource(sessionId, projectPath, source) {
|
|
31
|
+
const projectsDir = getProjectsDirFor(source);
|
|
38
32
|
let entries;
|
|
39
33
|
try {
|
|
40
34
|
entries = fs.readdirSync(projectsDir);
|
|
@@ -46,24 +40,35 @@ function findSessionFile(sessionId, projectPath) {
|
|
|
46
40
|
if (decoded === projectPath || dirName === projectPath) {
|
|
47
41
|
const filePath = path.join(projectsDir, dirName, `${sessionId}.jsonl`);
|
|
48
42
|
if (fs.existsSync(filePath)) {
|
|
49
|
-
return {
|
|
50
|
-
path: filePath,
|
|
51
|
-
dirName
|
|
52
|
-
};
|
|
43
|
+
return { path: filePath, dirName };
|
|
53
44
|
}
|
|
54
45
|
}
|
|
55
46
|
}
|
|
56
47
|
for (const dirName of entries) {
|
|
57
48
|
const filePath = path.join(projectsDir, dirName, `${sessionId}.jsonl`);
|
|
58
49
|
if (fs.existsSync(filePath)) {
|
|
59
|
-
return {
|
|
60
|
-
path: filePath,
|
|
61
|
-
dirName
|
|
62
|
-
};
|
|
50
|
+
return { path: filePath, dirName };
|
|
63
51
|
}
|
|
64
52
|
}
|
|
65
53
|
return null;
|
|
66
54
|
}
|
|
55
|
+
const getSessionDetail_createServerFn_handler = createServerRpc({
|
|
56
|
+
id: "71794080473579a94431392ab409ebd02772f6a9f6a08386cadbb8c0d3cf804a",
|
|
57
|
+
name: "getSessionDetail",
|
|
58
|
+
filename: "src/features/session-detail/session-detail.api.ts"
|
|
59
|
+
}, (opts) => getSessionDetail.__executeServer(opts));
|
|
60
|
+
const getSessionDetail = createServerFn({
|
|
61
|
+
method: "GET"
|
|
62
|
+
}).inputValidator((input) => input).handler(getSessionDetail_createServerFn_handler, async ({
|
|
63
|
+
data
|
|
64
|
+
}) => {
|
|
65
|
+
const filePath = await findSessionFile(data.sessionId, data.projectPath);
|
|
66
|
+
if (!filePath) {
|
|
67
|
+
throw new Error(`Session not found: ${data.sessionId}`);
|
|
68
|
+
}
|
|
69
|
+
const projectName = extractProjectName(data.projectPath);
|
|
70
|
+
return parseDetail(filePath.path, data.sessionId, data.projectPath, projectName);
|
|
71
|
+
});
|
|
67
72
|
export {
|
|
68
73
|
getSessionDetail_createServerFn_handler
|
|
69
74
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import * as os from "node:os";
|
|
3
|
-
import * as fs from "node:fs";
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import * as fs$1 from "node:fs";
|
|
4
5
|
import * as readline from "node:readline";
|
|
5
6
|
function resolveClaudeDir() {
|
|
6
7
|
if (process.env.CLAUDE_HOME) {
|
|
@@ -9,14 +10,25 @@ function resolveClaudeDir() {
|
|
|
9
10
|
return path.join(os.homedir(), ".claude");
|
|
10
11
|
}
|
|
11
12
|
const CLAUDE_DIR = resolveClaudeDir();
|
|
13
|
+
function getClaudeDir() {
|
|
14
|
+
return CLAUDE_DIR;
|
|
15
|
+
}
|
|
12
16
|
function getProjectsDir() {
|
|
13
17
|
return path.join(CLAUDE_DIR, "projects");
|
|
14
18
|
}
|
|
15
19
|
function getStatsPath() {
|
|
16
20
|
return path.join(CLAUDE_DIR, "stats-cache.json");
|
|
17
21
|
}
|
|
22
|
+
function getProjectsDirFor(source) {
|
|
23
|
+
return path.join(source.claudeDir, "projects");
|
|
24
|
+
}
|
|
18
25
|
function decodeProjectDirName(dirName) {
|
|
19
|
-
|
|
26
|
+
const decoded = dirName.replace(/^-/, "/").replace(/-/g, "/");
|
|
27
|
+
const windowsDrive = decoded.match(/^\/([A-Z])\/(.*)$/);
|
|
28
|
+
if (windowsDrive) {
|
|
29
|
+
return `${windowsDrive[1]}:/${windowsDrive[2]}`;
|
|
30
|
+
}
|
|
31
|
+
return decoded;
|
|
20
32
|
}
|
|
21
33
|
function extractProjectName(decodedPath) {
|
|
22
34
|
return path.basename(decodedPath);
|
|
@@ -24,6 +36,75 @@ function extractProjectName(decodedPath) {
|
|
|
24
36
|
function extractSessionId(filename) {
|
|
25
37
|
return filename.replace(/\.jsonl$/, "");
|
|
26
38
|
}
|
|
39
|
+
async function detectCurrentPlatform() {
|
|
40
|
+
if (process.platform === "win32") return "windows";
|
|
41
|
+
if (process.platform === "darwin") return "macos";
|
|
42
|
+
try {
|
|
43
|
+
const procVersion = await fs.readFile("/proc/version", "utf8");
|
|
44
|
+
if (procVersion.toLowerCase().includes("microsoft") || procVersion.toLowerCase().includes("wsl")) {
|
|
45
|
+
return "wsl";
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
return "linux";
|
|
50
|
+
}
|
|
51
|
+
async function detectWslDistros() {
|
|
52
|
+
if (process.platform !== "win32") return [];
|
|
53
|
+
const wslRoot = "\\\\wsl$";
|
|
54
|
+
let distros;
|
|
55
|
+
try {
|
|
56
|
+
distros = await fs.readdir(wslRoot);
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const sources = [];
|
|
61
|
+
for (const distro of distros) {
|
|
62
|
+
const homeDir = `${wslRoot}\\${distro}\\home`;
|
|
63
|
+
let users;
|
|
64
|
+
try {
|
|
65
|
+
users = await fs.readdir(homeDir);
|
|
66
|
+
} catch {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
for (const user of users) {
|
|
70
|
+
const claudeDir = `${wslRoot}\\${distro}\\home\\${user}\\.claude`;
|
|
71
|
+
try {
|
|
72
|
+
await fs.access(claudeDir);
|
|
73
|
+
sources.push({
|
|
74
|
+
id: `wsl-${distro.toLowerCase()}-${user}`,
|
|
75
|
+
label: `WSL - ${distro}`,
|
|
76
|
+
claudeDir,
|
|
77
|
+
platform: "wsl",
|
|
78
|
+
available: true
|
|
79
|
+
});
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return sources;
|
|
85
|
+
}
|
|
86
|
+
async function getDataSources() {
|
|
87
|
+
const claudeDir = getClaudeDir();
|
|
88
|
+
const platform = await detectCurrentPlatform();
|
|
89
|
+
let available = false;
|
|
90
|
+
try {
|
|
91
|
+
await fs.access(claudeDir);
|
|
92
|
+
available = true;
|
|
93
|
+
} catch {
|
|
94
|
+
available = false;
|
|
95
|
+
}
|
|
96
|
+
const primarySource = {
|
|
97
|
+
id: "primary",
|
|
98
|
+
label: platform === "windows" ? "Windows" : platform === "macos" ? "macOS" : platform === "wsl" ? "WSL" : "Linux",
|
|
99
|
+
claudeDir,
|
|
100
|
+
platform,
|
|
101
|
+
available
|
|
102
|
+
};
|
|
103
|
+
const sources = [primarySource];
|
|
104
|
+
const wslSources = await detectWslDistros();
|
|
105
|
+
sources.push(...wslSources);
|
|
106
|
+
return sources;
|
|
107
|
+
}
|
|
27
108
|
const AGENT_FILE_PATTERN = /^agent-(.+)\.jsonl$/;
|
|
28
109
|
async function discoverSubagentFiles(sessionDir) {
|
|
29
110
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -33,7 +114,7 @@ async function discoverSubagentFiles(sessionDir) {
|
|
|
33
114
|
];
|
|
34
115
|
for (const dir of candidateDirs) {
|
|
35
116
|
try {
|
|
36
|
-
const entries = await fs.promises.readdir(dir);
|
|
117
|
+
const entries = await fs$1.promises.readdir(dir);
|
|
37
118
|
for (const entry of entries) {
|
|
38
119
|
const match = AGENT_FILE_PATTERN.exec(entry);
|
|
39
120
|
if (match) {
|
|
@@ -131,7 +212,8 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
131
212
|
const taskById = /* @__PURE__ */ new Map();
|
|
132
213
|
const contextSnapshots = [];
|
|
133
214
|
let assistantTurnIndex = 0;
|
|
134
|
-
const
|
|
215
|
+
const seenRequestIds = /* @__PURE__ */ new Set();
|
|
216
|
+
const stream = fs$1.createReadStream(filePath, { encoding: "utf-8" });
|
|
135
217
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
136
218
|
for await (const line of rl) {
|
|
137
219
|
const msg = safeParse(line);
|
|
@@ -147,8 +229,11 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
147
229
|
if (progressModel && parentId) {
|
|
148
230
|
agentProgressModel.set(parentId, progressModel);
|
|
149
231
|
}
|
|
232
|
+
const progressRequestId = msg.requestId;
|
|
233
|
+
const isNewProgressRequest = !progressRequestId || !seenRequestIds.has(progressRequestId);
|
|
234
|
+
if (progressRequestId) seenRequestIds.add(progressRequestId);
|
|
150
235
|
const usage = msg.data?.message?.message?.usage;
|
|
151
|
-
if (usage) {
|
|
236
|
+
if (usage && isNewProgressRequest) {
|
|
152
237
|
const existing = agentProgressTokens.get(parentId) ?? {
|
|
153
238
|
inputTokens: 0,
|
|
154
239
|
outputTokens: 0,
|
|
@@ -266,23 +351,28 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
266
351
|
cacheReadInputTokens: u.cache_read_input_tokens ?? 0,
|
|
267
352
|
cacheCreationInputTokens: u.cache_creation_input_tokens ?? 0
|
|
268
353
|
};
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
354
|
+
const requestId = msg.requestId;
|
|
355
|
+
const isNewRequest = !requestId || !seenRequestIds.has(requestId);
|
|
356
|
+
if (requestId) seenRequestIds.add(requestId);
|
|
357
|
+
if (isNewRequest) {
|
|
358
|
+
totalTokens.inputTokens += tokens.inputTokens;
|
|
359
|
+
totalTokens.outputTokens += tokens.outputTokens;
|
|
360
|
+
totalTokens.cacheReadInputTokens += tokens.cacheReadInputTokens;
|
|
361
|
+
totalTokens.cacheCreationInputTokens += tokens.cacheCreationInputTokens;
|
|
362
|
+
if (msg.message.model) {
|
|
363
|
+
const modelId = msg.message.model;
|
|
364
|
+
const existing = tokensByModel[modelId] ?? {
|
|
365
|
+
inputTokens: 0,
|
|
366
|
+
outputTokens: 0,
|
|
367
|
+
cacheReadInputTokens: 0,
|
|
368
|
+
cacheCreationInputTokens: 0
|
|
369
|
+
};
|
|
370
|
+
existing.inputTokens += tokens.inputTokens;
|
|
371
|
+
existing.outputTokens += tokens.outputTokens;
|
|
372
|
+
existing.cacheReadInputTokens += tokens.cacheReadInputTokens;
|
|
373
|
+
existing.cacheCreationInputTokens += tokens.cacheCreationInputTokens;
|
|
374
|
+
tokensByModel[modelId] = existing;
|
|
375
|
+
}
|
|
286
376
|
}
|
|
287
377
|
const contextSize = tokens.inputTokens + tokens.cacheReadInputTokens + tokens.cacheCreationInputTokens;
|
|
288
378
|
const lastSnapshot = contextSnapshots[contextSnapshots.length - 1];
|
|
@@ -301,7 +391,7 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
301
391
|
timestamp: msg.timestamp ?? "",
|
|
302
392
|
model: msg.message.model,
|
|
303
393
|
toolCalls,
|
|
304
|
-
tokens,
|
|
394
|
+
tokens: isNewRequest ? tokens : void 0,
|
|
305
395
|
stopReason: msg.message.stop_reason
|
|
306
396
|
});
|
|
307
397
|
continue;
|
|
@@ -473,7 +563,7 @@ async function parseSubagentDetail(subagentFilePath) {
|
|
|
473
563
|
let model;
|
|
474
564
|
let totalToolUseCount = 0;
|
|
475
565
|
const seenRequestIds = /* @__PURE__ */ new Set();
|
|
476
|
-
const stream = fs.createReadStream(subagentFilePath, { encoding: "utf-8" });
|
|
566
|
+
const stream = fs$1.createReadStream(subagentFilePath, { encoding: "utf-8" });
|
|
477
567
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
478
568
|
let lineCount = 0;
|
|
479
569
|
const MAX_LINES_FOR_INJECTED = 20;
|
|
@@ -616,7 +706,7 @@ function mergeSubagentData(agent, detail, progressTokens, totalTokens, tokensByM
|
|
|
616
706
|
}
|
|
617
707
|
async function readHeadLines(filePath, count) {
|
|
618
708
|
const lines = [];
|
|
619
|
-
const stream = fs.createReadStream(filePath, { encoding: "utf-8" });
|
|
709
|
+
const stream = fs$1.createReadStream(filePath, { encoding: "utf-8" });
|
|
620
710
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
621
711
|
for await (const line of rl) {
|
|
622
712
|
lines.push(line);
|
|
@@ -627,10 +717,10 @@ async function readHeadLines(filePath, count) {
|
|
|
627
717
|
return lines;
|
|
628
718
|
}
|
|
629
719
|
async function readTailLines(filePath, count) {
|
|
630
|
-
const stat = await fs.promises.stat(filePath);
|
|
720
|
+
const stat = await fs$1.promises.stat(filePath);
|
|
631
721
|
const readSize = Math.min(stat.size, 65536);
|
|
632
722
|
const buffer = Buffer.alloc(readSize);
|
|
633
|
-
const fd = await fs.promises.open(filePath, "r");
|
|
723
|
+
const fd = await fs$1.promises.open(filePath, "r");
|
|
634
724
|
try {
|
|
635
725
|
await fd.read(buffer, 0, readSize, Math.max(0, stat.size - readSize));
|
|
636
726
|
} finally {
|
|
@@ -664,11 +754,13 @@ function extractTextContent(msg) {
|
|
|
664
754
|
return texts.length > 0 ? texts.join("\n").slice(0, 500) : void 0;
|
|
665
755
|
}
|
|
666
756
|
export {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
757
|
+
getDataSources as a,
|
|
758
|
+
getProjectsDirFor as b,
|
|
759
|
+
getProjectsDir as c,
|
|
670
760
|
decodeProjectDirName as d,
|
|
671
761
|
extractProjectName as e,
|
|
672
|
-
|
|
762
|
+
extractSessionId as f,
|
|
763
|
+
getStatsPath as g,
|
|
764
|
+
parseSummary as h,
|
|
673
765
|
parseDetail as p
|
|
674
766
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { c as getProjectsDir, d as decodeProjectDirName, e as extractProjectName, f as extractSessionId, h as parseSummary } from "./session-parser-DKZZMuh6.js";
|
|
4
4
|
async function scanProjects() {
|
|
5
5
|
const projectsDir = getProjectsDir();
|
|
6
6
|
let entries;
|
|
@@ -28,7 +28,7 @@ async function scanProjects() {
|
|
|
28
28
|
return projects;
|
|
29
29
|
}
|
|
30
30
|
const ACTIVE_THRESHOLD_MS = 12e4;
|
|
31
|
-
async function isSessionActive(projectDirName, sessionId) {
|
|
31
|
+
async function isSessionActive(projectDirName, sessionId, projectsDirOverride) {
|
|
32
32
|
const projectsDir = getProjectsDir();
|
|
33
33
|
const jsonlPath = path.join(projectsDir, projectDirName, `${sessionId}.jsonl`);
|
|
34
34
|
const lockDirPath = path.join(projectsDir, projectDirName, sessionId);
|
|
@@ -94,7 +94,7 @@ async function getActiveSessions() {
|
|
|
94
94
|
return all.filter((s) => s.isActive);
|
|
95
95
|
}
|
|
96
96
|
export {
|
|
97
|
-
|
|
97
|
+
scanAllSessionsWithPaths as a,
|
|
98
98
|
getActiveSessions as g,
|
|
99
|
-
|
|
99
|
+
scanAllSessions as s
|
|
100
100
|
};
|
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
import { c as createServerRpc } from "./createServerRpc-
|
|
1
|
+
import { c as createServerRpc } from "./createServerRpc-D_-6bKnO.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { s as scanAllSessions, g as getActiveSessions } from "./session-scanner-CECpfGFh.js";
|
|
4
4
|
import { c as createServerFn } from "../server.js";
|
|
5
5
|
import "node:fs";
|
|
6
6
|
import "node:path";
|
|
7
|
-
import "./session-parser-
|
|
7
|
+
import "./session-parser-DKZZMuh6.js";
|
|
8
8
|
import "node:os";
|
|
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 getSessionList_createServerFn_handler = createServerRpc({
|
|
22
|
-
id: "
|
|
24
|
+
id: "8fd6c4e5b4d5590acf1ec73da75f249978e8aced6dd2be23de06ade8431033be",
|
|
23
25
|
name: "getSessionList",
|
|
24
|
-
filename: "src/features/sessions/sessions.
|
|
26
|
+
filename: "src/features/sessions/sessions.api.ts"
|
|
25
27
|
}, (opts) => getSessionList.__executeServer(opts));
|
|
26
28
|
const getSessionList = createServerFn({
|
|
27
29
|
method: "GET"
|
|
@@ -29,9 +31,9 @@ const getSessionList = createServerFn({
|
|
|
29
31
|
return scanAllSessions();
|
|
30
32
|
});
|
|
31
33
|
const getActiveSessionList_createServerFn_handler = createServerRpc({
|
|
32
|
-
id: "
|
|
34
|
+
id: "946cc550946f64ee7985dc35913a690eb13183d7ba83cffe398e424e697b4265",
|
|
33
35
|
name: "getActiveSessionList",
|
|
34
|
-
filename: "src/features/sessions/sessions.
|
|
36
|
+
filename: "src/features/sessions/sessions.api.ts"
|
|
35
37
|
}, (opts) => getActiveSessionList.__executeServer(opts));
|
|
36
38
|
const getActiveSessionList = createServerFn({
|
|
37
39
|
method: "GET"
|
|
@@ -83,9 +85,9 @@ async function paginateAndFilterSessions(allSessions, input) {
|
|
|
83
85
|
};
|
|
84
86
|
}
|
|
85
87
|
const getPaginatedSessions_createServerFn_handler = createServerRpc({
|
|
86
|
-
id: "
|
|
88
|
+
id: "e574977967ea9b3387e72d70704b6ca87230e72becaf69f0b98cbc91c9cd1339",
|
|
87
89
|
name: "getPaginatedSessions",
|
|
88
|
-
filename: "src/features/sessions/sessions.
|
|
90
|
+
filename: "src/features/sessions/sessions.api.ts"
|
|
89
91
|
}, (opts) => getPaginatedSessions.__executeServer(opts));
|
|
90
92
|
const getPaginatedSessions = createServerFn({
|
|
91
93
|
method: "GET"
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { queryOptions, keepPreviousData } from "@tanstack/react-query";
|
|
2
|
-
import { c as createSsrRpc } from "./createSsrRpc-
|
|
2
|
+
import { c as createSsrRpc } from "./createSsrRpc-OFLSk08e.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { c as createServerFn } from "../server.js";
|
|
5
5
|
const getSessionList = createServerFn({
|
|
6
6
|
method: "GET"
|
|
7
|
-
}).handler(createSsrRpc("
|
|
7
|
+
}).handler(createSsrRpc("8fd6c4e5b4d5590acf1ec73da75f249978e8aced6dd2be23de06ade8431033be"));
|
|
8
8
|
const getActiveSessionList = createServerFn({
|
|
9
9
|
method: "GET"
|
|
10
|
-
}).handler(createSsrRpc("
|
|
10
|
+
}).handler(createSsrRpc("946cc550946f64ee7985dc35913a690eb13183d7ba83cffe398e424e697b4265"));
|
|
11
11
|
const paginatedSessionsInputSchema = z.object({
|
|
12
12
|
page: z.number().int().min(1),
|
|
13
13
|
pageSize: z.number().int().min(5).max(100),
|
|
@@ -17,7 +17,7 @@ const paginatedSessionsInputSchema = z.object({
|
|
|
17
17
|
});
|
|
18
18
|
const getPaginatedSessions = createServerFn({
|
|
19
19
|
method: "GET"
|
|
20
|
-
}).inputValidator((input) => paginatedSessionsInputSchema.parse(input)).handler(createSsrRpc("
|
|
20
|
+
}).inputValidator((input) => paginatedSessionsInputSchema.parse(input)).handler(createSsrRpc("e574977967ea9b3387e72d70704b6ca87230e72becaf69f0b98cbc91c9cd1339"));
|
|
21
21
|
queryOptions({
|
|
22
22
|
queryKey: ["sessions", "list"],
|
|
23
23
|
queryFn: () => getSessionList(),
|