@@ -184,6 +184,22 @@ class WebSocketManager {
184184
185185const wsManager = new WebSocketManager ( ) ;
186186
187+ // Cache workspace metadata to avoid async lookup during user gestures (popup blocker issue)
188+ let workspaceMetadataCache : Array < {
189+ id : string ;
190+ runtimeConfig ?: { type : "local" | "ssh" } ;
191+ } > = [ ] ;
192+
193+ // Update cache when workspace metadata changes
194+ function updateWorkspaceCache ( ) {
195+ void invokeIPC ( IPC_CHANNELS . WORKSPACE_LIST ) . then ( ( workspaces ) => {
196+ workspaceMetadataCache = workspaces as typeof workspaceMetadataCache ;
197+ } ) ;
198+ }
199+
200+ // Initialize cache
201+ updateWorkspaceCache ( ) ;
202+
187203// Create the Web API implementation
188204const webApi : IPCApi = {
189205 tokenizer : {
@@ -240,7 +256,12 @@ const webApi: IPCApi = {
240256 } ,
241257
242258 onMetadata : ( callback ) => {
243- return wsManager . on ( IPC_CHANNELS . WORKSPACE_METADATA , callback as ( data : unknown ) => void ) ;
259+ // Update cache whenever workspace metadata changes
260+ const unsubscribe = wsManager . on ( IPC_CHANNELS . WORKSPACE_METADATA , ( data : unknown ) => {
261+ updateWorkspaceCache ( ) ;
262+ callback ( data as Parameters < typeof callback > [ 0 ] ) ;
263+ } ) ;
264+ return unsubscribe ;
244265 } ,
245266 } ,
246267 window : {
@@ -268,10 +289,18 @@ const webApi: IPCApi = {
268289 return wsManager . on ( channel , callback as ( data : unknown ) => void ) ;
269290 } ,
270291 openWindow : ( workspaceId ) => {
271- // In browser mode, open a new window/tab with the terminal page
272- // Use a unique name with timestamp to create a new window each time
273- const url = `/terminal.html?workspaceId=${ encodeURIComponent ( workspaceId ) } ` ;
274- window . open ( url , `terminal-${ workspaceId } -${ Date . now ( ) } ` , "width=1000,height=600" ) ;
292+ // Check workspace runtime type using cached metadata (synchronous)
293+ // This must be synchronous to avoid popup blocker during user gesture
294+ const workspace = workspaceMetadataCache . find ( ( ws ) => ws . id === workspaceId ) ;
295+ const isSSH = workspace ?. runtimeConfig ?. type === "ssh" ;
296+
297+ if ( isSSH ) {
298+ // SSH workspace - open browser tab with terminal UI (must be synchronous)
299+ const url = `/terminal.html?workspaceId=${ encodeURIComponent ( workspaceId ) } ` ;
300+ window . open ( url , `terminal-${ workspaceId } -${ Date . now ( ) } ` , "width=1000,height=600" ) ;
301+ }
302+ // For local workspaces, the IPC handler will open a native terminal
303+
275304 return invokeIPC ( IPC_CHANNELS . TERMINAL_WINDOW_OPEN , workspaceId ) ;
276305 } ,
277306 closeWindow : ( workspaceId ) => invokeIPC ( IPC_CHANNELS . TERMINAL_WINDOW_CLOSE , workspaceId ) ,
0 commit comments