@kaitranntt/ccs 5.13.0-dev.1 → 5.13.0-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/dist/web-server/data-aggregator.d.ts +45 -0
- package/dist/web-server/data-aggregator.d.ts.map +1 -0
- package/dist/web-server/data-aggregator.js +305 -0
- package/dist/web-server/data-aggregator.js.map +1 -0
- package/dist/web-server/jsonl-parser.d.ts +68 -0
- package/dist/web-server/jsonl-parser.d.ts.map +1 -0
- package/dist/web-server/jsonl-parser.js +212 -0
- package/dist/web-server/jsonl-parser.js.map +1 -0
- package/dist/web-server/model-pricing.d.ts +42 -0
- package/dist/web-server/model-pricing.d.ts.map +1 -0
- package/dist/web-server/model-pricing.js +642 -0
- package/dist/web-server/model-pricing.js.map +1 -0
- package/dist/web-server/usage-disk-cache.d.ts +1 -2
- package/dist/web-server/usage-disk-cache.d.ts.map +1 -1
- package/dist/web-server/usage-disk-cache.js +2 -1
- package/dist/web-server/usage-disk-cache.js.map +1 -1
- package/dist/web-server/usage-routes.d.ts +1 -1
- package/dist/web-server/usage-routes.d.ts.map +1 -1
- package/dist/web-server/usage-routes.js +13 -32
- package/dist/web-server/usage-routes.js.map +1 -1
- package/dist/web-server/usage-types.d.ts +57 -0
- package/dist/web-server/usage-types.d.ts.map +1 -0
- package/dist/web-server/usage-types.js +9 -0
- package/dist/web-server/usage-types.js.map +1 -0
- package/package.json +1 -2
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.13.0-dev.
|
|
1
|
+
5.13.0-dev.2
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Aggregator for Claude Code Usage Analytics
|
|
3
|
+
*
|
|
4
|
+
* Aggregates raw JSONL entries into daily, monthly, and session summaries.
|
|
5
|
+
* Uses model-pricing.ts for cost calculations.
|
|
6
|
+
*/
|
|
7
|
+
import { type RawUsageEntry } from './jsonl-parser';
|
|
8
|
+
import { type DailyUsage, type MonthlyUsage, type SessionUsage } from './usage-types';
|
|
9
|
+
/**
|
|
10
|
+
* Aggregate raw entries into daily usage summaries
|
|
11
|
+
* Groups by date (YYYY-MM-DD), calculates costs per model
|
|
12
|
+
*/
|
|
13
|
+
export declare function aggregateDailyUsage(entries: RawUsageEntry[], source?: string): DailyUsage[];
|
|
14
|
+
/**
|
|
15
|
+
* Aggregate raw entries into monthly usage summaries
|
|
16
|
+
* Groups by month (YYYY-MM), calculates costs per model
|
|
17
|
+
*/
|
|
18
|
+
export declare function aggregateMonthlyUsage(entries: RawUsageEntry[], source?: string): MonthlyUsage[];
|
|
19
|
+
/**
|
|
20
|
+
* Aggregate raw entries into session usage summaries
|
|
21
|
+
* Groups by sessionId, tracks last activity and versions
|
|
22
|
+
*/
|
|
23
|
+
export declare function aggregateSessionUsage(entries: RawUsageEntry[], source?: string): SessionUsage[];
|
|
24
|
+
import { type ParserOptions } from './jsonl-parser';
|
|
25
|
+
/**
|
|
26
|
+
* Load daily usage data (replaces better-ccusage loadDailyUsageData)
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadDailyUsageData(options?: ParserOptions): Promise<DailyUsage[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Load monthly usage data (replaces better-ccusage loadMonthlyUsageData)
|
|
31
|
+
*/
|
|
32
|
+
export declare function loadMonthlyUsageData(options?: ParserOptions): Promise<MonthlyUsage[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Load session data (replaces better-ccusage loadSessionData)
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadSessionData(options?: ParserOptions): Promise<SessionUsage[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Load all usage data in a single pass (more efficient)
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadAllUsageData(options?: ParserOptions): Promise<{
|
|
41
|
+
daily: DailyUsage[];
|
|
42
|
+
monthly: MonthlyUsage[];
|
|
43
|
+
session: SessionUsage[];
|
|
44
|
+
}>;
|
|
45
|
+
//# sourceMappingURL=data-aggregator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-aggregator.d.ts","sourceRoot":"","sources":["../../src/web-server/data-aggregator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAmDvB;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,aAAa,EAAE,EACxB,MAAM,SAAkB,GACvB,UAAU,EAAE,CAgFd;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EAAE,EACxB,MAAM,SAAkB,GACvB,YAAY,EAAE,CA+EhB;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EAAE,EACxB,MAAM,SAAkB,GACvB,YAAY,EAAE,CAqGhB;AAMD,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvF;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAG3F;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAGtF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IACvE,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC,CAOD"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Data Aggregator for Claude Code Usage Analytics
|
|
4
|
+
*
|
|
5
|
+
* Aggregates raw JSONL entries into daily, monthly, and session summaries.
|
|
6
|
+
* Uses model-pricing.ts for cost calculations.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.loadAllUsageData = exports.loadSessionData = exports.loadMonthlyUsageData = exports.loadDailyUsageData = exports.aggregateSessionUsage = exports.aggregateMonthlyUsage = exports.aggregateDailyUsage = void 0;
|
|
10
|
+
const model_pricing_1 = require("./model-pricing");
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// HELPER FUNCTIONS
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/** Extract YYYY-MM-DD from ISO timestamp */
|
|
15
|
+
function extractDate(timestamp) {
|
|
16
|
+
return timestamp.slice(0, 10);
|
|
17
|
+
}
|
|
18
|
+
/** Extract YYYY-MM from ISO timestamp */
|
|
19
|
+
function extractMonth(timestamp) {
|
|
20
|
+
return timestamp.slice(0, 7);
|
|
21
|
+
}
|
|
22
|
+
/** Create model breakdown from accumulated data */
|
|
23
|
+
function createModelBreakdown(modelName, inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens) {
|
|
24
|
+
const cost = (0, model_pricing_1.calculateCost)({ inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens }, modelName);
|
|
25
|
+
return {
|
|
26
|
+
modelName,
|
|
27
|
+
inputTokens,
|
|
28
|
+
outputTokens,
|
|
29
|
+
cacheCreationTokens,
|
|
30
|
+
cacheReadTokens,
|
|
31
|
+
cost,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// DAILY AGGREGATION
|
|
36
|
+
// ============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Aggregate raw entries into daily usage summaries
|
|
39
|
+
* Groups by date (YYYY-MM-DD), calculates costs per model
|
|
40
|
+
*/
|
|
41
|
+
function aggregateDailyUsage(entries, source = 'custom-parser') {
|
|
42
|
+
// Group entries by date
|
|
43
|
+
const byDate = new Map();
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
const date = extractDate(entry.timestamp);
|
|
46
|
+
const existing = byDate.get(date) || [];
|
|
47
|
+
existing.push(entry);
|
|
48
|
+
byDate.set(date, existing);
|
|
49
|
+
}
|
|
50
|
+
// Build daily summaries
|
|
51
|
+
const dailyUsage = [];
|
|
52
|
+
for (const [date, dateEntries] of byDate) {
|
|
53
|
+
// Aggregate by model
|
|
54
|
+
const modelMap = new Map();
|
|
55
|
+
let totalInput = 0;
|
|
56
|
+
let totalOutput = 0;
|
|
57
|
+
let totalCacheCreation = 0;
|
|
58
|
+
let totalCacheRead = 0;
|
|
59
|
+
for (const entry of dateEntries) {
|
|
60
|
+
const model = entry.model;
|
|
61
|
+
const acc = modelMap.get(model) || {
|
|
62
|
+
inputTokens: 0,
|
|
63
|
+
outputTokens: 0,
|
|
64
|
+
cacheCreationTokens: 0,
|
|
65
|
+
cacheReadTokens: 0,
|
|
66
|
+
};
|
|
67
|
+
acc.inputTokens += entry.inputTokens;
|
|
68
|
+
acc.outputTokens += entry.outputTokens;
|
|
69
|
+
acc.cacheCreationTokens += entry.cacheCreationTokens;
|
|
70
|
+
acc.cacheReadTokens += entry.cacheReadTokens;
|
|
71
|
+
modelMap.set(model, acc);
|
|
72
|
+
totalInput += entry.inputTokens;
|
|
73
|
+
totalOutput += entry.outputTokens;
|
|
74
|
+
totalCacheCreation += entry.cacheCreationTokens;
|
|
75
|
+
totalCacheRead += entry.cacheReadTokens;
|
|
76
|
+
}
|
|
77
|
+
// Build model breakdowns
|
|
78
|
+
const modelBreakdowns = [];
|
|
79
|
+
let totalCost = 0;
|
|
80
|
+
for (const [modelName, acc] of modelMap) {
|
|
81
|
+
const breakdown = createModelBreakdown(modelName, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
|
|
82
|
+
modelBreakdowns.push(breakdown);
|
|
83
|
+
totalCost += breakdown.cost;
|
|
84
|
+
}
|
|
85
|
+
// Sort breakdowns by cost descending
|
|
86
|
+
modelBreakdowns.sort((a, b) => b.cost - a.cost);
|
|
87
|
+
dailyUsage.push({
|
|
88
|
+
date,
|
|
89
|
+
source,
|
|
90
|
+
inputTokens: totalInput,
|
|
91
|
+
outputTokens: totalOutput,
|
|
92
|
+
cacheCreationTokens: totalCacheCreation,
|
|
93
|
+
cacheReadTokens: totalCacheRead,
|
|
94
|
+
cost: totalCost,
|
|
95
|
+
totalCost,
|
|
96
|
+
modelsUsed: Array.from(modelMap.keys()),
|
|
97
|
+
modelBreakdowns,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Sort by date descending (most recent first)
|
|
101
|
+
dailyUsage.sort((a, b) => b.date.localeCompare(a.date));
|
|
102
|
+
return dailyUsage;
|
|
103
|
+
}
|
|
104
|
+
exports.aggregateDailyUsage = aggregateDailyUsage;
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// MONTHLY AGGREGATION
|
|
107
|
+
// ============================================================================
|
|
108
|
+
/**
|
|
109
|
+
* Aggregate raw entries into monthly usage summaries
|
|
110
|
+
* Groups by month (YYYY-MM), calculates costs per model
|
|
111
|
+
*/
|
|
112
|
+
function aggregateMonthlyUsage(entries, source = 'custom-parser') {
|
|
113
|
+
// Group entries by month
|
|
114
|
+
const byMonth = new Map();
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
const month = extractMonth(entry.timestamp);
|
|
117
|
+
const existing = byMonth.get(month) || [];
|
|
118
|
+
existing.push(entry);
|
|
119
|
+
byMonth.set(month, existing);
|
|
120
|
+
}
|
|
121
|
+
// Build monthly summaries
|
|
122
|
+
const monthlyUsage = [];
|
|
123
|
+
for (const [month, monthEntries] of byMonth) {
|
|
124
|
+
// Aggregate by model
|
|
125
|
+
const modelMap = new Map();
|
|
126
|
+
let totalInput = 0;
|
|
127
|
+
let totalOutput = 0;
|
|
128
|
+
let totalCacheCreation = 0;
|
|
129
|
+
let totalCacheRead = 0;
|
|
130
|
+
for (const entry of monthEntries) {
|
|
131
|
+
const model = entry.model;
|
|
132
|
+
const acc = modelMap.get(model) || {
|
|
133
|
+
inputTokens: 0,
|
|
134
|
+
outputTokens: 0,
|
|
135
|
+
cacheCreationTokens: 0,
|
|
136
|
+
cacheReadTokens: 0,
|
|
137
|
+
};
|
|
138
|
+
acc.inputTokens += entry.inputTokens;
|
|
139
|
+
acc.outputTokens += entry.outputTokens;
|
|
140
|
+
acc.cacheCreationTokens += entry.cacheCreationTokens;
|
|
141
|
+
acc.cacheReadTokens += entry.cacheReadTokens;
|
|
142
|
+
modelMap.set(model, acc);
|
|
143
|
+
totalInput += entry.inputTokens;
|
|
144
|
+
totalOutput += entry.outputTokens;
|
|
145
|
+
totalCacheCreation += entry.cacheCreationTokens;
|
|
146
|
+
totalCacheRead += entry.cacheReadTokens;
|
|
147
|
+
}
|
|
148
|
+
// Build model breakdowns
|
|
149
|
+
const modelBreakdowns = [];
|
|
150
|
+
let totalCost = 0;
|
|
151
|
+
for (const [modelName, acc] of modelMap) {
|
|
152
|
+
const breakdown = createModelBreakdown(modelName, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
|
|
153
|
+
modelBreakdowns.push(breakdown);
|
|
154
|
+
totalCost += breakdown.cost;
|
|
155
|
+
}
|
|
156
|
+
// Sort breakdowns by cost descending
|
|
157
|
+
modelBreakdowns.sort((a, b) => b.cost - a.cost);
|
|
158
|
+
monthlyUsage.push({
|
|
159
|
+
month,
|
|
160
|
+
source,
|
|
161
|
+
inputTokens: totalInput,
|
|
162
|
+
outputTokens: totalOutput,
|
|
163
|
+
cacheCreationTokens: totalCacheCreation,
|
|
164
|
+
cacheReadTokens: totalCacheRead,
|
|
165
|
+
totalCost,
|
|
166
|
+
modelsUsed: Array.from(modelMap.keys()),
|
|
167
|
+
modelBreakdowns,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Sort by month descending (most recent first)
|
|
171
|
+
monthlyUsage.sort((a, b) => b.month.localeCompare(a.month));
|
|
172
|
+
return monthlyUsage;
|
|
173
|
+
}
|
|
174
|
+
exports.aggregateMonthlyUsage = aggregateMonthlyUsage;
|
|
175
|
+
// ============================================================================
|
|
176
|
+
// SESSION AGGREGATION
|
|
177
|
+
// ============================================================================
|
|
178
|
+
/**
|
|
179
|
+
* Aggregate raw entries into session usage summaries
|
|
180
|
+
* Groups by sessionId, tracks last activity and versions
|
|
181
|
+
*/
|
|
182
|
+
function aggregateSessionUsage(entries, source = 'custom-parser') {
|
|
183
|
+
// Group entries by sessionId
|
|
184
|
+
const bySession = new Map();
|
|
185
|
+
for (const entry of entries) {
|
|
186
|
+
if (!entry.sessionId)
|
|
187
|
+
continue;
|
|
188
|
+
const existing = bySession.get(entry.sessionId) || [];
|
|
189
|
+
existing.push(entry);
|
|
190
|
+
bySession.set(entry.sessionId, existing);
|
|
191
|
+
}
|
|
192
|
+
// Build session summaries
|
|
193
|
+
const sessionUsage = [];
|
|
194
|
+
for (const [sessionId, sessionEntries] of bySession) {
|
|
195
|
+
// Aggregate by model
|
|
196
|
+
const modelMap = new Map();
|
|
197
|
+
const versions = new Set();
|
|
198
|
+
let totalInput = 0;
|
|
199
|
+
let totalOutput = 0;
|
|
200
|
+
let totalCacheCreation = 0;
|
|
201
|
+
let totalCacheRead = 0;
|
|
202
|
+
let lastActivity = '';
|
|
203
|
+
let projectPath = '';
|
|
204
|
+
for (const entry of sessionEntries) {
|
|
205
|
+
const model = entry.model;
|
|
206
|
+
const acc = modelMap.get(model) || {
|
|
207
|
+
inputTokens: 0,
|
|
208
|
+
outputTokens: 0,
|
|
209
|
+
cacheCreationTokens: 0,
|
|
210
|
+
cacheReadTokens: 0,
|
|
211
|
+
};
|
|
212
|
+
acc.inputTokens += entry.inputTokens;
|
|
213
|
+
acc.outputTokens += entry.outputTokens;
|
|
214
|
+
acc.cacheCreationTokens += entry.cacheCreationTokens;
|
|
215
|
+
acc.cacheReadTokens += entry.cacheReadTokens;
|
|
216
|
+
modelMap.set(model, acc);
|
|
217
|
+
totalInput += entry.inputTokens;
|
|
218
|
+
totalOutput += entry.outputTokens;
|
|
219
|
+
totalCacheCreation += entry.cacheCreationTokens;
|
|
220
|
+
totalCacheRead += entry.cacheReadTokens;
|
|
221
|
+
// Track latest timestamp
|
|
222
|
+
if (entry.timestamp > lastActivity) {
|
|
223
|
+
lastActivity = entry.timestamp;
|
|
224
|
+
}
|
|
225
|
+
// Track versions
|
|
226
|
+
if (entry.version) {
|
|
227
|
+
versions.add(entry.version);
|
|
228
|
+
}
|
|
229
|
+
// Use project path from entry
|
|
230
|
+
if (entry.projectPath) {
|
|
231
|
+
projectPath = entry.projectPath;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Build model breakdowns
|
|
235
|
+
const modelBreakdowns = [];
|
|
236
|
+
let totalCost = 0;
|
|
237
|
+
for (const [modelName, acc] of modelMap) {
|
|
238
|
+
const breakdown = createModelBreakdown(modelName, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
|
|
239
|
+
modelBreakdowns.push(breakdown);
|
|
240
|
+
totalCost += breakdown.cost;
|
|
241
|
+
}
|
|
242
|
+
// Sort breakdowns by cost descending
|
|
243
|
+
modelBreakdowns.sort((a, b) => b.cost - a.cost);
|
|
244
|
+
sessionUsage.push({
|
|
245
|
+
sessionId,
|
|
246
|
+
projectPath,
|
|
247
|
+
inputTokens: totalInput,
|
|
248
|
+
outputTokens: totalOutput,
|
|
249
|
+
cacheCreationTokens: totalCacheCreation,
|
|
250
|
+
cacheReadTokens: totalCacheRead,
|
|
251
|
+
cost: totalCost,
|
|
252
|
+
totalCost,
|
|
253
|
+
lastActivity,
|
|
254
|
+
versions: Array.from(versions),
|
|
255
|
+
modelsUsed: Array.from(modelMap.keys()),
|
|
256
|
+
modelBreakdowns,
|
|
257
|
+
source,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
// Sort by last activity descending (most recent first)
|
|
261
|
+
sessionUsage.sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));
|
|
262
|
+
return sessionUsage;
|
|
263
|
+
}
|
|
264
|
+
exports.aggregateSessionUsage = aggregateSessionUsage;
|
|
265
|
+
// ============================================================================
|
|
266
|
+
// MAIN DATA LOADER (drop-in replacement for better-ccusage)
|
|
267
|
+
// ============================================================================
|
|
268
|
+
const jsonl_parser_1 = require("./jsonl-parser");
|
|
269
|
+
/**
|
|
270
|
+
* Load daily usage data (replaces better-ccusage loadDailyUsageData)
|
|
271
|
+
*/
|
|
272
|
+
async function loadDailyUsageData(options) {
|
|
273
|
+
const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
|
|
274
|
+
return aggregateDailyUsage(entries);
|
|
275
|
+
}
|
|
276
|
+
exports.loadDailyUsageData = loadDailyUsageData;
|
|
277
|
+
/**
|
|
278
|
+
* Load monthly usage data (replaces better-ccusage loadMonthlyUsageData)
|
|
279
|
+
*/
|
|
280
|
+
async function loadMonthlyUsageData(options) {
|
|
281
|
+
const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
|
|
282
|
+
return aggregateMonthlyUsage(entries);
|
|
283
|
+
}
|
|
284
|
+
exports.loadMonthlyUsageData = loadMonthlyUsageData;
|
|
285
|
+
/**
|
|
286
|
+
* Load session data (replaces better-ccusage loadSessionData)
|
|
287
|
+
*/
|
|
288
|
+
async function loadSessionData(options) {
|
|
289
|
+
const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
|
|
290
|
+
return aggregateSessionUsage(entries);
|
|
291
|
+
}
|
|
292
|
+
exports.loadSessionData = loadSessionData;
|
|
293
|
+
/**
|
|
294
|
+
* Load all usage data in a single pass (more efficient)
|
|
295
|
+
*/
|
|
296
|
+
async function loadAllUsageData(options) {
|
|
297
|
+
const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
|
|
298
|
+
return {
|
|
299
|
+
daily: aggregateDailyUsage(entries),
|
|
300
|
+
monthly: aggregateMonthlyUsage(entries),
|
|
301
|
+
session: aggregateSessionUsage(entries),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
exports.loadAllUsageData = loadAllUsageData;
|
|
305
|
+
//# sourceMappingURL=data-aggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-aggregator.js","sourceRoot":"","sources":["../../src/web-server/data-aggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL Parser for Claude Code Usage Analytics
|
|
3
|
+
*
|
|
4
|
+
* High-performance streaming parser for ~/.claude/projects/ JSONL files.
|
|
5
|
+
* Replaces better-ccusage dependency with optimized custom implementation.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Streaming line-by-line parsing (memory efficient)
|
|
9
|
+
* - Only parses "assistant" entries with usage data
|
|
10
|
+
* - Parallel file processing with configurable concurrency
|
|
11
|
+
* - Graceful error handling for malformed entries
|
|
12
|
+
*/
|
|
13
|
+
/** Raw usage data from JSONL entry */
|
|
14
|
+
export interface RawUsageEntry {
|
|
15
|
+
inputTokens: number;
|
|
16
|
+
outputTokens: number;
|
|
17
|
+
cacheCreationTokens: number;
|
|
18
|
+
cacheReadTokens: number;
|
|
19
|
+
model: string;
|
|
20
|
+
sessionId: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
projectPath: string;
|
|
23
|
+
version?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Parser options */
|
|
26
|
+
export interface ParserOptions {
|
|
27
|
+
/** Max files to parse concurrently (default: 10) */
|
|
28
|
+
concurrency?: number;
|
|
29
|
+
/** Skip files older than this date */
|
|
30
|
+
minDate?: Date;
|
|
31
|
+
/** Custom projects directory (default: ~/.claude/projects) */
|
|
32
|
+
projectsDir?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parse a single JSONL line into RawUsageEntry if valid
|
|
36
|
+
* Returns null for non-assistant entries or entries without usage data
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseUsageEntry(line: string, projectPath: string): RawUsageEntry | null;
|
|
39
|
+
/**
|
|
40
|
+
* Stream-parse a single JSONL file
|
|
41
|
+
* Yields RawUsageEntry for each valid assistant entry
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseJsonlFile(filePath: string, projectPath: string): Promise<RawUsageEntry[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Parse all JSONL files in a single project directory
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseProjectDirectory(projectDir: string): Promise<RawUsageEntry[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Get default Claude projects directory
|
|
50
|
+
*/
|
|
51
|
+
export declare function getDefaultProjectsDir(): string;
|
|
52
|
+
/**
|
|
53
|
+
* Find all project directories under ~/.claude/projects/
|
|
54
|
+
*/
|
|
55
|
+
export declare function findProjectDirectories(projectsDir?: string): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Scan all projects and parse all JSONL files
|
|
58
|
+
* Main entry point for usage data extraction
|
|
59
|
+
*
|
|
60
|
+
* @param options - Parser configuration
|
|
61
|
+
* @returns All parsed usage entries from all projects
|
|
62
|
+
*/
|
|
63
|
+
export declare function scanProjectsDirectory(options?: ParserOptions): Promise<RawUsageEntry[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Get count of JSONL files across all projects (for progress reporting)
|
|
66
|
+
*/
|
|
67
|
+
export declare function countJsonlFiles(projectsDir?: string): number;
|
|
68
|
+
//# sourceMappingURL=jsonl-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl-parser.d.ts","sourceRoot":"","sources":["../../src/web-server/jsonl-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoBD,qBAAqB;AACrB,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA6BvF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,EAAE,CAAC,CAqB1B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAyBxF;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAG9C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAerE;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA8BjG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAc5D"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JSONL Parser for Claude Code Usage Analytics
|
|
4
|
+
*
|
|
5
|
+
* High-performance streaming parser for ~/.claude/projects/ JSONL files.
|
|
6
|
+
* Replaces better-ccusage dependency with optimized custom implementation.
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Streaming line-by-line parsing (memory efficient)
|
|
10
|
+
* - Only parses "assistant" entries with usage data
|
|
11
|
+
* - Parallel file processing with configurable concurrency
|
|
12
|
+
* - Graceful error handling for malformed entries
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.countJsonlFiles = exports.scanProjectsDirectory = exports.findProjectDirectories = exports.getDefaultProjectsDir = exports.parseProjectDirectory = exports.parseJsonlFile = exports.parseUsageEntry = void 0;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const readline = __importStar(require("readline"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// CORE PARSING FUNCTIONS
|
|
45
|
+
// ============================================================================
|
|
46
|
+
/**
|
|
47
|
+
* Parse a single JSONL line into RawUsageEntry if valid
|
|
48
|
+
* Returns null for non-assistant entries or entries without usage data
|
|
49
|
+
*/
|
|
50
|
+
function parseUsageEntry(line, projectPath) {
|
|
51
|
+
if (!line.trim())
|
|
52
|
+
return null;
|
|
53
|
+
try {
|
|
54
|
+
const entry = JSON.parse(line);
|
|
55
|
+
// Only process assistant entries with usage data
|
|
56
|
+
if (entry.type !== 'assistant')
|
|
57
|
+
return null;
|
|
58
|
+
if (!entry.message?.usage)
|
|
59
|
+
return null;
|
|
60
|
+
if (!entry.message?.model)
|
|
61
|
+
return null;
|
|
62
|
+
const usage = entry.message.usage;
|
|
63
|
+
const assistant = entry;
|
|
64
|
+
return {
|
|
65
|
+
inputTokens: usage.input_tokens || 0,
|
|
66
|
+
outputTokens: usage.output_tokens || 0,
|
|
67
|
+
cacheCreationTokens: usage.cache_creation_input_tokens || 0,
|
|
68
|
+
cacheReadTokens: usage.cache_read_input_tokens || 0,
|
|
69
|
+
model: assistant.message.model,
|
|
70
|
+
sessionId: assistant.sessionId || '',
|
|
71
|
+
timestamp: assistant.timestamp || new Date().toISOString(),
|
|
72
|
+
projectPath,
|
|
73
|
+
version: assistant.version,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Malformed JSON - skip silently
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.parseUsageEntry = parseUsageEntry;
|
|
82
|
+
/**
|
|
83
|
+
* Stream-parse a single JSONL file
|
|
84
|
+
* Yields RawUsageEntry for each valid assistant entry
|
|
85
|
+
*/
|
|
86
|
+
async function parseJsonlFile(filePath, projectPath) {
|
|
87
|
+
const entries = [];
|
|
88
|
+
if (!fs.existsSync(filePath)) {
|
|
89
|
+
return entries;
|
|
90
|
+
}
|
|
91
|
+
const fileStream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
92
|
+
const rl = readline.createInterface({
|
|
93
|
+
input: fileStream,
|
|
94
|
+
crlfDelay: Infinity,
|
|
95
|
+
});
|
|
96
|
+
for await (const line of rl) {
|
|
97
|
+
const entry = parseUsageEntry(line, projectPath);
|
|
98
|
+
if (entry) {
|
|
99
|
+
entries.push(entry);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return entries;
|
|
103
|
+
}
|
|
104
|
+
exports.parseJsonlFile = parseJsonlFile;
|
|
105
|
+
/**
|
|
106
|
+
* Parse all JSONL files in a single project directory
|
|
107
|
+
*/
|
|
108
|
+
async function parseProjectDirectory(projectDir) {
|
|
109
|
+
const entries = [];
|
|
110
|
+
if (!fs.existsSync(projectDir)) {
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
// Get project path from directory name (e.g., "-home-kai-project" -> "/home/kai/project")
|
|
114
|
+
const projectPath = path.basename(projectDir).replace(/-/g, '/');
|
|
115
|
+
try {
|
|
116
|
+
const files = fs.readdirSync(projectDir);
|
|
117
|
+
const jsonlFiles = files.filter((f) => f.endsWith('.jsonl'));
|
|
118
|
+
// Parse files sequentially within a project to avoid too many open handles
|
|
119
|
+
for (const file of jsonlFiles) {
|
|
120
|
+
const filePath = path.join(projectDir, file);
|
|
121
|
+
const fileEntries = await parseJsonlFile(filePath, projectPath);
|
|
122
|
+
entries.push(...fileEntries);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Directory access error - skip silently
|
|
127
|
+
}
|
|
128
|
+
return entries;
|
|
129
|
+
}
|
|
130
|
+
exports.parseProjectDirectory = parseProjectDirectory;
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// DIRECTORY SCANNING
|
|
133
|
+
// ============================================================================
|
|
134
|
+
/**
|
|
135
|
+
* Get default Claude projects directory
|
|
136
|
+
*/
|
|
137
|
+
function getDefaultProjectsDir() {
|
|
138
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
|
|
139
|
+
return path.join(configDir, 'projects');
|
|
140
|
+
}
|
|
141
|
+
exports.getDefaultProjectsDir = getDefaultProjectsDir;
|
|
142
|
+
/**
|
|
143
|
+
* Find all project directories under ~/.claude/projects/
|
|
144
|
+
*/
|
|
145
|
+
function findProjectDirectories(projectsDir) {
|
|
146
|
+
const dir = projectsDir || getDefaultProjectsDir();
|
|
147
|
+
if (!fs.existsSync(dir)) {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
152
|
+
return entries
|
|
153
|
+
.filter((entry) => entry.isDirectory())
|
|
154
|
+
.map((entry) => path.join(dir, entry.name));
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.findProjectDirectories = findProjectDirectories;
|
|
161
|
+
/**
|
|
162
|
+
* Scan all projects and parse all JSONL files
|
|
163
|
+
* Main entry point for usage data extraction
|
|
164
|
+
*
|
|
165
|
+
* @param options - Parser configuration
|
|
166
|
+
* @returns All parsed usage entries from all projects
|
|
167
|
+
*/
|
|
168
|
+
async function scanProjectsDirectory(options = {}) {
|
|
169
|
+
const { concurrency = 10, projectsDir } = options;
|
|
170
|
+
const allEntries = [];
|
|
171
|
+
const projectDirs = findProjectDirectories(projectsDir);
|
|
172
|
+
if (projectDirs.length === 0) {
|
|
173
|
+
return allEntries;
|
|
174
|
+
}
|
|
175
|
+
// Process projects in batches for controlled concurrency
|
|
176
|
+
for (let i = 0; i < projectDirs.length; i += concurrency) {
|
|
177
|
+
const batch = projectDirs.slice(i, i + concurrency);
|
|
178
|
+
const batchResults = await Promise.all(batch.map((dir) => parseProjectDirectory(dir)));
|
|
179
|
+
for (const entries of batchResults) {
|
|
180
|
+
allEntries.push(...entries);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Filter by date if specified
|
|
184
|
+
if (options.minDate) {
|
|
185
|
+
const minTime = options.minDate.getTime();
|
|
186
|
+
return allEntries.filter((entry) => {
|
|
187
|
+
const entryTime = new Date(entry.timestamp).getTime();
|
|
188
|
+
return entryTime >= minTime;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return allEntries;
|
|
192
|
+
}
|
|
193
|
+
exports.scanProjectsDirectory = scanProjectsDirectory;
|
|
194
|
+
/**
|
|
195
|
+
* Get count of JSONL files across all projects (for progress reporting)
|
|
196
|
+
*/
|
|
197
|
+
function countJsonlFiles(projectsDir) {
|
|
198
|
+
const projectDirs = findProjectDirectories(projectsDir);
|
|
199
|
+
let count = 0;
|
|
200
|
+
for (const dir of projectDirs) {
|
|
201
|
+
try {
|
|
202
|
+
const files = fs.readdirSync(dir);
|
|
203
|
+
count += files.filter((f) => f.endsWith('.jsonl')).length;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Skip inaccessible directories
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return count;
|
|
210
|
+
}
|
|
211
|
+
exports.countJsonlFiles = countJsonlFiles;
|
|
212
|
+
//# sourceMappingURL=jsonl-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl-parser.js","sourceRoot":"","sources":["../../src/web-server/jsonl-parser.ts"],"names":[],"mappings":"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"}
|