MCPcopy Index your code
hub / github.com/anomalyco/opencode / displayStats

Function displayStats

packages/opencode/src/cli/cmd/stats.ts:292–384  ·  view source on GitHub ↗
(stats: SessionStats, toolLimit?: number, modelLimit?: number)

Source from the content-addressed store, hash-verified

290})
291
292export function displayStats(stats: SessionStats, toolLimit?: number, modelLimit?: number) {
293 const width = 56
294
295 function renderRow(label: string, value: string): string {
296 const availableWidth = width - 1
297 const paddingNeeded = availableWidth - label.length - value.length
298 const padding = Math.max(0, paddingNeeded)
299 return `│${label}${" ".repeat(padding)}${value} │`
300 }
301
302 // Overview section
303 console.log("┌────────────────────────────────────────────────────────┐")
304 console.log("│ OVERVIEW │")
305 console.log("├────────────────────────────────────────────────────────┤")
306 console.log(renderRow("Sessions", stats.totalSessions.toLocaleString()))
307 console.log(renderRow("Messages", stats.totalMessages.toLocaleString()))
308 console.log(renderRow("Days", stats.days.toString()))
309 console.log("└────────────────────────────────────────────────────────┘")
310 console.log()
311
312 // Cost & Tokens section
313 console.log("┌────────────────────────────────────────────────────────┐")
314 console.log("│ COST & TOKENS │")
315 console.log("├────────────────────────────────────────────────────────┤")
316 const cost = isNaN(stats.totalCost) ? 0 : stats.totalCost
317 const costPerDay = isNaN(stats.costPerDay) ? 0 : stats.costPerDay
318 const tokensPerSession = isNaN(stats.tokensPerSession) ? 0 : stats.tokensPerSession
319 console.log(renderRow("Total Cost", `$${cost.toFixed(2)}`))
320 console.log(renderRow("Avg Cost/Day", `$${costPerDay.toFixed(2)}`))
321 console.log(renderRow("Avg Tokens/Session", formatNumber(Math.round(tokensPerSession))))
322 const medianTokensPerSession = isNaN(stats.medianTokensPerSession) ? 0 : stats.medianTokensPerSession
323 console.log(renderRow("Median Tokens/Session", formatNumber(Math.round(medianTokensPerSession))))
324 console.log(renderRow("Input", formatNumber(stats.totalTokens.input)))
325 console.log(renderRow("Output", formatNumber(stats.totalTokens.output)))
326 console.log(renderRow("Cache Read", formatNumber(stats.totalTokens.cache.read)))
327 console.log(renderRow("Cache Write", formatNumber(stats.totalTokens.cache.write)))
328 console.log("└────────────────────────────────────────────────────────┘")
329 console.log()
330
331 // Model Usage section
332 if (modelLimit !== undefined && Object.keys(stats.modelUsage).length > 0) {
333 const sortedModels = Object.entries(stats.modelUsage).sort(([, a], [, b]) => b.messages - a.messages)
334 const modelsToDisplay = modelLimit === Infinity ? sortedModels : sortedModels.slice(0, modelLimit)
335
336 console.log("┌────────────────────────────────────────────────────────┐")
337 console.log("│ MODEL USAGE │")
338 console.log("├────────────────────────────────────────────────────────┤")
339
340 for (const [model, usage] of modelsToDisplay) {
341 console.log(`│ ${model.padEnd(54)} │`)
342 console.log(renderRow(" Messages", usage.messages.toLocaleString()))
343 console.log(renderRow(" Input Tokens", formatNumber(usage.tokens.input)))
344 console.log(renderRow(" Output Tokens", formatNumber(usage.tokens.output)))
345 console.log(renderRow(" Cache Read", formatNumber(usage.tokens.cache.read)))
346 console.log(renderRow(" Cache Write", formatNumber(usage.tokens.cache.write)))
347 console.log(renderRow(" Cost", `$${usage.cost.toFixed(4)}`))
348 console.log("├────────────────────────────────────────────────────────┤")
349 }

Callers 1

stats.tsFile · 0.85

Calls 5

renderRowFunction · 0.85
writeMethod · 0.80
formatNumberFunction · 0.70
logMethod · 0.45
valuesMethod · 0.45

Tested by

no test coverage detected