import { app, BrowserWindow, ipcMain, screen, globalShortcut } from 'electron' import * as path from 'path' import { PTYManager } from './pty' import { loadConfig, saveConfig } from './config' const ptyManager = new PTYManager() let mainWindow: BrowserWindow | null = null const COLLAPSED_SIZE = { width: 80, height: 80 } const EXPANDED_SIZE = { width: 900, height: 600 } function createWindow() { const config = loadConfig() const display = screen.getPrimaryDisplay() const { width: screenWidth, height: screenHeight } = display.workAreaSize // Use saved position or default to bottom-right let x = config.windowPosition?.x ?? screenWidth - COLLAPSED_SIZE.width - 20 let y = config.windowPosition?.y ?? screenHeight - COLLAPSED_SIZE.height - 20 mainWindow = new BrowserWindow({ width: COLLAPSED_SIZE.width, height: COLLAPSED_SIZE.height, x, y, frame: false, transparent: true, backgroundColor: '#00000000', alwaysOnTop: true, skipTaskbar: true, hasShadow: false, resizable: false, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }) // Dock hide on macOS if (app.dock) { app.dock.hide() } if (process.env.VITE_DEV_SERVER_URL) { mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL) } else { mainWindow.loadFile(path.join(__dirname, '../dist/index.html')) } mainWindow.on('closed', () => { mainWindow = null }) // Save position when moved mainWindow.on('moved', () => { if (!mainWindow) return const [x, y] = mainWindow.getPosition() const config = loadConfig() saveConfig({ ...config, windowPosition: { x, y } }) }) } function expandWindow() { if (!mainWindow) return const display = screen.getPrimaryDisplay() const { width: screenWidth, height: screenHeight } = display.workAreaSize const currentPos = mainWindow.getPosition() let x = currentPos[0] let y = currentPos[1] // Ensure window stays on screen if (x + EXPANDED_SIZE.width > screenWidth) { x = screenWidth - EXPANDED_SIZE.width - 20 } if (y + EXPANDED_SIZE.height > screenHeight) { y = screenHeight - EXPANDED_SIZE.height - 20 } mainWindow.setResizable(true) mainWindow.setMinimumSize(EXPANDED_SIZE.width, EXPANDED_SIZE.height) mainWindow.setSize(EXPANDED_SIZE.width, EXPANDED_SIZE.height) mainWindow.setPosition(x, y) mainWindow.setAlwaysOnTop(true) mainWindow.setIgnoreMouseEvents(false) mainWindow.setHasShadow(true) const config = loadConfig() saveConfig({ ...config, collapsed: false }) } function collapseWindow() { if (!mainWindow) return const currentPos = mainWindow.getPosition() mainWindow.setResizable(false) mainWindow.setSize(COLLAPSED_SIZE.width, COLLAPSED_SIZE.height) mainWindow.setPosition(currentPos[0], currentPos[1]) mainWindow.setAlwaysOnTop(true) mainWindow.setIgnoreMouseEvents(true, { forward: true }) mainWindow.setHasShadow(false) const config = loadConfig() saveConfig({ ...config, collapsed: true, windowPosition: { x: currentPos[0], y: currentPos[1] } }) } function toggleWindow() { if (!mainWindow) { createWindow() return } if (mainWindow.isVisible()) { mainWindow.hide() } else { mainWindow.show() } } app.whenReady().then(() => { createWindow() ptyManager.start('claude') // Collapse after load to ensure pet mode mainWindow?.webContents.on('did-finish-load', () => { collapseWindow() }) // Register global shortcut const ret = globalShortcut.register('CommandOrControl+Shift+C', () => { if (!mainWindow) { createWindow() return } if (mainWindow.isVisible()) { mainWindow.hide() } else { mainWindow.show() mainWindow.focus() } }) if (!ret) { console.log('Global shortcut registration failed') } // IPC handlers ipcMain.on('pty:write', (_event, data: string) => { ptyManager.write(data) }) ipcMain.on('pty:resize', (_event, cols: number, rows: number) => { ptyManager.resize(cols, rows) }) ipcMain.on('window:expand', () => { expandWindow() }) ipcMain.on('window:collapse', () => { collapseWindow() }) ipcMain.on('window:set-position', (_event, x: number, y: number) => { mainWindow?.setPosition(x, y) }) ipcMain.on('window:set-ignore-mouse', (_event, ignore: boolean) => { mainWindow?.setIgnoreMouseEvents(ignore, { forward: true }) }) ipcMain.on('window:close', () => { mainWindow?.close() }) ipcMain.on('window:minimize', () => { mainWindow?.minimize() }) ptyManager.on('data', (data: string) => { mainWindow?.webContents.send('pty:data', data) }) ptyManager.on('exit', (code: number) => { mainWindow?.webContents.send('pty:exit', code) }) app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on('window-all-closed', () => { ptyManager.kill() globalShortcut.unregisterAll() if (process.platform !== 'darwin') { app.quit() } }) app.on('before-quit', () => { ptyManager.kill() globalShortcut.unregisterAll() }) app.on('will-quit', () => { globalShortcut.unregisterAll() })