Skip to content

Commit 34f0b27

Browse files
authored
fix: only spawn native terminals for local workspaces using electron (#618)
1 parent e455395 commit 34f0b27

File tree

4 files changed

+28
-39
lines changed

4 files changed

+28
-39
lines changed

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ include fmt.mk
5252
.PHONY: docs docs-build docs-watch
5353
.PHONY: storybook storybook-build test-storybook chromatic
5454
.PHONY: benchmark-terminal
55-
.PHONY: ensure-deps
55+
.PHONY: ensure-deps rebuild-native
5656
.PHONY: check-eager-imports check-bundle-size check-startup
5757

5858
# Build tools
@@ -95,6 +95,12 @@ node_modules/.installed: package.json bun.lock
9595
# Legacy target for backwards compatibility
9696
ensure-deps: node_modules/.installed
9797

98+
# Rebuild native modules for Electron
99+
rebuild-native: node_modules/.installed ## Rebuild native modules (node-pty) for Electron
100+
@echo "Rebuilding native modules for Electron..."
101+
@npx @electron/rebuild -f -m node_modules/node-pty
102+
@echo "Native modules rebuilt successfully"
103+
98104
## Help
99105
help: ## Show this help message
100106
@echo 'Usage: make [target]'

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"access": "public"
1717
},
1818
"scripts": {
19+
"postinstall": "npx @electron/rebuild -f -m node_modules/node-pty",
1920
"dev": "make dev",
2021
"prebuild:main": "./scripts/generate-version.sh",
2122
"build": "make build",

src/browser/api.ts

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -184,22 +184,6 @@ class WebSocketManager {
184184

185185
const 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-
203187
// Create the Web API implementation
204188
const webApi: IPCApi = {
205189
tokenizer: {
@@ -256,9 +240,7 @@ const webApi: IPCApi = {
256240
},
257241

258242
onMetadata: (callback) => {
259-
// Update cache whenever workspace metadata changes
260243
const unsubscribe = wsManager.on(IPC_CHANNELS.WORKSPACE_METADATA, (data: unknown) => {
261-
updateWorkspaceCache();
262244
callback(data as Parameters<typeof callback>[0]);
263245
});
264246
return unsubscribe;
@@ -289,18 +271,12 @@ const webApi: IPCApi = {
289271
return wsManager.on(channel, callback as (data: unknown) => void);
290272
},
291273
openWindow: (workspaceId) => {
292-
// Check workspace runtime type using cached metadata (synchronous)
274+
// In browser mode, always open terminal in a new browser window (for both local and SSH workspaces)
293275
// 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
276+
const url = `/terminal.html?workspaceId=${encodeURIComponent(workspaceId)}`;
277+
window.open(url, `terminal-${workspaceId}-${Date.now()}`, "width=1000,height=600,popup=yes");
303278

279+
// Also invoke IPC to let backend know (desktop mode will handle native/ghostty-web routing)
304280
return invokeIPC(IPC_CHANNELS.TERMINAL_WINDOW_OPEN, workspaceId);
305281
},
306282
closeWindow: (workspaceId) => invokeIPC(IPC_CHANNELS.TERMINAL_WINDOW_CLOSE, workspaceId),

src/services/ipcMain.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,21 +1575,27 @@ export class IpcMain {
15751575
}
15761576

15771577
const runtimeConfig = workspace.runtimeConfig;
1578-
1579-
// For local workspaces, use native terminal (both desktop and browser mode)
1580-
// For SSH workspaces, use ghostty-web (desktop) or browser terminal (browser mode)
1581-
if (!isSSHRuntime(runtimeConfig)) {
1582-
// Local workspace - use native terminal
1578+
const isSSH = isSSHRuntime(runtimeConfig);
1579+
const isDesktop = !!this.terminalWindowManager;
1580+
1581+
// Terminal routing logic:
1582+
// - Desktop + Local: Native terminal
1583+
// - Desktop + SSH: Web terminal (ghostty-web Electron window)
1584+
// - Browser + Local: Web terminal (browser tab)
1585+
// - Browser + SSH: Web terminal (browser tab)
1586+
if (isDesktop && !isSSH) {
1587+
// Desktop + Local: Native terminal
15831588
log.info(`Opening native terminal for local workspace: ${workspaceId}`);
15841589
await this.openTerminal({ type: "local", workspacePath: workspace.namedWorkspacePath });
1585-
} else if (this.terminalWindowManager) {
1586-
// SSH workspace in desktop mode - use ghostty-web Electron window
1590+
} else if (isDesktop && isSSH) {
1591+
// Desktop + SSH: Web terminal (ghostty-web Electron window)
15871592
log.info(`Opening ghostty-web terminal for SSH workspace: ${workspaceId}`);
1588-
await this.terminalWindowManager.openTerminalWindow(workspaceId);
1593+
await this.terminalWindowManager!.openTerminalWindow(workspaceId);
15891594
} else {
1590-
// SSH workspace in browser mode - let browser handle it
1595+
// Browser mode (local or SSH): Web terminal (browser window)
1596+
// Browser will handle opening the terminal window via window.open()
15911597
log.info(
1592-
`Browser mode: terminal UI handled by browser for SSH workspace: ${workspaceId}`
1598+
`Browser mode: terminal UI handled by browser for ${isSSH ? "SSH" : "local"} workspace: ${workspaceId}`
15931599
);
15941600
}
15951601

0 commit comments

Comments
 (0)