diff --git a/packages/opencode/src/cli/cmd/stats.ts b/packages/opencode/src/cli/cmd/stats.ts index e4b4c8c41a..b92d534441 100644 --- a/packages/opencode/src/cli/cmd/stats.ts +++ b/packages/opencode/src/cli/cmd/stats.ts @@ -197,12 +197,14 @@ export async function aggregateSessionStats(days?: number, projectFilter?: strin const sessionIds = batch.map((s) => s.id) // Bulk fetch messages for this batch of sessions - const messageRows = Database.use((db) => db.select().from(MessageTable).where(inArray(MessageTable.session_id, sessionIds)).all()) - + const messageRows = Database.use((db) => + db.select().from(MessageTable).where(inArray(MessageTable.session_id, sessionIds)).all(), + ) + // Group messages by session_id const messagesBySession = new Map() const messageIds = messageRows.map((r) => r.id) - + for (const row of messageRows) { const msgs = messagesBySession.get(row.session_id) || [] msgs.push(row) @@ -210,13 +212,15 @@ export async function aggregateSessionStats(days?: number, projectFilter?: strin } // Bulk fetch parts for all these messages - let partRows: typeof PartTable.$inferSelect[] = [] + let partRows: (typeof PartTable.$inferSelect)[] = [] if (messageIds.length > 0) { // Chunk message IDs if there are too many for a single IN clause (SQLite has limits) const PART_BATCH_SIZE = 500 for (let j = 0; j < messageIds.length; j += PART_BATCH_SIZE) { const idBatch = messageIds.slice(j, j + PART_BATCH_SIZE) - const parts = Database.use((db) => db.select().from(PartTable).where(inArray(PartTable.message_id, idBatch)).all()) + const parts = Database.use((db) => + db.select().from(PartTable).where(inArray(PartTable.message_id, idBatch)).all(), + ) partRows.push(...parts) } } @@ -229,18 +233,12 @@ export async function aggregateSessionStats(days?: number, projectFilter?: strin partsByMessage.set(row.message_id, parts) } - for (const session of batch) { + const batchResults = batch.map((session) => { const rawMessages = messagesBySession.get(session.id) || [] - // Construct the MessageV2 objects locally instead of doing another N queries - const messages = rawMessages.map( - (row) => - ({ - id: row.id, - sessionID: row.session_id, - info: row.data, - parts: partsByMessage.get(row.id) || [], - }) as MessageV2.WithParts, - ) + const messages = rawMessages.map((row) => ({ + info: { ...row.data, id: row.id, sessionID: row.session_id } as MessageV2.Info, + parts: partsByMessage.get(row.id) || [], + })) let sessionCost = 0 let sessionTokens = { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } } @@ -328,8 +326,6 @@ export async function aggregateSessionStats(days?: number, projectFilter?: strin } }) - const batchResults = await Promise.all(batchPromises) - for (const result of batchResults) { earliestTime = Math.min(earliestTime, result.earliestTime) latestTime = Math.max(latestTime, result.latestTime)