import { app, BrowserWindow, dialog, ipcMain } from 'electron' import { join } from 'path' import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs' let mainWindow = null const CONFIG_DIR = join(app.getPath('userData'), '.tunji') const CONFIG_FILE = join(CONFIG_DIR, 'config.json') function ensureConfigDir() { if (!existsSync(CONFIG_DIR)) { mkdirSync(CONFIG_DIR, { recursive: true }) } } function loadConfig() { ensureConfigDir() if (existsSync(CONFIG_FILE)) { try { return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8')) } catch { return {} } } return {} } function saveConfig(config) { ensureConfigDir() writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8') } function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 800, minWidth: 800, minHeight: 600, webPreferences: { preload: join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }) if (process.env.VITE_DEV_SERVER_URL) { mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL) mainWindow.webContents.openDevTools() } else { mainWindow.loadFile(join(__dirname, '../dist/index.html')) } } // IPC Handlers ipcMain.handle('workspace:select', async () => { const result = await dialog.showOpenDialog(mainWindow, { properties: ['openDirectory'], title: '选择工作目录', }) if (result.canceled) return null const workspacePath = result.filePaths[0] const config = loadConfig() config.workspace = workspacePath saveConfig(config) return workspacePath }) ipcMain.handle('workspace:get', () => { const config = loadConfig() return config.workspace || null }) ipcMain.handle('workspace:set', (_event, path) => { const config = loadConfig() config.workspace = path saveConfig(config) }) ipcMain.handle('workspace:ensure-structure', (_event, workspacePath) => { const tunjiDir = join(workspacePath, '.tunji') if (!existsSync(tunjiDir)) { mkdirSync(tunjiDir, { recursive: true }) } const configPath = join(tunjiDir, 'config.json') if (!existsSync(configPath)) { writeFileSync(configPath, JSON.stringify({ theme: 'light' }, null, 2), 'utf-8') } }) ipcMain.handle('file:read', (_event, filePath) => { try { return readFileSync(filePath, 'utf-8') } catch { return null } }) ipcMain.handle('file:write', (_event, filePath, content) => { writeFileSync(filePath, content, 'utf-8') }) ipcMain.handle('file:mkdir', (_event, dirPath) => { try { if (!existsSync(dirPath)) { mkdirSync(dirPath, { recursive: true }) } return true } catch { return false } }) ipcMain.handle('file:list', (_event, dirPath) => { try { const entries = readdirSync(dirPath, { withFileTypes: true }) return entries .filter(e => !e.name.startsWith('.')) .map(e => ({ name: e.name, path: join(dirPath, e.name), isDirectory: e.isDirectory(), isFile: e.isFile(), })) } catch { return [] } }) app.whenReady().then(createWindow) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } })