@@ -42,16 +42,7 @@ interface ResolveSymbolPayload {
4242}
4343
4444interface FindReferencesPayload {
45- symbol : {
46- name : string ;
47- location : {
48- file : string ;
49- line : number ;
50- column : number ;
51- context : string ;
52- } ;
53- extra : any ;
54- } ;
45+ symbol : SymbolDef ;
5546}
5647
5748interface ResponsePayload {
@@ -60,14 +51,41 @@ interface ResponsePayload {
6051 data ?: any ;
6152}
6253
54+ // 💡: Corresponds to `dialectic_mcp_server::ide::SymbolRef` in the Rust code
55+ interface SymbolDef {
56+ name : String ,
57+ kind ?: String ,
58+ definedAt : FileRange ,
59+ }
60+
61+ // 💡: Corresponds to `dialectic_mcp_server::ide::SymbolRef` in the Rust code
62+ interface SymbolRef {
63+ definition : SymbolDef ,
64+ referencedAt : FileLocation ,
65+ }
66+
67+ // 💡: Corresponds to `dialectic_mcp_server::ide::FileRange` in the Rust code
68+ interface FileRange {
69+ path : string ,
70+ start : FileLocation ,
71+ end : FileLocation ,
72+ content ?: string ,
73+ }
74+
75+ // 💡: Corresponds to `dialectic_mcp_server::ide::FileLocation` in the Rust code
76+ interface FileLocation {
77+ line : number , // 💡: 1-based, vscode is 0-based
78+ column : number , // 💡: 1-based, vscode is 0-based
79+ }
80+
6381// 💡: Daemon client for connecting to message bus
6482class DaemonClient implements vscode . Disposable {
6583 private socket : net . Socket | null = null ;
6684 private reconnectTimer : NodeJS . Timeout | null = null ;
6785 private isDisposed = false ;
6886 private buffer = '' ;
6987 private readonly RECONNECT_INTERVAL_MS = 5000 ; // 5 seconds
70-
88+
7189 // Terminal registry: track active shell PIDs with MCP servers
7290 private activeTerminals : Set < number > = new Set ( ) ;
7391
@@ -199,7 +217,7 @@ class DaemonClient implements vscode.Disposable {
199217 // Handle Polo messages - MCP server announcing presence
200218 try {
201219 this . outputChannel . appendLine ( `[DISCOVERY] MCP server connected in terminal PID ${ message . shellPid } ` ) ;
202-
220+
203221 // Add to terminal registry for Ask Socratic Shell integration
204222 this . activeTerminals . add ( message . shellPid ) ;
205223 this . outputChannel . appendLine ( `[REGISTRY] Active terminals: [${ Array . from ( this . activeTerminals ) . join ( ', ' ) } ]` ) ;
@@ -210,7 +228,7 @@ class DaemonClient implements vscode.Disposable {
210228 // Handle Goodbye messages - MCP server announcing departure
211229 try {
212230 this . outputChannel . appendLine ( `[DISCOVERY] MCP server disconnected from terminal PID ${ message . shellPid } ` ) ;
213-
231+
214232 // Remove from terminal registry for Ask Socratic Shell integration
215233 this . activeTerminals . delete ( message . shellPid ) ;
216234 this . outputChannel . appendLine ( `[REGISTRY] Active terminals: [${ Array . from ( this . activeTerminals ) . join ( ', ' ) } ]` ) ;
@@ -226,10 +244,10 @@ class DaemonClient implements vscode.Disposable {
226244 const symbolPayload = message . payload as ResolveSymbolPayload ;
227245
228246 this . outputChannel . appendLine ( `[LSP] Resolving symbol: ${ symbolPayload . name } ` ) ;
229-
247+
230248 // Call VSCode's LSP to find symbol definitions
231249 const symbols = await this . resolveSymbolByName ( symbolPayload . name ) ;
232-
250+
233251 this . sendResponse ( message . id , {
234252 success : true ,
235253 data : symbols
@@ -247,10 +265,10 @@ class DaemonClient implements vscode.Disposable {
247265 const referencesPayload = message . payload as FindReferencesPayload ;
248266
249267 this . outputChannel . appendLine ( `[LSP] Finding references for symbol: ${ referencesPayload . symbol . name } ` ) ;
250-
268+
251269 // Call VSCode's LSP to find all references
252270 const references = await this . findAllReferences ( referencesPayload . symbol ) ;
253-
271+
254272 this . sendResponse ( message . id , {
255273 success : true ,
256274 data : references
@@ -346,16 +364,17 @@ class DaemonClient implements vscode.Disposable {
346364 } ;
347365 }
348366
349- private sendResponse ( messageId : string , response : { success : boolean ; error ?: string ; data ?: any } ) : void {
367+ private sendResponse ( messageId : string , response : ResponsePayload ) : void {
350368 if ( ! this . socket || this . socket . destroyed ) {
351369 this . outputChannel . appendLine ( `Cannot send response - socket not connected` ) ;
352370 return ;
353371 }
354372
355- const responseMessage = {
373+ const responseMessage : IPCMessage = {
356374 type : 'response' ,
357375 payload : response ,
358- id : messageId
376+ id : messageId ,
377+ shellPid : 0 ,
359378 } ;
360379
361380 try {
@@ -414,7 +433,7 @@ class DaemonClient implements vscode.Disposable {
414433 /**
415434 * Resolve symbol by name using VSCode's LSP
416435 */
417- private async resolveSymbolByName ( symbolName : string ) : Promise < any [ ] > {
436+ private async resolveSymbolByName ( symbolName : string ) : Promise < SymbolDef [ ] > {
418437 try {
419438 // Get all workspace symbols matching the name
420439 const symbols = await vscode . commands . executeCommand < vscode . SymbolInformation [ ] > (
@@ -427,19 +446,7 @@ class DaemonClient implements vscode.Disposable {
427446 }
428447
429448 // Convert VSCode symbols to our format
430- const resolvedSymbols = symbols . map ( symbol => ( {
431- name : symbol . name ,
432- location : {
433- file : vscode . workspace . asRelativePath ( symbol . location . uri ) ,
434- line : symbol . location . range . start . line + 1 , // Convert to 1-based
435- column : symbol . location . range . start . character , // Keep 0-based
436- context : this . getContextAroundLocation ( symbol . location . uri , symbol . location . range . start . line )
437- } ,
438- extra : {
439- kind : vscode . SymbolKind [ symbol . kind ] ,
440- containerName : symbol . containerName
441- }
442- } ) ) ;
449+ const resolvedSymbols : SymbolDef [ ] = symbols . map ( symbol => this . vscodeSymbolToSymbolDef ( symbol ) ) ;
443450
444451 return resolvedSymbols ;
445452 } catch ( error ) {
@@ -448,67 +455,85 @@ class DaemonClient implements vscode.Disposable {
448455 }
449456 }
450457
458+ private vscodeSymbolToSymbolDef ( symbol : vscode . SymbolInformation ) : SymbolDef {
459+ let definedAt = symbol . location
460+ let result : SymbolDef = {
461+ name : symbol . name ,
462+ definedAt : this . vscodeLocationToRange ( symbol . location ) ,
463+ } ;
464+
465+ switch ( symbol . kind ) {
466+ case vscode . SymbolKind . File : result . kind = "File" ; break ;
467+ case vscode . SymbolKind . Module : result . kind = "Module" ; break ;
468+ case vscode . SymbolKind . Namespace : result . kind = "Namespace" ; break ;
469+ case vscode . SymbolKind . Package : result . kind = "Package" ; break ;
470+ case vscode . SymbolKind . Class : result . kind = "Class" ; break ;
471+ case vscode . SymbolKind . Method : result . kind = "Method" ; break ;
472+ case vscode . SymbolKind . Property : result . kind = "Property" ; break ;
473+ case vscode . SymbolKind . Field : result . kind = "Field" ; break ;
474+ case vscode . SymbolKind . Constructor : result . kind = "Constructor" ; break ;
475+ case vscode . SymbolKind . Enum : result . kind = "Enum" ; break ;
476+ case vscode . SymbolKind . Interface : result . kind = "Interface" ; break ;
477+ case vscode . SymbolKind . Function : result . kind = "Function" ; break ;
478+ case vscode . SymbolKind . Variable : result . kind = "Variable" ; break ;
479+ case vscode . SymbolKind . Constant : result . kind = "Constant" ; break ;
480+ case vscode . SymbolKind . String : result . kind = "String" ; break ;
481+ case vscode . SymbolKind . Number : result . kind = "Number" ; break ;
482+ case vscode . SymbolKind . Boolean : result . kind = "Boolean" ; break ;
483+ case vscode . SymbolKind . Array : result . kind = "Array" ; break ;
484+ case vscode . SymbolKind . Object : result . kind = "Object" ; break ;
485+ case vscode . SymbolKind . Key : result . kind = "Key" ; break ;
486+ case vscode . SymbolKind . Null : result . kind = "Null" ; break ;
487+ case vscode . SymbolKind . EnumMember : result . kind = "EnumMember" ; break ;
488+ case vscode . SymbolKind . Struct : result . kind = "Struct" ; break ;
489+ case vscode . SymbolKind . Event : result . kind = "Event" ; break ;
490+ case vscode . SymbolKind . Operator : result . kind = "Operator" ; break ;
491+ case vscode . SymbolKind . TypeParameter : result . kind = "TypeParameter" ; break ;
492+ }
493+
494+ return result ;
495+ }
496+
497+ private vscodeLocationToRange ( location : vscode . Location ) : FileRange {
498+ return {
499+ path : location . uri . fsPath ,
500+ start : {
501+ line : location . range . start . line + 1 ,
502+ column : location . range . start . character + 1 ,
503+ } ,
504+ end : {
505+ line : location . range . end . line + 1 ,
506+ column : location . range . end . character + 1 ,
507+ } ,
508+ } ;
509+ }
510+
511+
451512 /**
452513 * Find all references to a symbol using VSCode's LSP
453514 */
454- private async findAllReferences ( symbol : any ) : Promise < any [ ] > {
515+ private async findAllReferences ( symbol : SymbolDef ) : Promise < FileRange [ ] > {
455516 try {
456517 // Convert relative path back to URI
457518 const workspaceFolder = vscode . workspace . workspaceFolders ?. [ 0 ] ;
458519 if ( ! workspaceFolder ) {
459520 throw new Error ( 'No workspace folder found' ) ;
460521 }
461522
462- const fileUri = vscode . Uri . joinPath ( workspaceFolder . uri , symbol . location . file ) ;
463- const position = new vscode . Position (
464- symbol . location . line - 1 , // Convert from 1-based to 0-based
465- symbol . location . column // Already 0-based
466- ) ;
467-
468523 // Find all references using LSP
469- const references = await vscode . commands . executeCommand < vscode . Location [ ] > (
524+ const locations = await vscode . commands . executeCommand < vscode . Location [ ] > (
470525 'vscode.executeReferenceProvider' ,
471- fileUri ,
472- position
526+ vscode . Uri . joinPath ( workspaceFolder . uri , symbol . definedAt . path ) ,
527+ new vscode . Position ( symbol . definedAt . start . line - 1 , symbol . definedAt . start . column - 1 )
473528 ) ;
474529
475- if ( ! references || references . length === 0 ) {
476- return [ ] ;
477- }
478-
479- // Convert VSCode locations to our format
480- const referenceLocations = references . map ( ref => ( {
481- file : vscode . workspace . asRelativePath ( ref . uri ) ,
482- line : ref . range . start . line + 1 , // Convert to 1-based
483- column : ref . range . start . character , // Keep 0-based
484- context : this . getContextAroundLocation ( ref . uri , ref . range . start . line )
485- } ) ) ;
486-
487- return referenceLocations ;
530+ return locations . map ( location => this . vscodeLocationToRange ( location ) ) ;
488531 } catch ( error ) {
489532 this . outputChannel . appendLine ( `Error in findAllReferences: ${ error } ` ) ;
490533 throw error ;
491534 }
492535 }
493536
494- /**
495- * Get context around a specific location for display purposes
496- */
497- private getContextAroundLocation ( uri : vscode . Uri , line : number ) : string {
498- try {
499- // Try to get the document if it's already open
500- const document = vscode . workspace . textDocuments . find ( doc => doc . uri . toString ( ) === uri . toString ( ) ) ;
501- if ( document && line < document . lineCount ) {
502- return document . lineAt ( line ) . text . trim ( ) ;
503- }
504-
505- // If document isn't open, return a placeholder
506- return `Line ${ line + 1 } ` ;
507- } catch ( error ) {
508- return `Line ${ line + 1 } ` ;
509- }
510- }
511-
512537 dispose ( ) : void {
513538 this . isDisposed = true ;
514539 this . clearReconnectTimer ( ) ;
@@ -689,10 +714,10 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
689714 terminals . map ( async ( terminal ) => {
690715 // Extract the shell PID from the terminal (async)
691716 const shellPID = await terminal . processId ;
692-
717+
693718 // Log terminal for debugging
694719 outputChannel . appendLine ( ` Checking terminal: "${ terminal . name } " (PID: ${ shellPID } )` ) ;
695-
720+
696721 // Check if this terminal's shell PID is in our active registry
697722 if ( shellPID && activeTerminals . has ( shellPID ) ) {
698723 outputChannel . appendLine ( ` ✅ Terminal "${ terminal . name } " has active MCP server (PID: ${ shellPID } )` ) ;
@@ -721,17 +746,17 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
721746 // 💡: Multiple AI-enabled terminals - show picker UI with memory
722747 if ( aiEnabledTerminals . length > 1 ) {
723748 outputChannel . appendLine ( `Multiple AI-enabled terminals found: ${ aiEnabledTerminals . length } ` ) ;
724-
749+
725750 // Get previously selected terminal PID from workspace state
726751 const lastSelectedPID = context . workspaceState . get < number > ( 'dialectic.lastSelectedTerminalPID' ) ;
727752 outputChannel . appendLine ( `Last selected terminal PID: ${ lastSelectedPID } ` ) ;
728-
753+
729754 // Create picker items with terminal info
730755 interface TerminalQuickPickItem extends vscode . QuickPickItem {
731756 terminal : vscode . Terminal ;
732757 pid : number | undefined ;
733758 }
734-
759+
735760 const terminalItems : TerminalQuickPickItem [ ] = await Promise . all (
736761 aiEnabledTerminals . map ( async ( terminal ) : Promise < TerminalQuickPickItem > => {
737762 const pid = await terminal . processId ;
@@ -750,10 +775,10 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
750775
751776 // Find the last selected terminal for the quick option
752777 const lastSelectedItem = terminalItems . find ( item => item . pid === lastSelectedPID ) ;
753-
778+
754779 // Create picker items with optional "use last" entry at top
755780 const pickerItems : TerminalQuickPickItem [ ] = [ ] ;
756-
781+
757782 // Add "use last terminal" option if we have a previous selection
758783 if ( lastSelectedItem ) {
759784 pickerItems . push ( {
@@ -763,7 +788,7 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
763788 terminal : lastSelectedItem . terminal ,
764789 pid : lastSelectedItem . pid
765790 } ) ;
766-
791+
767792 // Add separator
768793 pickerItems . push ( {
769794 label : '$(dash) All available terminals' ,
@@ -774,13 +799,13 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
774799 kind : vscode . QuickPickItemKind . Separator
775800 } ) ;
776801 }
777-
802+
778803 // Add all terminals (keeping natural order)
779804 pickerItems . push ( ...terminalItems ) ;
780805
781806 // Show the picker to user
782807 const selectedItem = await vscode . window . showQuickPick ( pickerItems , {
783- placeHolder : lastSelectedItem
808+ placeHolder : lastSelectedItem
784809 ? 'Select terminal for AI chat (first option = quick access to last used)'
785810 : 'Select terminal for AI chat' ,
786811 title : 'Multiple AI-enabled terminals found'
@@ -792,13 +817,13 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
792817 outputChannel . appendLine ( 'User selected separator or invalid item, ignoring' ) ;
793818 return null ;
794819 }
795-
820+
796821 outputChannel . appendLine ( `User selected terminal: ${ selectedItem . terminal . name } (PID: ${ selectedItem . pid } )` ) ;
797-
822+
798823 // Remember this selection for next time
799824 await context . workspaceState . update ( 'dialectic.lastSelectedTerminalPID' , selectedItem . pid ) ;
800825 outputChannel . appendLine ( `Saved terminal PID ${ selectedItem . pid } as last selected` ) ;
801-
826+
802827 return selectedItem . terminal ;
803828 } else {
804829 outputChannel . appendLine ( 'User cancelled terminal selection' ) ;
@@ -808,7 +833,7 @@ async function findQChatTerminal(outputChannel: vscode.OutputChannel, daemonClie
808833
809834 // 💡: No AI-enabled terminals found - fall back to old logic for compatibility
810835 outputChannel . appendLine ( 'No AI-enabled terminals found, falling back to name-based detection' ) ;
811-
836+
812837 if ( terminals . length === 1 ) {
813838 const terminal = terminals [ 0 ] ;
814839 outputChannel . appendLine ( `Using single terminal (fallback): ${ terminal . name } ` ) ;
0 commit comments