mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-24 13:38:43 +02:00
fix: resolve Quick Prompt hotkey registration and startup resilience
- Fix accelerator: convert 'Super' to 'Meta' in toElectronAccelerator() since Electron uses 'Meta' for the Win/Cmd key, not 'Super' - Defer quick prompt window creation until after workspace loads so a failure cannot block the main window from rendering - Extract registerQuickPromptIpcHandlers into a separate function called after the quick prompt window is created - Wrap quick prompt window creation in try/catch for resilience Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+13
-4
@@ -1,7 +1,7 @@
|
||||
import electron from 'electron';
|
||||
import type { BrowserWindow as BrowserWindowType } from 'electron';
|
||||
|
||||
import { registerIpcHandlers } from '@main/ipc/registerIpcHandlers';
|
||||
import { registerIpcHandlers, registerQuickPromptIpcHandlers } from '@main/ipc/registerIpcHandlers';
|
||||
import { AryxAppService } from '@main/AryxAppService';
|
||||
import { AutoUpdateService } from '@main/services/autoUpdater';
|
||||
import { GlobalHotkeyService } from '@main/services/globalHotkey';
|
||||
@@ -29,8 +29,10 @@ async function bootstrap(): Promise<void> {
|
||||
autoUpdateService = new AutoUpdateService({ isPackaged: app.isPackaged });
|
||||
|
||||
mainWindow = createMainWindow();
|
||||
quickPromptWindow = createQuickPromptWindow();
|
||||
registerIpcHandlers(mainWindow, appService, autoUpdateService, quickPromptWindow);
|
||||
|
||||
// Defer quick prompt window creation — create it lazily when workspace is ready
|
||||
// so a failure here cannot block the main window from loading.
|
||||
registerIpcHandlers(mainWindow, appService, autoUpdateService);
|
||||
|
||||
// Start workspace loading in parallel — don't block window from showing.
|
||||
// The renderer fetches the workspace via its own IPC call after mount.
|
||||
@@ -57,7 +59,14 @@ async function bootstrap(): Promise<void> {
|
||||
systemTray?.updateRunningCount(updatedWorkspace);
|
||||
});
|
||||
|
||||
// Register global hotkey for Quick Prompt
|
||||
// Create quick prompt window and register global hotkey
|
||||
try {
|
||||
quickPromptWindow = createQuickPromptWindow();
|
||||
registerQuickPromptIpcHandlers(mainWindow!, appService!, quickPromptWindow);
|
||||
} catch (err) {
|
||||
console.error('[aryx] Failed to create quick prompt window:', err);
|
||||
}
|
||||
|
||||
globalHotkeyService = new GlobalHotkeyService();
|
||||
const hotkeySettings = workspace.settings.quickPrompt ?? createDefaultQuickPromptSettings();
|
||||
globalHotkeyService.register(hotkeySettings, () => {
|
||||
|
||||
@@ -71,7 +71,6 @@ export function registerIpcHandlers(
|
||||
window: BrowserWindow,
|
||||
service: AryxAppService,
|
||||
autoUpdateService: AutoUpdateService,
|
||||
quickPromptWindow?: BrowserWindow,
|
||||
): void {
|
||||
window.on('focus', () => {
|
||||
if (service.isGitAutoRefreshEnabled()) {
|
||||
@@ -354,9 +353,39 @@ export function registerIpcHandlers(
|
||||
window.webContents.send(ipcChannels.terminalExit, info);
|
||||
});
|
||||
|
||||
// --- Quick Prompt IPC ---
|
||||
// --- Quick Prompt IPC (window-independent) ---
|
||||
|
||||
// Track the active quick prompt session so events can be routed
|
||||
ipcMain.handle(ipcChannels.quickPromptGetCapabilities, async () => {
|
||||
const capabilities = await service.describeSidecarCapabilities();
|
||||
const settings = service.getQuickPromptSettings();
|
||||
const models = buildAvailableModelCatalog(capabilities.models);
|
||||
return {
|
||||
models,
|
||||
defaultModel: settings.defaultModel,
|
||||
defaultReasoningEffort: settings.defaultReasoningEffort,
|
||||
};
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
ipcChannels.quickPromptSetSettings,
|
||||
(_event, settings: Partial<QuickPromptSettings>) => service.setQuickPromptSettings(settings),
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
ipcChannels.quickPromptGetSettings,
|
||||
() => service.getQuickPromptSettings(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register IPC handlers that depend on the quick prompt BrowserWindow.
|
||||
* Called separately after the quick prompt window is created (deferred from bootstrap).
|
||||
*/
|
||||
export function registerQuickPromptIpcHandlers(
|
||||
mainWindow: BrowserWindow,
|
||||
service: AryxAppService,
|
||||
quickPromptWindow: BrowserWindow,
|
||||
): void {
|
||||
let quickPromptSessionId: string | undefined;
|
||||
|
||||
ipcMain.handle(ipcChannels.quickPromptSend, async (_event, input: QuickPromptSendInput) => {
|
||||
@@ -392,12 +421,12 @@ export function registerIpcHandlers(
|
||||
await service.deleteSession(quickPromptSessionId);
|
||||
quickPromptSessionId = undefined;
|
||||
}
|
||||
if (quickPromptWindow) hideQuickPromptWindow(quickPromptWindow);
|
||||
hideQuickPromptWindow(quickPromptWindow);
|
||||
});
|
||||
|
||||
ipcMain.handle(ipcChannels.quickPromptClose, async () => {
|
||||
quickPromptSessionId = undefined;
|
||||
if (quickPromptWindow) hideQuickPromptWindow(quickPromptWindow);
|
||||
hideQuickPromptWindow(quickPromptWindow);
|
||||
});
|
||||
|
||||
ipcMain.handle(ipcChannels.quickPromptContinueInAryx, async () => {
|
||||
@@ -405,42 +434,19 @@ export function registerIpcHandlers(
|
||||
await service.selectSession(quickPromptSessionId);
|
||||
quickPromptSessionId = undefined;
|
||||
}
|
||||
if (quickPromptWindow) hideQuickPromptWindow(quickPromptWindow);
|
||||
hideQuickPromptWindow(quickPromptWindow);
|
||||
// Show and focus the main window
|
||||
if (!window.isDestroyed()) {
|
||||
if (window.isMinimized()) window.restore();
|
||||
window.show();
|
||||
window.focus();
|
||||
if (!mainWindow.isDestroyed()) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||
mainWindow.show();
|
||||
mainWindow.focus();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle(ipcChannels.quickPromptGetCapabilities, async () => {
|
||||
const capabilities = await service.describeSidecarCapabilities();
|
||||
const settings = service.getQuickPromptSettings();
|
||||
const models = buildAvailableModelCatalog(capabilities.models);
|
||||
return {
|
||||
models,
|
||||
defaultModel: settings.defaultModel,
|
||||
defaultReasoningEffort: settings.defaultReasoningEffort,
|
||||
};
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
ipcChannels.quickPromptSetSettings,
|
||||
(_event, settings: Partial<QuickPromptSettings>) => service.setQuickPromptSettings(settings),
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
ipcChannels.quickPromptGetSettings,
|
||||
() => service.getQuickPromptSettings(),
|
||||
);
|
||||
|
||||
// Route session events to the quick prompt window
|
||||
if (quickPromptWindow) {
|
||||
service.on('session-event', (event) => {
|
||||
if (event.sessionId === quickPromptSessionId && !quickPromptWindow.isDestroyed()) {
|
||||
quickPromptWindow.webContents.send(ipcChannels.quickPromptSessionEvent, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
service.on('session-event', (event) => {
|
||||
if (event.sessionId === quickPromptSessionId && !quickPromptWindow.isDestroyed()) {
|
||||
quickPromptWindow.webContents.send(ipcChannels.quickPromptSessionEvent, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ export class GlobalHotkeyService {
|
||||
|
||||
/**
|
||||
* Convert our portable hotkey string (e.g. "Super+Shift+A") to an Electron
|
||||
* accelerator string. Electron uses "Super" on all platforms, which maps to
|
||||
* Cmd on macOS and Win on Windows/Linux.
|
||||
* accelerator string. Electron uses "Meta" which maps to Cmd on macOS and
|
||||
* Win key on Windows/Linux.
|
||||
*/
|
||||
function toElectronAccelerator(hotkey: string): string {
|
||||
return hotkey;
|
||||
return hotkey.replace(/Super/gi, 'Meta');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user