Use setWindowOpenHandler to intercept window.open calls and route them through shell.openExternal instead of navigating inside Electron. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
// Patch console methods to handle EPIPE errors in Electron main process
|
|
// This MUST be done before any other imports that might use console
|
|
// EPIPE happens when stdout/stderr pipes are closed unexpectedly
|
|
const originalConsoleLog = console.log.bind(console)
|
|
const originalConsoleError = console.error.bind(console)
|
|
const originalConsoleWarn = console.warn.bind(console)
|
|
|
|
const safeLog = (...args: unknown[]) => {
|
|
try {
|
|
originalConsoleLog(...args)
|
|
} catch {
|
|
// Ignore EPIPE errors silently
|
|
}
|
|
}
|
|
|
|
const safeError = (...args: unknown[]) => {
|
|
try {
|
|
originalConsoleError(...args)
|
|
} catch {
|
|
// Ignore EPIPE errors silently
|
|
}
|
|
}
|
|
|
|
const safeWarn = (...args: unknown[]) => {
|
|
try {
|
|
originalConsoleWarn(...args)
|
|
} catch {
|
|
// Ignore EPIPE errors silently
|
|
}
|
|
}
|
|
|
|
// Override global console
|
|
console.log = safeLog
|
|
console.error = safeError
|
|
console.warn = safeWarn
|
|
|
|
// Also handle process stdout/stderr EPIPE errors
|
|
process.stdout?.on?.('error', (err: NodeJS.ErrnoException) => {
|
|
if (err.code === 'EPIPE') return // Ignore
|
|
throw err
|
|
})
|
|
process.stderr?.on?.('error', (err: NodeJS.ErrnoException) => {
|
|
if (err.code === 'EPIPE') return // Ignore
|
|
throw err
|
|
})
|
|
|
|
import { app, BrowserWindow, shell } from 'electron'
|
|
import { fileURLToPath } from 'node:url'
|
|
import path from 'node:path'
|
|
import { registerAllIpcHandlers, initializeApp, cleanupAll, setupDeviceConfirmation } from './ipc/index.js'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
|
|
process.env.APP_ROOT = path.join(__dirname, '..')
|
|
|
|
export const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL']
|
|
export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron')
|
|
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')
|
|
|
|
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, 'public') : RENDERER_DIST
|
|
|
|
let win: BrowserWindow | null
|
|
|
|
function createWindow() {
|
|
win = new BrowserWindow({
|
|
width: 1200,
|
|
height: 800,
|
|
webPreferences: {
|
|
preload: path.join(__dirname, 'preload.mjs'),
|
|
// Enable node integration for IPC
|
|
contextIsolation: true,
|
|
nodeIntegration: false,
|
|
},
|
|
})
|
|
|
|
// Open external links in system browser instead of inside Electron
|
|
win.webContents.setWindowOpenHandler(({ url }) => {
|
|
shell.openExternal(url)
|
|
return { action: 'deny' }
|
|
})
|
|
|
|
if (VITE_DEV_SERVER_URL) {
|
|
win.loadURL(VITE_DEV_SERVER_URL)
|
|
} else {
|
|
win.loadFile(path.join(RENDERER_DIST, 'index.html'))
|
|
}
|
|
}
|
|
|
|
app.on('window-all-closed', () => {
|
|
if (process.platform !== 'darwin') {
|
|
app.quit()
|
|
win = null
|
|
}
|
|
})
|
|
|
|
app.on('activate', () => {
|
|
if (BrowserWindow.getAllWindows().length === 0) {
|
|
createWindow()
|
|
}
|
|
})
|
|
|
|
app.on('before-quit', () => {
|
|
cleanupAll()
|
|
})
|
|
|
|
app.whenReady().then(async () => {
|
|
// Register all IPC handlers before creating window
|
|
registerAllIpcHandlers()
|
|
|
|
// Initialize Hub and create default agent
|
|
await initializeApp()
|
|
|
|
createWindow()
|
|
|
|
// Set up device confirmation flow (requires both Hub and window)
|
|
if (win) {
|
|
setupDeviceConfirmation(win)
|
|
}
|
|
})
|