From 139a0c43ea439d11e97f150ad49c2f29cf54fdc5 Mon Sep 17 00:00:00 2001 From: Rob Bos Date: Thu, 15 Jan 2026 23:17:50 +0100 Subject: [PATCH] Update model colors --- src/extension.ts | 348 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 338 insertions(+), 10 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index bcccd5d..9d71f08 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,6 +25,13 @@ interface ModelPricing { category?: string; } +interface EditorUsage { + [editorType: string]: { + tokens: number; + sessions: number; + }; +} + interface DetailedStats { today: { tokens: number; @@ -32,6 +39,7 @@ interface DetailedStats { avgInteractionsPerSession: number; avgTokensPerSession: number; modelUsage: ModelUsage; + editorUsage: EditorUsage; co2: number; treesEquivalent: number; waterUsage: number; @@ -43,6 +51,7 @@ interface DetailedStats { avgInteractionsPerSession: number; avgTokensPerSession: number; modelUsage: ModelUsage; + editorUsage: EditorUsage; co2: number; treesEquivalent: number; waterUsage: number; @@ -57,6 +66,7 @@ interface DailyTokenStats { sessions: number; interactions: number; modelUsage: ModelUsage; + editorUsage: EditorUsage; } interface SessionFileCache { @@ -97,6 +107,41 @@ class CopilotTokenTracker implements vscode.Disposable { return repoUrl || 'https://github.com/rajbos/github-copilot-token-usage'; } + /** + * Determine the editor type from a session file path + * Returns: 'VS Code', 'VS Code Insiders', 'VSCodium', 'Cursor', 'Copilot CLI', or 'Unknown' + */ + private getEditorTypeFromPath(filePath: string): string { + const normalizedPath = filePath.toLowerCase().replace(/\\/g, '/'); + + if (normalizedPath.includes('/.copilot/session-state/')) { + return 'Copilot CLI'; + } + if (normalizedPath.includes('/code - insiders/') || normalizedPath.includes('/code%20-%20insiders/')) { + return 'VS Code Insiders'; + } + if (normalizedPath.includes('/code - exploration/') || normalizedPath.includes('/code%20-%20exploration/')) { + return 'VS Code Exploration'; + } + if (normalizedPath.includes('/vscodium/')) { + return 'VSCodium'; + } + if (normalizedPath.includes('/cursor/')) { + return 'Cursor'; + } + if (normalizedPath.includes('.vscode-server-insiders/')) { + return 'VS Code Server (Insiders)'; + } + if (normalizedPath.includes('.vscode-server/') || normalizedPath.includes('.vscode-remote/')) { + return 'VS Code Server'; + } + if (normalizedPath.includes('/code/')) { + return 'VS Code'; + } + + return 'Unknown'; + } + // Logging methods public log(message: string): void { const timestamp = new Date().toLocaleTimeString(); @@ -351,8 +396,8 @@ class CopilotTokenTracker implements vscode.Disposable { const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const monthStart = new Date(now.getFullYear(), now.getMonth(), 1); - const todayStats = { tokens: 0, sessions: 0, interactions: 0, modelUsage: {} as ModelUsage }; - const monthStats = { tokens: 0, sessions: 0, interactions: 0, modelUsage: {} as ModelUsage }; + const todayStats = { tokens: 0, sessions: 0, interactions: 0, modelUsage: {} as ModelUsage, editorUsage: {} as EditorUsage }; + const monthStats = { tokens: 0, sessions: 0, interactions: 0, modelUsage: {} as ModelUsage, editorUsage: {} as EditorUsage }; try { // Clean expired cache entries @@ -385,6 +430,7 @@ class CopilotTokenTracker implements vscode.Disposable { const tokens = await this.estimateTokensFromSessionCached(sessionFile, fileStats.mtime.getTime()); const interactions = await this.countInteractionsInSessionCached(sessionFile, fileStats.mtime.getTime()); const modelUsage = await this.getModelUsageFromSessionCached(sessionFile, fileStats.mtime.getTime()); + const editorType = this.getEditorTypeFromPath(sessionFile); // Update cache statistics if (wasCached) { @@ -393,12 +439,19 @@ class CopilotTokenTracker implements vscode.Disposable { cacheMisses++; } - this.log(`Session ${path.basename(sessionFile)}: ${tokens} tokens, ${interactions} interactions`); + this.log(`Session ${path.basename(sessionFile)}: ${tokens} tokens, ${interactions} interactions, editor: ${editorType}`); monthStats.tokens += tokens; monthStats.sessions += 1; monthStats.interactions += interactions; + // Add editor usage to month stats + if (!monthStats.editorUsage[editorType]) { + monthStats.editorUsage[editorType] = { tokens: 0, sessions: 0 }; + } + monthStats.editorUsage[editorType].tokens += tokens; + monthStats.editorUsage[editorType].sessions += 1; + // Add model usage to month stats for (const [model, usage] of Object.entries(modelUsage)) { if (!monthStats.modelUsage[model]) { @@ -413,6 +466,13 @@ class CopilotTokenTracker implements vscode.Disposable { todayStats.sessions += 1; todayStats.interactions += interactions; + // Add editor usage to today stats + if (!todayStats.editorUsage[editorType]) { + todayStats.editorUsage[editorType] = { tokens: 0, sessions: 0 }; + } + todayStats.editorUsage[editorType].tokens += tokens; + todayStats.editorUsage[editorType].sessions += 1; + // Add model usage to today stats for (const [model, usage] of Object.entries(modelUsage)) { if (!todayStats.modelUsage[model]) { @@ -449,6 +509,7 @@ class CopilotTokenTracker implements vscode.Disposable { avgInteractionsPerSession: todayStats.sessions > 0 ? Math.round(todayStats.interactions / todayStats.sessions) : 0, avgTokensPerSession: todayStats.sessions > 0 ? Math.round(todayStats.tokens / todayStats.sessions) : 0, modelUsage: todayStats.modelUsage, + editorUsage: todayStats.editorUsage, co2: todayCo2, treesEquivalent: todayCo2 / this.co2AbsorptionPerTreePerYear, waterUsage: todayWater, @@ -460,6 +521,7 @@ class CopilotTokenTracker implements vscode.Disposable { avgInteractionsPerSession: monthStats.sessions > 0 ? Math.round(monthStats.interactions / monthStats.sessions) : 0, avgTokensPerSession: monthStats.sessions > 0 ? Math.round(monthStats.tokens / monthStats.sessions) : 0, modelUsage: monthStats.modelUsage, + editorUsage: monthStats.editorUsage, co2: monthCo2, treesEquivalent: monthCo2 / this.co2AbsorptionPerTreePerYear, waterUsage: monthWater, @@ -498,6 +560,7 @@ class CopilotTokenTracker implements vscode.Disposable { const tokens = await this.estimateTokensFromSessionCached(sessionFile, fileStats.mtime.getTime()); const interactions = await this.countInteractionsInSessionCached(sessionFile, fileStats.mtime.getTime()); const modelUsage = await this.getModelUsageFromSessionCached(sessionFile, fileStats.mtime.getTime()); + const editorType = this.getEditorTypeFromPath(sessionFile); // Get the date in YYYY-MM-DD format const dateKey = this.formatDateKey(new Date(fileStats.mtime)); @@ -509,7 +572,8 @@ class CopilotTokenTracker implements vscode.Disposable { tokens: 0, sessions: 0, interactions: 0, - modelUsage: {} + modelUsage: {}, + editorUsage: {} }); } @@ -518,6 +582,13 @@ class CopilotTokenTracker implements vscode.Disposable { dailyStats.sessions += 1; dailyStats.interactions += interactions; + // Merge editor usage + if (!dailyStats.editorUsage[editorType]) { + dailyStats.editorUsage[editorType] = { tokens: 0, sessions: 0 }; + } + dailyStats.editorUsage[editorType].tokens += tokens; + dailyStats.editorUsage[editorType].sessions += 1; + // Merge model usage for (const [model, usage] of Object.entries(modelUsage)) { if (!dailyStats.modelUsage[model]) { @@ -1451,6 +1522,8 @@ class CopilotTokenTracker implements vscode.Disposable { + ${this.getEditorUsageHtml(stats)} + ${this.getModelUsageHtml(stats)}
@@ -1487,7 +1560,6 @@ class CopilotTokenTracker implements vscode.Disposable {
-