@@ -279,6 +279,74 @@ function renderToolsTable(byTool: { [key: string]: number }, limit = 10, nameRes
279279 </table>` ;
280280}
281281
282+ function sanitizeStats ( raw : any ) : UsageAnalysisStats | null {
283+ if ( ! raw || typeof raw !== 'object' ) {
284+ return null ;
285+ }
286+
287+ const coerceNumber = ( value : any ) : number => {
288+ const n = Number ( value ) ;
289+ return Number . isFinite ( n ) ? n : 0 ;
290+ } ;
291+
292+ const sanitizeModeUsage = ( mode : any ) : ModeUsage => ( {
293+ ask : coerceNumber ( mode ?. ask ) ,
294+ edit : coerceNumber ( mode ?. edit ) ,
295+ agent : coerceNumber ( mode ?. agent ) ,
296+ plan : coerceNumber ( mode ?. plan ) ,
297+ customAgent : coerceNumber ( mode ?. customAgent ) ,
298+ } ) ;
299+
300+ const sanitizeContextRefs = ( refs : any ) : ContextReferenceUsage => ( {
301+ file : coerceNumber ( refs ?. file ) ,
302+ selection : coerceNumber ( refs ?. selection ) ,
303+ implicitSelection : coerceNumber ( refs ?. implicitSelection ) ,
304+ symbol : coerceNumber ( refs ?. symbol ) ,
305+ codebase : coerceNumber ( refs ?. codebase ) ,
306+ workspace : coerceNumber ( refs ?. workspace ) ,
307+ } ) ;
308+
309+ try {
310+ const today = raw . today ?? { } ;
311+ const last30Days = raw . last30Days ?? { } ;
312+
313+ const sanitized : UsageAnalysisStats = {
314+ today : {
315+ modeUsage : sanitizeModeUsage ( today . modeUsage ?? { } ) ,
316+ contextReferences : sanitizeContextRefs ( today . contextReferences ?? { } ) ,
317+ toolUsage : {
318+ total : coerceNumber ( today . toolUsage ?. total ) ,
319+ byTool : today . toolUsage ?. byTool ?? { } ,
320+ } ,
321+ mcpToolUsage : {
322+ total : coerceNumber ( today . mcpToolUsage ?. total ) ,
323+ byServer : today . mcpToolUsage ?. byServer ?? { } ,
324+ byTool : today . mcpToolUsage ?. byTool ?? { } ,
325+ } ,
326+ } ,
327+ last30Days : {
328+ modeUsage : sanitizeModeUsage ( last30Days . modeUsage ?? { } ) ,
329+ contextReferences : sanitizeContextRefs ( last30Days . contextReferences ?? { } ) ,
330+ toolUsage : {
331+ total : coerceNumber ( last30Days . toolUsage ?. total ) ,
332+ byTool : last30Days . toolUsage ?. byTool ?? { } ,
333+ } ,
334+ mcpToolUsage : {
335+ total : coerceNumber ( last30Days . mcpToolUsage ?. total ) ,
336+ byServer : last30Days . mcpToolUsage ?. byServer ?? { } ,
337+ byTool : last30Days . mcpToolUsage ?. byTool ?? { } ,
338+ } ,
339+ } ,
340+ backendConfigured : ! ! raw . backendConfigured ,
341+ repoAnalysis : raw . repoAnalysis ,
342+ } ;
343+
344+ return sanitized ;
345+ } catch {
346+ return null ;
347+ }
348+ }
349+
282350function renderLayout ( stats : UsageAnalysisStats ) : void {
283351 const root = document . getElementById ( 'root' ) ;
284352 if ( ! root ) {
@@ -1007,8 +1075,13 @@ window.addEventListener('message', (event) => {
10071075 if ( message . data ?. locale ) {
10081076 setFormatLocale ( message . data . locale ) ;
10091077 }
1010- renderLayout ( message . data as UsageAnalysisStats ) ;
1011- renderRepositoryHygienePanels ( ) ;
1078+ {
1079+ const sanitized = sanitizeStats ( message . data ) ;
1080+ if ( sanitized ) {
1081+ renderLayout ( sanitized ) ;
1082+ renderRepositoryHygienePanels ( ) ;
1083+ }
1084+ }
10121085 break ;
10131086 case 'highlightUnknownTools' : {
10141087 const el = document . getElementById ( 'unknown-mcp-tools-section' ) ;
0 commit comments