@@ -55,6 +55,7 @@ interface DetailedStats {
5555 today : PeriodStats ;
5656 month : PeriodStats ;
5757 lastMonth : PeriodStats ;
58+ last30Days : PeriodStats ;
5859 lastUpdated : Date ;
5960}
6061
@@ -670,10 +671,13 @@ class CopilotTokenTracker implements vscode.Disposable {
670671 // Calculate last month boundaries
671672 const lastMonthEnd = new Date ( now . getFullYear ( ) , now . getMonth ( ) , 0 , 23 , 59 , 59 , 999 ) ; // Last day of previous month
672673 const lastMonthStart = new Date ( lastMonthEnd . getFullYear ( ) , lastMonthEnd . getMonth ( ) , 1 ) ;
674+ // Calculate last 30 days boundary
675+ const last30DaysStart = new Date ( now . getTime ( ) - 30 * 24 * 60 * 60 * 1000 ) ;
673676
674677 const todayStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
675678 const monthStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
676679 const lastMonthStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
680+ const last30DaysStats = { tokens : 0 , sessions : 0 , interactions : 0 , modelUsage : { } as ModelUsage , editorUsage : { } as EditorUsage } ;
677681
678682 try {
679683 // Clean expired cache entries
@@ -701,14 +705,14 @@ class CopilotTokenTracker implements vscode.Disposable {
701705 // Fast check: Get file stats first to avoid processing old files
702706 const fileStats = fs . statSync ( sessionFile ) ;
703707
704- // Skip files modified before last month (quick filter)
708+ // Skip files modified before last 30 days (quick filter)
705709 // This is the main performance optimization - filters out old sessions without reading file content
706- if ( fileStats . mtime < lastMonthStart ) {
710+ if ( fileStats . mtime < last30DaysStart ) {
707711 skippedFiles ++ ;
708712 continue ;
709713 }
710714
711- // For files within current month , check if data is cached to avoid redundant reads
715+ // For files within last 30 days , check if data is cached to avoid redundant reads
712716 const mtime = fileStats . mtime . getTime ( ) ;
713717 const fileSize = fileStats . size ;
714718 const wasCached = this . isCacheValid ( sessionFile , mtime , fileSize ) ;
@@ -732,15 +736,37 @@ class CopilotTokenTracker implements vscode.Disposable {
732736 ? new Date ( details . lastInteraction )
733737 : new Date ( details . modified ) ;
734738
735- if ( lastActivity >= monthStart ) {
739+ // Update cache statistics (do this once per file)
740+ if ( wasCached ) {
741+ cacheHits ++ ;
742+ } else {
743+ cacheMisses ++ ;
744+ }
736745
737- // Update cache statistics
738- if ( wasCached ) {
739- cacheHits ++ ;
740- } else {
741- cacheMisses ++ ;
746+ // Check if activity is within last 30 days
747+ if ( lastActivity >= last30DaysStart ) {
748+ last30DaysStats . tokens += tokens ;
749+ last30DaysStats . sessions += 1 ;
750+ last30DaysStats . interactions += interactions ;
751+
752+ // Add editor usage to last 30 days stats
753+ if ( ! last30DaysStats . editorUsage [ editorType ] ) {
754+ last30DaysStats . editorUsage [ editorType ] = { tokens : 0 , sessions : 0 } ;
755+ }
756+ last30DaysStats . editorUsage [ editorType ] . tokens += tokens ;
757+ last30DaysStats . editorUsage [ editorType ] . sessions += 1 ;
758+
759+ // Add model usage to last 30 days stats
760+ for ( const [ model , usage ] of Object . entries ( modelUsage ) ) {
761+ if ( ! last30DaysStats . modelUsage [ model ] ) {
762+ last30DaysStats . modelUsage [ model ] = { inputTokens : 0 , outputTokens : 0 } ;
763+ }
764+ last30DaysStats . modelUsage [ model ] . inputTokens += usage . inputTokens ;
765+ last30DaysStats . modelUsage [ model ] . outputTokens += usage . outputTokens ;
742766 }
767+ }
743768
769+ if ( lastActivity >= monthStart ) {
744770 monthStats . tokens += tokens ;
745771 monthStats . sessions += 1 ;
746772 monthStats . interactions += interactions ;
@@ -785,12 +811,6 @@ class CopilotTokenTracker implements vscode.Disposable {
785811 }
786812 else if ( lastActivity >= lastMonthStart && lastActivity <= lastMonthEnd ) {
787813 // Session is from last month - only track lastMonth stats
788- if ( wasCached ) {
789- cacheHits ++ ;
790- } else {
791- cacheMisses ++ ;
792- }
793-
794814 lastMonthStats . tokens += tokens ;
795815 lastMonthStats . sessions += 1 ;
796816 lastMonthStats . interactions += interactions ;
@@ -812,15 +832,15 @@ class CopilotTokenTracker implements vscode.Disposable {
812832 }
813833 }
814834 else {
815- // Session is too old (no activity in current or last month ), skip it
835+ // Session is too old (no activity in last 30 days ), skip it
816836 skippedFiles ++ ;
817837 }
818838 } catch ( fileError ) {
819839 this . warn ( `Error processing session file ${ sessionFile } : ${ fileError } ` ) ;
820840 }
821841 }
822842
823- this . log ( `✅ Analysis complete: Today ${ todayStats . sessions } sessions, Month ${ monthStats . sessions } sessions, Last Month ${ lastMonthStats . sessions } sessions` ) ;
843+ this . log ( `✅ Analysis complete: Today ${ todayStats . sessions } sessions, Month ${ monthStats . sessions } sessions, Last 30 Days ${ last30DaysStats . sessions } sessions, Last Month ${ lastMonthStats . sessions } sessions` ) ;
824844 if ( skippedFiles > 0 ) {
825845 this . log ( `⏭️ Skipped ${ skippedFiles } session file(s) (empty or no activity in recent months)` ) ;
826846 }
@@ -833,14 +853,17 @@ class CopilotTokenTracker implements vscode.Disposable {
833853 const todayCo2 = ( todayStats . tokens / 1000 ) * this . co2Per1kTokens ;
834854 const monthCo2 = ( monthStats . tokens / 1000 ) * this . co2Per1kTokens ;
835855 const lastMonthCo2 = ( lastMonthStats . tokens / 1000 ) * this . co2Per1kTokens ;
856+ const last30DaysCo2 = ( last30DaysStats . tokens / 1000 ) * this . co2Per1kTokens ;
836857
837858 const todayWater = ( todayStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
838859 const monthWater = ( monthStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
839860 const lastMonthWater = ( lastMonthStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
861+ const last30DaysWater = ( last30DaysStats . tokens / 1000 ) * this . waterUsagePer1kTokens ;
840862
841863 const todayCost = this . calculateEstimatedCost ( todayStats . modelUsage ) ;
842864 const monthCost = this . calculateEstimatedCost ( monthStats . modelUsage ) ;
843865 const lastMonthCost = this . calculateEstimatedCost ( lastMonthStats . modelUsage ) ;
866+ const last30DaysCost = this . calculateEstimatedCost ( last30DaysStats . modelUsage ) ;
844867
845868 const result : DetailedStats = {
846869 today : {
@@ -879,6 +902,18 @@ class CopilotTokenTracker implements vscode.Disposable {
879902 waterUsage : lastMonthWater ,
880903 estimatedCost : lastMonthCost
881904 } ,
905+ last30Days : {
906+ tokens : last30DaysStats . tokens ,
907+ sessions : last30DaysStats . sessions ,
908+ avgInteractionsPerSession : last30DaysStats . sessions > 0 ? Math . round ( last30DaysStats . interactions / last30DaysStats . sessions ) : 0 ,
909+ avgTokensPerSession : last30DaysStats . sessions > 0 ? Math . round ( last30DaysStats . tokens / last30DaysStats . sessions ) : 0 ,
910+ modelUsage : last30DaysStats . modelUsage ,
911+ editorUsage : last30DaysStats . editorUsage ,
912+ co2 : last30DaysCo2 ,
913+ treesEquivalent : last30DaysCo2 / this . co2AbsorptionPerTreePerYear ,
914+ waterUsage : last30DaysWater ,
915+ estimatedCost : last30DaysCost
916+ } ,
882917 lastUpdated : now
883918 } ;
884919
0 commit comments