const { app, BrowserWindow, ipcMain, shell } = require('electron') const path = require('path') const { execFile } = require('child_process') const fs = require('fs') const os = require('os') const isDev = process.env.NODE_ENV === 'development' const VITE_PORT = 5173 let mainWindow = null // ── Wallet storage directory ─────────────────────────────────────────────────── const WALLET_DIR = path.join(os.homedir(), '.wallet-generator', 'wallet') function ensureWalletDir() { fs.mkdirSync(WALLET_DIR, { recursive: true }) } // ── Resolve Python executable ────────────────────────────────────────────────── function findPython() { const repoRoot = path.join(__dirname, '..', '..') const venvPython = path.join(repoRoot, 'venv', 'bin', 'python') return fs.existsSync(venvPython) ? venvPython : 'python3' } // ── Call Python CLI ──────────────────────────────────────────────────────────── function callPython(command, args = {}) { return new Promise((resolve, reject) => { const python = findPython() const repoRoot = path.join(__dirname, '..', '..') const cliPath = path.join(repoRoot, 'src', 'cli.py') execFile(python, [cliPath, command, JSON.stringify(args)], { cwd: repoRoot }, (err, stdout, stderr) => { if (err) { reject(new Error(stderr || err.message)); return } try { const result = JSON.parse(stdout.trim()) if (result.ok) resolve(result.data) else reject(new Error(result.error)) } catch { reject(new Error('Invalid Python output: ' + stdout)) } }) }) } // ── IPC handlers ─────────────────────────────────────────────────────────────── ipcMain.handle('hd-generate', (_, args) => callPython('hd_generate', args)) ipcMain.handle('hd-encrypt', (_, args) => callPython('hd_encrypt', args)) ipcMain.handle('hd-decrypt', (_, args) => callPython('hd_decrypt', args)) ipcMain.handle('p2pk', (_, args) => callPython('p2pk', args)) ipcMain.handle('p2pkh', (_, args) => callPython('p2pkh', args)) ipcMain.handle('p2sh', (_, args) => callPython('p2sh', args)) ipcMain.handle('p2wpkh', (_, args) => callPython('p2wpkh', args)) ipcMain.handle('p2tr', (_, args) => callPython('p2tr', args)) ipcMain.handle('single-encrypt', (_, args) => callPython('single_encrypt', args)) ipcMain.handle('save-wallet', (_, { filename, data }) => { ensureWalletDir() const filePath = path.join(WALLET_DIR, filename) fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8') return filePath }) ipcMain.handle('get-wallet-dir', () => { ensureWalletDir() return WALLET_DIR }) // ── Create window ────────────────────────────────────────────────────────────── function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 750, minWidth: 900, minHeight: 600, title: 'Wallet Generator', backgroundColor: '#0f1117', webPreferences: { nodeIntegration: false, contextIsolation: true, preload: path.join(__dirname, 'preload.cjs'), }, }) mainWindow.setMenuBarVisibility(false) const url = isDev ? `http://localhost:${VITE_PORT}` : `file://${path.join(__dirname, '..', 'dist', 'index.html')}` mainWindow.loadURL(url) mainWindow.webContents.setWindowOpenHandler(({ url }) => { shell.openExternal(url) return { action: 'deny' } }) mainWindow.on('closed', () => { mainWindow = null }) } // ── App lifecycle ────────────────────────────────────────────────────────────── app.whenReady().then(createWindow) app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit() }) app.on('activate', () => { if (mainWindow === null) createWindow() })