if (require('electron-squirrel-startup')) { process.exit(0); } const { app, BrowserWindow, shell, ipcMain } = require('electron'); const { createWindow, updateGlobalShortcuts } = require('./utils/window'); const { setupAIProviderIpcHandlers } = require('./utils/ai-provider-manager'); const { stopMacOSAudioCapture } = require('./utils/gemini'); const { initLogger, closeLogger, getLogPath } = require('./utils/logger'); const storage = require('./storage'); const geminiSessionRef = { current: null }; let mainWindow = null; function sendToRenderer(channel, data) { const windows = BrowserWindow.getAllWindows(); if (windows.length > 0) { windows[0].webContents.send(channel, data); } } function createMainWindow() { mainWindow = createWindow(sendToRenderer, geminiSessionRef); return mainWindow; } app.whenReady().then(async () => { // Initialize file logger first const logPath = initLogger(); console.log('App starting, log file:', logPath); // Initialize storage (checks version, resets if needed) storage.initializeStorage(); createMainWindow(); setupAIProviderIpcHandlers(geminiSessionRef); setupStorageIpcHandlers(); setupGeneralIpcHandlers(); // Add handler to get log path from renderer ipcMain.handle('get-log-path', () => getLogPath()); // Add handler for renderer logs (so they go to the log file) ipcMain.on('renderer-log', (event, { level, message }) => { const prefix = '[RENDERER]'; if (level === 'error') console.error(prefix, message); else if (level === 'warn') console.warn(prefix, message); else console.log(prefix, message); }); }); app.on('window-all-closed', () => { stopMacOSAudioCapture(); closeLogger(); if (process.platform !== 'darwin') { app.quit(); } }); app.on('before-quit', () => { stopMacOSAudioCapture(); closeLogger(); }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createMainWindow(); } }); function setupStorageIpcHandlers() { // ============ CONFIG ============ ipcMain.handle('storage:get-config', async () => { try { return { success: true, data: storage.getConfig() }; } catch (error) { console.error('Error getting config:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-config', async (event, config) => { try { storage.setConfig(config); return { success: true }; } catch (error) { console.error('Error setting config:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:update-config', async (event, key, value) => { try { storage.updateConfig(key, value); return { success: true }; } catch (error) { console.error('Error updating config:', error); return { success: false, error: error.message }; } }); // ============ CREDENTIALS ============ ipcMain.handle('storage:get-credentials', async () => { try { return { success: true, data: storage.getCredentials() }; } catch (error) { console.error('Error getting credentials:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-credentials', async (event, credentials) => { try { storage.setCredentials(credentials); return { success: true }; } catch (error) { console.error('Error setting credentials:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:get-api-key', async () => { try { return { success: true, data: storage.getApiKey() }; } catch (error) { console.error('Error getting API key:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-api-key', async (event, apiKey) => { try { storage.setApiKey(apiKey); return { success: true }; } catch (error) { console.error('Error setting API key:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:get-openai-credentials', async () => { try { return { success: true, data: storage.getOpenAICredentials() }; } catch (error) { console.error('Error getting OpenAI credentials:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-openai-credentials', async (event, config) => { try { storage.setOpenAICredentials(config); return { success: true }; } catch (error) { console.error('Error setting OpenAI credentials:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:get-openai-sdk-credentials', async () => { try { return { success: true, data: storage.getOpenAISDKCredentials() }; } catch (error) { console.error('Error getting OpenAI SDK credentials:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-openai-sdk-credentials', async (event, config) => { try { storage.setOpenAISDKCredentials(config); return { success: true }; } catch (error) { console.error('Error setting OpenAI SDK credentials:', error); return { success: false, error: error.message }; } }); // ============ PREFERENCES ============ ipcMain.handle('storage:get-preferences', async () => { try { return { success: true, data: storage.getPreferences() }; } catch (error) { console.error('Error getting preferences:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-preferences', async (event, preferences) => { try { storage.setPreferences(preferences); return { success: true }; } catch (error) { console.error('Error setting preferences:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:update-preference', async (event, key, value) => { try { storage.updatePreference(key, value); return { success: true }; } catch (error) { console.error('Error updating preference:', error); return { success: false, error: error.message }; } }); // ============ KEYBINDS ============ ipcMain.handle('storage:get-keybinds', async () => { try { return { success: true, data: storage.getKeybinds() }; } catch (error) { console.error('Error getting keybinds:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:set-keybinds', async (event, keybinds) => { try { storage.setKeybinds(keybinds); return { success: true }; } catch (error) { console.error('Error setting keybinds:', error); return { success: false, error: error.message }; } }); // ============ HISTORY ============ ipcMain.handle('storage:get-all-sessions', async () => { try { return { success: true, data: storage.getAllSessions() }; } catch (error) { console.error('Error getting sessions:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:get-session', async (event, sessionId) => { try { return { success: true, data: storage.getSession(sessionId) }; } catch (error) { console.error('Error getting session:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:save-session', async (event, sessionId, data) => { try { storage.saveSession(sessionId, data); return { success: true }; } catch (error) { console.error('Error saving session:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:delete-session', async (event, sessionId) => { try { storage.deleteSession(sessionId); return { success: true }; } catch (error) { console.error('Error deleting session:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:delete-all-sessions', async () => { try { storage.deleteAllSessions(); return { success: true }; } catch (error) { console.error('Error deleting all sessions:', error); return { success: false, error: error.message }; } }); // ============ LIMITS ============ ipcMain.handle('storage:get-today-limits', async () => { try { return { success: true, data: storage.getTodayLimits() }; } catch (error) { console.error('Error getting today limits:', error); return { success: false, error: error.message }; } }); // ============ CLEAR ALL ============ ipcMain.handle('storage:clear-all', async () => { try { storage.clearAllData(); return { success: true }; } catch (error) { console.error('Error clearing all data:', error); return { success: false, error: error.message }; } }); // ============ MIGRATION ============ ipcMain.handle('storage:has-old-config', async () => { try { return { success: true, data: storage.hasOldConfig() }; } catch (error) { console.error('Error checking old config:', error); return { success: false, error: error.message }; } }); ipcMain.handle('storage:migrate-from-old-config', async () => { try { const success = storage.migrateFromOldConfig(); return { success: true, data: success }; } catch (error) { console.error('Error migrating from old config:', error); return { success: false, error: error.message }; } }); } function setupGeneralIpcHandlers() { ipcMain.handle('get-app-version', async () => { return app.getVersion(); }); ipcMain.handle('open-logs-folder', async () => { try { const logPath = getLogPath(); const logsDir = require('path').dirname(logPath); await shell.openPath(logsDir); return { success: true, path: logsDir }; } catch (error) { console.error('Error opening logs folder:', error); return { success: false, error: error.message }; } }); ipcMain.handle('quit-application', async event => { try { stopMacOSAudioCapture(); app.quit(); return { success: true }; } catch (error) { console.error('Error quitting application:', error); return { success: false, error: error.message }; } }); ipcMain.handle('open-external', async (event, url) => { try { await shell.openExternal(url); return { success: true }; } catch (error) { console.error('Error opening external URL:', error); return { success: false, error: error.message }; } }); ipcMain.on('update-keybinds', (event, newKeybinds) => { if (mainWindow) { // Also save to storage storage.setKeybinds(newKeybinds); updateGlobalShortcuts(newKeybinds, mainWindow, sendToRenderer, geminiSessionRef); } }); // Debug logging from renderer ipcMain.on('log-message', (event, msg) => { console.log(msg); }); }