import { app, BrowserWindow, Menu, nativeImage, Tray } from 'electron';
import path from 'path';
import { fileURLToPath } from 'url';
import { CONFIG, TRAY_MENU_LABELS, TRAY_TOOLTIP, WINDOW_TITLE } from './config.js';
import { Logger } from './logger.js';
import { startMcpServer } from './mcp-server.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
let mainWindow;
let tray;
/**
* システムトレイを作成・初期化
* @throws {Error} アイコン読み込みに失敗した場合
*/
function createTray() {
try {
const isWin = process.platform === 'win32';
const iconName = isWin ? 'icon.ico' : 'icon.png';
const iconPath = path.join(__dirname, iconName);
Logger.debug('Creating tray icon', { iconPath });
const icon = nativeImage.createFromPath(iconPath);
if (icon.isEmpty()) {
Logger.warn('Tray icon is empty');
}
tray = new Tray(icon);
const contextMenu = Menu.buildFromTemplate([
{
label: TRAY_MENU_LABELS.open,
click: () => {
Logger.debug('Opening main window from tray');
mainWindow.show();
},
},
{ type: 'separator' },
{
label: TRAY_MENU_LABELS.quit,
click: () => {
Logger.info('Quit application from tray');
app.isQuitting = true;
app.quit();
},
},
]);
tray.setToolTip(TRAY_TOOLTIP);
tray.setContextMenu(contextMenu);
tray.on('double-click', () => {
Logger.debug('Tray double-click');
mainWindow.show();
});
Logger.info('Tray created successfully');
} catch (error) {
Logger.error('Failed to create tray', error);
throw error;
}
}
/**
* メインウィンドウを作成・初期化
* @throws {Error} ウィンドウ作成に失敗した場合
*/
function createWindow() {
try {
Logger.debug('Creating main window', CONFIG.window);
mainWindow = new BrowserWindow({
width: CONFIG.window.width,
height: CONFIG.window.height,
show: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},
});
const htmlPath = path.join(__dirname, 'index.html');
mainWindow.loadFile(htmlPath);
mainWindow.setTitle(WINDOW_TITLE);
mainWindow.on('close', (event) => {
if (!app.isQuitting) {
Logger.debug('Minimizing to tray instead of closing');
event.preventDefault();
mainWindow.hide();
}
return false;
});
mainWindow.on('closed', () => {
Logger.debug('Main window closed');
mainWindow = null;
});
Logger.info('Main window created successfully');
} catch (error) {
Logger.error('Failed to create main window', error);
throw error;
}
}
/**
* アプリケーション初期化
*/
app.whenReady().then(async () => {
try {
Logger.info('Electron app is ready');
createWindow();
createTray();
const mcpPort = CONFIG.mcp.defaultPort;
await startMcpServer(mcpPort);
Logger.info(`MCP server started on port ${mcpPort}`);
} catch (error) {
Logger.error('Failed to initialize application', error);
app.quit();
}
});
/**
* 全ウィンドウが閉じても終了しない(常駐アプリケーション)
*/
app.on('window-all-closed', () => {
Logger.debug('All windows closed, keeping app alive');
// 常駐のため何もしない
});
/**
* 終了前処理
*/
app.on('before-quit', () => {
Logger.info('Quitting application');
app.isQuitting = true;
});