diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 05632fc..7fca90b 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -39,6 +39,18 @@ process.on('unhandledRejection', (reason) => { let server: any = null let chatRunServer: any = null +/** + * 安全获取网络接口信息(兼容 Termux/proot 环境) + * 在 proot 环境中 os.networkInterfaces() 会抛出权限错误(errno 13) + */ +function safeNetworkInterfaces() { + try { + return os.networkInterfaces() + } catch { + return {} + } +} + export async function bootstrap() { console.log(`hermes-web-ui v${APP_VERSION} starting...`) await mkdir(config.uploadDir, { recursive: true }) @@ -123,7 +135,7 @@ export async function bootstrap() { }) server.on('listening', () => { - const interfaces = os.networkInterfaces() + const interfaces = safeNetworkInterfaces() const localIp = Object.values(interfaces).flat().find(i => i?.family === 'IPv4' && !i?.internal)?.address || 'localhost' console.log(`Server: http://localhost:${config.port} (LAN: http://${localIp}:${config.port})`) console.log(`Upstream: ${config.upstream}`) diff --git a/packages/server/src/services/hermes/gateway-manager.ts b/packages/server/src/services/hermes/gateway-manager.ts index f282e8e..803efb3 100644 --- a/packages/server/src/services/hermes/gateway-manager.ts +++ b/packages/server/src/services/hermes/gateway-manager.ts @@ -49,10 +49,49 @@ const execFileAsync = promisify(execFile) const HERMES_BASE = resolve(homedir(), '.hermes') const HERMES_BIN = process.env.HERMES_BIN?.trim() || 'hermes' -// WSL / Docker 没有 systemd 或 launchd,需要用 "gateway run" 代替 "gateway start" -const isWsl = existsSync('/proc/version') && readFileSync('/proc/version', 'utf-8').toLowerCase().includes('microsoft') -const isDocker = existsSync('/.dockerenv') -const needsRunMode = isWsl || isDocker +/** + * 检测系统的 init 系统(服务管理器) + * - macOS → launchd + * - Windows → windows-service + * - Linux → systemd / sysvinit / other + * + * 没有 systemd/launchd/windows-service 的环境需要用 "gateway run" 代替 "gateway start" + * (适用于 WSL/Docker/Termux/proot 等无服务管理器的环境) + */ +function detectInitSystem(): string { + const platform = process.platform + + // macOS → launchd + if (platform === 'darwin') { + return 'launchd' + } + + // Windows → Service Manager + if (platform === 'win32') { + return 'windows-service' + } + + // Linux 才检查 /proc + if (platform === 'linux') { + try { + const comm = readFileSync('/proc/1/comm', 'utf-8').trim() + + if (comm === 'systemd') return 'systemd' + if (comm === 'init') return 'sysvinit' + + return 'other' + } catch { + return 'unknown' + } + } + + return 'unknown' +} + +const initSystem = detectInitSystem() +const needsRunMode = !['systemd', 'launchd', 'windows-service'].includes(initSystem) +// 启动时输出 init 系统检测结果(方便调试) +logger.debug('Detected init system: %s (needsRunMode: %s)', initSystem, needsRunMode) // ============================ // 类型定义