diff --git a/src/extension.ts b/src/extension.ts index 3f7b4fa..9d1eab2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -102,13 +102,14 @@ interface ModeUsage { } interface ContextReferenceUsage { - file: number; // #file references - selection: number; // #selection references - symbol: number; // #symbol references - codebase: number; // #codebase references - workspace: number; // @workspace references - terminal: number; // @terminal references - vscode: number; // @vscode references + file: number; // #file references + selection: number; // #selection references + implicitSelection: number; // Implicit selections via inputState.selections + symbol: number; // #symbol references + codebase: number; // #codebase references + workspace: number; // @workspace references + terminal: number; // @terminal references + vscode: number; // @vscode references } interface McpToolUsage { @@ -194,7 +195,7 @@ interface SessionLogData { class CopilotTokenTracker implements vscode.Disposable { // Cache version - increment this when making changes that require cache invalidation - private static readonly CACHE_VERSION = 8; // Skip sessions with 0 models in avg calculation (2026-02-02) + private static readonly CACHE_VERSION = 9; // Added implicitSelection to ContextReferenceUsage (2026-02-02) private diagnosticsPanel?: vscode.WebviewPanel; // Tracks whether the diagnostics panel has already received its session files @@ -980,6 +981,7 @@ class CopilotTokenTracker implements vscode.Disposable { contextReferences: { file: 0, selection: 0, + implicitSelection: 0, symbol: 0, codebase: 0, workspace: 0, @@ -1079,6 +1081,7 @@ class CopilotTokenTracker implements vscode.Disposable { // Merge context references period.contextReferences.file += analysis.contextReferences.file; period.contextReferences.selection += analysis.contextReferences.selection; + period.contextReferences.implicitSelection += analysis.contextReferences.implicitSelection || 0; period.contextReferences.symbol += analysis.contextReferences.symbol; period.contextReferences.codebase += analysis.contextReferences.codebase; period.contextReferences.workspace += analysis.contextReferences.workspace; @@ -1359,6 +1362,7 @@ class CopilotTokenTracker implements vscode.Disposable { contextReferences: { file: 0, selection: 0, + implicitSelection: 0, symbol: 0, codebase: 0, workspace: 0, @@ -1392,6 +1396,11 @@ class CopilotTokenTracker implements vscode.Disposable { // Handle VS Code incremental format - detect mode from session header if (event.kind === 0 && event.v?.inputState?.mode?.kind) { sessionMode = event.v.inputState.mode.kind; + + // Detect implicit selections in initial state + if (event.v?.inputState?.selections && Array.isArray(event.v.inputState.selections) && event.v.inputState.selections.length > 0) { + analysis.contextReferences.implicitSelection++; + } } // Handle mode changes (kind: 1 with mode update) @@ -1399,6 +1408,11 @@ class CopilotTokenTracker implements vscode.Disposable { sessionMode = event.v.kind; } + // Detect implicit selections in updates to inputState.selections + if (event.kind === 1 && event.k?.includes('selections') && Array.isArray(event.v) && event.v.length > 0) { + analysis.contextReferences.implicitSelection++; + } + // Handle VS Code incremental format - count requests as interactions if (event.kind === 2 && event.k?.[0] === 'requests' && Array.isArray(event.v)) { for (const request of event.v) { @@ -1763,6 +1777,7 @@ class CopilotTokenTracker implements vscode.Disposable { contextReferences: { file: 0, selection: 0, + implicitSelection: 0, symbol: 0, codebase: 0, workspace: 0, @@ -1805,7 +1820,7 @@ class CopilotTokenTracker implements vscode.Disposable { modified: stat.mtime.toISOString(), interactions: 0, contextReferences: { - file: 0, selection: 0, symbol: 0, codebase: 0, + file: 0, selection: 0, implicitSelection: 0, symbol: 0, codebase: 0, workspace: 0, terminal: 0, vscode: 0 }, firstInteraction: null, @@ -2266,7 +2281,7 @@ class CopilotTokenTracker implements vscode.Disposable { */ private createEmptyContextRefs(): ContextReferenceUsage { return { - file: 0, selection: 0, symbol: 0, codebase: 0, + file: 0, selection: 0, implicitSelection: 0, symbol: 0, codebase: 0, workspace: 0, terminal: 0, vscode: 0 }; } diff --git a/src/webview/usage/main.ts b/src/webview/usage/main.ts index 925c621..37511a9 100644 --- a/src/webview/usage/main.ts +++ b/src/webview/usage/main.ts @@ -6,6 +6,7 @@ type ModeUsage = { ask: number; edit: number; agent: number }; type ContextReferenceUsage = { file: number; selection: number; + implicitSelection: number; symbol: number; codebase: number; workspace: number; @@ -67,7 +68,7 @@ function escapeHtml(text: string): string { } function getTotalContextRefs(refs: ContextReferenceUsage): number { - return refs.file + refs.selection + refs.symbol + refs.codebase + + return refs.file + refs.selection + refs.implicitSelection + refs.symbol + refs.codebase + refs.workspace + refs.terminal + refs.vscode; } @@ -205,6 +206,7 @@ function renderLayout(stats: UsageAnalysisStats): void { padding: 12px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } + .stat-card[title] { cursor: help; } .stat-label { font-size: 11px; color: #b8b8b8; margin-bottom: 4px; } .stat-value { font-size: 20px; font-weight: 700; color: #f6f6f6; } .bar-chart { @@ -320,6 +322,7 @@ function renderLayout(stats: UsageAnalysisStats): void {
📄 #file
${stats.month.contextReferences.file}
Today: ${stats.today.contextReferences.file}
✂️ #selection
${stats.month.contextReferences.selection}
Today: ${stats.today.contextReferences.selection}
+
✨ Implicit Selection
${stats.month.contextReferences.implicitSelection}
Today: ${stats.today.contextReferences.implicitSelection}
🔤 #symbol
${stats.month.contextReferences.symbol}
Today: ${stats.today.contextReferences.symbol}
🗂️ #codebase
${stats.month.contextReferences.codebase}
Today: ${stats.today.contextReferences.codebase}
📁 @workspace
${stats.month.contextReferences.workspace}
Today: ${stats.today.contextReferences.workspace}