@@ -25,6 +25,46 @@ import {
2525import { ValidationError , DatabaseError } from "../errors.js" ;
2626import { ZodError } from "zod" ;
2727
28+
29+ const EMPTY_AGGREGATE : AggregateUsage = {
30+ totalSdlTokens : 0 ,
31+ totalRawEquivalent : 0 ,
32+ totalSavedTokens : 0 ,
33+ overallSavingsPercent : 0 ,
34+ totalCalls : 0 ,
35+ sessionCount : 0 ,
36+ } ;
37+
38+ function toAggregateUsage ( aggregate : Record < string , number > ) : AggregateUsage {
39+ return {
40+ totalSdlTokens : aggregate . totalSdlTokens ,
41+ totalRawEquivalent : aggregate . totalRawEquivalent ,
42+ totalSavedTokens : aggregate . totalSavedTokens ,
43+ overallSavingsPercent : aggregate . overallSavingsPercent ,
44+ totalCalls : aggregate . totalCalls ,
45+ sessionCount : aggregate . sessionCount ,
46+ } ;
47+ }
48+
49+ async function fetchLifetimeAggregate (
50+ repoId : string | undefined ,
51+ ) : Promise < { ltAggregate : AggregateUsage ; allToolEntries : import ( "../token-accumulator.js" ) . ToolUsageEntry [ ] } > {
52+ try {
53+ const conn = await getLadybugConn ( ) ;
54+ const aggregate = await getAggregateUsage ( conn , { repoId } ) ;
55+ const snapshots = await getUsageSnapshots ( conn , { repoId, limit : 100 } ) ;
56+ const allToolEntries = aggregateToolBreakdowns (
57+ snapshots . map ( ( s ) => s . toolBreakdownJson ) ,
58+ ) ;
59+ return { ltAggregate : toAggregateUsage ( aggregate ) , allToolEntries } ;
60+ } catch {
61+ process . stderr . write (
62+ "[sdl-mcp] Usage stats: could not fetch lifetime data from LadybugDB\n" ,
63+ ) ;
64+ return { ltAggregate : EMPTY_AGGREGATE , allToolEntries : [ ] } ;
65+ }
66+ }
67+
2868export async function handleUsageStats (
2969 args : unknown ,
3070) : Promise < UsageStatsResponse > {
@@ -107,14 +147,7 @@ export async function handleUsageStats(
107147 } ;
108148
109149 // Build formatted summary for history-aware scopes
110- const ltAggregate : AggregateUsage = {
111- totalSdlTokens : aggregate . totalSdlTokens ,
112- totalRawEquivalent : aggregate . totalRawEquivalent ,
113- totalSavedTokens : aggregate . totalSavedTokens ,
114- overallSavingsPercent : aggregate . overallSavingsPercent ,
115- totalCalls : aggregate . totalCalls ,
116- sessionCount : aggregate . sessionCount ,
117- } ;
150+ const ltAggregate : AggregateUsage = toAggregateUsage ( aggregate ) ;
118151
119152 if ( request . scope === "both" && response . session ) {
120153 response . formattedSummary = renderSessionSummary (
@@ -132,36 +165,12 @@ export async function handleUsageStats(
132165
133166 // Session-only: still fetch lifetime for the combined summary
134167 if ( request . scope === "session" && response . session ) {
135- try {
136- const conn = await getLadybugConn ( ) ;
137- const aggregate = await getAggregateUsage ( conn , { repoId : request . repoId } ) ;
138- const snapshots = await getUsageSnapshots ( conn , { repoId : request . repoId , limit : 100 } ) ;
139- const allToolEntries = aggregateToolBreakdowns ( snapshots . map ( ( s ) => s . toolBreakdownJson ) ) ;
140- const ltAggregate : AggregateUsage = {
141- totalSdlTokens : aggregate . totalSdlTokens ,
142- totalRawEquivalent : aggregate . totalRawEquivalent ,
143- totalSavedTokens : aggregate . totalSavedTokens ,
144- overallSavingsPercent : aggregate . overallSavingsPercent ,
145- totalCalls : aggregate . totalCalls ,
146- sessionCount : aggregate . sessionCount ,
147- } ;
148- response . formattedSummary = renderSessionSummary (
149- response . session ,
150- ltAggregate ,
151- allToolEntries ,
152- ) ;
153- } catch {
154- // Fallback: session-only without lifetime (DB unavailable)
155- process . stderr . write (
156- "[sdl-mcp] Usage stats: could not fetch lifetime data from LadybugDB\n" ,
157- ) ;
158- // Render session section only — omit lifetime to avoid showing misleading zeros
159- response . formattedSummary = renderSessionSummary (
160- response . session ,
161- { totalSdlTokens : 0 , totalRawEquivalent : 0 , totalSavedTokens : 0 , overallSavingsPercent : 0 , totalCalls : 0 , sessionCount : 0 } ,
162- [ ] ,
163- ) ;
164- }
168+ const { ltAggregate, allToolEntries } = await fetchLifetimeAggregate ( request . repoId ) ;
169+ response . formattedSummary = renderSessionSummary (
170+ response . session ,
171+ ltAggregate ,
172+ allToolEntries ,
173+ ) ;
165174 }
166175
167176 return response ;
0 commit comments