Skip to content

Commit 66848b6

Browse files
committed
Show data for last month
1 parent 3062b5b commit 66848b6

3 files changed

Lines changed: 136 additions & 75 deletions

File tree

src/extension.ts

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3750
interface 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

Comments
 (0)