@@ -34,31 +34,23 @@ interface EditorUsage {
3434 } ;
3535}
3636
37+ interface PeriodStats {
38+ tokens : number ;
39+ sessions : number ;
40+ avgInteractionsPerSession : number ;
41+ avgTokensPerSession : number ;
42+ modelUsage : ModelUsage ;
43+ editorUsage : EditorUsage ;
44+ co2 : number ;
45+ treesEquivalent : number ;
46+ waterUsage : number ;
47+ estimatedCost : number ;
48+ }
49+
3750interface DetailedStats {
38- today : {
39- tokens : number ;
40- sessions : number ;
41- avgInteractionsPerSession : number ;
42- avgTokensPerSession : number ;
43- modelUsage : ModelUsage ;
44- editorUsage : EditorUsage ;
45- co2 : number ;
46- treesEquivalent : number ;
47- waterUsage : number ;
48- estimatedCost : number ;
49- } ;
50- month : {
51- tokens : number ;
52- sessions : number ;
53- avgInteractionsPerSession : number ;
54- avgTokensPerSession : number ;
55- modelUsage : ModelUsage ;
56- editorUsage : EditorUsage ;
57- co2 : number ;
58- treesEquivalent : number ;
59- waterUsage : number ;
60- estimatedCost : number ;
61- } ;
51+ today : PeriodStats ;
52+ month : PeriodStats ;
53+ lastMonth : PeriodStats ;
6254 lastUpdated : Date ;
6355}
6456
@@ -368,7 +360,7 @@ class CopilotTokenTracker implements vscode.Disposable {
368360 try {
369361 // Show the output channel so users can see what's happening
370362 this . outputChannel . show ( true ) ;
371- this . log ( '[ DEBUG] clearCache() called' ) ;
363+ this . log ( 'DEBUG clearCache() called' ) ;
372364 this . log ( 'Clearing session file cache...' ) ;
373365
374366 const cacheSize = this . sessionFileCache . size ;
@@ -377,6 +369,8 @@ class CopilotTokenTracker implements vscode.Disposable {
377369 // Reset diagnostics loaded flag so the diagnostics view will reload files
378370 this . diagnosticsHasLoadedFiles = false ;
379371 this . diagnosticsCachedFiles = [ ] ;
372+ // Clear cached computed stats so details panel doesn't show stale data
373+ this . lastDetailedStats = undefined ;
380374
381375 this . log ( `Cache cleared successfully. Removed ${ cacheSize } entries.` ) ;
382376 vscode . window . showInformationMessage ( 'Cache cleared successfully. Reloading statistics...' ) ;
@@ -595,9 +589,13 @@ class CopilotTokenTracker implements vscode.Disposable {
595589 const now = new Date ( ) ;
596590 const todayStart = new Date ( now . getFullYear ( ) , now . getMonth ( ) , now . getDate ( ) ) ;
597591 const monthStart = new Date ( now . getFullYear ( ) , now . getMonth ( ) , 1 ) ;
592+ // Calculate last month boundaries
593+ const lastMonthEnd = new Date ( now . getFullYear ( ) , now . getMonth ( ) , 0 , 23 , 59 , 59 , 999 ) ; // Last day of previous month
594+ const lastMonthStart = new Date ( lastMonthEnd . getFullYear ( ) , lastMonthEnd . getMonth ( ) , 1 ) ;
598595
599596 const todayStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
600597 const monthStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
598+ const lastMonthStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
601599
602600 try {
603601 // Clean expired cache entries
@@ -625,9 +623,9 @@ class CopilotTokenTracker implements vscode.Disposable {
625623 // Fast check: Get file stats first to avoid processing old files
626624 const fileStats = fs . statSync ( sessionFile ) ;
627625
628- // Skip files modified before the current month (quick filter)
626+ // Skip files modified before last month (quick filter)
629627 // This is the main performance optimization - filters out old sessions without reading file content
630- if ( fileStats . mtime < monthStart ) {
628+ if ( fileStats . mtime < lastMonthStart ) {
631629 skippedFiles ++ ;
632630 continue ;
633631 }
@@ -707,18 +705,46 @@ class CopilotTokenTracker implements vscode.Disposable {
707705 }
708706 }
709707 }
708+ else if ( lastActivity >= lastMonthStart && lastActivity <= lastMonthEnd ) {
709+ // Session is from last month - only track lastMonth stats
710+ if ( wasCached ) {
711+ cacheHits ++ ;
712+ } else {
713+ cacheMisses ++ ;
714+ }
715+
716+ lastMonthStats . tokens += tokens ;
717+ lastMonthStats . sessions += 1 ;
718+ lastMonthStats . interactions += interactions ;
719+
720+ // Add editor usage to last month stats
721+ if ( ! lastMonthStats . editorUsage [ editorType ] ) {
722+ lastMonthStats . editorUsage [ editorType ] = { tokens : 0 , sessions : 0 } ;
723+ }
724+ lastMonthStats . editorUsage [ editorType ] . tokens += tokens ;
725+ lastMonthStats . editorUsage [ editorType ] . sessions += 1 ;
726+
727+ // Add model usage to last month stats
728+ for ( const [ model , usage ] of Object . entries ( modelUsage ) ) {
729+ if ( ! lastMonthStats . modelUsage [ model ] ) {
730+ lastMonthStats . modelUsage [ model ] = { inputTokens : 0 , outputTokens : 0 } ;
731+ }
732+ lastMonthStats . modelUsage [ model ] . inputTokens += usage . inputTokens ;
733+ lastMonthStats . modelUsage [ model ] . outputTokens += usage . outputTokens ;
734+ }
735+ }
710736 else {
711- // Session is too old (no activity in current month), skip it
737+ // Session is too old (no activity in current or last month), skip it
712738 skippedFiles ++ ;
713739 }
714740 } catch ( fileError ) {
715741 this . warn ( `Error processing session file ${ sessionFile } : ${ fileError } ` ) ;
716742 }
717743 }
718744
719- this . log ( `✅ Analysis complete: Today ${ todayStats . sessions } sessions, Month ${ monthStats . sessions } sessions` ) ;
745+ this . log ( `✅ Analysis complete: Today ${ todayStats . sessions } sessions, Month ${ monthStats . sessions } sessions, Last Month ${ lastMonthStats . sessions } sessions ` ) ;
720746 if ( skippedFiles > 0 ) {
721- this . log ( `⏭️ Skipped ${ skippedFiles } session file(s) (empty or no activity in current month )` ) ;
747+ this . log ( `⏭️ Skipped ${ skippedFiles } session file(s) (empty or no activity in recent months )` ) ;
722748 }
723749 const totalCacheAccesses = cacheHits + cacheMisses ;
724750 this . log ( `💾 Cache performance: ${ cacheHits } hits, ${ cacheMisses } misses (${ totalCacheAccesses > 0 ? ( ( cacheHits / totalCacheAccesses ) * 100 ) . toFixed ( 1 ) : 0 } % hit rate)` ) ;
@@ -728,12 +754,15 @@ class CopilotTokenTracker implements vscode.Disposable {
728754
729755 const todayCo2 = ( todayStats . tokens / 1000 ) * this . co2Per1kTokens ;
730756 const monthCo2 = ( monthStats . tokens / 1000 ) * this . co2Per1kTokens ;
757+ const lastMonthCo2 = ( lastMonthStats . tokens / 1000 ) * this . co2Per1kTokens ;
731758
732759 const todayWater = ( todayStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
733760 const monthWater = ( monthStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
761+ const lastMonthWater = ( lastMonthStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
734762
735763 const todayCost = this . calculateEstimatedCost ( todayStats . modelUsage ) ;
736764 const monthCost = this . calculateEstimatedCost ( monthStats . modelUsage ) ;
765+ const lastMonthCost = this . calculateEstimatedCost ( lastMonthStats . modelUsage ) ;
737766
738767 const result : DetailedStats = {
739768 today : {
@@ -760,6 +789,18 @@ class CopilotTokenTracker implements vscode.Disposable {
760789 waterUsage : monthWater ,
761790 estimatedCost : monthCost
762791 } ,
792+ lastMonth : {
793+ tokens : lastMonthStats . tokens ,
794+ sessions : lastMonthStats . sessions ,
795+ avgInteractionsPerSession : lastMonthStats . sessions > 0 ? Math . round ( lastMonthStats . interactions / lastMonthStats . sessions ) : 0 ,
796+ avgTokensPerSession : lastMonthStats . sessions > 0 ? Math . round ( lastMonthStats . tokens / lastMonthStats . sessions ) : 0 ,
797+ modelUsage : lastMonthStats . modelUsage ,
798+ editorUsage : lastMonthStats . editorUsage ,
799+ co2 : lastMonthCo2 ,
800+ treesEquivalent : lastMonthCo2 / this . co2AbsorptionPerTreePerYear ,
801+ waterUsage : lastMonthWater ,
802+ estimatedCost : lastMonthCost
803+ } ,
763804 lastUpdated : now
764805 } ;
765806
@@ -3218,7 +3259,7 @@ class CopilotTokenTracker implements vscode.Disposable {
32183259
32193260 // Handle messages from the webview
32203261 this . diagnosticsPanel . webview . onDidReceiveMessage ( async ( message ) => {
3221- this . log ( `[ DEBUG] Diagnostics webview message: ${ JSON . stringify ( message ) } ` ) ;
3262+ this . log ( `DEBUG Diagnostics webview message: ${ JSON . stringify ( message ) } ` ) ;
32223263 switch ( message . command ) {
32233264 case 'copyReport' :
32243265 await vscode . env . clipboard . writeText ( report ) ;
@@ -3278,7 +3319,7 @@ class CopilotTokenTracker implements vscode.Disposable {
32783319 await this . showUsageAnalysis ( ) ;
32793320 break ;
32803321 case 'clearCache' :
3281- this . log ( '[ DEBUG] clearCache message received from diagnostics webview' ) ;
3322+ this . log ( 'DEBUG clearCache message received from diagnostics webview' ) ;
32823323 await this . clearCache ( ) ;
32833324 // After clearing cache, refresh the diagnostic report if it's open
32843325 if ( this . diagnosticsPanel ) {
0 commit comments