diff --git a/apps/frontend/package-lock.json b/apps/frontend/package-lock.json index 9378a74459..d752feab4b 100644 --- a/apps/frontend/package-lock.json +++ b/apps/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "auto-claude-ui", - "version": "2.7.2", + "version": "2.7.2-beta.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "auto-claude-ui", - "version": "2.7.2", + "version": "2.7.2-beta.9", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/apps/frontend/src/main/ipc-handlers/settings-handlers.ts b/apps/frontend/src/main/ipc-handlers/settings-handlers.ts index d1b4769260..03a3819feb 100644 --- a/apps/frontend/src/main/ipc-handlers/settings-handlers.ts +++ b/apps/frontend/src/main/ipc-handlers/settings-handlers.ts @@ -299,4 +299,88 @@ export function registerSettingsHandlers( await shell.openExternal(url); } ); + + ipcMain.handle( + IPC_CHANNELS.SHELL_OPEN_PATH, + async (_, folderPath: string): Promise => { + await shell.openPath(folderPath); + } + ); + + ipcMain.handle( + IPC_CHANNELS.SHELL_OPEN_IN_IDE, + async (_, folderPath: string, ide?: 'cursor' | 'vscode' | 'finder'): Promise => { + try { + // Validate path exists + if (!existsSync(folderPath)) { + return { success: false, error: `Path does not exist: ${folderPath}` }; + } + + // Determine which IDE to use + const ideToUse = ide || 'cursor'; // Default to Cursor + + if (ideToUse === 'finder') { + // Open in Finder (macOS) or Explorer (Windows) + await shell.openPath(folderPath); + return { success: true }; + } + + // Try to open in the specified IDE + const commands: Record = { + cursor: ['cursor', '.'], + vscode: ['code', '.'] + }; + + const [cmd, ...args] = commands[ideToUse] || commands.cursor; + + try { + // Use execSync to run the command - this opens the IDE + execSync(`${cmd} ${args.join(' ')}`, { + cwd: folderPath, + stdio: 'ignore', + timeout: 5000 + }); + return { success: true }; + } catch (execError) { + // If the command fails, try alternative approaches + console.warn(`[SHELL_OPEN_IN_IDE] ${cmd} command failed:`, execError); + + // On macOS, try using 'open' command with the app + if (process.platform === 'darwin') { + const appNames: Record = { + cursor: ['Cursor', 'Cursor.app'], + vscode: ['Visual Studio Code', 'Visual Studio Code.app', 'VSCode', 'Code'] + }; + + const apps = appNames[ideToUse] || appNames.cursor; + for (const appName of apps) { + try { + execSync(`open -a "${appName}" "${folderPath}"`, { + stdio: 'ignore', + timeout: 5000 + }); + return { success: true }; + } catch { + // Try next app name + continue; + } + } + } + + // Fallback: open in Finder/Explorer + console.warn(`[SHELL_OPEN_IN_IDE] Falling back to system file browser`); + await shell.openPath(folderPath); + return { + success: true, + error: `${ideToUse} not found. Opened in file browser instead.` + }; + } + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to open in IDE' + }; + } + } + ); } diff --git a/apps/frontend/src/preload/api/modules/shell-api.ts b/apps/frontend/src/preload/api/modules/shell-api.ts index a5d4b4ea3a..339ad12332 100644 --- a/apps/frontend/src/preload/api/modules/shell-api.ts +++ b/apps/frontend/src/preload/api/modules/shell-api.ts @@ -1,11 +1,18 @@ import { IPC_CHANNELS } from '../../../shared/constants'; import { invokeIpc } from './ipc-utils'; +/** + * IDE types supported for opening folders + */ +export type IDEType = 'cursor' | 'vscode' | 'finder'; + /** * Shell Operations API */ export interface ShellAPI { openExternal: (url: string) => Promise; + openPath: (path: string) => Promise; + openInIde: (path: string, ide?: IDEType) => Promise<{ success: boolean; error?: string }>; } /** @@ -13,5 +20,9 @@ export interface ShellAPI { */ export const createShellAPI = (): ShellAPI => ({ openExternal: (url: string): Promise => - invokeIpc(IPC_CHANNELS.SHELL_OPEN_EXTERNAL, url) + invokeIpc(IPC_CHANNELS.SHELL_OPEN_EXTERNAL, url), + openPath: (path: string): Promise => + invokeIpc(IPC_CHANNELS.SHELL_OPEN_PATH, path), + openInIde: (path: string, ide?: IDEType): Promise<{ success: boolean; error?: string }> => + invokeIpc(IPC_CHANNELS.SHELL_OPEN_IN_IDE, path, ide) }); diff --git a/apps/frontend/src/renderer/components/Worktrees.tsx b/apps/frontend/src/renderer/components/Worktrees.tsx index 70d1927f5d..6c9aca3ca8 100644 --- a/apps/frontend/src/renderer/components/Worktrees.tsx +++ b/apps/frontend/src/renderer/components/Worktrees.tsx @@ -12,7 +12,9 @@ import { Minus, ChevronRight, Check, - X + X, + Code2, + ExternalLink } from 'lucide-react'; import { Button } from './ui/button'; import { Badge } from './ui/badge'; @@ -305,13 +307,41 @@ export function Worktrees({ projectId }: WorktreesProps) { + +