UNPKG

@whyuds/ask-user

Version:

A cross-platform command-line tool and MCP server to show dialog windows and get user input for AI code editors

253 lines (231 loc) 6.52 kB
import { app, BrowserWindow, ipcMain } from 'electron'; import path from 'path'; let mainWindow = null; let userInputPromise = null; // 从命令行参数获取标题和消息 const args = process.argv.slice(2); let title = ''; let message = ''; for (let i = 0; i < args.length; i++) { if (args[i] === '--title' && i + 1 < args.length) { title = args[i + 1]; i++; } else if (args[i] === '--message' && i + 1 < args.length) { message = args[i + 1]; i++; } } // 确保在无头模式下也能运行 Electron if (process.platform === 'linux') { app.disableHardwareAcceleration(); } // 防止应用在所有窗口关闭时退出 app.on('window-all-closed', () => { app.quit(); }); // 防止多个实例 app.on('second-instance', () => { if (mainWindow) { if (mainWindow.isMinimized()) mainWindow.restore(); mainWindow.focus(); } }); function createWindow() { mainWindow = new BrowserWindow({ width: 500, height: 400, resizable: true, alwaysOnTop: true, center: true, frame: false, show: false, // 先不显示,等内容加载完再显示 title: title || 'Ask User', webPreferences: { nodeIntegration: true, contextIsolation: false } }); const htmlContent = generateHTML(title, message); mainWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(htmlContent)}`); // 内容加载完成后立即显示并聚焦窗口 mainWindow.once('ready-to-show', () => { mainWindow.show(); mainWindow.focus(); mainWindow.setAlwaysOnTop(true, 'screen-saver'); }); // 添加超时机制,确保窗口一定会显示 setTimeout(() => { if (mainWindow && !mainWindow.isVisible()) { mainWindow.show(); mainWindow.focus(); mainWindow.setAlwaysOnTop(true, 'screen-saver'); } }, 1000); // 1秒后强制显示 mainWindow.on('closed', () => { mainWindow = null; console.log(''); // 输出空字符串表示取消 app.quit(); }); } function generateHTML(title, message) { return ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>${title || 'Ask User'}</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 0; background: #f5f5f5; display: flex; flex-direction: column; height: 100vh; } .title-bar { background: #007acc; color: white; padding: 8px 15px; display: flex; justify-content: space-between; align-items: center; -webkit-app-region: drag; user-select: none; } .title-bar-text { font-size: 14px; font-weight: 500; } .close-btn { background: none; border: none; color: white; font-size: 16px; cursor: pointer; padding: 4px 8px; border-radius: 3px; -webkit-app-region: no-drag; } .close-btn:hover { background: rgba(255,255,255,0.2); } .container { background: white; padding: 20px; flex: 1; display: flex; flex-direction: column; margin: 0; } .message { font-size: 14px; margin-bottom: 20px; color: #666; flex: 1; } .input-area { display: flex; flex-direction: column; gap: 10px; } textarea { padding: 10px; border: 2px solid #ddd; border-radius: 4px; font-size: 14px; outline: none; transition: border-color 0.2s; resize: vertical; min-height: 80px; font-family: inherit; } textarea:focus { border-color: #007acc; } .buttons { display: flex; gap: 10px; justify-content: flex-end; } button { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background-color 0.2s; } .btn-primary { background: #007acc; color: white; } .btn-primary:hover { background: #005a9e; } .btn-secondary { background: #ddd; color: #333; } .btn-secondary:hover { background: #ccc; } </style> </head> <body> <div class="title-bar"> <div class="title-bar-text">${title || 'Ask User'}</div> <button class="close-btn" onclick="cancel()">×</button> </div> <div class="container"> <div class="message">${message || 'Enter your response below:'}</div> <div class="input-area"> <textarea id="userInput" placeholder="Type your answer here..." autofocus></textarea> <div class="buttons"> <button class="btn-secondary" onclick="cancel()">Cancel</button> <button class="btn-primary" onclick="submit()">Submit</button> </div> </div> </div> <script> const { ipcRenderer } = window.require('electron'); function submit() { const input = document.getElementById('userInput').value; ipcRenderer.send('user-input', input); } function cancel() { ipcRenderer.send('user-input', ''); } // 监听 Ctrl+Enter 提交 document.getElementById('userInput').addEventListener('keydown', function(e) { if (e.key === 'Enter' && e.ctrlKey) { submit(); } }); // 监听 ESC 键 document.addEventListener('keydown', function(e) { if (e.key === 'Escape') { cancel(); } }); </script> </body> </html> `; } // 监听用户输入 ipcMain.on('user-input', (event, input) => { console.log(input); app.quit(); }); // 当应用准备就绪时创建窗口 app.whenReady().then(() => { // 确保应用能够获得焦点 if (process.platform === 'darwin') { app.dock.show(); } createWindow(); // 确保窗口能够显示在最前面 app.focus(); });