usage-board 2.1.2 → 3.0.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/index.mjs +10 -4
- package/dist/public/_nuxt/{chy2QJx0.js → 7Dy4NLP8.js} +32 -32
- package/dist/public/_nuxt/B-VlGWDb.js +21 -0
- package/dist/public/_nuxt/{BeEwECnn.js → Be3rizqy.js} +1 -1
- package/dist/public/_nuxt/{15CW3D68.js → C0azgqnZ.js} +1 -1
- package/dist/public/_nuxt/{B6G-s9D-.js → CMNdiQCa.js} +1 -1
- package/dist/public/_nuxt/CPuXQJE_.js +1 -0
- package/dist/public/_nuxt/DenksPSi.js +119 -0
- package/dist/public/_nuxt/Dkya5WaL.js +9 -0
- package/dist/public/_nuxt/HN9OZyaQ.js +25 -0
- package/dist/public/_nuxt/{Bu4SpN_a.js → JtK-nXxy.js} +1 -1
- package/dist/public/_nuxt/builds/latest.json +1 -1
- package/dist/public/_nuxt/builds/meta/37e8bb21-a086-45bf-93dc-47eeeada7299.json +1 -0
- package/dist/public/_nuxt/{BeygfM9p.js → y3weNNd-.js} +2 -2
- package/dist/server/chunks/_/error-500.mjs +8 -4
- package/dist/server/chunks/_/shared.cjs.prod.mjs +1 -1
- package/dist/server/chunks/build/client.precomputed.mjs +1 -1
- package/dist/server/chunks/nitro/nitro.mjs +8218 -2844
- package/dist/server/chunks/routes/api/payload.json.mjs +11 -626
- package/dist/server/chunks/routes/api/projects/_project/modules.get.mjs +36 -0
- package/dist/server/chunks/routes/api/projects/catalog.get.mjs +26 -0
- package/dist/server/chunks/routes/renderer.mjs +9 -5
- package/dist/server/chunks/routes/ws.mjs +29 -971
- package/dist/server/index.mjs +9 -5
- package/package.json +7 -6
- package/dist/public/_nuxt/C6ydMk2z.js +0 -25
- package/dist/public/_nuxt/Dn8cXZx3.js +0 -9
- package/dist/public/_nuxt/DysUC14A.js +0 -119
- package/dist/public/_nuxt/KLhV325n.js +0 -1
- package/dist/public/_nuxt/builds/meta/ac4b25d6-d6eb-44bb-8c5b-b1d6f651c196.json +0 -1
- package/dist/public/_nuxt/pmnAmEjb.js +0 -21
- package/dist/server/chunks/_/index.min.mjs +0 -348
|
@@ -1,642 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { basename, join } from 'node:path';
|
|
4
|
-
import { c as createLiteLLMPricingResolver, a as calculateUsageCostUSD, Z as Ze, C as CLAUDE_MODEL_ALIASES, b as CLAUDE_FALLBACK_MODEL, d as CODEX_FALLBACK_MODEL, e as CODEX_MODEL_ALIASES, G as GEMINI_FALLBACK_MODEL, f as GEMINI_MODEL_ALIASES, g as GEMINI_FALLBACK_PRICING_TABLE } from '../../_/index.min.mjs';
|
|
5
|
-
import 'node:os';
|
|
6
|
-
import 'node:fs/promises';
|
|
1
|
+
import { d as defineEventHandler, r as resolveConfig, g as getUsageDataRuntime, u as useRuntimeConfig } from '../../nitro/nitro.mjs';
|
|
7
2
|
import 'node:http';
|
|
8
3
|
import 'node:https';
|
|
9
4
|
import 'node:events';
|
|
10
5
|
import 'node:buffer';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'node:path';
|
|
11
8
|
import 'node:crypto';
|
|
9
|
+
import 'node:sqlite';
|
|
12
10
|
import 'node:url';
|
|
13
|
-
import 'node:util';
|
|
14
|
-
import 'node:process';
|
|
15
|
-
import 'node:tty';
|
|
16
11
|
import 'fs';
|
|
12
|
+
import 'node:fs/promises';
|
|
17
13
|
import 'node:stream';
|
|
18
14
|
import 'node:string_decoder';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
fallbackModel: CLAUDE_FALLBACK_MODEL,
|
|
24
|
-
getLookupCandidates: getClaudeLookupCandidates
|
|
25
|
-
});
|
|
26
|
-
const entries = await loadClaudeUsageEntries(config, resolvePricing);
|
|
27
|
-
const sessionSummaries = buildClaudeSessionSummaries(entries).sort((a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity));
|
|
28
|
-
const sessionOptions = {
|
|
29
|
-
getCachedInputTokens: (session) => session.cacheCreationTokens + session.cacheReadTokens,
|
|
30
|
-
getReasoningOutputTokens: () => 0
|
|
31
|
-
};
|
|
32
|
-
const events = entries.map(toClaudeAggregateEvent);
|
|
33
|
-
const aggregateOptions = {
|
|
34
|
-
includeModel: (event) => event.model !== "<synthetic>"
|
|
35
|
-
};
|
|
36
|
-
return buildLoadUsageResult(events, sessionSummaries, {
|
|
37
|
-
aggregateOptions,
|
|
38
|
-
sessionOptions
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
async function loadClaudeUsageEntries(config, resolvePricing) {
|
|
42
|
-
var _a, _b, _c, _d;
|
|
43
|
-
const claudePaths = getConfiguredClaudePaths(config);
|
|
44
|
-
const files = await globClaudeUsageFiles(claudePaths);
|
|
45
|
-
if (files.length === 0) {
|
|
46
|
-
return [];
|
|
47
|
-
}
|
|
48
|
-
const sortedFiles = sortFilesByTimestamp(files);
|
|
49
|
-
const processedHashes = /* @__PURE__ */ new Set();
|
|
50
|
-
const entries = [];
|
|
51
|
-
for (const filePath of sortedFiles) {
|
|
52
|
-
const projectPath = extractClaudeProjectFromPath(filePath);
|
|
53
|
-
const fallbackSessionId = basename(filePath, ".jsonl");
|
|
54
|
-
const lines = parseJsonlFile(filePath);
|
|
55
|
-
for (const line of lines) {
|
|
56
|
-
if (!isClaudeUsageRecord(line)) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const uniqueHash = createUniqueHash(line);
|
|
60
|
-
if (uniqueHash != null && processedHashes.has(uniqueHash)) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (uniqueHash != null) {
|
|
64
|
-
processedHashes.add(uniqueHash);
|
|
65
|
-
}
|
|
66
|
-
const usage = line.message.usage;
|
|
67
|
-
const rawModel = (_a = line.message.model) == null ? void 0 : _a.trim();
|
|
68
|
-
const model = (_b = getDisplayModelName(line)) != null ? _b : "unknown";
|
|
69
|
-
const cacheCreationTokens = normalizeNumber(usage.cache_creation_input_tokens);
|
|
70
|
-
const cacheReadTokens = normalizeNumber(usage.cache_read_input_tokens);
|
|
71
|
-
const inputTokens = normalizeNumber(usage.input_tokens);
|
|
72
|
-
const outputTokens = normalizeNumber(usage.output_tokens);
|
|
73
|
-
const costUSD = (_c = line.costUSD) != null ? _c : rawModel ? calculateUsageCostUSD({
|
|
74
|
-
cacheCreationTokens,
|
|
75
|
-
cachedInputTokens: cacheReadTokens,
|
|
76
|
-
inputTokens,
|
|
77
|
-
outputTokens
|
|
78
|
-
}, resolvePricing(rawModel), {
|
|
79
|
-
speed: usage.speed
|
|
80
|
-
}) : 0;
|
|
81
|
-
entries.push({
|
|
82
|
-
cacheCreationTokens,
|
|
83
|
-
cacheReadTokens,
|
|
84
|
-
costUSD,
|
|
85
|
-
cwd: line.cwd,
|
|
86
|
-
inputTokens,
|
|
87
|
-
model,
|
|
88
|
-
outputTokens,
|
|
89
|
-
projectPath,
|
|
90
|
-
rawModel,
|
|
91
|
-
sessionId: ((_d = line.sessionId) == null ? void 0 : _d.trim()) || fallbackSessionId,
|
|
92
|
-
timestamp: new Date(line.timestamp).toISOString()
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return entries;
|
|
97
|
-
}
|
|
98
|
-
function getConfiguredClaudePaths(config) {
|
|
99
|
-
var _a;
|
|
100
|
-
return ((_a = config.claudeCodePaths) == null ? void 0 : _a.length) ? config.claudeCodePaths : [config.claudeCodePath];
|
|
101
|
-
}
|
|
102
|
-
async function globClaudeUsageFiles(claudePaths) {
|
|
103
|
-
const fileGroups = await Promise.all(claudePaths.map(async (claudePath) => {
|
|
104
|
-
const projectsDir = `${claudePath}/projects`;
|
|
105
|
-
if (!existsSync(projectsDir)) {
|
|
106
|
-
return [];
|
|
107
|
-
}
|
|
108
|
-
return Ze(`${claudePath}/projects/**/*.jsonl`, {
|
|
109
|
-
absolute: true
|
|
110
|
-
}).catch(() => []);
|
|
111
|
-
}));
|
|
112
|
-
return fileGroups.flat();
|
|
113
|
-
}
|
|
114
|
-
function sortFilesByTimestamp(files) {
|
|
115
|
-
return files.map((file) => ({
|
|
116
|
-
file,
|
|
117
|
-
timestamp: getEarliestTimestamp(file)
|
|
118
|
-
})).sort((a, b) => {
|
|
119
|
-
if (a.timestamp == null && b.timestamp == null) {
|
|
120
|
-
return 0;
|
|
121
|
-
}
|
|
122
|
-
if (a.timestamp == null) {
|
|
123
|
-
return 1;
|
|
124
|
-
}
|
|
125
|
-
if (b.timestamp == null) {
|
|
126
|
-
return -1;
|
|
127
|
-
}
|
|
128
|
-
return a.timestamp.getTime() - b.timestamp.getTime();
|
|
129
|
-
}).map((item) => item.file);
|
|
130
|
-
}
|
|
131
|
-
function getEarliestTimestamp(filePath) {
|
|
132
|
-
for (const line of parseJsonlFile(filePath)) {
|
|
133
|
-
if (!line || typeof line !== "object") {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
const timestamp = line.timestamp;
|
|
137
|
-
if (typeof timestamp !== "string") {
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
const date = new Date(timestamp);
|
|
141
|
-
if (!Number.isNaN(date.getTime())) {
|
|
142
|
-
return date;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
function isClaudeUsageRecord(value) {
|
|
148
|
-
if (!value || typeof value !== "object") {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
const record = value;
|
|
152
|
-
const message = record.message;
|
|
153
|
-
if (typeof record.timestamp !== "string" || !message || typeof message !== "object") {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
const usage = message.usage;
|
|
157
|
-
if (!usage || typeof usage !== "object") {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
const usageRecord = usage;
|
|
161
|
-
return typeof usageRecord.input_tokens === "number" && typeof usageRecord.output_tokens === "number" && Number.isFinite(Date.parse(record.timestamp));
|
|
162
|
-
}
|
|
163
|
-
function createUniqueHash(data) {
|
|
164
|
-
const messageId = data.message.id;
|
|
165
|
-
const requestId = data.requestId;
|
|
166
|
-
if (messageId == null || requestId == null) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
return `${messageId}:${requestId}`;
|
|
170
|
-
}
|
|
171
|
-
function getDisplayModelName(data) {
|
|
172
|
-
var _a;
|
|
173
|
-
const model = (_a = data.message.model) == null ? void 0 : _a.trim();
|
|
174
|
-
if (!model) {
|
|
175
|
-
return void 0;
|
|
176
|
-
}
|
|
177
|
-
return data.message.usage.speed === "fast" ? `${model}-fast` : model;
|
|
178
|
-
}
|
|
179
|
-
function buildClaudeSessionSummaries(entries) {
|
|
180
|
-
var _a;
|
|
181
|
-
const groups = /* @__PURE__ */ new Map();
|
|
182
|
-
for (const entry of entries) {
|
|
183
|
-
const key = `${entry.projectPath}/${entry.sessionId}`;
|
|
184
|
-
const group = (_a = groups.get(key)) != null ? _a : [];
|
|
185
|
-
group.push(entry);
|
|
186
|
-
groups.set(key, group);
|
|
187
|
-
}
|
|
188
|
-
return Array.from(groups.values()).map((sessionEntries) => {
|
|
189
|
-
var _a2, _b, _c;
|
|
190
|
-
const sortedEntries = [...sessionEntries].sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
191
|
-
const firstEntry = sortedEntries[0];
|
|
192
|
-
const lastEntry = sortedEntries.at(-1);
|
|
193
|
-
const usageByModel = /* @__PURE__ */ new Map();
|
|
194
|
-
let inputTokens = 0;
|
|
195
|
-
let cacheCreationTokens = 0;
|
|
196
|
-
let cacheReadTokens = 0;
|
|
197
|
-
let outputTokens = 0;
|
|
198
|
-
let costUSD = 0;
|
|
199
|
-
for (const entry of sortedEntries) {
|
|
200
|
-
inputTokens += entry.inputTokens;
|
|
201
|
-
cacheCreationTokens += entry.cacheCreationTokens;
|
|
202
|
-
cacheReadTokens += entry.cacheReadTokens;
|
|
203
|
-
outputTokens += entry.outputTokens;
|
|
204
|
-
costUSD += entry.costUSD;
|
|
205
|
-
const modelUsage = (_a2 = usageByModel.get(entry.model)) != null ? _a2 : {
|
|
206
|
-
cacheCreationTokens: 0,
|
|
207
|
-
cacheReadTokens: 0,
|
|
208
|
-
cachedInputTokens: 0,
|
|
209
|
-
costUSD: 0,
|
|
210
|
-
inputTokens: 0,
|
|
211
|
-
outputTokens: 0,
|
|
212
|
-
reasoningOutputTokens: 0,
|
|
213
|
-
totalTokens: 0
|
|
214
|
-
};
|
|
215
|
-
modelUsage.cacheCreationTokens += entry.cacheCreationTokens;
|
|
216
|
-
modelUsage.cacheReadTokens += entry.cacheReadTokens;
|
|
217
|
-
modelUsage.cachedInputTokens += entry.cacheCreationTokens + entry.cacheReadTokens;
|
|
218
|
-
modelUsage.costUSD += entry.costUSD;
|
|
219
|
-
modelUsage.inputTokens += entry.inputTokens;
|
|
220
|
-
modelUsage.outputTokens += entry.outputTokens;
|
|
221
|
-
modelUsage.totalTokens += getTotalTokens(entry);
|
|
222
|
-
usageByModel.set(entry.model, modelUsage);
|
|
223
|
-
}
|
|
224
|
-
const models = Array.from(usageByModel.keys()).filter((model) => model !== "<synthetic>").sort((a, b) => a.localeCompare(b));
|
|
225
|
-
const topModel = (_c = (_b = Array.from(usageByModel.entries()).filter(([model]) => model !== "<synthetic>").sort((a, b) => b[1].totalTokens - a[1].totalTokens || a[0].localeCompare(b[0]))[0]) == null ? void 0 : _b[0]) != null ? _c : "unknown";
|
|
226
|
-
const project = getProjectName(firstEntry.cwd, "") || decodeClaudeProjectPath(firstEntry.projectPath);
|
|
227
|
-
return {
|
|
228
|
-
cacheCreationTokens,
|
|
229
|
-
cacheReadTokens,
|
|
230
|
-
costUSD: roundCurrency(costUSD),
|
|
231
|
-
durationMinutes: getDurationMinutes(firstEntry.timestamp, lastEntry.timestamp),
|
|
232
|
-
inputTokens,
|
|
233
|
-
lastActivity: lastEntry.timestamp,
|
|
234
|
-
models,
|
|
235
|
-
outputTokens,
|
|
236
|
-
project,
|
|
237
|
-
repository: `local/${project}`,
|
|
238
|
-
sessionId: firstEntry.sessionId,
|
|
239
|
-
startedAt: firstEntry.timestamp,
|
|
240
|
-
threadName: `Session for ${project}`,
|
|
241
|
-
tokenTotal: getTotalTokens({
|
|
242
|
-
cacheCreationTokens,
|
|
243
|
-
cacheReadTokens,
|
|
244
|
-
inputTokens,
|
|
245
|
-
outputTokens
|
|
246
|
-
}),
|
|
247
|
-
topModel
|
|
248
|
-
};
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
function toClaudeAggregateEvent(entry) {
|
|
252
|
-
const project = getProjectName(entry.cwd, "") || decodeClaudeProjectPath(entry.projectPath);
|
|
253
|
-
return {
|
|
254
|
-
cacheCreationTokens: entry.cacheCreationTokens,
|
|
255
|
-
cacheReadTokens: entry.cacheReadTokens,
|
|
256
|
-
cachedInputTokens: entry.cacheCreationTokens + entry.cacheReadTokens,
|
|
257
|
-
costUSD: entry.costUSD,
|
|
258
|
-
inputTokens: entry.inputTokens,
|
|
259
|
-
isFallbackModel: entry.model === "unknown",
|
|
260
|
-
model: entry.model,
|
|
261
|
-
outputTokens: entry.outputTokens,
|
|
262
|
-
project,
|
|
263
|
-
reasoningOutputTokens: 0,
|
|
264
|
-
repository: `local/${project}`,
|
|
265
|
-
sessionId: entry.sessionId,
|
|
266
|
-
timestamp: entry.timestamp,
|
|
267
|
-
totalTokens: getTotalTokens(entry)
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
function getTotalTokens(tokens) {
|
|
271
|
-
return tokens.inputTokens + tokens.outputTokens + tokens.cacheCreationTokens + tokens.cacheReadTokens;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
async function loadCodexUsage(config) {
|
|
275
|
-
const resolvePricing = await createLiteLLMPricingResolver({
|
|
276
|
-
aliases: CODEX_MODEL_ALIASES,
|
|
277
|
-
fallbackModel: CODEX_FALLBACK_MODEL,
|
|
278
|
-
isZeroCostModel: isOpenRouterFreeModel
|
|
279
|
-
});
|
|
280
|
-
const sessionFiles = await loadSessionFiles(config);
|
|
281
|
-
const tokenEvents = sessionFiles.flatMap((item) => item.events).sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
282
|
-
const sessionSummaries = buildSessionSummaries$1(sessionFiles, resolvePricing).sort((a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity));
|
|
283
|
-
const getEventCostUSD = (event) => calculateUsageCost(event.model, event, resolvePricing);
|
|
284
|
-
const aggregateOptions = { getCostUSD: getEventCostUSD };
|
|
285
|
-
return buildLoadUsageResult(tokenEvents, sessionSummaries, { aggregateOptions });
|
|
286
|
-
}
|
|
287
|
-
async function loadSessionFiles(config) {
|
|
288
|
-
const sessionsDir = join(config.codexPath, "sessions");
|
|
289
|
-
if (!existsSync(sessionsDir)) {
|
|
290
|
-
return [];
|
|
291
|
-
}
|
|
292
|
-
const sessionIndex = loadSessionIndex(config.codexPath);
|
|
293
|
-
const files = await Ze(`**/*.jsonl`, {
|
|
294
|
-
cwd: sessionsDir,
|
|
295
|
-
absolute: true
|
|
296
|
-
});
|
|
297
|
-
return files.map((filePath) => loadSessionFile(filePath, sessionIndex)).filter((item) => item !== null);
|
|
298
|
-
}
|
|
299
|
-
function loadSessionIndex(codexPath) {
|
|
300
|
-
const indexPath = join(codexPath, "session_index.jsonl");
|
|
301
|
-
const threadNames = /* @__PURE__ */ new Map();
|
|
302
|
-
if (!existsSync(indexPath)) {
|
|
303
|
-
return threadNames;
|
|
304
|
-
}
|
|
305
|
-
const lines = parseJsonlFile(indexPath);
|
|
306
|
-
for (const line of lines) {
|
|
307
|
-
const id = typeof line.id === "string" ? line.id.trim() : "";
|
|
308
|
-
const threadName = typeof line.thread_name === "string" ? line.thread_name.trim() : "";
|
|
309
|
-
if (id && threadName) {
|
|
310
|
-
threadNames.set(id, threadName);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return threadNames;
|
|
314
|
-
}
|
|
315
|
-
function loadSessionFile(filePath, sessionIndex) {
|
|
316
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
317
|
-
const lines = parseJsonlFile(filePath);
|
|
318
|
-
if (lines.length === 0) {
|
|
319
|
-
return null;
|
|
320
|
-
}
|
|
321
|
-
const sessionMeta = (_a = lines.find((line) => line.type === "session_meta")) == null ? void 0 : _a.payload;
|
|
322
|
-
const startedAt = (_c = toIsoString(sessionMeta == null ? void 0 : sessionMeta.timestamp)) != null ? _c : toIsoString((_b = lines[0]) == null ? void 0 : _b.timestamp);
|
|
323
|
-
if (!startedAt) {
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
const lastTimestamp = [...lines].reverse().map((line) => toIsoString(line.timestamp)).find(Boolean);
|
|
327
|
-
const userMessage = (_e = (_d = lines.find((line) => {
|
|
328
|
-
var _a2;
|
|
329
|
-
return line.type === "event_msg" && ((_a2 = line.payload) == null ? void 0 : _a2.type) === "user_message";
|
|
330
|
-
})) == null ? void 0 : _d.payload) == null ? void 0 : _e.message;
|
|
331
|
-
const sessionId = getSessionId(filePath, typeof (sessionMeta == null ? void 0 : sessionMeta.id) === "string" ? sessionMeta.id : void 0);
|
|
332
|
-
const project = getProjectName(typeof (sessionMeta == null ? void 0 : sessionMeta.cwd) === "string" ? sessionMeta.cwd : void 0);
|
|
333
|
-
const repository = normalizeRepositoryUrl((_f = sessionMeta == null ? void 0 : sessionMeta.git) == null ? void 0 : _f.repository_url) || `local/${project}`;
|
|
334
|
-
const meta = {
|
|
335
|
-
sessionId,
|
|
336
|
-
threadName: (_g = sessionIndex.get(sessionId)) != null ? _g : getThreadName(typeof userMessage === "string" ? userMessage : "", project),
|
|
337
|
-
project,
|
|
338
|
-
repository,
|
|
339
|
-
startedAt,
|
|
340
|
-
durationMinutes: getDurationMinutes(startedAt, lastTimestamp)
|
|
341
|
-
};
|
|
342
|
-
const events = extractTokenUsageEvents$1(lines, meta);
|
|
343
|
-
if (events.length === 0) {
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
return {
|
|
347
|
-
events,
|
|
348
|
-
meta
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
function getSessionId(filePath, sessionMetaId) {
|
|
352
|
-
const normalizedSessionMetaId = sessionMetaId == null ? void 0 : sessionMetaId.trim();
|
|
353
|
-
return normalizedSessionMetaId || basename(filePath, ".jsonl");
|
|
354
|
-
}
|
|
355
|
-
function extractTokenUsageEvents$1(lines, meta) {
|
|
356
|
-
var _a, _b, _c;
|
|
357
|
-
const events = [];
|
|
358
|
-
let previousTotals = null;
|
|
359
|
-
let currentModel;
|
|
360
|
-
let currentModelIsFallback = false;
|
|
361
|
-
for (const line of lines) {
|
|
362
|
-
if (line.type === "turn_context") {
|
|
363
|
-
const contextModel = extractModelName(line.payload);
|
|
364
|
-
if (contextModel) {
|
|
365
|
-
currentModel = contextModel;
|
|
366
|
-
currentModelIsFallback = false;
|
|
367
|
-
}
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
if (line.type !== "event_msg" || ((_a = line.payload) == null ? void 0 : _a.type) !== "token_count") {
|
|
371
|
-
continue;
|
|
372
|
-
}
|
|
373
|
-
const timestamp = toIsoString(line.timestamp);
|
|
374
|
-
if (!timestamp) {
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
const info = (_b = line.payload) == null ? void 0 : _b.info;
|
|
378
|
-
const lastUsage = normalizeRawUsage(info == null ? void 0 : info.last_token_usage);
|
|
379
|
-
const totalUsage = normalizeRawUsage(info == null ? void 0 : info.total_token_usage);
|
|
380
|
-
const rawUsage = lastUsage != null ? lastUsage : totalUsage ? subtractRawUsage(totalUsage, previousTotals) : null;
|
|
381
|
-
if (totalUsage) {
|
|
382
|
-
previousTotals = totalUsage;
|
|
383
|
-
}
|
|
384
|
-
if (!rawUsage) {
|
|
385
|
-
continue;
|
|
386
|
-
}
|
|
387
|
-
const delta = convertCodexRawUsage(rawUsage);
|
|
388
|
-
if (isZeroUsage(delta)) {
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
const extractedModel = extractModelName({
|
|
392
|
-
...(_c = line.payload) != null ? _c : {},
|
|
393
|
-
info: info != null ? info : void 0
|
|
394
|
-
});
|
|
395
|
-
if (extractedModel) {
|
|
396
|
-
currentModel = extractedModel;
|
|
397
|
-
currentModelIsFallback = false;
|
|
398
|
-
}
|
|
399
|
-
let model = extractedModel != null ? extractedModel : currentModel;
|
|
400
|
-
let isFallbackModel = false;
|
|
401
|
-
if (!model) {
|
|
402
|
-
model = CODEX_FALLBACK_MODEL;
|
|
403
|
-
isFallbackModel = true;
|
|
404
|
-
currentModel = model;
|
|
405
|
-
currentModelIsFallback = true;
|
|
406
|
-
} else if (!extractedModel && currentModelIsFallback) {
|
|
407
|
-
isFallbackModel = true;
|
|
408
|
-
}
|
|
409
|
-
events.push({
|
|
410
|
-
...delta,
|
|
411
|
-
isFallbackModel,
|
|
412
|
-
model,
|
|
413
|
-
project: meta.project,
|
|
414
|
-
repository: meta.repository,
|
|
415
|
-
sessionId: meta.sessionId,
|
|
416
|
-
timestamp
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
return events;
|
|
420
|
-
}
|
|
421
|
-
function buildSessionSummaries$1(sessionFiles, resolvePricing) {
|
|
422
|
-
var _a, _b, _c;
|
|
423
|
-
const summaries = [];
|
|
424
|
-
for (const sessionFile of sessionFiles) {
|
|
425
|
-
const usageByModel = /* @__PURE__ */ new Map();
|
|
426
|
-
let inputTokens = 0;
|
|
427
|
-
let cachedInputTokens = 0;
|
|
428
|
-
let outputTokens = 0;
|
|
429
|
-
let reasoningOutputTokens = 0;
|
|
430
|
-
let totalTokens = 0;
|
|
431
|
-
let lastActivity = sessionFile.meta.startedAt;
|
|
432
|
-
for (const event of sessionFile.events) {
|
|
433
|
-
inputTokens += event.inputTokens;
|
|
434
|
-
cachedInputTokens += event.cachedInputTokens;
|
|
435
|
-
outputTokens += event.outputTokens;
|
|
436
|
-
reasoningOutputTokens += event.reasoningOutputTokens;
|
|
437
|
-
totalTokens += event.totalTokens;
|
|
438
|
-
if (event.timestamp > lastActivity) {
|
|
439
|
-
lastActivity = event.timestamp;
|
|
440
|
-
}
|
|
441
|
-
const modelUsage = (_a = usageByModel.get(event.model)) != null ? _a : createEmptyUsage();
|
|
442
|
-
addUsage(modelUsage, event);
|
|
443
|
-
usageByModel.set(event.model, modelUsage);
|
|
444
|
-
}
|
|
445
|
-
let costUSD = 0;
|
|
446
|
-
for (const [model, usage] of usageByModel) {
|
|
447
|
-
costUSD += calculateUsageCost(model, usage, resolvePricing);
|
|
448
|
-
}
|
|
449
|
-
const models = Array.from(usageByModel.keys()).sort((a, b) => a.localeCompare(b));
|
|
450
|
-
const topModel = (_c = (_b = Array.from(usageByModel.entries()).sort((a, b) => b[1].totalTokens - a[1].totalTokens || a[0].localeCompare(b[0]))[0]) == null ? void 0 : _b[0]) != null ? _c : CODEX_FALLBACK_MODEL;
|
|
451
|
-
summaries.push({
|
|
452
|
-
sessionId: sessionFile.meta.sessionId,
|
|
453
|
-
threadName: sessionFile.meta.threadName,
|
|
454
|
-
project: sessionFile.meta.project,
|
|
455
|
-
repository: sessionFile.meta.repository,
|
|
456
|
-
startedAt: sessionFile.meta.startedAt,
|
|
457
|
-
durationMinutes: sessionFile.meta.durationMinutes,
|
|
458
|
-
inputTokens,
|
|
459
|
-
cachedInputTokens,
|
|
460
|
-
outputTokens,
|
|
461
|
-
reasoningOutputTokens,
|
|
462
|
-
tokenTotal: totalTokens,
|
|
463
|
-
costUSD: roundCurrency(costUSD),
|
|
464
|
-
lastActivity,
|
|
465
|
-
models,
|
|
466
|
-
topModel
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
return summaries;
|
|
470
|
-
}
|
|
471
|
-
function calculateUsageCost(model, usage, resolvePricing) {
|
|
472
|
-
return calculateUsageCostUSD(usage, resolvePricing(model));
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
async function loadGeminiUsage(config) {
|
|
476
|
-
const resolvePricing = await createLiteLLMPricingResolver({
|
|
477
|
-
aliases: GEMINI_MODEL_ALIASES,
|
|
478
|
-
fallbackModel: GEMINI_FALLBACK_MODEL,
|
|
479
|
-
fallbackPricingTable: GEMINI_FALLBACK_PRICING_TABLE,
|
|
480
|
-
getLookupCandidates: getGeminiLookupCandidates
|
|
481
|
-
});
|
|
482
|
-
const sessionFiles = await loadGeminiSessionFiles(config, resolvePricing);
|
|
483
|
-
const events = sessionFiles.flatMap((item) => item.events).sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
|
|
484
|
-
const sessionSummaries = buildSessionSummaries(sessionFiles).sort((a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity));
|
|
485
|
-
return buildLoadUsageResult(events, sessionSummaries);
|
|
486
|
-
}
|
|
487
|
-
async function loadGeminiSessionFiles(config, resolvePricing) {
|
|
488
|
-
const tmpDir = `${config.geminiPath}/tmp`;
|
|
489
|
-
if (!existsSync(tmpDir)) {
|
|
490
|
-
return [];
|
|
491
|
-
}
|
|
492
|
-
const fileGroups = await Promise.all([
|
|
493
|
-
Ze(`${tmpDir}/*/chats/session-*.json`, { absolute: true }),
|
|
494
|
-
Ze(`${tmpDir}/*/chats/sessions-*.json`, { absolute: true })
|
|
495
|
-
]);
|
|
496
|
-
const files = uniqueItems(fileGroups.flat()).sort((a, b) => a.localeCompare(b));
|
|
497
|
-
return files.map((filePath) => loadGeminiSessionFile(filePath, resolvePricing)).filter((item) => item !== null);
|
|
498
|
-
}
|
|
499
|
-
function loadGeminiSessionFile(filePath, resolvePricing) {
|
|
500
|
-
var _a, _b, _c;
|
|
501
|
-
const data = parseJsonFile(filePath);
|
|
502
|
-
if (!isGeminiSessionFile(data)) {
|
|
503
|
-
return null;
|
|
504
|
-
}
|
|
505
|
-
const startedAt = (_a = toIsoString(data.startTime)) != null ? _a : data.messages.map((message) => toIsoString(message.timestamp)).find(Boolean);
|
|
506
|
-
if (!startedAt) {
|
|
507
|
-
return null;
|
|
508
|
-
}
|
|
509
|
-
const lastTimestamp = (_b = toIsoString(data.lastUpdated)) != null ? _b : [...data.messages].reverse().map((message) => toIsoString(message.timestamp)).find(Boolean);
|
|
510
|
-
const projectRoot = getGeminiProjectRoot(filePath);
|
|
511
|
-
const project = getProjectName(projectRoot, "") || getGeminiProjectKeyFromPath(filePath);
|
|
512
|
-
const repository = getRepositoryNameFromProjectRoot(projectRoot) || `local/${project}`;
|
|
513
|
-
const sessionId = ((_c = data.sessionId) == null ? void 0 : _c.trim()) || basename(filePath, ".json");
|
|
514
|
-
const meta = {
|
|
515
|
-
durationMinutes: getDurationMinutes(startedAt, lastTimestamp),
|
|
516
|
-
project,
|
|
517
|
-
repository,
|
|
518
|
-
sessionId,
|
|
519
|
-
startedAt,
|
|
520
|
-
threadName: getThreadName(getFirstUserMessage(data), project, data.summary)
|
|
521
|
-
};
|
|
522
|
-
const events = extractTokenUsageEvents(data.messages, meta, resolvePricing);
|
|
523
|
-
if (events.length === 0) {
|
|
524
|
-
return null;
|
|
525
|
-
}
|
|
526
|
-
return {
|
|
527
|
-
events,
|
|
528
|
-
meta
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
function isGeminiSessionFile(value) {
|
|
532
|
-
if (!value || typeof value !== "object") {
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
const record = value;
|
|
536
|
-
return Array.isArray(record.messages);
|
|
537
|
-
}
|
|
538
|
-
function extractTokenUsageEvents(messages, meta, resolvePricing) {
|
|
539
|
-
var _a, _b;
|
|
540
|
-
const events = [];
|
|
541
|
-
for (const message of messages) {
|
|
542
|
-
if (message.type !== "gemini" || !message.tokens) {
|
|
543
|
-
continue;
|
|
544
|
-
}
|
|
545
|
-
const timestamp = toIsoString(message.timestamp);
|
|
546
|
-
if (!timestamp) {
|
|
547
|
-
continue;
|
|
548
|
-
}
|
|
549
|
-
const model = ((_a = message.model) == null ? void 0 : _a.trim()) || GEMINI_FALLBACK_MODEL;
|
|
550
|
-
const isFallbackModel = !((_b = message.model) == null ? void 0 : _b.trim());
|
|
551
|
-
const usage = convertGeminiTokenUsage(message.tokens);
|
|
552
|
-
if (isZeroUsage(usage)) {
|
|
553
|
-
continue;
|
|
554
|
-
}
|
|
555
|
-
const toolTokens = normalizeNumber(message.tokens.tool);
|
|
556
|
-
const costUSD = calculateUsageCostUSD({
|
|
557
|
-
cachedInputTokens: usage.cachedInputTokens,
|
|
558
|
-
inputTokens: usage.inputTokens,
|
|
559
|
-
outputTokens: usage.outputTokens + usage.reasoningOutputTokens + toolTokens
|
|
560
|
-
}, resolvePricing(model));
|
|
561
|
-
events.push({
|
|
562
|
-
...usage,
|
|
563
|
-
costUSD,
|
|
564
|
-
isFallbackModel,
|
|
565
|
-
model,
|
|
566
|
-
project: meta.project,
|
|
567
|
-
repository: meta.repository,
|
|
568
|
-
sessionId: meta.sessionId,
|
|
569
|
-
timestamp,
|
|
570
|
-
toolTokens
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
return events;
|
|
574
|
-
}
|
|
575
|
-
function buildSessionSummaries(sessionFiles) {
|
|
576
|
-
var _a, _b, _c;
|
|
577
|
-
const summaries = [];
|
|
578
|
-
for (const sessionFile of sessionFiles) {
|
|
579
|
-
const usageByModel = /* @__PURE__ */ new Map();
|
|
580
|
-
let inputTokens = 0;
|
|
581
|
-
let cachedInputTokens = 0;
|
|
582
|
-
let outputTokens = 0;
|
|
583
|
-
let reasoningOutputTokens = 0;
|
|
584
|
-
let totalTokens = 0;
|
|
585
|
-
let costUSD = 0;
|
|
586
|
-
let lastActivity = sessionFile.meta.startedAt;
|
|
587
|
-
for (const event of sessionFile.events) {
|
|
588
|
-
inputTokens += event.inputTokens;
|
|
589
|
-
cachedInputTokens += event.cachedInputTokens;
|
|
590
|
-
outputTokens += event.outputTokens;
|
|
591
|
-
reasoningOutputTokens += event.reasoningOutputTokens;
|
|
592
|
-
totalTokens += event.totalTokens;
|
|
593
|
-
costUSD += event.costUSD;
|
|
594
|
-
if (event.timestamp > lastActivity) {
|
|
595
|
-
lastActivity = event.timestamp;
|
|
596
|
-
}
|
|
597
|
-
const modelUsage = (_a = usageByModel.get(event.model)) != null ? _a : createEmptyUsage();
|
|
598
|
-
addUsage(modelUsage, event);
|
|
599
|
-
usageByModel.set(event.model, modelUsage);
|
|
600
|
-
}
|
|
601
|
-
const models = Array.from(usageByModel.keys()).sort((a, b) => a.localeCompare(b));
|
|
602
|
-
const topModel = (_c = (_b = Array.from(usageByModel.entries()).sort((a, b) => b[1].totalTokens - a[1].totalTokens || a[0].localeCompare(b[0]))[0]) == null ? void 0 : _b[0]) != null ? _c : GEMINI_FALLBACK_MODEL;
|
|
603
|
-
summaries.push({
|
|
604
|
-
cachedInputTokens,
|
|
605
|
-
costUSD: roundCurrency(costUSD),
|
|
606
|
-
durationMinutes: sessionFile.meta.durationMinutes,
|
|
607
|
-
inputTokens,
|
|
608
|
-
lastActivity,
|
|
609
|
-
models,
|
|
610
|
-
outputTokens,
|
|
611
|
-
project: sessionFile.meta.project,
|
|
612
|
-
reasoningOutputTokens,
|
|
613
|
-
repository: sessionFile.meta.repository,
|
|
614
|
-
sessionId: sessionFile.meta.sessionId,
|
|
615
|
-
startedAt: sessionFile.meta.startedAt,
|
|
616
|
-
threadName: sessionFile.meta.threadName,
|
|
617
|
-
tokenTotal: totalTokens,
|
|
618
|
-
topModel
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
return summaries;
|
|
622
|
-
}
|
|
623
|
-
function getFirstUserMessage(data) {
|
|
624
|
-
var _a, _b;
|
|
625
|
-
return (_b = (_a = data.messages) == null ? void 0 : _a.filter((message) => message.type === "user").map((message) => extractGeminiMessageText(message.content)).find(Boolean)) != null ? _b : "";
|
|
626
|
-
}
|
|
15
|
+
import 'node:os';
|
|
16
|
+
import 'node:util';
|
|
17
|
+
import 'node:process';
|
|
18
|
+
import 'node:tty';
|
|
627
19
|
|
|
628
20
|
const payload_json = defineEventHandler(async () => {
|
|
629
21
|
const runtimeConfig = useRuntimeConfig();
|
|
630
22
|
const config = resolveConfig(runtimeConfig.public);
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
const gemini = await loadGeminiUsage(config);
|
|
634
|
-
return {
|
|
635
|
-
...config,
|
|
636
|
-
claudeCode,
|
|
637
|
-
codex,
|
|
638
|
-
gemini
|
|
639
|
-
};
|
|
23
|
+
const runtime = getUsageDataRuntime(config);
|
|
24
|
+
return runtime.getBootstrap();
|
|
640
25
|
});
|
|
641
26
|
|
|
642
27
|
export { payload_json as default };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { d as defineEventHandler, r as resolveConfig, a as getRouterParam, b as getQuery, n as normalizeStringValue, c as normalizeStringList, g as getUsageDataRuntime, u as useRuntimeConfig } from '../../../../nitro/nitro.mjs';
|
|
2
|
+
import 'node:http';
|
|
3
|
+
import 'node:https';
|
|
4
|
+
import 'node:events';
|
|
5
|
+
import 'node:buffer';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'node:path';
|
|
8
|
+
import 'node:crypto';
|
|
9
|
+
import 'node:sqlite';
|
|
10
|
+
import 'node:url';
|
|
11
|
+
import 'fs';
|
|
12
|
+
import 'node:fs/promises';
|
|
13
|
+
import 'node:stream';
|
|
14
|
+
import 'node:string_decoder';
|
|
15
|
+
import 'node:os';
|
|
16
|
+
import 'node:util';
|
|
17
|
+
import 'node:process';
|
|
18
|
+
import 'node:tty';
|
|
19
|
+
|
|
20
|
+
const modules_get = defineEventHandler(async (event) => {
|
|
21
|
+
const runtimeConfig = useRuntimeConfig();
|
|
22
|
+
const config = resolveConfig(runtimeConfig.public);
|
|
23
|
+
const project = decodeURIComponent(getRouterParam(event, "project") || "").trim();
|
|
24
|
+
const query = getQuery(event);
|
|
25
|
+
const module = normalizeStringValue(query.module);
|
|
26
|
+
const modules = normalizeStringList(query.modules);
|
|
27
|
+
const platform = normalizeStringValue(query.platform);
|
|
28
|
+
return getUsageDataRuntime(config).getProjectDataModules({
|
|
29
|
+
module,
|
|
30
|
+
modules,
|
|
31
|
+
platform,
|
|
32
|
+
project
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export { modules_get as default };
|