claude-session-dashboard 0.4.2 → 0.4.4
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-DLFGahko.js +1 -0
- package/dist/client/assets/{_sessionId-D4Tpmmb5.js → _sessionId-xiPzwrlf.js} +1 -1
- package/dist/client/assets/{createServerFn-BYTDoNe-.js → createServerFn-BLR4iNR3.js} +1 -1
- package/dist/client/assets/{index-DnK_zh3s.js → index-D_9sS4oJ.js} +1 -1
- package/dist/client/assets/{main-CV28H4XG.js → main-BcKPK-4E.js} +3 -3
- package/dist/client/assets/{sessions.queries-tzrs5GhP.js → sessions.queries-CHKiZnLm.js} +1 -1
- package/dist/client/assets/{settings-D8yv1q93.js → settings-B2tG1vy0.js} +1 -1
- package/dist/client/assets/{settings.types-CMYAW0cQ.js → settings.types-DHC6rkil.js} +1 -1
- package/dist/client/assets/{stats-C_6E4jyb.js → stats-BlA0NIHc.js} +1 -1
- package/dist/client/assets/{useSessionCost-BBu3AmcX.js → useSessionCost-BikgEmWy.js} +1 -1
- package/dist/server/assets/{_dashboard-TUzgwLqB.js → _dashboard-smfIqyQC.js} +56 -30
- package/dist/server/assets/{_sessionId-DyFxvcBN.js → _sessionId-DIUMcrWR.js} +1 -1
- package/dist/server/assets/_tanstack-start-manifest_v-Dmhlhehg.js +4 -0
- package/dist/server/assets/app-info.server-CXcS0a5s.js +40 -0
- package/dist/server/assets/{index-Bx7vBs4O.js → index-hFrIPkke.js} +1 -1
- package/dist/server/assets/{project-analytics.server-BsmZ4xil.js → project-analytics.server-Bxk8-NnT.js} +2 -3
- package/dist/server/assets/{router-Cd4jLk4T.js → router-5hznwWqr.js} +5 -5
- package/dist/server/assets/{session-detail.server-BDup9xb0.js → session-detail.server-BIoOQwSE.js} +1 -2
- package/dist/server/assets/{session-parser-75iTexM0.js → session-parser-B0pdBvgT.js} +168 -48
- package/dist/server/assets/{session-scanner-CPud4KGP.js → session-scanner-CpgOq5m1.js} +4 -5
- package/dist/server/assets/{sessions.server-60puUvjv.js → sessions.server-Biq8gbAJ.js} +2 -3
- package/dist/server/assets/{settings-KKaz1ty7.js → settings-D0FgLIR5.js} +1 -1
- package/dist/server/assets/{stats-Bsrkajci.js → stats-Ae6umrPI.js} +1 -1
- package/dist/server/assets/{stats.server-qTOvID9-.js → stats.server-DhzOihwM.js} +86 -83
- package/dist/server/server.js +16 -13
- package/package.json +1 -1
- package/dist/client/assets/_dashboard-t702m22X.js +0 -1
- package/dist/server/assets/_tanstack-start-manifest_v-RaGuPsWw.js +0 -4
- package/dist/server/assets/claude-path-BdwflgZ1.js +0 -31
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMatches, Link, Outlet } from "@tanstack/react-router";
|
|
3
|
-
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { useQuery, queryOptions } from "@tanstack/react-query";
|
|
4
4
|
import { a as activeSessionsQuery } from "./sessions.queries-B5ZBiVJy.js";
|
|
5
|
-
import "./createSsrRpc-CVg2UDl0.js";
|
|
6
|
-
import "../server.js";
|
|
5
|
+
import { c as createSsrRpc } from "./createSsrRpc-CVg2UDl0.js";
|
|
6
|
+
import { c as createServerFn } from "../server.js";
|
|
7
|
+
import "zod";
|
|
7
8
|
import "@tanstack/history";
|
|
8
9
|
import "@tanstack/router-core/ssr/client";
|
|
9
10
|
import "@tanstack/router-core";
|
|
@@ -13,13 +14,22 @@ import "h3-v2";
|
|
|
13
14
|
import "tiny-invariant";
|
|
14
15
|
import "seroval";
|
|
15
16
|
import "@tanstack/react-router/ssr/server";
|
|
16
|
-
import "zod";
|
|
17
17
|
function ActiveSessionsBadge() {
|
|
18
18
|
const { data: activeSessions } = useQuery(activeSessionsQuery);
|
|
19
19
|
const count = activeSessions?.length ?? 0;
|
|
20
20
|
if (count === 0) return null;
|
|
21
21
|
return /* @__PURE__ */ jsx("span", { className: "ml-auto rounded-full bg-emerald-500/20 px-1.5 py-0.5 text-[10px] font-medium text-emerald-400", children: count });
|
|
22
22
|
}
|
|
23
|
+
const getAppInfo = createServerFn({
|
|
24
|
+
method: "GET"
|
|
25
|
+
}).handler(createSsrRpc("955327d72ca3168c4751159ca07b8fb0fe0d2381dd0b991f06b941480959fbe8"));
|
|
26
|
+
const appInfoQuery = queryOptions({
|
|
27
|
+
queryKey: ["app-info"],
|
|
28
|
+
queryFn: () => getAppInfo(),
|
|
29
|
+
staleTime: Infinity,
|
|
30
|
+
// Version and path never change at runtime
|
|
31
|
+
refetchOnWindowFocus: false
|
|
32
|
+
});
|
|
23
33
|
const NAV_ITEMS = [
|
|
24
34
|
{
|
|
25
35
|
to: "/sessions",
|
|
@@ -51,6 +61,7 @@ const NAV_ITEMS = [
|
|
|
51
61
|
function AppShell({ children }) {
|
|
52
62
|
const matches = useMatches();
|
|
53
63
|
const currentPath = matches[matches.length - 1]?.pathname ?? "";
|
|
64
|
+
const { data: appInfo } = useQuery(appInfoQuery);
|
|
54
65
|
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-screen", children: [
|
|
55
66
|
/* @__PURE__ */ jsxs("aside", { className: "flex w-56 shrink-0 flex-col border-r border-gray-800 bg-gray-950", children: [
|
|
56
67
|
/* @__PURE__ */ jsx("div", { className: "flex h-14 items-center border-b border-gray-800 px-4", children: /* @__PURE__ */ jsxs(Link, { to: "/sessions", className: "text-sm font-bold text-white", children: [
|
|
@@ -73,33 +84,48 @@ function AppShell({ children }) {
|
|
|
73
84
|
item.to
|
|
74
85
|
);
|
|
75
86
|
}) }),
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
87
|
+
/* @__PURE__ */ jsxs("div", { className: "border-t border-gray-800 p-3", children: [
|
|
88
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
89
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
90
|
+
/* @__PURE__ */ jsx(
|
|
91
|
+
"a",
|
|
92
|
+
{
|
|
93
|
+
href: "https://github.com/dlupiak/claude-session-dashboard",
|
|
94
|
+
target: "_blank",
|
|
95
|
+
rel: "noopener noreferrer",
|
|
96
|
+
className: "text-gray-500 hover:text-gray-300 transition-colors",
|
|
97
|
+
title: "GitHub Repository",
|
|
98
|
+
children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" }) })
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
"a",
|
|
103
|
+
{
|
|
104
|
+
href: "https://www.npmjs.com/package/claude-session-dashboard",
|
|
105
|
+
target: "_blank",
|
|
106
|
+
rel: "noopener noreferrer",
|
|
107
|
+
className: "text-gray-500 hover:text-gray-300 transition-colors",
|
|
108
|
+
title: "npm Package",
|
|
109
|
+
children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M0 0v16h16V0H0zm13 13H8V5H5v8H3V3h10v10z" }) })
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
] }),
|
|
113
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-600", children: "Read-only" })
|
|
100
114
|
] }),
|
|
101
|
-
/* @__PURE__ */
|
|
102
|
-
|
|
115
|
+
appInfo && /* @__PURE__ */ jsxs(
|
|
116
|
+
"p",
|
|
117
|
+
{
|
|
118
|
+
className: "mt-1.5 truncate text-[10px] text-gray-600",
|
|
119
|
+
title: `v${appInfo.version} · ${appInfo.appPath}`,
|
|
120
|
+
children: [
|
|
121
|
+
"v",
|
|
122
|
+
appInfo.version,
|
|
123
|
+
" · ",
|
|
124
|
+
appInfo.appPath
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
] })
|
|
103
129
|
] }),
|
|
104
130
|
/* @__PURE__ */ jsx("main", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-5xl px-6 py-6", children }) })
|
|
105
131
|
] });
|
|
@@ -10,7 +10,7 @@ import { ResponsiveContainer, AreaChart, YAxis, Tooltip, ReferenceLine, Area } f
|
|
|
10
10
|
import { s as settingsQuery } from "./settings.queries-DSQd324O.js";
|
|
11
11
|
import { g as getMergedPricing, c as calculateSessionCost, u as useSessionCost, E as ExportDropdown, d as downloadFile, e as sessionToJSON } from "./useSessionCost-CYs5UOX-.js";
|
|
12
12
|
import { a as activeSessionsQuery } from "./sessions.queries-B5ZBiVJy.js";
|
|
13
|
-
import { b as Route, u as usePrivacy } from "./router-
|
|
13
|
+
import { b as Route, u as usePrivacy } from "./router-5hznwWqr.js";
|
|
14
14
|
import "@tanstack/history";
|
|
15
15
|
import "@tanstack/router-core/ssr/client";
|
|
16
16
|
import "@tanstack/router-core";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/__root.tsx", "children": ["/", "/_dashboard"], "preloads": ["/assets/main-BcKPK-4E.js"], "assets": [] }, "/": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/index.tsx" }, "/_dashboard": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard.tsx", "children": ["/_dashboard/settings", "/_dashboard/stats", "/_dashboard/sessions/$sessionId", "/_dashboard/sessions/"], "assets": [], "preloads": ["/assets/_dashboard-DLFGahko.js", "/assets/createServerFn-BLR4iNR3.js", "/assets/sessions.queries-CHKiZnLm.js"] }, "/_dashboard/settings": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/settings.tsx", "assets": [], "preloads": ["/assets/settings-B2tG1vy0.js", "/assets/settings.types-DHC6rkil.js"] }, "/_dashboard/stats": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/stats.tsx", "assets": [], "preloads": ["/assets/stats-BlA0NIHc.js", "/assets/format-Bsprb3az.js", "/assets/useSessionCost-BikgEmWy.js", "/assets/settings.types-DHC6rkil.js"] }, "/_dashboard/sessions/$sessionId": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/sessions/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-xiPzwrlf.js", "/assets/format-Bsprb3az.js", "/assets/useSessionCost-BikgEmWy.js", "/assets/settings.types-DHC6rkil.js"] }, "/_dashboard/sessions/": { "filePath": "/Users/dmytro.lupiak/GitHub/claude-session-dashboard/apps/web/src/routes/_dashboard/sessions/index.tsx", "assets": [], "preloads": ["/assets/index-D_9sS4oJ.js", "/assets/format-Bsprb3az.js"] } }, "clientEntry": "/assets/main-BcKPK-4E.js" });
|
|
2
|
+
export {
|
|
3
|
+
tsrStartManifest
|
|
4
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { c as createServerFn } from "../server.js";
|
|
5
|
+
import "@tanstack/history";
|
|
6
|
+
import "@tanstack/router-core/ssr/client";
|
|
7
|
+
import "@tanstack/router-core";
|
|
8
|
+
import "node:async_hooks";
|
|
9
|
+
import "@tanstack/router-core/ssr/server";
|
|
10
|
+
import "h3-v2";
|
|
11
|
+
import "tiny-invariant";
|
|
12
|
+
import "seroval";
|
|
13
|
+
import "react/jsx-runtime";
|
|
14
|
+
import "@tanstack/react-router/ssr/server";
|
|
15
|
+
import "@tanstack/react-router";
|
|
16
|
+
const getAppInfo_createServerFn_handler = createServerRpc({
|
|
17
|
+
id: "955327d72ca3168c4751159ca07b8fb0fe0d2381dd0b991f06b941480959fbe8",
|
|
18
|
+
name: "getAppInfo",
|
|
19
|
+
filename: "src/features/settings/app-info.server.ts"
|
|
20
|
+
}, (opts) => getAppInfo.__executeServer(opts));
|
|
21
|
+
const getAppInfo = createServerFn({
|
|
22
|
+
method: "GET"
|
|
23
|
+
}).handler(getAppInfo_createServerFn_handler, async () => {
|
|
24
|
+
let version = "unknown";
|
|
25
|
+
try {
|
|
26
|
+
const pkgPath = path.resolve(process.cwd(), "package.json");
|
|
27
|
+
const raw = fs.readFileSync(pkgPath, "utf-8");
|
|
28
|
+
const pkg = JSON.parse(raw);
|
|
29
|
+
version = pkg.version ?? "unknown";
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
version,
|
|
34
|
+
appPath: process.cwd(),
|
|
35
|
+
nodeEnv: "production"
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
export {
|
|
39
|
+
getAppInfo_createServerFn_handler
|
|
40
|
+
};
|
|
@@ -4,7 +4,7 @@ import { useQuery } from "@tanstack/react-query";
|
|
|
4
4
|
import { Link, useNavigate } from "@tanstack/react-router";
|
|
5
5
|
import { p as paginatedSessionListQuery, a as activeSessionsQuery } from "./sessions.queries-B5ZBiVJy.js";
|
|
6
6
|
import { a as formatDuration, b as formatRelativeTime, d as formatBytes } from "./format-DIZHV7IJ.js";
|
|
7
|
-
import { u as usePrivacy, a as Route } from "./router-
|
|
7
|
+
import { u as usePrivacy, a as Route } from "./router-5hznwWqr.js";
|
|
8
8
|
import "./createSsrRpc-CVg2UDl0.js";
|
|
9
9
|
import "../server.js";
|
|
10
10
|
import "@tanstack/history";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
2
|
-
import {
|
|
2
|
+
import { a as scanAllSessions } from "./session-scanner-CpgOq5m1.js";
|
|
3
3
|
import { c as createServerFn } from "../server.js";
|
|
4
4
|
import "node:fs";
|
|
5
5
|
import "node:path";
|
|
6
|
-
import "./
|
|
6
|
+
import "./session-parser-B0pdBvgT.js";
|
|
7
7
|
import "node:os";
|
|
8
|
-
import "./session-parser-75iTexM0.js";
|
|
9
8
|
import "node:readline";
|
|
10
9
|
import "@tanstack/history";
|
|
11
10
|
import "@tanstack/router-core/ssr/client";
|
|
@@ -136,7 +136,7 @@ function RootDocument({ children }) {
|
|
|
136
136
|
] })
|
|
137
137
|
] });
|
|
138
138
|
}
|
|
139
|
-
const $$splitComponentImporter$4 = () => import("./_dashboard-
|
|
139
|
+
const $$splitComponentImporter$4 = () => import("./_dashboard-smfIqyQC.js");
|
|
140
140
|
const Route$5 = createFileRoute("/_dashboard")({
|
|
141
141
|
component: lazyRouteComponent($$splitComponentImporter$4, "component")
|
|
142
142
|
});
|
|
@@ -145,7 +145,7 @@ const Route$4 = createFileRoute("/")({
|
|
|
145
145
|
throw redirect({ to: "/sessions" });
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
|
-
const $$splitComponentImporter$3 = () => import("./stats-
|
|
148
|
+
const $$splitComponentImporter$3 = () => import("./stats-Ae6umrPI.js");
|
|
149
149
|
const statsSearchSchema = z.object({
|
|
150
150
|
tab: z.enum(["overview", "projects"]).default("overview").catch("overview")
|
|
151
151
|
});
|
|
@@ -153,11 +153,11 @@ const Route$3 = createFileRoute("/_dashboard/stats")({
|
|
|
153
153
|
validateSearch: statsSearchSchema,
|
|
154
154
|
component: lazyRouteComponent($$splitComponentImporter$3, "component")
|
|
155
155
|
});
|
|
156
|
-
const $$splitComponentImporter$2 = () => import("./settings-
|
|
156
|
+
const $$splitComponentImporter$2 = () => import("./settings-D0FgLIR5.js");
|
|
157
157
|
const Route$2 = createFileRoute("/_dashboard/settings")({
|
|
158
158
|
component: lazyRouteComponent($$splitComponentImporter$2, "component")
|
|
159
159
|
});
|
|
160
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
160
|
+
const $$splitComponentImporter$1 = () => import("./index-hFrIPkke.js");
|
|
161
161
|
const sessionsSearchSchema = z.object({
|
|
162
162
|
page: z.number().int().min(1).default(1).catch(1),
|
|
163
163
|
pageSize: z.number().int().min(5).max(100).default(5).catch(5),
|
|
@@ -169,7 +169,7 @@ const Route$1 = createFileRoute("/_dashboard/sessions/")({
|
|
|
169
169
|
validateSearch: sessionsSearchSchema,
|
|
170
170
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
171
171
|
});
|
|
172
|
-
const $$splitComponentImporter = () => import("./_sessionId-
|
|
172
|
+
const $$splitComponentImporter = () => import("./_sessionId-DIUMcrWR.js");
|
|
173
173
|
const searchSchema = z.object({
|
|
174
174
|
project: z.string().optional()
|
|
175
175
|
});
|
package/dist/server/assets/{session-detail.server-BDup9xb0.js → session-detail.server-BIoOQwSE.js}
RENAMED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
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
|
-
import { e as extractProjectName,
|
|
5
|
-
import { a as parseDetail } from "./session-parser-75iTexM0.js";
|
|
4
|
+
import { e as extractProjectName, p as parseDetail, g as getProjectsDir, d as decodeProjectDirName } from "./session-parser-B0pdBvgT.js";
|
|
6
5
|
import { c as createServerFn } from "../server.js";
|
|
7
6
|
import "node:os";
|
|
8
7
|
import "node:readline";
|
|
@@ -1,5 +1,54 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import * as os from "node:os";
|
|
1
3
|
import * as fs from "node:fs";
|
|
2
4
|
import * as readline from "node:readline";
|
|
5
|
+
function resolveClaudeDir() {
|
|
6
|
+
if (process.env.CLAUDE_HOME) {
|
|
7
|
+
return path.resolve(process.env.CLAUDE_HOME);
|
|
8
|
+
}
|
|
9
|
+
return path.join(os.homedir(), ".claude");
|
|
10
|
+
}
|
|
11
|
+
const CLAUDE_DIR = resolveClaudeDir();
|
|
12
|
+
function getProjectsDir() {
|
|
13
|
+
return path.join(CLAUDE_DIR, "projects");
|
|
14
|
+
}
|
|
15
|
+
function getStatsPath() {
|
|
16
|
+
return path.join(CLAUDE_DIR, "stats-cache.json");
|
|
17
|
+
}
|
|
18
|
+
function decodeProjectDirName(dirName) {
|
|
19
|
+
return dirName.replace(/^-/, "/").replace(/-/g, "/");
|
|
20
|
+
}
|
|
21
|
+
function extractProjectName(decodedPath) {
|
|
22
|
+
return path.basename(decodedPath);
|
|
23
|
+
}
|
|
24
|
+
function extractSessionId(filename) {
|
|
25
|
+
return filename.replace(/\.jsonl$/, "");
|
|
26
|
+
}
|
|
27
|
+
const AGENT_FILE_PATTERN = /^agent-(.+)\.jsonl$/;
|
|
28
|
+
async function discoverSubagentFiles(sessionDir) {
|
|
29
|
+
const result = /* @__PURE__ */ new Map();
|
|
30
|
+
const candidateDirs = [
|
|
31
|
+
path.join(sessionDir, "subagents"),
|
|
32
|
+
path.join(sessionDir, "agents")
|
|
33
|
+
];
|
|
34
|
+
for (const dir of candidateDirs) {
|
|
35
|
+
try {
|
|
36
|
+
const entries = await fs.promises.readdir(dir);
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const match = AGENT_FILE_PATTERN.exec(entry);
|
|
39
|
+
if (match) {
|
|
40
|
+
const agentId = match[1];
|
|
41
|
+
if (!result.has(agentId)) {
|
|
42
|
+
result.set(agentId, path.join(dir, entry));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
const AGENT_DISPATCH_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
|
|
3
52
|
const HEAD_LINES = 15;
|
|
4
53
|
async function parseSummary(filePath, sessionId, projectPath, projectName, fileSizeBytes) {
|
|
5
54
|
const headLines = await readHeadLines(filePath, HEAD_LINES);
|
|
@@ -159,12 +208,13 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
159
208
|
input: block.input
|
|
160
209
|
});
|
|
161
210
|
toolFrequency[block.name] = (toolFrequency[block.name] ?? 0) + 1;
|
|
162
|
-
if (block.name
|
|
211
|
+
if (AGENT_DISPATCH_TOOL_NAMES.has(block.name) && block.input) {
|
|
163
212
|
const inp = block.input;
|
|
164
|
-
|
|
213
|
+
const subagentType = inp.subagent_type ?? inp.agent_type;
|
|
214
|
+
if (subagentType) {
|
|
165
215
|
const agent = {
|
|
166
|
-
subagentType: String(
|
|
167
|
-
description: String(inp.description ?? ""),
|
|
216
|
+
subagentType: String(subagentType),
|
|
217
|
+
description: String(inp.description ?? inp.prompt ?? ""),
|
|
168
218
|
timestamp: msg.timestamp ?? "",
|
|
169
219
|
toolUseId: block.id ?? "",
|
|
170
220
|
model: inp.model ? String(inp.model) : void 0
|
|
@@ -275,24 +325,24 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
275
325
|
}
|
|
276
326
|
}
|
|
277
327
|
if (resultText && toolUseId) {
|
|
278
|
-
const agentIdMatch = resultText.match(/agentId:\s*(\w+)/);
|
|
328
|
+
const agentIdMatch = resultText.match(/agentId:\s*([\w-]+)/);
|
|
279
329
|
if (agentIdMatch) {
|
|
280
330
|
agentIdByToolUseId.set(String(toolUseId), agentIdMatch[1]);
|
|
281
331
|
}
|
|
282
332
|
}
|
|
283
333
|
if (msg.toolUseResult && toolUseId) {
|
|
334
|
+
const result = msg.toolUseResult;
|
|
335
|
+
if (result.agentId) {
|
|
336
|
+
agentIdByToolUseId.set(String(toolUseId), result.agentId);
|
|
337
|
+
}
|
|
338
|
+
if (result.retrieval_status && result.task?.task_id) {
|
|
339
|
+
agentIdByToolUseId.set(String(toolUseId), result.task.task_id);
|
|
340
|
+
}
|
|
284
341
|
const agent = agentByToolUseId.get(String(toolUseId));
|
|
285
342
|
if (agent) {
|
|
286
|
-
const result = msg.toolUseResult;
|
|
287
343
|
if (result.totalTokens) agent.totalTokens = result.totalTokens;
|
|
288
344
|
if (result.totalToolUseCount) agent.totalToolUseCount = result.totalToolUseCount;
|
|
289
345
|
if (result.totalDurationMs) agent.durationMs = result.totalDurationMs;
|
|
290
|
-
if (result.isAsync === true && result.agentId) {
|
|
291
|
-
agentIdByToolUseId.set(String(toolUseId), result.agentId);
|
|
292
|
-
}
|
|
293
|
-
if (result.retrieval_status && result.task?.task_id) {
|
|
294
|
-
agentIdByToolUseId.set(String(toolUseId), result.task.task_id);
|
|
295
|
-
}
|
|
296
346
|
}
|
|
297
347
|
}
|
|
298
348
|
}
|
|
@@ -330,50 +380,64 @@ async function parseDetail(filePath, sessionId, projectPath, projectName) {
|
|
|
330
380
|
agent.model = actualModel;
|
|
331
381
|
}
|
|
332
382
|
}
|
|
333
|
-
const
|
|
383
|
+
const sessionDir = filePath.replace(/\.jsonl$/, "");
|
|
384
|
+
const subagentFileMap = await discoverSubagentFiles(sessionDir);
|
|
385
|
+
const matchedAgentIds = /* @__PURE__ */ new Set();
|
|
334
386
|
await Promise.all(
|
|
335
387
|
agents.map(async (agent) => {
|
|
336
388
|
const agentId = agentIdByToolUseId.get(agent.toolUseId);
|
|
337
389
|
if (!agentId) return;
|
|
338
390
|
agent.agentId = agentId;
|
|
339
|
-
|
|
391
|
+
matchedAgentIds.add(agentId);
|
|
392
|
+
const subagentFilePath = subagentFileMap.get(agentId);
|
|
393
|
+
if (!subagentFilePath) return;
|
|
340
394
|
try {
|
|
341
395
|
const detail = await parseSubagentDetail(subagentFilePath);
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
totalTokens
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (detail.model) {
|
|
350
|
-
const modelId = detail.model;
|
|
351
|
-
const existing = tokensByModel[modelId] ?? {
|
|
352
|
-
inputTokens: 0,
|
|
353
|
-
outputTokens: 0,
|
|
354
|
-
cacheReadInputTokens: 0,
|
|
355
|
-
cacheCreationInputTokens: 0
|
|
356
|
-
};
|
|
357
|
-
existing.inputTokens += detail.tokens.inputTokens;
|
|
358
|
-
existing.outputTokens += detail.tokens.outputTokens;
|
|
359
|
-
existing.cacheReadInputTokens += detail.tokens.cacheReadInputTokens;
|
|
360
|
-
existing.cacheCreationInputTokens += detail.tokens.cacheCreationInputTokens;
|
|
361
|
-
tokensByModel[modelId] = existing;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
if (!agent.toolCalls) {
|
|
365
|
-
agent.toolCalls = detail.toolCalls;
|
|
366
|
-
}
|
|
367
|
-
if (!agent.model && detail.model) {
|
|
368
|
-
agent.model = detail.model;
|
|
369
|
-
}
|
|
370
|
-
if (!agent.totalToolUseCount && detail.totalToolUseCount > 0) {
|
|
371
|
-
agent.totalToolUseCount = detail.totalToolUseCount;
|
|
372
|
-
}
|
|
396
|
+
mergeSubagentData(
|
|
397
|
+
agent,
|
|
398
|
+
detail,
|
|
399
|
+
agentProgressTokens.get(agent.toolUseId),
|
|
400
|
+
totalTokens,
|
|
401
|
+
tokensByModel
|
|
402
|
+
);
|
|
373
403
|
} catch {
|
|
374
404
|
}
|
|
375
405
|
})
|
|
376
406
|
);
|
|
407
|
+
for (const [agentId, subagentFilePath] of subagentFileMap) {
|
|
408
|
+
if (matchedAgentIds.has(agentId)) continue;
|
|
409
|
+
try {
|
|
410
|
+
const detail = await parseSubagentDetail(subagentFilePath);
|
|
411
|
+
const hasTokens = detail.tokens.inputTokens > 0 || detail.tokens.outputTokens > 0;
|
|
412
|
+
const hasActivity = hasTokens || detail.skills.length > 0 || detail.totalToolUseCount > 0;
|
|
413
|
+
if (hasTokens) {
|
|
414
|
+
addTokens(totalTokens, detail.tokens);
|
|
415
|
+
if (detail.model) {
|
|
416
|
+
const existing = tokensByModel[detail.model] ?? createEmptyTokenUsage();
|
|
417
|
+
addTokens(existing, detail.tokens);
|
|
418
|
+
tokensByModel[detail.model] = existing;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
for (const [toolName, count] of Object.entries(detail.toolCalls)) {
|
|
422
|
+
toolFrequency[toolName] = (toolFrequency[toolName] ?? 0) + count;
|
|
423
|
+
}
|
|
424
|
+
if (hasActivity) {
|
|
425
|
+
agents.push({
|
|
426
|
+
subagentType: "unknown",
|
|
427
|
+
description: "",
|
|
428
|
+
timestamp: "",
|
|
429
|
+
toolUseId: `orphan-${agentId}`,
|
|
430
|
+
agentId,
|
|
431
|
+
tokens: detail.tokens,
|
|
432
|
+
toolCalls: detail.toolCalls,
|
|
433
|
+
model: detail.model,
|
|
434
|
+
totalToolUseCount: detail.totalToolUseCount,
|
|
435
|
+
skills: detail.skills
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
} catch {
|
|
439
|
+
}
|
|
440
|
+
}
|
|
377
441
|
const modelName = modelsSet.size > 0 ? Array.from(modelsSet)[0] : "unknown";
|
|
378
442
|
const contextWindow = buildContextWindowData(
|
|
379
443
|
contextSnapshots,
|
|
@@ -430,7 +494,7 @@ async function parseSubagentDetail(subagentFilePath) {
|
|
|
430
494
|
skill: skillName,
|
|
431
495
|
args: null,
|
|
432
496
|
timestamp: msg.timestamp ?? "",
|
|
433
|
-
toolUseId: `injected-${skillName}-${
|
|
497
|
+
toolUseId: `injected-${skillName}-${lineCount}`,
|
|
434
498
|
source: "injected"
|
|
435
499
|
});
|
|
436
500
|
}
|
|
@@ -500,6 +564,56 @@ function buildContextWindowData(snapshots, modelName) {
|
|
|
500
564
|
snapshots
|
|
501
565
|
};
|
|
502
566
|
}
|
|
567
|
+
function createEmptyTokenUsage() {
|
|
568
|
+
return {
|
|
569
|
+
inputTokens: 0,
|
|
570
|
+
outputTokens: 0,
|
|
571
|
+
cacheReadInputTokens: 0,
|
|
572
|
+
cacheCreationInputTokens: 0
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
function addTokens(target, source) {
|
|
576
|
+
target.inputTokens += source.inputTokens;
|
|
577
|
+
target.outputTokens += source.outputTokens;
|
|
578
|
+
target.cacheReadInputTokens += source.cacheReadInputTokens;
|
|
579
|
+
target.cacheCreationInputTokens += source.cacheCreationInputTokens;
|
|
580
|
+
}
|
|
581
|
+
function subtractTokens(target, source) {
|
|
582
|
+
target.inputTokens -= source.inputTokens;
|
|
583
|
+
target.outputTokens -= source.outputTokens;
|
|
584
|
+
target.cacheReadInputTokens -= source.cacheReadInputTokens;
|
|
585
|
+
target.cacheCreationInputTokens -= source.cacheCreationInputTokens;
|
|
586
|
+
}
|
|
587
|
+
function mergeSubagentData(agent, detail, progressTokens, totalTokens, tokensByModel) {
|
|
588
|
+
agent.skills = detail.skills;
|
|
589
|
+
if (detail.tokens.inputTokens > 0 || detail.tokens.outputTokens > 0) {
|
|
590
|
+
if (progressTokens) {
|
|
591
|
+
subtractTokens(totalTokens, progressTokens);
|
|
592
|
+
const progressModel = agent.model;
|
|
593
|
+
if (progressModel && tokensByModel[progressModel]) {
|
|
594
|
+
subtractTokens(tokensByModel[progressModel], progressTokens);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
agent.tokens = detail.tokens;
|
|
598
|
+
addTokens(totalTokens, detail.tokens);
|
|
599
|
+
if (detail.model) {
|
|
600
|
+
const existing = tokensByModel[detail.model] ?? createEmptyTokenUsage();
|
|
601
|
+
addTokens(existing, detail.tokens);
|
|
602
|
+
tokensByModel[detail.model] = existing;
|
|
603
|
+
}
|
|
604
|
+
} else if (!agent.tokens && progressTokens) {
|
|
605
|
+
agent.tokens = progressTokens;
|
|
606
|
+
}
|
|
607
|
+
if (!agent.toolCalls && Object.keys(detail.toolCalls).length > 0) {
|
|
608
|
+
agent.toolCalls = detail.toolCalls;
|
|
609
|
+
}
|
|
610
|
+
if (!agent.model && detail.model) {
|
|
611
|
+
agent.model = detail.model;
|
|
612
|
+
}
|
|
613
|
+
if (!agent.totalToolUseCount && detail.totalToolUseCount > 0) {
|
|
614
|
+
agent.totalToolUseCount = detail.totalToolUseCount;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
503
617
|
async function readHeadLines(filePath, count) {
|
|
504
618
|
const lines = [];
|
|
505
619
|
const stream = fs.createReadStream(filePath, { encoding: "utf-8" });
|
|
@@ -509,6 +623,7 @@ async function readHeadLines(filePath, count) {
|
|
|
509
623
|
if (lines.length >= count) break;
|
|
510
624
|
}
|
|
511
625
|
stream.destroy();
|
|
626
|
+
rl.close();
|
|
512
627
|
return lines;
|
|
513
628
|
}
|
|
514
629
|
async function readTailLines(filePath, count) {
|
|
@@ -549,6 +664,11 @@ function extractTextContent(msg) {
|
|
|
549
664
|
return texts.length > 0 ? texts.join("\n").slice(0, 500) : void 0;
|
|
550
665
|
}
|
|
551
666
|
export {
|
|
552
|
-
|
|
553
|
-
|
|
667
|
+
getStatsPath as a,
|
|
668
|
+
extractSessionId as b,
|
|
669
|
+
parseSummary as c,
|
|
670
|
+
decodeProjectDirName as d,
|
|
671
|
+
extractProjectName as e,
|
|
672
|
+
getProjectsDir as g,
|
|
673
|
+
parseDetail as p
|
|
554
674
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import { p as parseSummary } from "./session-parser-75iTexM0.js";
|
|
3
|
+
import { g as getProjectsDir, d as decodeProjectDirName, e as extractProjectName, b as extractSessionId, c as parseSummary } from "./session-parser-B0pdBvgT.js";
|
|
5
4
|
async function scanProjects() {
|
|
6
5
|
const projectsDir = getProjectsDir();
|
|
7
6
|
let entries;
|
|
@@ -85,7 +84,7 @@ async function scanSessionsInternal() {
|
|
|
85
84
|
}
|
|
86
85
|
async function scanAllSessions() {
|
|
87
86
|
const results = await scanSessionsInternal();
|
|
88
|
-
return results.map(({ filePath:
|
|
87
|
+
return results.map(({ filePath: _filePath, ...summary }) => summary);
|
|
89
88
|
}
|
|
90
89
|
async function scanAllSessionsWithPaths() {
|
|
91
90
|
return scanSessionsInternal();
|
|
@@ -95,7 +94,7 @@ async function getActiveSessions() {
|
|
|
95
94
|
return all.filter((s) => s.isActive);
|
|
96
95
|
}
|
|
97
96
|
export {
|
|
97
|
+
scanAllSessions as a,
|
|
98
98
|
getActiveSessions as g,
|
|
99
|
-
|
|
100
|
-
scanAllSessionsWithPaths as w
|
|
99
|
+
scanAllSessionsWithPaths as s
|
|
101
100
|
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { c as createServerRpc } from "./createServerRpc-Bd3B-Ah9.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { a as scanAllSessions, g as getActiveSessions } from "./session-scanner-CpgOq5m1.js";
|
|
4
4
|
import { c as createServerFn } from "../server.js";
|
|
5
5
|
import "node:fs";
|
|
6
6
|
import "node:path";
|
|
7
|
-
import "./
|
|
7
|
+
import "./session-parser-B0pdBvgT.js";
|
|
8
8
|
import "node:os";
|
|
9
|
-
import "./session-parser-75iTexM0.js";
|
|
10
9
|
import "node:readline";
|
|
11
10
|
import "@tanstack/history";
|
|
12
11
|
import "@tanstack/router-core/ssr/client";
|
|
@@ -3,7 +3,7 @@ import { useState } from "react";
|
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
4
|
import { s as settingsQuery, u as useSettingsMutation } from "./settings.queries-DSQd324O.js";
|
|
5
5
|
import { a as SUBSCRIPTION_TIERS, b as DEFAULT_PRICING, D as DEFAULT_SETTINGS } from "./settings.types-DntadCHo.js";
|
|
6
|
-
import { u as usePrivacy } from "./router-
|
|
6
|
+
import { u as usePrivacy } from "./router-5hznwWqr.js";
|
|
7
7
|
import "./createSsrRpc-CVg2UDl0.js";
|
|
8
8
|
import "../server.js";
|
|
9
9
|
import "@tanstack/history";
|
|
@@ -8,7 +8,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-
|
|
11
|
+
import { u as usePrivacy, R as Route } from "./router-5hznwWqr.js";
|
|
12
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-CYs5UOX-.js";
|
|
13
13
|
import "@tanstack/history";
|
|
14
14
|
import "@tanstack/router-core/ssr/client";
|