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.
Files changed (32) hide show
  1. package/dist/index.mjs +10 -4
  2. package/dist/public/_nuxt/{chy2QJx0.js → 7Dy4NLP8.js} +32 -32
  3. package/dist/public/_nuxt/B-VlGWDb.js +21 -0
  4. package/dist/public/_nuxt/{BeEwECnn.js → Be3rizqy.js} +1 -1
  5. package/dist/public/_nuxt/{15CW3D68.js → C0azgqnZ.js} +1 -1
  6. package/dist/public/_nuxt/{B6G-s9D-.js → CMNdiQCa.js} +1 -1
  7. package/dist/public/_nuxt/CPuXQJE_.js +1 -0
  8. package/dist/public/_nuxt/DenksPSi.js +119 -0
  9. package/dist/public/_nuxt/Dkya5WaL.js +9 -0
  10. package/dist/public/_nuxt/HN9OZyaQ.js +25 -0
  11. package/dist/public/_nuxt/{Bu4SpN_a.js → JtK-nXxy.js} +1 -1
  12. package/dist/public/_nuxt/builds/latest.json +1 -1
  13. package/dist/public/_nuxt/builds/meta/37e8bb21-a086-45bf-93dc-47eeeada7299.json +1 -0
  14. package/dist/public/_nuxt/{BeygfM9p.js → y3weNNd-.js} +2 -2
  15. package/dist/server/chunks/_/error-500.mjs +8 -4
  16. package/dist/server/chunks/_/shared.cjs.prod.mjs +1 -1
  17. package/dist/server/chunks/build/client.precomputed.mjs +1 -1
  18. package/dist/server/chunks/nitro/nitro.mjs +8218 -2844
  19. package/dist/server/chunks/routes/api/payload.json.mjs +11 -626
  20. package/dist/server/chunks/routes/api/projects/_project/modules.get.mjs +36 -0
  21. package/dist/server/chunks/routes/api/projects/catalog.get.mjs +26 -0
  22. package/dist/server/chunks/routes/renderer.mjs +9 -5
  23. package/dist/server/chunks/routes/ws.mjs +29 -971
  24. package/dist/server/index.mjs +9 -5
  25. package/package.json +7 -6
  26. package/dist/public/_nuxt/C6ydMk2z.js +0 -25
  27. package/dist/public/_nuxt/Dn8cXZx3.js +0 -9
  28. package/dist/public/_nuxt/DysUC14A.js +0 -119
  29. package/dist/public/_nuxt/KLhV325n.js +0 -1
  30. package/dist/public/_nuxt/builds/meta/ac4b25d6-d6eb-44bb-8c5b-b1d6f651c196.json +0 -1
  31. package/dist/public/_nuxt/pmnAmEjb.js +0 -21
  32. package/dist/server/chunks/_/index.min.mjs +0 -348
@@ -1,642 +1,27 @@
1
- import { b as buildLoadUsageResult, e as extractClaudeProjectFromPath, p as parseJsonlFile, n as normalizeNumber, g as getProjectName, d as decodeClaudeProjectPath, a as getDurationMinutes, r as roundCurrency, c as getClaudeLookupCandidates, f as createEmptyUsage, h as addUsage, t as toIsoString, i as normalizeRepositoryUrl, j as getThreadName, k as extractModelName, l as normalizeRawUsage, s as subtractRawUsage, m as convertCodexRawUsage, o as isZeroUsage, q as isOpenRouterFreeModel, u as uniqueItems, v as parseJsonFile, w as getGeminiProjectRoot, x as getGeminiProjectKeyFromPath, y as getRepositoryNameFromProjectRoot, z as extractGeminiMessageText, A as convertGeminiTokenUsage, B as getGeminiLookupCandidates, C as defineEventHandler, D as resolveConfig, E as useRuntimeConfig } from '../../nitro/nitro.mjs';
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
- async function loadClaudeCodeUsage(config) {
21
- const resolvePricing = await createLiteLLMPricingResolver({
22
- aliases: CLAUDE_MODEL_ALIASES,
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 claudeCode = await loadClaudeCodeUsage(config);
632
- const codex = await loadCodexUsage(config);
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 };