@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 CHANGED
@@ -1 +1 @@
1
- 5.13.0-dev.1
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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"}