Showing the changes to apps/server/src/usage/usageTranscriptReader.ts (1 of 33 files). Show all
Unified · Split
| @@ -22,6 +22,7 @@ import { · 21 unmodified lines | ||
| 22 | 22 | mightCarryUsage, |
| 23 | 23 | parseClaudeLine, |
| 24 | 24 | parseCodexLine, |
| 25 | + parseGrokLine, | |
| 25 | 26 | type UsageRecord, |
| 26 | 27 | } from "./usageTranscripts.ts"; |
| 27 | 28 | |
| @@ -37,12 +38,18 @@ export interface TranscriptFile { · 9 unmodified lines | ||
| 37 | 38 | * Errors on individual entries are swallowed: session files rotate and get |
| 38 | 39 | * removed while the walk is in flight, and a partial listing is far better than |
| 39 | 40 | * failing the page. |
| 41 | + * | |
| 42 | + * `fileName` restricts the walk to a single basename (Grok's `updates.jsonl`). | |
| 43 | + * Grok sessions also ship multi-megabyte `chat_history` and `events` logs that | |
| 44 | + * never carry usage, so the basename filter keeps a cold scan off those files. | |
| 40 | 45 | */ |
| 41 | 46 | export async function listTranscriptFiles( |
| 42 | 47 | root: string, |
| 43 | 48 | sinceMs: number, |
| 49 | + options?: { readonly fileName?: string }, | |
| 44 | 50 | ): Promise<readonly TranscriptFile[]> { |
| 45 | 51 | const found: TranscriptFile[] = []; |
| 52 | + const fileName = options?.fileName; | |
| 46 | 53 | |
| 47 | 54 | const walk = async (dir: string): Promise<void> => { |
| 48 | 55 | let entries; |
| @@ -57,7 +64,11 @@ export async function listTranscriptFiles( · 8 unmodified lines | ||
| 57 | 64 | await walk(child); |
| 58 | 65 | continue; |
| 59 | 66 | } |
| 60 | − if (!entry.name.endsWith(".jsonl")) continue; | |
| 67 | + if (fileName !== undefined) { | |
| 68 | + if (entry.name !== fileName) continue; | |
| 69 | + } else if (!entry.name.endsWith(".jsonl")) { | |
| 70 | + continue; | |
| 71 | + } | |
| 61 | 72 | try { |
| 62 | 73 | const stats = await NodeFSP.stat(child); |
| 63 | 74 | if (stats.mtimeMs >= sinceMs) { |
| @@ -129,6 +140,12 @@ export async function readTranscriptRecords( · 65 unmodified lines | ||
| 129 | 140 | continue; |
| 130 | 141 | } |
| 131 | 142 | |
| 143 | + if (provider === "grok") { | |
| 144 | + if (!mightCarryUsage(line, provider)) continue; | |
| 145 | + for (const grokRecord of parseGrokLine(line)) records.push(grokRecord); | |
| 146 | + continue; | |
| 147 | + } | |
| 148 | + | |
| 132 | 149 | if (!mightCarryUsage(line, provider)) continue; |
| 133 | 150 | const record = parseClaudeLine(line); |
| 134 | 151 | if (record !== null) records.push(record); |