@@ -7,7 +7,7 @@ import { ReviewWebviewProvider } from './reviewWebview';
77
88// 💡: Types for IPC communication with MCP server
99interface IPCMessage {
10- type : 'present_review' | 'log' | 'get_selection' | 'response' ;
10+ type : 'present_review' | 'log' | 'get_selection' | 'response' | 'marco' | 'polo' | 'goodbye' ;
1111 payload : {
1212 content : string ;
1313 mode : 'replace' | 'update-section' | 'append' ;
@@ -52,6 +52,9 @@ class DaemonClient implements vscode.Disposable {
5252 this . socket . on ( 'connect' , ( ) => {
5353 this . outputChannel . appendLine ( '✅ Connected to message bus daemon' ) ;
5454 this . clearReconnectTimer ( ) ;
55+
56+ // Send Marco broadcast to discover existing MCP servers
57+ this . sendMarco ( ) ;
5558 } ) ;
5659
5760 this . socket . on ( 'error' , ( error ) => {
@@ -98,17 +101,6 @@ class DaemonClient implements vscode.Disposable {
98101 }
99102
100103 private async handleIncomingMessage ( message : IPCMessage ) : Promise < void > {
101- // Extract shell PID from message payload for filtering
102- const shellPid = this . extractShellPidFromMessage ( message ) ;
103-
104- if ( shellPid ) {
105- // Check if this message is intended for our VSCode window
106- const isForOurWindow = await this . isMessageForOurWindow ( shellPid ) ;
107- if ( ! isForOurWindow ) {
108- this . outputChannel . appendLine ( `Debug: Ignoring message from shell PID ${ shellPid } (not in our window)` ) ;
109- return ;
110- }
111- }
112104 if ( message . type === 'present_review' ) {
113105 try {
114106 const reviewPayload = message . payload as {
@@ -119,14 +111,16 @@ class DaemonClient implements vscode.Disposable {
119111 terminal_shell_pid : number ;
120112 } ;
121113
122- this . reviewProvider . updateReview (
123- reviewPayload . content ,
124- reviewPayload . mode ,
125- reviewPayload . baseUri
126- ) ;
114+ if ( await this . isMessageForOurWindow ( reviewPayload . terminal_shell_pid ) ) {
115+ this . reviewProvider . updateReview (
116+ reviewPayload . content ,
117+ reviewPayload . mode ,
118+ reviewPayload . baseUri
119+ ) ;
127120
128- // Send success response back through daemon
129- this . sendResponse ( message . id , { success : true } ) ;
121+ // Send success response back through daemon
122+ this . sendResponse ( message . id , { success : true } ) ;
123+ }
130124 } catch ( error ) {
131125 this . outputChannel . appendLine ( `Error handling present_review: ${ error } ` ) ;
132126 this . sendResponse ( message . id , {
@@ -136,11 +130,17 @@ class DaemonClient implements vscode.Disposable {
136130 }
137131 } else if ( message . type === 'get_selection' ) {
138132 try {
139- const selectionData = this . getCurrentSelection ( ) ;
140- this . sendResponse ( message . id , {
141- success : true ,
142- data : selectionData
143- } ) ;
133+ const selectionPayload = message . payload as {
134+ terminal_shell_pid : number ;
135+ } ;
136+
137+ if ( await this . isMessageForOurWindow ( selectionPayload . terminal_shell_pid ) ) {
138+ const selectionData = this . getCurrentSelection ( ) ;
139+ this . sendResponse ( message . id , {
140+ success : true ,
141+ data : selectionData
142+ } ) ;
143+ }
144144 } catch ( error ) {
145145 this . outputChannel . appendLine ( `Error handling get_selection: ${ error } ` ) ;
146146 this . sendResponse ( message . id , {
@@ -156,12 +156,45 @@ class DaemonClient implements vscode.Disposable {
156156 message : string ;
157157 terminal_shell_pid : number ;
158158 } ;
159-
160- const levelPrefix = logPayload . level . toUpperCase ( ) ;
161- this . outputChannel . appendLine ( `[${ levelPrefix } ] ${ logPayload . message } ` ) ;
159+
160+ if ( await this . isMessageForOurWindow ( logPayload . terminal_shell_pid ) ) {
161+ const levelPrefix = logPayload . level . toUpperCase ( ) ;
162+ this . outputChannel . appendLine ( `[${ levelPrefix } ] ${ logPayload . message } ` ) ;
163+ }
162164 } catch ( error ) {
163165 this . outputChannel . appendLine ( `Error handling log message: ${ error } ` ) ;
164166 }
167+ } else if ( message . type === 'polo' ) {
168+ // Handle Polo messages - MCP server announcing presence
169+ try {
170+ const poloPayload = message . payload as {
171+ terminal_shell_pid : number ;
172+ } ;
173+
174+ if ( await this . isMessageForOurWindow ( poloPayload . terminal_shell_pid ) ) {
175+ this . outputChannel . appendLine ( `[DISCOVERY] MCP server connected in terminal PID ${ poloPayload . terminal_shell_pid } ` ) ;
176+ // TODO: Add to terminal registry for Ask Socratic Shell integration
177+ }
178+ } catch ( error ) {
179+ this . outputChannel . appendLine ( `Error handling polo message: ${ error } ` ) ;
180+ }
181+ } else if ( message . type === 'goodbye' ) {
182+ // Handle Goodbye messages - MCP server announcing departure
183+ try {
184+ const goodbyePayload = message . payload as {
185+ terminal_shell_pid : number ;
186+ } ;
187+
188+ if ( await this . isMessageForOurWindow ( goodbyePayload . terminal_shell_pid ) ) {
189+ this . outputChannel . appendLine ( `[DISCOVERY] MCP server disconnected from terminal PID ${ goodbyePayload . terminal_shell_pid } ` ) ;
190+ // TODO: Remove from terminal registry for Ask Socratic Shell integration
191+ }
192+ } catch ( error ) {
193+ this . outputChannel . appendLine ( `Error handling goodbye message: ${ error } ` ) ;
194+ }
195+ } else if ( message . type === 'marco' ) {
196+ // Ignore Marco messages - these are broadcasts we send, MCP servers respond to them
197+ // Extensions don't need to respond to Marco broadcasts
165198 } else if ( message . type == 'response' ) {
166199 // Ignore this, response messages are messages that WE send to clients.
167200 } else {
@@ -201,6 +234,7 @@ class DaemonClient implements vscode.Disposable {
201234 try {
202235 const terminalPid = await terminal . processId ;
203236 if ( terminalPid === shellPid ) {
237+ this . outputChannel . appendLine ( `Debug: shell PID ${ shellPid } is in our window` ) ;
204238 return true ;
205239 }
206240 } catch ( error ) {
@@ -209,6 +243,7 @@ class DaemonClient implements vscode.Disposable {
209243 }
210244 }
211245
246+ this . outputChannel . appendLine ( `Debug: shell PID ${ shellPid } is not in our window` ) ;
212247 return false ;
213248 } catch ( error ) {
214249 this . outputChannel . appendLine ( `Error checking if message is for our window: ${ error } ` ) ;
@@ -278,6 +313,26 @@ class DaemonClient implements vscode.Disposable {
278313 }
279314 }
280315
316+ private sendMarco ( ) : void {
317+ if ( ! this . socket || this . socket . destroyed ) {
318+ this . outputChannel . appendLine ( `Cannot send Marco - socket not connected` ) ;
319+ return ;
320+ }
321+
322+ const marcoMessage = {
323+ type : 'marco' ,
324+ payload : { } ,
325+ id : crypto . randomUUID ( )
326+ } ;
327+
328+ try {
329+ this . socket . write ( JSON . stringify ( marcoMessage ) + '\n' ) ;
330+ this . outputChannel . appendLine ( '[DISCOVERY] Sent Marco broadcast to discover MCP servers' ) ;
331+ } catch ( error ) {
332+ this . outputChannel . appendLine ( `Failed to send Marco: ${ error } ` ) ;
333+ }
334+ }
335+
281336 private getDaemonSocketPath ( ) : string {
282337 const discoveredPid = findVSCodePID ( this . outputChannel ) ;
283338 const vscodePid = discoveredPid || ( ( ) => {
0 commit comments