feat(hermes): align dashboard APIs and add xintian engine

This commit is contained in:
晴天
2026-04-25 10:31:32 +08:00
parent b25808f7f0
commit 3ed59fcb2b
40 changed files with 15246 additions and 1105 deletions

View File

@@ -82,6 +82,10 @@ export async function activateEngine(id, persist = true) {
_activeEngine = engine
// 给 <body> 设置 data-active-engine 属性供全局组件sidebar 等)做
// 引擎级样式切换e.g. Hermes 激活时 sidebar 套 editorial luxury 主题)
try { document.body.dataset.activeEngine = engine.id } catch {}
// 注册引擎路由 + 设置默认路由
const routes = engine.getRoutes()
for (const r of routes) {

View File

@@ -9,6 +9,7 @@ const PATHS = {
'x-circle': '<circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/>',
'alert-triangle': '<path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>',
'info': '<circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/>',
'circle': '<circle cx="12" cy="12" r="10"/>',
// 简单指示符
'check': '<polyline points="20 6 9 17 4 12"/>',

View File

@@ -404,20 +404,38 @@ export const api = {
hermesEnvReadUnmanaged: () => invoke('hermes_env_read_unmanaged'),
hermesEnvSet: (key, value) => invoke('hermes_env_set', { key, value }),
hermesEnvDelete: (key) => invoke('hermes_env_delete', { key }),
hermesEnvReveal: (key) => invoke('hermes_env_reveal', { key }),
hermesConfigRawRead: () => invoke('hermes_config_raw_read'),
hermesConfigRawWrite: (yamlText) => invoke('hermes_config_raw_write', { yamlText }),
hermesDetectEnvironments: () => invoke('hermes_detect_environments'),
hermesSetGatewayUrl: (url) => invoke('hermes_set_gateway_url', { url: url || null }),
updateHermes: () => invoke('update_hermes'),
uninstallHermes: (cleanConfig = false) => invoke('uninstall_hermes', { cleanConfig }),
// Hermes Sessions / Logs / Skills / Memory
hermesSessionsList: (source, limit) => invoke('hermes_sessions_list', { source: source || null, limit: limit || null }),
hermesSessionDetail: (sessionId) => invoke('hermes_session_detail', { sessionId }),
hermesSessionDelete: (sessionId) => invoke('hermes_session_delete', { sessionId }),
hermesSessionRename: (sessionId, title) => invoke('hermes_session_rename', { sessionId, title }),
hermesSessionsList: (source, limit, profile) => invoke('hermes_sessions_list', { source: source || null, limit: limit || null, profile: profile || null }),
hermesSessionsSummaryList: (source, limit, profile) => invoke('hermes_sessions_summary_list', { source: source || null, limit: limit || null, profile: profile || null }),
hermesUsageAnalytics: (days, profile) => invoke('hermes_usage_analytics', { days: days || 30, profile: profile || null }),
hermesSessionDetail: (sessionId, profile) => invoke('hermes_session_detail', { sessionId, profile: profile || null }),
hermesSessionDelete: (sessionId, profile) => invoke('hermes_session_delete', { sessionId, profile: profile || null }),
hermesSessionRename: (sessionId, title, profile) => invoke('hermes_session_rename', { sessionId, title, profile: profile || null }),
hermesProfilesList: () => invoke('hermes_profiles_list'),
hermesProfileUse: (name) => invoke('hermes_profile_use', { name }),
hermesLogsList: () => invoke('hermes_logs_list'),
hermesLogsRead: (name, lines, level) => invoke('hermes_logs_read', { name, lines: lines || 200, level: level || null }),
hermesLogsDownload: (name, saveToDisk = isTauriRuntime()) => invoke('hermes_logs_download', { name, saveToDisk }),
hermesDashboardThemes: () => invoke('hermes_dashboard_themes'),
hermesDashboardThemeSet: (name) => invoke('hermes_dashboard_theme_set', { name }),
hermesDashboardPlugins: () => invoke('hermes_dashboard_plugins'),
hermesDashboardPluginsRescan: () => invoke('hermes_dashboard_plugins_rescan'),
hermesToolsetsList: () => invoke('hermes_toolsets_list'),
hermesCronJobsList: () => invoke('hermes_cron_jobs_list'),
hermesSkillsList: () => invoke('hermes_skills_list'),
hermesSkillDetail: (filePath) => invoke('hermes_skill_detail', { filePath }),
hermesSkillToggle: (name, enabled) => invoke('hermes_skill_toggle', { name, enabled }),
hermesSkillFiles: (category, skill) => invoke('hermes_skill_files', { category, skill }),
hermesSkillWrite: (filePath, content) => invoke('hermes_skill_write', { filePath, content }),
hermesMemoryRead: (type) => invoke('hermes_memory_read', { type: type || 'memory' }),
hermesMemoryWrite: (type, content) => invoke('hermes_memory_write', { type: type || 'memory', content }),
hermesMemoryReadAll: () => invoke('hermes_memory_read_all'),
}

View File

@@ -1,8 +1,45 @@
/**
* 主题管理(日间/夜间模式)
*
* 桌面端:除了切换 `<html data-theme>`,还会同步 Tauri 原生窗口标题栏的
* 主题Windows 下通过 DwmSetWindowAttribute 切 immersive dark mode
* 避免夜间模式下出现"应用黑、窗口栏白"的割裂观感。Web 端该步骤会安静跳过。
*/
import { isTauriRuntime } from './tauri-api.js'
const THEME_KEY = 'clawpanel-theme'
// 延迟加载 Tauri window 模块Web 构建不会真正拉取
let _tauriWindowModule = null
async function getTauriCurrentWindow() {
if (!isTauriRuntime()) return null
if (_tauriWindowModule === false) return null
if (!_tauriWindowModule) {
try {
_tauriWindowModule = await import('@tauri-apps/api/window')
} catch (_) {
_tauriWindowModule = false
return null
}
}
try {
return _tauriWindowModule.getCurrentWindow()
} catch (_) {
return null
}
}
async function syncTauriTitleBar(theme) {
const win = await getTauriCurrentWindow()
if (!win || typeof win.setTheme !== 'function') return
try {
// Tauri v2: 接受 'light' | 'dark' | nullnull = 跟随系统)
await win.setTheme(theme === 'dark' ? 'dark' : 'light')
} catch (_) {
// 某些 WebView2 版本或未授权时会抛错,静默忽略
}
}
export function initTheme() {
const saved = localStorage.getItem(THEME_KEY)
const theme = saved || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
@@ -39,4 +76,6 @@ export function getTheme() {
function applyTheme(theme) {
document.documentElement.dataset.theme = theme
localStorage.setItem(THEME_KEY, theme)
// Fire-and-forget不等待 Tauri IPC 返回,避免阻塞 DOM 更新和过渡动画
syncTauriTitleBar(theme)
}