@@ -22,7 +22,13 @@ import {
2222 type ResolvedDeepcodingSettings ,
2323 setShellIfWindows ,
2424} from "@vegamo/deepcode-core" ;
25- import { collectPromptImageUrls , getNonce , isAllowedExternalUrl } from "./utils.js" ;
25+ import {
26+ collectPromptImageUrls ,
27+ formatContextStatus ,
28+ formatTokenCount ,
29+ getNonce ,
30+ isAllowedExternalUrl ,
31+ } from "./utils.js" ;
2632import { handleWebviewMessage , postUndoState , releaseQueueEdit } from "./provider.js" ;
2733import { createSharpLoader } from "./sharp-loader.js" ;
2834import { prepareToolDiffContent } from "./tool-diff.js" ;
@@ -34,6 +40,24 @@ type ReasoningMessageParams = {
3440 reasoning_content ?: string ;
3541} ;
3642
43+ type TokenUsage = {
44+ prompt_tokens ?: number ;
45+ completion_tokens ?: number ;
46+ prompt_cache_hit_tokens ?: number ;
47+ prompt_tokens_details ?: { cached_tokens ?: number } ;
48+ completion_tokens_details ?: { reasoning_tokens ?: number } ;
49+ } ;
50+
51+ type TokenTelemetry = {
52+ model : string ;
53+ thinkingEnabled : boolean ;
54+ reasoningEffort : ReasoningEffort ;
55+ activeTokens : number ;
56+ contextWindow : number ;
57+ compactPromptTokenThreshold : number ;
58+ usage : unknown | null ;
59+ } ;
60+
3761export class DeepCodeViewProvider implements vscode . WebviewViewProvider {
3862 public static readonly viewType = "deepcode.chatView" ;
3963
@@ -42,6 +66,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
4266 private readonly md : MarkdownIt ;
4367 private readonly sessionManager : SessionManager ;
4468 private unsubscribeRuntime ?: ( ) => void ;
69+ private readonly statusBar : vscode . StatusBarItem ;
4570
4671 constructor ( context : vscode . ExtensionContext ) {
4772 this . context = context ;
@@ -50,6 +75,12 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
5075 linkify : false ,
5176 breaks : true ,
5277 } ) ;
78+ this . statusBar = vscode . window . createStatusBarItem ( vscode . StatusBarAlignment . Right , 100 ) ;
79+ this . statusBar . name = "Deep Code" ;
80+ this . statusBar . command = "deepcode.openView" ;
81+ this . statusBar . text = "$(comment-discussion) Deep Code" ;
82+ this . statusBar . tooltip = "Open Deep Code" ;
83+ this . statusBar . show ( ) ;
5384 this . sessionManager = new SessionManager ( {
5485 projectRoot : this . getWorkspaceRoot ( ) ,
5586 loadSharp : createSharpLoader ( {
@@ -103,6 +134,8 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
103134 } ) ;
104135 } ,
105136 onSessionEntryUpdated : ( entry ) => {
137+ const tokenTelemetry = this . buildTokenTelemetry ( entry ) ;
138+ this . updateStatusBar ( tokenTelemetry ) ;
106139 if ( ! this . webviewView ) {
107140 return ;
108141 }
@@ -114,7 +147,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
114147 pluginRateLimitedTool : entry . pluginRateLimitedTool ?? null ,
115148 askPermissions : entry . askPermissions ,
116149 processes : this . serializeProcesses ( entry . processes ) ,
117- tokenTelemetry : this . buildTokenTelemetry ( entry ) ,
150+ tokenTelemetry,
118151 } ) ;
119152 } ,
120153 onLlmStreamProgress : ( progress : LlmStreamProgress ) => {
@@ -143,6 +176,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
143176 }
144177
145178 dispose ( ) : void {
179+ this . statusBar . dispose ( ) ;
146180 this . unsubscribeRuntime ?.( ) ;
147181 releaseQueueEdit ( this . sessionManager ) ;
148182 this . sessionManager . dispose ( ) ;
@@ -157,6 +191,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
157191 if ( this . webviewView === webviewView ) this . webviewView = undefined ;
158192 releaseQueueEdit ( this . sessionManager ) ;
159193 } ) ;
194+ this . refreshStatusBar ( ) ;
160195
161196 webviewView . webview . options = {
162197 enableScripts : true ,
@@ -191,6 +226,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
191226 renderMarkdown : ( text ) => this . md . render ( text ) ,
192227 copyToClipboard : ( text ) => void vscode . env . clipboard . writeText ( text ) ,
193228 } ) ;
229+ this . refreshStatusBar ( ) ;
194230
195231 if ( ! handled ) {
196232 // unrecognized message type — no-op
@@ -512,15 +548,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
512548 } ;
513549 }
514550
515- private buildTokenTelemetry ( session : SessionEntry | null ) : {
516- model : string ;
517- thinkingEnabled : boolean ;
518- reasoningEffort : ReasoningEffort ;
519- activeTokens : number ;
520- contextWindow : number ;
521- compactPromptTokenThreshold : number ;
522- usage : unknown | null ;
523- } {
551+ private buildTokenTelemetry ( session : SessionEntry | null ) : TokenTelemetry {
524552 const settings = this . resolveCurrentSettings ( ) ;
525553 return {
526554 model : settings . model ,
@@ -533,6 +561,38 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider {
533561 } ;
534562 }
535563
564+ private refreshStatusBar ( ) : void {
565+ const sessionId = this . sessionManager . getActiveSessionId ( ) ;
566+ const session = sessionId ? this . sessionManager . getSession ( sessionId ) : null ;
567+ this . updateStatusBar ( this . buildTokenTelemetry ( session ) ) ;
568+ }
569+
570+ private updateStatusBar ( telemetry : TokenTelemetry ) : void {
571+ const activeTokens = Number . isFinite ( telemetry . activeTokens ) ? Math . max ( 0 , telemetry . activeTokens ) : 0 ;
572+ const contextWindow = Number . isFinite ( telemetry . contextWindow ) ? Math . max ( 0 , telemetry . contextWindow ) : 0 ;
573+ const usage = ( telemetry . usage ?? { } ) as TokenUsage ;
574+ const promptTokens = Number ( usage . prompt_tokens ?? 0 ) ;
575+ const completionTokens = Number ( usage . completion_tokens ?? 0 ) ;
576+ const cachedTokens = Number ( usage . prompt_tokens_details ?. cached_tokens ?? usage . prompt_cache_hit_tokens ?? 0 ) ;
577+ const reasoningTokens = Number ( usage . completion_tokens_details ?. reasoning_tokens ?? 0 ) ;
578+
579+ if ( activeTokens === 0 && promptTokens === 0 && completionTokens === 0 ) {
580+ this . statusBar . text = "$(comment-discussion) Deep Code" ;
581+ this . statusBar . tooltip = "Open Deep Code" ;
582+ return ;
583+ }
584+
585+ this . statusBar . text = `$(comment-discussion) ${ formatContextStatus ( activeTokens , contextWindow ) } ` ;
586+ const tooltip = new vscode . MarkdownString ( ) ;
587+ tooltip . appendMarkdown ( `**Deep Code** · ${ telemetry . model } \n\n` ) ;
588+ tooltip . appendMarkdown ( `Context: ${ formatContextStatus ( activeTokens , contextWindow ) } \n\n` ) ;
589+ tooltip . appendMarkdown ( `Prompt: ${ formatTokenCount ( promptTokens ) } \n` ) ;
590+ tooltip . appendMarkdown ( `Completion: ${ formatTokenCount ( completionTokens ) } \n` ) ;
591+ tooltip . appendMarkdown ( `Cached: ${ formatTokenCount ( cachedTokens ) } \n` ) ;
592+ tooltip . appendMarkdown ( `Reasoning: ${ formatTokenCount ( reasoningTokens ) } ` ) ;
593+ this . statusBar . tooltip = tooltip ;
594+ }
595+
536596 private async initializeMcpServers ( ) : Promise < void > {
537597 try {
538598 await this . sessionManager . initMcpServers ( this . resolveCurrentSettings ( ) . mcpServers ) ;
0 commit comments