mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-31 21:29:59 +08:00
- detectHermesStatus 每次调用前清除 check_hermes 缓存,确保拿到最新数据 - setup 向导检测到已安装+Gateway 运行中时,自动调用 engine.detect() 更新 _ready - refreshHermes 同样清缓存+自动跳转,覆盖安装/配置/启动后的刷新场景 - 修复 sidebar 停留在"初始设置"的问题
127 lines
3.8 KiB
JavaScript
127 lines
3.8 KiB
JavaScript
/**
|
||
* Hermes Agent 引擎
|
||
*/
|
||
import { t } from '../../lib/i18n.js'
|
||
import { api, invalidate } from '../../lib/tauri-api.js'
|
||
|
||
// Hermes 状态
|
||
let _ready = false
|
||
let _running = false
|
||
let _listeners = []
|
||
let _pollTimer = null
|
||
|
||
async function detectHermesStatus() {
|
||
try {
|
||
invalidate('check_hermes')
|
||
const info = await api.checkHermes()
|
||
_ready = !!info?.installed && !!info?.configExists
|
||
_running = !!info?.gatewayRunning
|
||
} catch (_) {
|
||
_ready = false
|
||
_running = false
|
||
}
|
||
_listeners.forEach(fn => { try { fn({ ready: _ready, running: _running }) } catch (_) {} })
|
||
return _ready
|
||
}
|
||
|
||
function startPoll() {
|
||
if (_pollTimer) return
|
||
_pollTimer = setInterval(detectHermesStatus, 15000)
|
||
}
|
||
|
||
function stopPoll() {
|
||
if (_pollTimer) { clearInterval(_pollTimer); _pollTimer = null }
|
||
}
|
||
|
||
export default {
|
||
id: 'hermes',
|
||
name: 'Hermes Agent',
|
||
description: 'Hermes AI Agent with tool-calling capabilities',
|
||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>',
|
||
|
||
async detect() {
|
||
await detectHermesStatus()
|
||
return { installed: _ready, ready: _ready }
|
||
},
|
||
|
||
async boot() {
|
||
await detectHermesStatus()
|
||
startPoll()
|
||
},
|
||
|
||
cleanup() {
|
||
stopPoll()
|
||
},
|
||
|
||
getNavItems() {
|
||
// 未就绪时显示 Setup 菜单
|
||
if (!_ready) {
|
||
return [{
|
||
section: '',
|
||
items: [
|
||
{ route: '/h/setup', label: t('sidebar.setup'), icon: 'setup' },
|
||
{ route: '/assistant', label: t('sidebar.assistant'), icon: 'assistant' },
|
||
]
|
||
}, {
|
||
section: '',
|
||
items: [
|
||
{ route: '/settings', label: t('sidebar.settings'), icon: 'settings' },
|
||
{ route: '/about', label: t('sidebar.about'), icon: 'about' },
|
||
]
|
||
}]
|
||
}
|
||
// 就绪后显示完整菜单
|
||
// 仅展示已开发的页面,stub 页面暂时隐藏
|
||
return [{
|
||
section: t('sidebar.sectionMonitor'),
|
||
items: [
|
||
{ route: '/h/dashboard', label: t('sidebar.dashboard'), icon: 'dashboard' },
|
||
{ route: '/assistant', label: t('sidebar.assistant'), icon: 'assistant' },
|
||
{ route: '/h/chat', label: t('sidebar.chat'), icon: 'chat' },
|
||
]
|
||
}, {
|
||
section: '',
|
||
items: [
|
||
{ route: '/settings', label: t('sidebar.settings'), icon: 'settings' },
|
||
{ route: '/about', label: t('sidebar.about'), icon: 'about' },
|
||
]
|
||
}]
|
||
},
|
||
|
||
getRoutes() {
|
||
return [
|
||
// Hermes 专属页面(/h/ 前缀)— Phase 2 实现
|
||
{ path: '/h/setup', loader: () => import('./pages/setup.js') },
|
||
{ path: '/h/dashboard', loader: () => import('./pages/dashboard.js') },
|
||
{ path: '/h/chat', loader: () => import('./pages/chat.js') },
|
||
{ path: '/h/services', loader: () => import('./pages/services.js') },
|
||
{ path: '/h/config', loader: () => import('./pages/config.js') },
|
||
{ path: '/h/channels', loader: () => import('./pages/channels.js') },
|
||
{ path: '/h/cron', loader: () => import('./pages/cron.js') },
|
||
{ path: '/h/skills', loader: () => import('./pages/skills.js') },
|
||
// 共用页面(引擎无关)
|
||
{ path: '/assistant', loader: () => import('../../pages/assistant.js') },
|
||
{ path: '/settings', loader: () => import('../../pages/settings.js') },
|
||
{ path: '/about', loader: () => import('../../pages/about.js') },
|
||
]
|
||
},
|
||
|
||
getSetupRoute() { return '/h/setup' },
|
||
getDefaultRoute() { return '/h/dashboard' },
|
||
|
||
isReady() { return _ready },
|
||
isGatewayRunning() { return _running },
|
||
isGatewayForeign() { return false },
|
||
|
||
onStateChange(fn) {
|
||
_listeners.push(fn)
|
||
return () => { _listeners = _listeners.filter(cb => cb !== fn) }
|
||
},
|
||
onReadyChange(fn) {
|
||
_listeners.push(fn)
|
||
return () => { _listeners = _listeners.filter(cb => cb !== fn) }
|
||
},
|
||
|
||
isFeatureAvailable() { return true },
|
||
}
|