fix: resolve hotkey registration failures and renderer crash

- Change default hotkey from Super+Shift+A to Alt+Shift+A — Win key
  combinations are frequently reserved by the OS and fail to register
- Make quick prompt window creation lazy (first hotkey press) so it
  cannot interfere with main window startup
- Track failed accelerators to prevent error log spam from repeated
  workspace-updated events
- Fix process.platform crash in renderer SettingsPanel — use isMac
  from @renderer/lib/platform instead (renderer has no node globals)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-04-13 11:54:10 +02:00
co-authored by Copilot
parent 6714b93bed
commit fb5970cfa7
5 changed files with 103 additions and 42 deletions
+29 -14
View File
@@ -1,34 +1,49 @@
import electron from 'electron';
import { ipcChannels } from '@shared/contracts/channels';
import type { QuickPromptElectronApi } from '@shared/contracts/ipc';
const { contextBridge, ipcRenderer } = electron;
// Channel constants are inlined here (not imported from @shared/contracts/channels)
// to avoid Rollup code-splitting a shared chunk that Electron's sandboxed preload
// environment cannot resolve at runtime.
const ch = {
send: 'quick-prompt:send',
discard: 'quick-prompt:discard',
close: 'quick-prompt:close',
continueInAryx: 'quick-prompt:continue-in-aryx',
cancelTurn: 'quick-prompt:cancel-turn',
getCapabilities: 'quick-prompt:get-capabilities',
setSettings: 'quick-prompt:set-settings',
sessionEvent: 'quick-prompt:session-event',
show: 'quick-prompt:show',
hide: 'quick-prompt:hide',
} as const;
const api: QuickPromptElectronApi = {
send: (input) => ipcRenderer.invoke(ipcChannels.quickPromptSend, input),
discard: () => ipcRenderer.invoke(ipcChannels.quickPromptDiscard),
close: () => ipcRenderer.invoke(ipcChannels.quickPromptClose),
continueInAryx: () => ipcRenderer.invoke(ipcChannels.quickPromptContinueInAryx),
cancelTurn: () => ipcRenderer.invoke(ipcChannels.quickPromptCancelTurn),
getCapabilities: () => ipcRenderer.invoke(ipcChannels.quickPromptGetCapabilities),
setSettings: (settings) => ipcRenderer.invoke(ipcChannels.quickPromptSetSettings, settings),
send: (input) => ipcRenderer.invoke(ch.send, input),
discard: () => ipcRenderer.invoke(ch.discard),
close: () => ipcRenderer.invoke(ch.close),
continueInAryx: () => ipcRenderer.invoke(ch.continueInAryx),
cancelTurn: () => ipcRenderer.invoke(ch.cancelTurn),
getCapabilities: () => ipcRenderer.invoke(ch.getCapabilities),
setSettings: (settings) => ipcRenderer.invoke(ch.setSettings, settings),
onSessionEvent: (listener) => {
const handler = (_event: Electron.IpcRendererEvent, sessionEvent: Parameters<typeof listener>[0]) =>
listener(sessionEvent);
ipcRenderer.on(ipcChannels.quickPromptSessionEvent, handler);
return () => ipcRenderer.off(ipcChannels.quickPromptSessionEvent, handler);
ipcRenderer.on(ch.sessionEvent, handler);
return () => ipcRenderer.off(ch.sessionEvent, handler);
},
onShow: (listener) => {
const handler = () => listener();
ipcRenderer.on(ipcChannels.quickPromptShow, handler);
return () => ipcRenderer.off(ipcChannels.quickPromptShow, handler);
ipcRenderer.on(ch.show, handler);
return () => ipcRenderer.off(ch.show, handler);
},
onHide: (listener) => {
const handler = () => listener();
ipcRenderer.on(ipcChannels.quickPromptHide, handler);
return () => ipcRenderer.off(ipcChannels.quickPromptHide, handler);
ipcRenderer.on(ch.hide, handler);
return () => ipcRenderer.off(ch.hide, handler);
},
};