feat: bootstrap secure cross-platform assistant

Establish the Electron foundation and pluggable agent runtime so desktop workflows can evolve safely across supported platforms.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
lofyer
2026-07-29 22:42:30 +08:00
co-authored by factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
commit 1b6178b841
30 changed files with 12017 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
import {
app,
BrowserWindow,
globalShortcut,
Menu,
nativeImage,
session,
Tray
} from 'electron'
import { homedir } from 'node:os'
import { createAgentRuntime } from './agent/create-runtime'
import { registerIpcHandlers } from './ipc'
import { createMainWindow, showWindow, toggleWindow } from './window'
const shortcut = 'CommandOrControl+Shift+Space'
const hasSingleInstanceLock = app.requestSingleInstanceLock()
if (!hasSingleInstanceLock) {
app.quit()
}
let mainWindow: BrowserWindow | undefined
let tray: Tray | undefined
let isQuitting = false
let removeIpcHandlers: (() => void) | undefined
const runtime = createAgentRuntime(
process.env.GOODBUDDY_WORKSPACE ?? homedir()
)
function createTrayIcon(): Electron.NativeImage {
const svg = [
'<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">',
'<rect width="32" height="32" rx="10" fill="#18392b"/>',
'<path d="M9 10.5h14v9a5 5 0 0 1-5 5h-4a5 5 0 0 1-5-5z" fill="#f3bb60"/>',
'<circle cx="13" cy="16" r="1.5" fill="#18392b"/>',
'<circle cx="19" cy="16" r="1.5" fill="#18392b"/>',
'<path d="M13 20h6" stroke="#18392b" stroke-width="1.8" stroke-linecap="round"/>',
'</svg>'
].join('')
const dataUrl = `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`
return nativeImage.createFromDataURL(dataUrl)
}
function buildTray(): Tray {
const nextTray = new Tray(createTrayIcon())
nextTray.setToolTip('GoodBuddy')
nextTray.setContextMenu(
Menu.buildFromTemplate([
{
label: '打开 GoodBuddy',
click: () => mainWindow && showWindow(mainWindow)
},
{
label: '新建对话',
click: () => {
if (mainWindow) {
showWindow(mainWindow)
mainWindow.webContents.send('conversation:new')
}
}
},
{ type: 'separator' },
{
label: '退出',
click: () => {
isQuitting = true
app.quit()
}
}
])
)
nextTray.on('click', () => {
if (mainWindow) {
toggleWindow(mainWindow)
}
})
return nextTray
}
if (hasSingleInstanceLock) {
app.on('second-instance', () => {
if (mainWindow) {
showWindow(mainWindow)
}
})
void app.whenReady().then(() => {
app.setAppUserModelId('live.digiman.goodbuddy')
session.defaultSession.setPermissionRequestHandler(
(_webContents, _permission, callback) => callback(false)
)
session.defaultSession.setPermissionCheckHandler(() => false)
mainWindow = createMainWindow(() => isQuitting)
tray = buildTray()
const shortcutRegistered = globalShortcut.register(shortcut, () => {
if (mainWindow) {
toggleWindow(mainWindow)
}
})
removeIpcHandlers = registerIpcHandlers(
mainWindow,
runtime,
shortcutRegistered ? shortcut : '未注册'
)
app.on('activate', () => {
if (mainWindow) {
showWindow(mainWindow)
}
})
})
}
app.on('before-quit', () => {
isQuitting = true
})
app.on('will-quit', () => {
removeIpcHandlers?.()
globalShortcut.unregisterAll()
tray?.destroy()
void runtime.dispose()
})