Files
hermes-desktop/electron/runtime.ts
T
toor 01d9e301fc
Build / build (push) Canceled after 0s
Playwright / browser (push) Canceled after 0s
initialize Electron desktop app and remove unused files
2026-10-25 01:09:01 +08:00

48 lines
2.2 KiB
TypeScript

import { delimiter, join, resolve } from 'node:path'
import { homedir, tmpdir } from 'node:os'
import { createHash } from 'node:crypto'
export function desktopEnvironment(root: string, stateHome: string, port: number, env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
const home = homedir()
return {
...env,
NODE_ENV: 'production',
HERMES_DESKTOP: 'true',
BIND_HOST: '127.0.0.1',
PORT: String(port),
HERMES_WEB_UI_HOME: stateHome,
HERMES_WEBUI_STATE_DIR: stateHome,
HERMES_WEB_UI_MCP_BIN: join(root, 'bin/hermes-ui-mcp.mjs'),
HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN: '1',
HERMES_AGENT_BRIDGE_STOP_ON_SHUTDOWN: '1',
HERMES_LAN_DISCOVERY_ENABLED: 'false',
HERMES_WEB_UI_DISABLE_UPDATE_CHECK: 'true',
...(process.platform === 'win32' ? {} : {
HERMES_AGENT_BRIDGE_ENDPOINT: env.HERMES_AGENT_BRIDGE_ENDPOINT || `ipc://${join(tmpdir(), `hermes-desktop-${createHash('sha256').update(stateHome).digest('hex').slice(0, 16)}.sock`)}`,
}),
PATH: [env.PATH, join(home, '.local/bin'), join(home, '.npm-global/bin'), '/opt/homebrew/bin', '/usr/local/bin'].filter(Boolean).join(delimiter),
}
}
export function desktopStateHome(userData: string, env: NodeJS.ProcessEnv = process.env): string {
return resolve(env.HERMES_WEB_UI_HOME?.trim() || env.HERMES_WEBUI_STATE_DIR?.trim() || join(userData, 'state'))
}
export function isInternalUrl(value: string, origin: string): boolean {
try { return new URL(value).origin === origin } catch { return false }
}
export function isExternalUrl(value: string): boolean {
try { return ['https:', 'http:', 'mailto:'].includes(new URL(value).protocol) } catch { return false }
}
export function storedPort(value: unknown): number {
return typeof value === 'number' && Number.isInteger(value) && value >= 1024 && value <= 65535 ? value : 0
}
export function isDesktopPermissionAllowed(permission: string, requestingOrigin: string, origin: string, mediaTypes: string[] = []): boolean {
if (!isInternalUrl(requestingOrigin, origin)) return false
if (permission === 'notifications' || permission === 'clipboard-sanitized-write') return true
return permission === 'media' && mediaTypes.length > 0 && mediaTypes.every(type => type === 'audio')
}