晴天
a13c9ee6ba
fix(models): stop auto-filling fallback chain and add clear-all button
...
The fallback editor's "Add" buttons appeared to do nothing because
applyDefaultModel auto-populated defaults.model.fallbacks with every
non-primary model whenever the list was empty (and the same for
defaults.models). After any save with an empty chain, the chain got
filled with all 17+ candidates; the candidate pool became "No candidate
models available" and any subsequent Add click hit the early return
`if (modelConfig.fallbacks.includes(full)) return`.
Even worse, the auto-fill made it impossible for users to keep an empty
fallback chain on purpose: deleting all chips would silently get
replaced with every model on the next debounced autosave.
Remove the auto-fill in applyDefaultModel. An empty fallback chain is a
valid configuration that means "no implicit fallback"; Gateway already
surfaces a clear primary-model error in that case. normalizeDefaultModel
Selection still cleans up invalid/duplicate entries.
Also add a small "Clear All" button next to the active chain title so
users can drop the entire fallback list in one click instead of removing
chips one by one (especially useful for the existing bloated 17-fallback
state created by the old auto-fill path).
## Verification
- node --check src/pages/models.js
- node --check src/locales/modules/models.js
- npm run build
- Playwright repro: open /#/models → Clear All → fallbacks on disk
go from 17 → 0 → click Add on one candidate → fallbacks on disk are
exactly that one entry, no longer auto-expanded back to 17.
2026-05-16 12:07:35 +08:00
晴天
207b1c7c55
fix(windows): make gateway terminal window actually visible
...
The previous implementation passed CREATE_NEW_CONSOLE to a Rust
StdCommand spawning cmd.exe directly, but Rust's default Stdio::inherit
copies the parent stdio handles into STARTUPINFO with
STARTF_USESTDHANDLES, which neutralizes CREATE_NEW_CONSOLE. The cmd
process then ran without a visible window (MainWindowHandle = 0), so
users only saw the OpenClaw node child started by runner.cmd in Task
Manager and got the impression that "the terminal does not pop up".
Wrap the launch in `cmd /c start "OpenClaw Gateway" /D <dir> cmd /D /K
runner.cmd` so the new console is created by the `start` builtin via a
fresh CreateProcess call without inherited stdio. The outer cmd /c
itself is short-lived and uses CREATE_NO_WINDOW so it does not flash a
window, and the inner cmd hosting runner.cmd reliably becomes a normal
visible terminal that the user can close to stop Gateway.
Because the visible terminal is now detached from our process tree,
spawn().id() can no longer be tracked. Instead, poll netstat after the
launch and record the listener PID as the active Gateway PID, which is
what the stop path actually needs to send a precise kill to.
## Verification
- cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check
- cargo check --manifest-path src-tauri/Cargo.toml
2026-05-16 12:07:04 +08:00
晴天
9742786f8c
fix(models): normalize invalid primary model
2026-05-16 00:16:39 +08:00
晴天
c318ff3b37
fix(assistant): normalize OpenClaw context path
2026-05-15 23:37:28 +08:00
晴天
e1eda2db55
feat(models): import external client configs
...
Add a model client import flow that scans local Codex, Claude Code, Gemini CLI, and common environment variable configurations without reading or copying OAuth tokens.
The new backend command returns safe import candidates with provider metadata, model IDs, and API key environment-variable references. Tauri and Web/dev-api both implement the scanner, and Web mode keeps the scan local even when a remote instance is active.
The Models page now offers an import wizard that lets users select importable candidates, adds providers without overwriting existing keys, preserves secrets as ${ENV_VAR} references, and leaves OAuth-only Codex entries as guidance rather than direct OpenClaw imports.
## Verification
- node --check src/pages/models.js
- node --check src/lib/tauri-api.js
- node --check src/locales/modules/models.js
- node --check scripts/dev-api.js
- cargo fmt --check
- cargo check
- npm run build
2026-05-15 23:18:50 +08:00
晴天
f411386ab5
fix(ui): polish docker and model configuration views
...
Treat an unavailable local Docker socket with no containers as an optional Docker management capability instead of showing a meaningless offline default node.
Improve the model configuration layout for large model/fallback lists by wrapping controls, truncating long IDs safely, capping collapsed fallback chips, and making the fallback editor responsive.
Guard chat message insertion against route changes so async history/hosted output cannot insert into an unloaded chat DOM.
## Verification
- node --check src/pages/models.js
- node --check src/pages/services.js
- node --check src/pages/chat.js
- node --check src/locales/modules/services.js
- npm run build
2026-05-15 21:01:27 +08:00
晴天
322bf1a0a6
fix(dashboard): avoid startup skeleton deadlock
...
Delay heavy dashboard requests until after the first stat-card render so slow version checks, agent scans, MCP reads, backups, channel discovery, or log tail reads cannot occupy the backend before the initial paint.
Add a 1.2s first-paint fallback that replaces skeleton cards with safe unknown-state cards and logs a warning when dashboard APIs are still pending.
## Verification
- npm run build
2026-05-15 20:48:14 +08:00
晴天
2f7cd6d429
perf(ui): speed up dashboard startup rendering
...
Render the dashboard first wave without waiting for get_version_info, which may spawn CLI work and query the registry. Version data now updates the stat cards asynchronously after the core service/config data is shown.
Also shorten the desktop Gateway port probe before WebSocket connection from 20s/2s polling to 3s/300ms polling, relying on the WebSocket reconnect path instead of blocking startup for a long time.
## Verification
- npm run build
2026-05-15 20:15:06 +08:00
晴天
c592f47217
fix(windows): harden gateway terminal runner
...
Use a generated clawpanel-gateway.cmd runner for the visible Windows Gateway terminal instead of embedding the resolved CLI path directly in the cmd /K command string. This keeps the simple visible-terminal model while improving quoting behavior for standalone, npm shim, and .js CLI paths.
## Verification
- cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check
- cargo check --manifest-path src-tauri/Cargo.toml
- cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings
- npm run build
2026-05-15 19:58:15 +08:00
晴天
807a1d87a9
fix(windows): launch gateway in visible terminal
...
Windows users can now start OpenClaw Gateway in a normal terminal window instead of relying on a hidden background process. Keeping the terminal open keeps Gateway running; closing it stops Gateway.
The backend guardian also treats a closed Windows Gateway terminal as an intentional stop, so it will not immediately pop a new terminal back up after the user closes it. macOS and Linux keep their existing startup behavior.
## Verification
- cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check
- cargo check --manifest-path src-tauri/Cargo.toml
- cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings
- npm run build
2026-05-15 19:51:52 +08:00
晴天
6af9819b89
fix(ui): sync latest upgrade copy in locale bundles
...
The runtime locale JSON bundles still contained the older About/Services policy copy even after the module-level strings were updated, so the About page could continue to show the old "recommended only" message in Chinese.
This syncs the zh-CN/en locale bundles with the latest-upstream upgrade copy and mirrors the suffixed OpenClaw version comparison fix in the Web dev API.
## Verification
- npm run build
- node --check scripts/dev-api.js
- cargo check
2026-05-15 19:31:44 +08:00
晴天
dcafd29e51
fix(openclaw): allow upgrading kernel to latest patch
...
OpenClaw Chinese edition has advanced to 2026.5.12-zh.2 while the panel still recommended 2026.5.12-zh.1 and treated same-base zh patch versions as equivalent.
This updates the recommended Chinese kernel target and makes the version comparison detect suffix-level upgrades such as zh.1 -> zh.2 when both sides expose suffixes. It also adds explicit latest-upstream upgrade actions on the Services and About version cards so users can upgrade to the latest detected upstream version without going through the manual version picker.
## Changes
- update OpenClaw Chinese recommended target to 2026.5.12-zh.2
- detect same-base suffixed patch upgrades in version info
- add Services page "upgrade to latest" action and confirmation copy
- add About page latest-upstream action
## Verification
- npm run build
- cargo check
2026-05-15 19:08:42 +08:00
晴天
7f078a3c49
fix(ui): import term tooltip helpers in config pages
...
Gateway 配置页和模型配置页都会在 label 中渲染术语帮助按钮,并在页面渲染后调用 tooltip 绑定逻辑。
这两个页面之前引用了 termHelpHtml / attachTermTooltips,但没有导入对应 helper,导致 Gateway 配置页加载配置后直接抛出 ReferenceError,页面停在加载失败状态。
## 修复
- Gateway 配置页补充 term-tooltip helper import
- 模型配置页补充同一 helper import,避免进入编辑服务商弹窗时触发同类运行时错误
## 验证
- npm run build:PASS
2026-05-15 18:54:13 +08:00
晴天
8b690cb6a7
fix(openclaw): update recommended kernel target and delta protocol handling
...
面板原本只声明 maxProtocol=3 的握手范围,且 chat delta 处理只接受前缀扩展。
连接到 2026.5.12+ 内核时会出现握手兼容问题;agent 输出在内容回滚或重排场景也会
丢失最新文本,前端 streaming 气泡停留在旧前缀。
## Connect 握手协议范围
- 将桌面端 connect frame 的 maxProtocol 从 3 扩展到 4
- 将 Web 模式 connect frame 的 maxProtocol 从 3 扩展到 4
- minProtocol 继续保留 3,用于兼容历史内核
- 范围 [3, 4] 同时覆盖旧内核和 5.12+ 内核,不需要按版本分支
## Chat delta replace 语义
- 当 payload.replace=true 时,无条件覆盖当前 AI 文本缓存
- 保留前缀扩展场景的增量更新逻辑
- 修复内容回滚或重排时文本长度变短导致 UI 不刷新的问题
## 推荐内核版本
- official 推荐目标升到 2026.5.12
- chinese 推荐目标升到 2026.5.12-zh.1
- KERNEL_FLOOR 不变,继续兼容历史安装
## 验证
- cargo check:PASS
- npm run build:PASS
2026-05-15 18:30:04 +08:00
晴天
0b4ef11971
fix(hermes): restore gateway message sending dependencies
...
Hermes Gateway 能启动但消息发送链路仍可能不可用:工具安装环境缺少运行时依赖,
同时自定义端点场景下 provider 字段可能被省略,导致消息路由继续落到错误 provider。
## 补齐运行时依赖
- uv tool install 固定带上 HTTP 客户端依赖
- 补齐 OpenAI SDK 依赖
- 补齐 Gateway HTTP server 所需 aiohttp
- 补齐 browser/dialog 等工具链会触发的 websocket 依赖
- 安装日志同步展示完整安装参数,便于用户排查环境问题
## 明确 custom provider
- 自定义 base_url 时显式写入 provider: custom
- 如果 model 段已有 provider,则覆盖为 custom
- 如果 model 段缺少 provider,则补写 provider: custom
- 继续保留 OPENAI_API_KEY alias 自愈,确保辅助客户端和主流程读取同一份凭证
## 范围
- 桌面 Tauri 安装与配置自愈逻辑
- Web dev API 安装与配置自愈逻辑
2026-05-15 17:32:56 +08:00
晴天
583f5401ac
fix(hermes): stabilize gateway provider routing and startup
...
Hermes Gateway 之前容易出现两类问题:配置里的 provider 与 base_url 不一致,
以及多个启动入口并发触发 Gateway start,导致日志里反复出现启动流程,运行状态也不稳定。
## Provider / base_url 自愈
- 归一化 provider URL(去掉尾斜杠和常见 API path 后缀)
- 当 openrouter provider 搭配自定义 base_url 时,自动切换为 custom provider
- 在读取配置、写入模型配置、启动 Gateway 前都执行一次自愈
- Web 模式同步实现相同逻辑,避免桌面端和浏览器端行为不一致
## API Key 别名兼容
- custom provider 优先读取 OPENAI_API_KEY
- 当 .env 只有 CUSTOM_API_KEY 时,自动补齐 OPENAI_API_KEY
- 避免辅助客户端读取不到凭证或落到错误 provider
## Gateway 启动互斥
- 增加 Gateway start guard,串行化启动流程
- 如果已有启动流程在进行中,直接复用健康检查结果
- 避免重复 Gateway 进程、重复日志和竞态状态覆盖
## 范围
- 桌面 Tauri 命令
- Web dev API 运行时
- Hermes provider 注册表
2026-05-15 17:32:38 +08:00
晴天
2256c2c711
fix(audit): 复查第三波 — Hermes 安装向导 i18n 化漏网中文
...
第三轮逐文件复查发现 hermes/pages/setup.js 还有大量用户首屏可见的
中文硬编码(之前两轮主要扫 timer/cleanup/syntax/listener 类 bug)。
## 涉及修复
### setup.js phase 标签(5 处)
phase indicator 是用户最早看到的 UI 元素:
```
{ id: 'detect', label: '检测' } → t('engine.hermesPhaseDetect')
{ id: 'install', label: '安装' } → t('engine.hermesPhaseInstall')
{ id: 'configure', label: '配置' } → t('engine.hermesPhaseConfigure')
{ id: 'gateway', label: '启动' } → t('engine.hermesPhaseGateway')
{ id: 'complete', label: '完成' } → t('engine.hermesPhaseComplete')
```
英文用户原本看到的是 5 个汉字,现在按系统语言显示
Detect / Install / Configure / Start / Complete。
### setup.js Provider 分组标题(4 组)
configure 阶段渲染 provider 选择按钮时分组标题:
```
'国际 · API Key' → hermesProviderGroupIntl
'国内 · API Key' → hermesProviderGroupCn
'聚合 / 路由' → hermesProviderGroupAggregator
'OAuth 登录(需终端)' → hermesProviderGroupOAuth
'<provider>:需运行' → hermesProviderOAuthRunHint
```
### setup.js Provider 加载失败 fallback 文案
Web 模式下 provider 列表加载失败时的 12 行多行 hint,原本只有中文,
现已 11 语言 i18n。
### setup.js 检测异常日志 prefix
```js
logs.push(`检测错误: ${e}`) → `[detect error] ${e?.message || e}`
```
日志输出(用户在向导首屏可见)跟其他英文 prefix 一致,便于日志聚合。
## 新增 i18n key(engine 模块)
- hermesPhaseDetect / Install / Configure / Gateway / Complete
- hermesProviderGroupIntl / Cn / Aggregator / OAuth
- hermesProviderOAuthRunHint
- hermesProvidersLoadFallback
11 语言全覆盖(zh-CN / zh-TW / en / ja / ko / vi / es / pt / ru / fr / de)。
## 复查范围(第三轮)
- src-tauri/src/commands/*.rs unwrap 全 safe(regex / SystemTime / Mutex)
- src/lib/ humanize-error / engine-manager / ws-client / message-db / tts 全部健全
- src/components/ modal / toast 无问题
- scripts/dev-api.js 176 个 handler 无 duplicate / 关键命令全有
- src/pages/ 没发现新硬编码(之前的 i18n 覆盖到位)
- src/engines/hermes/pages/ setup.js 是唯一遗漏的中文重灾区,已修
## 验证
- npm run build:PASS(1.46s)
- 总计三轮复查共修 11 个 bug + 5 个 i18n 漏网
2026-05-14 07:41:01 +08:00
晴天
d30714d406
fix(audit): 复查第二波 — alert/confirm 统一 + chat.js 潜伏语法 bug
...
## Bug #6 — chat.js 末尾多余 `}` 让 Vite build 卡死
src/engines/hermes/pages/chat.js
文件结尾 line 1635 已经闭合 render 函数,但 line 1636 多了一个孤立的
`}`,导致 esbuild 解析陷入回溯(build 卡在 transforming 47 modules
不退出)。删除多余括号后 build 1.55s 通过。
## Bug #7 — alert() / window.confirm 跨平台行为不一致
- src/engines/hermes/pages/setup.js 3 处 alert()
· API Key 必填校验
· 配置保存失败
· Gateway 启动失败 fallback
- src/engines/hermes/pages/memory.js 2 处 window.confirm
· 关闭未保存编辑窗
· 取消编辑前的确认
- src/engines/hermes/pages/env-editor.js 1 处 confirm()
· 删除环境变量
Tauri webview 在 macOS / Windows / Linux 三平台对原生 alert/confirm
处理不同(macOS 需要 webview 设置 navigation_handler,部分场景直接
忽略)。统一改用项目 components/toast + components/modal.showConfirm,
保证跨平台一致 + 可被样式化。
涉及函数 closeWithConfirm 改为 async 以等待 showConfirm Promise。
## Bug #8 — gateways.js 错误显示与其他页面风格不一致
src/engines/hermes/pages/gateways.js
`error = String(e?.message || e)` 直接显示 raw error 字符串,与
profiles/kanban/oauth 三个最近升级的页面不一致。改用 humanizeError
让用户看到友好提示 + 可折叠原始错误详情。
emoji ⚙️ 设置图标改用项目 svg-icons.js 的 settings SVG,与 Bug #5
emoji→SVG 重构保持一致。
## 验证
- npm run build:PASS(1.55s)
- 受影响场景:
- 安装向导 API Key 缺失提示(toast 而不是阻塞 alert)
- 记忆页未保存确认(modal 而不是平台原生 confirm)
- 环境变量删除确认(modal 而不是平台原生 confirm)
- 多 Gateway 加载失败错误展示(友好 + 可展开技术详情)
2026-05-14 07:24:47 +08:00
晴天
b9a7c043d2
fix(audit): 复查发现的 5 个 bug — 双 listener / duplicate stub / timer leak / i18n
...
逐项排错盘点(OpenClaw + Hermes 引擎 + 共享层全面复查)。
## Bug #1 — Hermes 引擎双 listener 数组混用
src/engines/hermes/index.js
onStateChange / onReadyChange 共用一个 `_listeners` 数组:
```js
onStateChange(fn) { _listeners.push(fn); ... }
onReadyChange(fn) { _listeners.push(fn); ... } ← 同一数组
```
main.js 注册 sidebar 渲染回调时两个都注册:
```js
_engineStateUnsub = engine.onStateChange(() => renderSidebar(sidebar))
_engineReadyUnsub = engine.onReadyChange(() => renderSidebar(sidebar))
```
结果:每次 detectHermesStatus(15s 一次 poll)触发,sidebar 被
renderSidebar 调两遍。OpenClaw 引擎用的 lib/app-state.js 早就是分开
两个数组(_gwListeners + _listeners),Hermes 是退化实现。
修复:
- 拆成 _stateListeners / _readyListeners 两个数组
- 加 prevReady / prevRunning 做 diff,仅在状态实际变化时通知
## Bug #2 — Web 模式下 check_panel_update 永远返回 false
scripts/dev-api.js
`check_panel_update` 在 line 6785 有完整实现(fetch GitHub/Gitee
release API),但 line 8586 又 stub 了一次:
```js
check_panel_update() { return { hasUpdate: false } }
```
Object literal 后定义覆盖前定义,Web 模式下用户永远看不到「有新版」
提示,必须升级到桌面客户端才能查更新。
修复:删掉重复 stub,留注释说明真实实现位置。
esbuild 之前就在 build 里 warn `Duplicate key "check_panel_update"
in object literal`,现在 warning 也消失了。
## Bug #3 — engine-select.js setTimeout 不在 cleanup 时清
src/pages/engine-select.js
choose 动画里两个 setTimeout (600ms + 1300ms) 没保存 id,路由
cleanup 时不清。极端情况:用户点完 OpenClaw 后立刻点 secondary
"稍后再说" → 1300ms 后被强制 navigate 回原 targetRoute,把用户拉走。
修复:
- 模块级 _animTimers 数组追踪所有动画 setTimeout id
- cleanup 时 clearTimeout 全清
- stage.dataset 防御性访问(路由切走后 stage 可能已不在 DOM)
## Bug #4 — router.js 三处中文硬编码
src/router.js
之前页面 loading / 加载失败 / 重新加载按钮直接写死"加载中..."
"页面加载失败" "重新加载"。i18n 里 `common.loading` /
`common.pageLoadFailed` / `common.reloadRetry` 早已存在但没用上。
修复:import t() + 三处替换。
## Bug #5 — dashboard.js Promise 超时 Error 写死中文
src/pages/dashboard.js
`new Error(\`超时(${ms/1000}s)\`)` — 这条错误最后被 humanizeError
处理后展示给用户,本来应该走 i18n。改成英文 `Timed out after Xs`,
统一与日志聚合(其他地方都是英文)。
## 验证
- npm run build:PASS(1.85s, 无 duplicate-key warning)
- cargo fmt --check:PASS(无改动)
- 受影响场景:
- 引擎切换 sidebar 性能(Hermes 双重渲染消失)
- Web 模式更新提示(恢复正常)
- engine-select 动画中途切走(不再被强拉回)
- 加载/错误页(i18n 完整)
2026-05-14 07:17:28 +08:00
晴天
c264224e7c
fix(rust): 修 CI 失败的 4 个 clippy + fmt 问题
...
之前 3 个 commit (cc19a07/1873e23/d97e196/6a0d874/bf55ca0) 推上去后 CI
全部 fail(三平台都 fail),原因不是 JS 改动而是历史 Rust 代码累积的
clippy/fmt 检查问题,本次一次性修齐让 CI 重新跑通。
## 4 个 clippy errors(-D warnings 模式)
1. `field 'name' is never read` (HermesAttachment::name)
- 该字段是前端可选传入的附件原文件名,目前后端未消费
- 加 #[allow(dead_code)] + 说明性 doc,保留字段供后续展开附件清单 UI
2. `unnecessary closure used to substitute value for Result::Err` × 2
- hermes_dashboard_api_proxy 里
`unwrap_or_else(|_| Value::String(body))` →
`unwrap_or(Value::String(body))`
- 闭包捕获 _ 但不用,直接用 unwrap_or
3. `manually reimplementing div_ceil`
- base64_encode 里 `(bytes.len() + 2) / 3` →
`bytes.len().div_ceil(3)`(标准库 1.73+ 支持)
## fmt 修复
hermes.rs 多处长 match arm + long argument list 不符合 rustfmt 默认风格,
跑 cargo fmt --all 自动修齐。
## 验证
✓ cargo fmt --all -- --check PASS
✓ cargo check PASS
✓ cargo clippy --all-targets -- -D warnings PASS(无 warning 无 error)
## 影响
- 不改变任何运行时行为
- 不影响前端 / 不影响 i18n / 不影响 Tauri 命令签名
- 纯代码风格 + lint 修复
2026-05-14 06:54:13 +08:00
晴天
bf55ca0135
refactor(hermes): emoji → SVG 图标,统一视觉语言
...
## 问题
新加的 hermes 页面里到处是 emoji(⚠️ 📁 📋 💬 🔐 🔗 🖼️ 📝 ⚙️ 📦 💬 🔊 🎙🔍 ✓ 等),
不同 OS 渲染样式差异大(macOS Apple Color Emoji vs Windows Segoe UI Emoji
vs Linux Noto Color Emoji),看着很不专业,也跟现有 SVG 图标系统割裂。
## 方案
新建 src/engines/hermes/lib/svg-icons.js — 集中所有需要的 SVG path:
状态:alert-triangle, check, x, check-circle, x-circle, info
文件:folder, folder-up, file, file-text, image, link-2, settings
列表:clipboard-list, message-square, inbox
安全:lock, shield, key
媒体:volume, mic, search
导出 svgIcon(name, opts) — 渲染时统一 viewBox / stroke-width / currentColor,
size 可选覆盖。
## 替换覆盖(7 个页面 + 2 处 CSS)
- profiles.js: ⚠️ → alert-triangle, 📁 → folder
- kanban.js: ⚠️ → alert-triangle, 📋 → clipboard-list, 💬 → message-square
- oauth.js: ⚠️ → alert-triangle, 🔐 → lock
- group-chat.js: ⚠️ → alert-triangle
- logs.js: ⚠️ → 纯文本 [ERROR](log raw 字段不需要图标)
- files.js: 📁 🔗 🖼️ 📝 ⚙️ 📄 全部 → folder/link-2/image/file-text/settings/file
".." → folder-up
- lazy-deps.js: 7 个 category emoji → message-square/volume/mic/search/
shield/inbox/image
✓ 装好标识 → check svg
📦 empty → inbox
CSS 适配:
- .page-inline-error-icon: 加 inline-flex + 自动 currentColor,svg 20×20
- .empty-state .empty-icon: 加 inline-flex + svg 跟 font-size 走(1em)
## 范围控制
本次只处理我最近 3 个 commit 里新加的页面 emoji。
历史代码(setup.js / services.js / chat.js 的 ✅ ❌ ✓ 等)暂不动 — 那是
跨工作流的复杂改动,单独评估再做,避免连锁影响 CI。
## 验证
✓ npm run build PASS(1.80s)
2026-05-14 06:50:14 +08:00
晴天
d97e196a48
fix(chat): 会话列表无区分度,让用户误以为是 mock 数据
...
## 问题
用户截图:会话列表 20+ 项全部显示「新对话 / QC-505 / 5月8日」,
完全相同,怀疑是写死的 mock 数据。
## 真相
数据其实是真实的(hermes sessions export 输出的 JSONL):
- title 全空 → fallback 到 t('chatNewSession') = "新对话"
- 用户用同一模型 QC-505 跑了所有会话
- 用户在同一天(5月8日)跑的
- 视觉冗余 100% → 看起来像写死
## 修复(让真实数据显示出区分度)
1. sessionDisplayTitle: 没标题时不再统一显示「新对话」,
改为「未命名 · {id 后6位}」(每个会话不同后缀,一眼能区分)
2. meta 行加 messageCount —— 显示「N 条」让每个会话有自己的数字
3. 加 i18n 键 chatUntitledSession + chatSessionMsgCount(11 语完整)
## 效果
之前:
新对话
QC-505 5月8日
新对话
QC-505 5月8日
... × 20
之后:
未命名 · a3f2b8
QC-505 5月8日 28 条
未命名 · 7c91d4
QC-505 5月8日 14 条
未命名 · e082f1
QC-505 5月8日 3 条
...
用户立刻能看出每个会话是真实独立的,不会再怀疑 mock。
2026-05-14 06:40:41 +08:00
晴天
1873e23371
fix(critical): 5 个用户报告的真 bug 一次性修
...
## P0 Bug 1: chat.js `t is not defined` (页面渲染崩溃)
- chat.js 用了 30+ 处 t() 但**完全忘记 import i18n**
- 路由进入 /h/chat 立即抛 ReferenceError,整页渲染失败
- 修复:补 `import { t } from '../../../lib/i18n.js'`
## P0 Bug 2: i18n 嵌套对象解析失败 (所有 humanizeError 显示原始 key)
- 用户截图:`common.errorHint.generic` 直接显示而非翻译
- 根因:buildLocales() 不递归嵌套对象,把 common.error / errorHint /
errorAction 这种嵌套 dict 当作 _() 翻译对象处理 →
`result[lang].common.errorHint = 'errorHint'` (字符串)
- 影响:t('common.errorHint.network'/auth/timeout/...) 全部返回 key 自身
→ toast 用 humanizeError 的所有页面都看到原始 key
- 修复:buildLocales 加 _isTranslationObject + _materialize 递归
## P0 Bug 3: dev-api.js `Dynamic require of "node:fs" is not supported`
- 用户截图:文件管理器红字 "Dynamic require of node:fs"
- 根因:我之前在 hermes_fs_* / _validateFsPath / _hermesHome 用了
`const fs = require('node:fs')` —— 但 Vite 插件运行在 ESM 上下文,
CommonJS dynamic require 不支持
- 修复:删除所有 require('node:fs/path/os') —— 文件顶部已经 ESM
`import fs from 'fs'` 等,直接复用即可
## P1 Bug 4: profiles/kanban/oauth fetch failed 错误丑陋
- 用户截图:3 个页面都显示红字 "fetch failed"(无任何上下文)
- 修复 1(dev-api.js):hermes_dashboard_api_proxy 把 ECONNREFUSED /
fetch failed 转成 "Hermes Dashboard 未运行(端口 9119 无服务)。
请在桌面端 ClawPanel 启动 Hermes Agent" — 含「未运行」关键字会被
humanizeError 的 gatewayDown 正则匹配
- 修复 2(3 个页面):用 humanizeError 拆出 message + hint + 折叠 raw,
渲染统一的 .page-inline-error 卡片(icon + 主行 + 副提示 + 技术详情
details)。错误对象不再 stringify,保留给 humanizeError 完整识别
## P2 Bug 5: 重复的 require('node:path') in hermes_fs_list
- 同 Bug 3,循环里又 require 了一次 path,现已用顶部 import
## 影响面
✅ /h/chat 不再崩溃,profile switcher 正常显示
✅ 所有用 humanizeError 的 toast 看到正确翻译(不再显示原始 key)
✅ 文件管理器 Web 模式正常列出 ~/.hermes 目录
✅ Profile / Kanban / OAuth 显示「Hermes Dashboard 未运行」+
「请前往仪表盘启动 Gateway 后重试」+ 折叠原始错误(点击展开)
✅ npm build pass
2026-05-14 06:35:20 +08:00
晴天
6a0d87479c
feat(engine-select): Monolith 对角线全屏选择屏
...
替换原卡片网格为「左上 OpenClaw(石墨黑)vs 右下 Hermes(象牙白)」对角线全屏设计。
启动屏 / 引擎切换时给用户一个有冲击力的「选择时刻」。
## 核心设计
- position: fixed 跳出 #content 范围,覆盖整个 viewport(含 sidebar)
- 双三角形 clip-path: polygon (0 0, 0 100%, 100% 0) / (100% 0, 100% 100%, 0 100%)
- 内容用 absolute 定位到三角形质心(左上 11%/6.5% / 右下 11%/6.5%),永不重叠
- 微妙的 60px 网格纹 + 角落极光(紫蓝 / 橙金)+ 极细中线分割
- clamp(80px, 13vw, 200px) 巨字标题 + 序号 + Logo + tagline + 特性列表 + CTA
## 交互
- hover 联动:用 [data-hover] attribute 替代 :has(),兼容旧 WebKit
- 鼠标悬停一侧 → 该侧亮起 + 内容平移 + CTA 反白;另一侧变暗 + 内容模糊缩小
- 点击三角形 → 三角形 clip-path 扩满(0.8s)→ 中心圆扩散(0.9s)→ 进入主页
- reveal 节点 attach 到 body,跨路由切换存活,新页面渲染后再淡出
## Both / Later 处理
- 两个次级选项保留,做成底部居中的玻璃 pill 链接(不抢戏)
- 不走对角线扩散动画,点击后直接 applyEngineSelection + navigate
## 兼容性
- prefers-reduced-motion: reduce → 关闭所有动画
- 移动端响应式:< 760px 调整字号 / 边距 / 角标
- 用 Vite define 注入的 __APP_VERSION__ 显示版本号(与 main.js / sidebar.js 一致)
## i18n
- engine.choiceTopBanner / choiceCtaEnter
- choiceOpenclaw{Tagline,Feat1,Feat2,Feat3,Category}
- choiceHermes{Tagline,Feat1,Feat2,Feat3,Category}
- choiceSecondary{Both,Later}
- 三语完整(zh-CN / en / zh-TW)
## 抽卡 prototype
保留 docs/engine-select-mockups/ 下的 V2 4 张设计 + 索引页(v2-monolith.html
即本次接入的最终版本)。
2026-05-14 06:22:32 +08:00
晴天
cc19a07999
fix(hermes): sidebar 缺失 group-chat / files 入口 + 补 folder 图标
...
复查发现 2 个真 bug:路由注册了但 sidebar 没入口,用户点不到。
## §N 群聊 - sidebar 缺入口
- /h/group-chat 已注册路由(debce2f),但 sidebar monitor section 没加
- 修复:紧跟 /h/chat 之后插入「群聊」(agents 图标)
## §L 文件管理器 - sidebar 缺入口
- /h/files 已注册路由(129d8c0),但 sidebar manage section 没加
- 修复:紧跟 /h/oauth 之后插入「文件管理器」(folder 图标)
## sidebar.js 补 folder 图标
- ICONS 表里没有 'folder',导致 /h/files sidebar 项无图标(fallback 到空字符串)
- 加进去(24x24 viewBox 的标准 folder svg)
## 复查覆盖
✓ 61 个 hermes_* Tauri 命令全部在 lib.rs invoke_handler 注册
✓ 63 个 invoke('hermes_*') 调用在 dev-api.js 都有 fallback (除 hermes_agent_run_stream 走 webStream)
✓ 6 个新页面所有 t('engine.*') 键在 engine.js 都有定义(含 zh-CN/en/zh-TW 三语)
✓ 19 个 Hermes 页面文件齐备(最大 chat.js 1626 行,最小 channels.js 占位 17 行)
✓ cargo check 干净(仅 1 个 unused field 警告,不影响)
✓ npm build ✓
2026-05-14 05:53:32 +08:00
晴天
6b118877f1
refactor(hermes): UX 小白化最后一波 - skills/memory/cron 升级 humanizeError
...
完成 Hermes 引擎所有页面的统一错误处理改造。
## skills.js (2 处)
- 加载技能失败 → humanizeError(e, t('engine.skillsLoadFailed'))
- 启用/禁用切换失败 → humanizeError(e, t('engine.skillsToggleFailed'))
## memory.js (1 处)
- 保存记忆失败 → humanizeError(e, t('engine.memorySaveFailed'))
## cron.js (2 处)
- 加载定时任务失败 → humanizeError(e, t('engine.cronLoadFailed'))
- 保存定时任务失败 → humanizeError(e, t('engine.cronSaveFailed'))
## i18n 新增 2 键
- cronLoadFailed / cronSaveFailed × 3 语言
## 现在 Hermes 全部 16 个页面均统一了错误处理
统计:sessions / extensions / env-editor / usage / lazy-deps / config /
skills / memory / cron / chat / setup / dashboard / services /
profiles / kanban / oauth / files / gateways / group-chat
剩余原始 raw error 显示的位置都是合理的:
- dashboard.js install modal 日志 — 用户在看安装日志,raw 信息有用
- setup.js fetch 模型 — 已分类处理 403/404/timeout
- chat.js RUNNING_SESSION 错误 — 已特殊处理
2026-05-14 05:46:44 +08:00
晴天
dcac1d6d21
refactor(hermes): UX 小白化收尾 - 6 个页面统一 humanizeError + 修 usage.js bug
...
把 raw error toast 升级为 humanizeError,让用户看到分类友好的错误提示
(自动加 action button 如「打开设置」「重试」「查看文档」)。
## sessions.js (5 处)
- 加载会话失败 → humanizeError(err, t('engine.sessionsLoadFailed'))
- 详情加载失败 → humanizeError(err, t('engine.sessionsDetailLoadFailed'))
- 切换会话失败 → humanizeError(err, t('engine.sessionsSwitchFailed'))
- 删除失败 → humanizeError(err, t('engine.chatDeleteFailed'))
- 导出失败 → humanizeError(err, t('engine.sessionsExportFailed'))
## extensions.js (5 处)
- dashboard 打开失败 (probe / start) - 2 处
- 主题保存失败 → humanizeError(err, t('engine.extensionsThemeSaveFailed'))
- 加载扩展失败 → humanizeError(err, t('engine.extensionsLoadFailed'))
- 重新扫描失败 → humanizeError(err, t('engine.extensionsRescanFailed'))
## env-editor.js (4 处)
- reveal / save / delete / load 错误 → humanizeError
- 文案保留 inline 中文(页面尚未 i18n 化)
## usage.js (1 bug + 1 升级)
- **修真 bug**: catch (_) {...} 内部却用了 err 引用 → 改为 catch (err) {...}
- 失败时 humanizeError(err, t('engine.usageLoadFailed'))
## lazy-deps.js (1 处)
- features API 失败显示 humanizeError + escapeHtml
## config.js (2 处)
- 加载配置失败 → humanizeError(err, t('engine.hermesConfigLoadFailed'))
- 保存配置失败 → humanizeError(err, t('engine.hermesConfigSaveFailed'))
## hermes.css 修 lint
- .hm-kanban-task-summary 加 line-clamp 标准属性(不只是 -webkit-line-clamp)
## i18n 新增 8 键
- sessionsLoadFailed / sessionsSwitchFailed / usageLoadFailed
- extensionsThemeSaveFailed / extensionsLoadFailed / extensionsRescanFailed
- hermesConfigLoadFailed / hermesConfigSaveFailed
- 全部 × 3 语言
## 累计影响
- 6 个 hermes 页面(sessions/extensions/env-editor/usage/lazy-deps/config)统一错误处理
- 修 usage.js 1 个真 bug(catch 参数名错配)
- 8 个新 i18n × 3 语言
- 1 个 CSS lint 警告修复
- npm build ✓
2026-05-14 05:45:33 +08:00
晴天
debce2f810
feat(hermes): Batch 3 §N - 群聊(多 Agent 并行响应)
...
Hermes 内核没有「群聊」概念,由 ClawPanel 前端编排:
- 用户选 1-N 个 Profile(每个对应一个 Agent 配置)
- 发消息 → 串行调度(用 hermes_profile_use 切换 + hermesAgentRun 阻塞调用)
- 每个 Profile 的回复用 @profile_name 标记后显示在统一界面
## 新页面 /h/group-chat(~250 行)
### UI 布局
- 左侧 240px: Profile 多选列表
· 顶部说明 + 已选 N 个统计
· checkbox 风格,is-checked 高亮
- 右侧主区: 消息列表 + 输入框
· user 消息右对齐(accent 蓝色气泡)
· assistant 消息左对齐(每条带 @profile 徽章)
· loading 状态用三点跳动动画
· error 状态红色 + ⚠️ 图标
· 输入框 Enter 发送 / Shift+Enter 换行
### 调度策略
- 当前实现:串行(hermes_profile_use 切换 + hermesAgentRun)
· 简单稳健,避免后端并发对同一 profile 状态的竞态
· 缺点:N 个 profile 总耗时 = N × 单次耗时
- 真正并发需后端支持 hermes_agent_run(profile=...) 参数
· 留作下次内核改造(设计稿已记下)
### 限制(明确告知用户)
- 仅 Tauri 桌面端(Web 模式显示禁用提示)
- 非流式(用阻塞式 hermesAgentRun,等所有完成后一起显示)
- 不持久化(一次性会话,刷新清空,不挂 chat-store)
- 切 profile 后不还原(用户后续 /h/chat 会保持最后切到的 profile)
### sidebar
- 监控 section 加群聊入口(agents icon,紧跟 /h/chat 之后)
- /h/group-chat 路由注册
### CSS(~180 行)
- .hm-gc-layout: grid 双栏(响应式 → 单栏)
- .hm-gc-side: 左侧 profile 多选
- .hm-gc-main: 右侧消息列表 + 输入区
- 加载点动画 hm-gc-pulse
- @profile 徽章用 mono 字体 + accent 色
### i18n
- 13 个新键 × 3 语言(hermesGroupChat*)
## 累计
- 1 个新页面 ~250 行 + CSS ~180 行 + i18n 39 字符串
- npm build ✓
2026-05-14 05:39:36 +08:00
晴天
129d8c0ac1
feat(hermes): Batch 3 §L - 文件管理器(限定在 ~/.hermes 子树内)
...
校对:Hermes 没有 file HTTP API,必须自建。
## Rust 后端:3 个安全 fs 命令(~180 行)
### 安全策略
- 所有路径必须在 hermes_home() 子树内(防 path traversal)
- canonicalize 后用 starts_with 验证
- 拒绝绝对路径跳出 + .. 跳出
- 5 MB 文件大小上限
- 单次列目录最多 2000 条
### 命令
- hermes_fs_list(path) → { path, entries: [{name, kind, size, modified}] }
· 隐藏文件默认不显示(.env 除外)
· 排序:目录在前,文件在后,按名字
- hermes_fs_read(path) → { path, size, text?, binary_b64? }
· UTF-8 文本 → text
· 二进制 → 内置 base64 编码(不引新依赖)
- hermes_fs_write(path, content) → { path, size }
· 父目录必须存在
· 5 MB 上限
## 前端 /h/files 页面(~270 行)
### UI 布局
- 左侧:面包屑 + 目录树(点目录进入 / 点文件选中)
- 右侧:编辑器(文本)/ 预览(图片)/ 元信息(其他二进制)
### 文件树
- 文件图标按扩展名(📁 /🔗 /🖼️ /📝 /⚙️ /📄 )
- 文件大小显示(B/KB/MB)
- ".." 返回上级
- 选中态高亮
### 编辑器
- textarea 编辑,monospace 字体
- "保存 *" 状态标记 dirty
- 切目录/文件前 showConfirm 「丢弃未保存修改?」
- 保存成功 toast
### 二进制预览
- 图片 (png/jpg/gif/webp/svg) → 用 data: URL 显示
- 其他 → 「二进制文件(不可编辑)」+ 文件大小
## sidebar
- 「管理」section 加文件管理器入口(folder icon)
- /h/files 路由注册(含意外的 routes 顺序修复)
### dev-api.js
- Web 模式走 Node fs.readdirSync/readFileSync/writeFileSync
- 同样的安全策略:根目录 hermes_home() = process.env.HERMES_HOME 或 ~/.hermes
- realpath 验证 + 5 MB 限制
### CSS(~165 行)
- .hm-files-layout: grid 双栏(响应式 → 单栏)
- .hm-files-tree: 左侧树,breadcrumb + entry 列表
- .hm-files-pane: 右侧编辑器/预览
- .hm-files-editor: 全宽 textarea,monospace
- 响应式:768px 以下单栏
### i18n
- 12 个新键 × 3 语言(hermesFiles*)
## 修复
- src/engines/hermes/index.js 末尾多余 `}` 删除(之前 edit 留下)
## 累计
- Rust ~180 行 + 前端 ~270 行 + CSS ~165 行 + dev-api ~55 行
- 12 个 i18n × 3 语言
- cargo check ✓ + npm build ✓
2026-05-14 05:36:50 +08:00
晴天
0d6c4614e4
feat(hermes): Batch 2 §G - 多 Gateway 看板(同时运行多 profile Gateway)
...
设计:让用户给多个 profile 各自配 Gateway 实例,同时运行。
端口完全由 profile 的 config.yaml model.gateway.port 决定,ClawPanel 只负责 spawn + PID 跟踪。
## Rust 后端(~350 行)
### 数据结构
- MULTI_GW_PIDS: Mutex<Option<HashMap<String, u32>>> 全局 PID 表
- 持久化在 panelConfig.hermes.multiGateways: [{name, profile}]
### Helper 函数
- multi_gw_pids_get/set/remove: 线程安全 PID 表读写
- read_multi_gateways_config / write_multi_gateways_config: panel config R/W(保留其他字段)
- read_profile_gateway_port(profile): 缩进感知解析 profile config.yaml 的 model.gateway.port
- pid_is_alive(pid): Windows 用 tasklist /FI,Unix 用 kill -0 检测
### 5 个新 Tauri 命令
- hermes_multi_gateway_list() → [{name, profile, port, running, pid, owned}]
· running = PID 存活 || TCP 探测可达
· owned = ClawPanel spawn(可控制)vs 外部进程占着端口
- hermes_multi_gateway_add(name, profile) - 写入 panel config,名称合法性检查
- hermes_multi_gateway_remove(name) - 先停掉,再从配置删除
- hermes_multi_gateway_start(name) - spawn `hermes --profile <name> gateway run`
· 注入 profile 的 .env
· 等待端口可达(8 秒超时)
· 记 PID
- hermes_multi_gateway_stop(name) - taskkill /F /PID (Windows) 或 kill -TERM (Unix)
### 发射 hermes-multi-gateway-changed 事件(前端可监听刷新)
## 前端(~230 行)
### /h/gateways 页面
- 顶部 + 添加 按钮
- 卡片网格(复用 .lazy-deps-grid)显示每个 Gateway:
· name + status badge (运行中/已停止)
· profile + port + PID + owned 提示
· 启动 / 停止 / 删除 按钮
- 添加弹窗:name 输入 + profile 下拉(拉自 hermesProfilesList)
- 停止 / 删除均有 showConfirm(带 in-flight 警告)
- 外部进程占端口时 stop 按钮 disabled + tooltip
### sidebar
- 「管理」section 加 Gateways 入口(gateway icon)
- /h/gateways 路由注册
### dev-api.js
- Web 模式 fallback: 多 Gateway 不支持本地进程管理(throw friendly error)
### i18n
- 26 个新键 × 3 语言(hermesGateway*)
## 累计
- Rust ~350 行 + 前端 ~230 行 + i18n 78 字符串 + 路由/sidebar
- cargo check ✓ + npm build ✓
2026-05-14 05:30:18 +08:00
晴天
b656ce74f8
refactor(hermes): UX 小白化 - chat.js profile 切换错误用 humanizeError
...
之前是 toast(err?.message || String(err)),raw error 用户看到一堆英文 traceback。
现在用 humanizeError 自动:
- 分类(NETWORK/TIMEOUT/AUTH/NOT_FOUND/PERMISSION/...)
- 友好文案(中英繁三语)
- 自动加 action button(如「打开设置」「重试」「查看文档」)
## 文件
- chat.js: import humanizeError,profile 切换 catch 改 humanizeError(err, t('engine.chatProfileSwitchFailed'))
- i18n: 新增 chatProfileSwitchFailed × 3 语言
## 范围
仅 profile 切换这个高频操作 — 其他 chat-store 路径错误已通过系统消息气泡展示
(chat-store.js 添加错误消息时本身已经友好),不需要再改。
2026-05-14 05:25:08 +08:00
晴天
d483e5bff9
feat(hermes): Batch 3 §Q - OAuth 三种登录 (PKCE / device_code / external)
...
校对发现端点 + token 注入已就位(前一 commit),可直接做 UI。
## 新页面 /h/oauth (~250 行)
### 数据流
- GET /api/providers/oauth - 列表 + 状态(公开)
- POST /api/providers/oauth/{id}/start - PKCE 返回 auth_url,device_code 返回 user_code + verification_url
- POST /api/providers/oauth/{id}/submit { session_id, code } - PKCE 提交
- GET /api/providers/oauth/{id}/poll/{session_id} - device_code 轮询(公开)
- DELETE /api/providers/oauth/{id} - 断开
### UI
- 卡片网格(复用 .lazy-deps-grid)展示每个 provider
- active 徽章 + flow 标签 + token preview + expires 信息
- 「登录」按钮按 flow 类型分发:
· **external** (claude-code 等):showContentModal 显示 CLI 命令,用户终端运行后回点刷新
· **PKCE** (anthropic):
1. 系统 window.open(auth_url) 打开浏览器授权
2. showModal 弹窗:显示授权链接 + 让用户粘贴回调 code
3. POST submit → 刷新状态
· **device_code** (qwen / minimax / nous / openai):
1. window.open(verification_url) 打开授权页
2. showContentModal 显示 6 位 user_code(大字号 mono 字体)
3. 每 2.5s 自动 GET poll 轮询直到 success/failed/expired
4. 10 分钟超时
5. MutationObserver 监听模态关闭自动停轮询
### sidebar
- 管理 section 加 OAuth 入口(memory icon)
- 路由 /h/oauth 注册
### 修复:之前 edit 弄坏的 sidebar 结构
- 恢复 monitor 5 项(dashboard/chat/sessions/logs/usage)
- 恢复 manage 8 项(skills/memory/cron/profiles/kanban/oauth/lazy-deps/extensions)
- 删除文件末尾多余的 `}`
### i18n
- 26 个新键 × 3 语言(hermesOAuth*)
## 复用基础设施
- hermes_dashboard_api_proxy 自动注入 session token(前一 commit 已做)
- humanizeError 友好错误
- showModal / showContentModal / toast / lazy-deps-grid 样式
## 累计
- 1 个新页面 ~250 行
- sidebar 结构修复 + /h/oauth 路由注册
- 26 个 i18n 键 × 3 语言
- npm build ✓
2026-05-14 05:23:02 +08:00
晴天
64f4668522
feat(hermes): Batch 3 §P TTS + Dashboard session token 自动注入
...
核查发现:
- §P TTS: Hermes 内核没有 HTTP TTS 端点(只有 lazy_deps 的 tts.edge/elevenlabs PyPI 包) → 改用浏览器 Web Speech API(100% 离线、跨平台)
- Dashboard token: 9119 大部分 /api/* 需要 token 鉴权,token 注入到 SPA HTML 的 window.__HERMES_SESSION_TOKEN__ → 必须从 HTML 抓
## §P TTS — 浏览器原生(src/lib/tts.js)
新工具模块 src/lib/tts.js(~110 行):
- speak(text, lang?) - 异步播放,返回 Promise
- toggle(text, lang?) - 重复播放则停止
- stopSpeaking() / isSpeaking() / isSupported()
- 自动语言检测:中/英/日/韩
- pickVoice 启发式:精确匹配 > 前缀匹配 > 默认
- Chrome bug 兼容:voiceschanged 异步加载 + 100ms 兜底
### chat.js 接入
- assistant 消息 footer 复制按钮旁加 🔊 朗读按钮(图标 speaker)
- 仅 tts.isSupported() 时渲染(不支持的浏览器隐藏)
- 点击 toggle,简化文本(去 markdown 代码块、url)
- 失败 toast 提示
### i18n
- chatSpeak / chatSpeakShort / chatSpeakFailed × 3 语言
### CSS
- .hm-chat-msg-tts 复用 copy 按钮风格
## Dashboard session token 自动注入器(解锁 §J/§O/§Q)
校对发现:dashboard 9119 大部分 /api/* 端点 _require_token 保护,
token 是进程启动时 secrets.token_urlsafe(32) 生成,没有公开获取 API,
只能 GET / 抓 SPA HTML 提取 window.__HERMES_SESSION_TOKEN__="..."。
### Rust 后端增强 hermes_dashboard_api_proxy
- 模块级 DASHBOARD_SESSION_TOKEN: Mutex<Option<String>> 缓存
- fetch_dashboard_session_token(port): GET / + 字符串搜索 needle 提取 token
- dashboard_session_token(port, force_refresh): 缓存 + 强刷接口
- proxy 实现:
1. 拿缓存 token,注入 X-Hermes-Session-Token header
2. 发请求;若 401 → 强刷 token 重试一次
3. 仍失败抛 HTTP 错
- build_request 闭包复用避免重复代码
### Web 模式 dev-api 同步
- _fetchDashboardToken(port) 抓 HTML 正则提取
- _getDashboardToken(port, forceRefresh) 模块级缓存
- hermes_dashboard_api_proxy 401 重试逻辑
## 影响
- 已用 dashboard_api_proxy 的 §H Profiles + §M Kanban 立即受益(之前 401 会失败)
- §J dashboard plugin 可见性、§Q OAuth 现在可直接复用
- §O Terminal 走 WS,token 注入路径不同,但 _getDashboardToken 可复用
## 累计
- Rust: ~60 行(token 抓取 + 缓存 + 重试)
- 前端: tts.js 新文件 110 行 + chat.js TTS 按钮 + dev-api token 注入
- i18n: 3 个新键 × 3 语言
- cargo check ✓ + npm build ✓
2026-05-14 05:19:02 +08:00
晴天
6a45c12d67
feat(hermes): UX 小白化第一步 - services restart/stop 加 showConfirm 防误触
...
Gateway restart/stop 是高影响动作(in-flight agent runs 会断),
对应 Approval Flow / multimodal 等改进可能正在跑 — 误触代价大。
## services.js
- runGatewayAction('restart' | 'stop') 调用前先 showConfirm
- 文案:「正在进行的 Agent 会话会被中断」(impact 列表)
- danger 变体(红色确认按钮)
- start 不加 confirm(用户主动启动不需要)
- 复用 confirmText 用 dashRestartGw / dashStopGw(已有 i18n)
## i18n
- servicesConfirmRestart / servicesConfirmStop / servicesImpactInflight 3 个新键 × 3 语言
2026-05-14 05:15:03 +08:00
晴天
3c8c315402
feat(hermes): Batch 2 §I + Batch 3 §M - 流恢复 + Kanban 看板
...
## Batch 2 §I 流恢复(chat 在切页/刷新后能接上 run)
校对稿:用 run_id 持久化到 localStorage,新页面挂载时查询 status 决定是否重连。
### 后端
- 新 Tauri 命令 hermes_run_status(run_id):
· GET /v1/runs/{run_id} 返回 { run_id, status, last_event, output?, ... }
· status: running / stopping / completed / failed / cancelled / waiting_for_approval
· 404 友好返回 status='not_found' 而不是抛错
### 前端 chat-store
- 新 STORAGE_ACTIVE_RUN 持久化 { runId, sessionId, profile, t }
- hermes-run-started 监听里 safeSet 持久化
- cleanupAfterRun 里 safeRemove 清理
- 新方法 recoverIfRunning():
· 跨 profile / 1 小时过期 → 直接清
· status=running/stopping/waiting_for_approval → attachStreamListeners + 恢复 streaming
· status=已结束 → 拉最新 messages
· 404 → 静默清
### chat.js
- 页面挂载时 store.recoverIfRunning() — 切页/刷新后无缝接上流
## Batch 3 §M Kanban 看板(Hermes 已内置)
校对稿:「Hermes 已内置 kanban 系统,直接调 /api/plugins/kanban/* 即可」。
设计稿原本是「自建本地存储」(~800 行),复用 Hermes 内置后大幅缩减。
### 新页面 /h/kanban
- 全部走 hermesDashboardApi(复用 §H 的基础设施)
- 顶部 board 切换器 + 「+ 新任务」按钮
- 渲染 board.columns(按状态分列:todo / in_progress / blocked / done / archived)
- 任务卡片:title + summary(2 行截断)+ priority badge + assignee + 评论数
- 点卡片 → showContentModal 显示详情 + 「修改状态」按钮
- 修改状态 → PATCH /api/plugins/kanban/tasks/{id} { status }
- board 切换 → POST /api/plugins/kanban/boards/{slug}/switch
### sidebar
- 「管理」section 加 Kanban 入口(inbox 图标)
- /h/kanban 路由注册
### CSS (.hm-kanban-*)
- 水平滚动 board 容器
- 280px 固定宽度列 + 内部滚动
- 卡片 hover 边框变 accent 色 + 轻阴影
- 优先级 badge(琥珀色)/ assignee(accent 色)
### i18n
- 27 个新键 × 3 语言(zh-CN/en/zh-TW)
## 累计
- Rust: 1 个新命令(hermes_run_status ~30 行)
- 前端: chat-store 流恢复(~40 行)+ kanban 新页面(~230 行)
- i18n: 27 个新键 × 3 语言
- CSS: ~100 行
- cargo check ✓ + npm build ✓
2026-05-14 05:12:37 +08:00
晴天
3168551569
feat(hermes): Batch 2 §H - Profiles 管理 UI + Dashboard API 通用代理
...
校对稿要点:「Profiles 全部走 HTTP /api/profiles*,无需自己写 CLI 桥接」。
## 基础设施: hermes_dashboard_api_proxy(通用 9119 HTTP 代理)
新增 Tauri 命令 hermes_dashboard_api_proxy(method, path, body, headers):
- 支持 GET/POST/PUT/PATCH/DELETE
- 走 Dashboard 9119 端口(无需 API_SERVER_KEY,本地绑定)
- 自动 JSON parse + 错误时友好提示「请先启动 Dashboard」
- 一次实现,未来 Batch 2/3 的 Profiles/Kanban/OAuth/Sessions 都走这一个入口
前端 wrapper: api.hermesDashboardApi(method, path, body, headers)
dev-api.js: Web 模式同步实现
## Profiles 管理页 /h/profiles
新文件 src/engines/hermes/pages/profiles.js:
- GET /api/profiles 列表 → 渲染卡片网格(复用 .lazy-deps-grid 样式)
- 每张卡片:profile 名 + active 徽章 + Switch/Rename/Delete 按钮
- 「+ 新建」按钮 → showModal 弹窗(name + clone_from_default 选项)
- 「重命名」→ PATCH /api/profiles/{name} { new_name }
- 「删除」→ showConfirm(带 impact 提示「永久清除会话/凭据/记忆」)→ DELETE /api/profiles/{name}
- 「切换到此」→ 复用现有 chatStore.switchProfile(CLI 实现)
- 失败走 humanizeError 友好提示
- active profile 与 chatStore.state.activeProfile 对齐
## sidebar + 路由
- Hermes 引擎「管理」section 加 Profile 管理入口
- 路由 /h/profiles 注册到 hermes/index.js
## i18n
- engine.hermesProfilesTitle / hermesProfilesDesc / hermesProfilesEmpty
- hermesProfileNew / NewTitle / NameLabel / NameRequired / CloneFromDefault / CloneHint
- hermesProfileSwitch / Switched / SwitchFailed
- hermesProfileRename / RenameTitle / NewNameLabel / Renamed / RenameFailed
- hermesProfileDelete / DeleteConfirm / DeleteImpact / Deleted / DeleteFailed
- hermesProfileActive / Created / CreateFailed
- 共 21 个键 × 3 语言
## 累计
- Rust: 1 个新命令(hermes_dashboard_api_proxy ~50 行)
- 前端: 1 个 wrapper + 新页面 ~180 行
- dev-api.js: 1 个 handler
- i18n: 21 个新键 × 3 语言
- cargo check ✓ + npm build ✓
2026-05-14 05:04:53 +08:00
晴天
8eb8a7666e
feat(hermes): Batch 3 §K - 多模态图片上传(chat attach + 拖拽 + 粘贴 + base64)
...
Hermes Agent 已支持 OpenAI 多模态格式(tests/gateway/test_api_server_multimodal.py),
ClawPanel 前端补 attach UI 即可对接 Claude 3.5 / GPT-4o / Gemini 等视觉模型。
## 后端
- HermesAttachment 结构:{ kind, mime, name?, data_base64 }
- build_multimodal_input(text, attachments) 把 text 转成
[{type:"text",text}, {type:"image_url",image_url:{url:"data:..;base64,.."}}, ...]
- hermes_agent_run 加 attachments 参数(向后兼容:未传时走原 string input)
## 前端
- tauri-api.js: hermesAgentRun 加 attachments 参数
- chat-store sendMessage:
· 允许 text 空但有 attachments 也能发
· user 消息记录 attachments[].dataUrl 用于气泡内渲染
· isTauriRuntime 时 await api.hermesAgentRun(...,atts)
- chat.js 渲染层:
· renderMessage 在内容前插入 .hm-chat-msg-attachments + .hm-chat-msg-image(点击放大)
· 输入栏前面增加 .hm-chat-attach-preview 预览条(缩略图 + 文件名 + × 移除)
· 输入框左侧加 paperclip attach 按钮 + 隐藏 <input type="file" accept="image/*" multiple>
· 发送按钮 disabled 条件改为 (!text && !attachments)
- chat.js 交互:
· fileToBase64 用 FileReader 转纯 base64
· addAttachmentFromFile 校验 image/* + 10MB + 最多 5 张
· attach 按钮 click → 触发文件选择器
· 拖拽到输入区 → dragover 高亮 + drop 加附件
· 粘贴图片 → clipboardData 读 image 文件
· 移除按钮 splice
- chat-store.sendMessage 后清 pendingAttachments
## 限制
- 单图最大 10 MB(base64 后约 13 MB)
- 一次最多 5 张
- 超限 toast 友好提示
- 非图片格式拒收
## CSS
- .hm-chat-attach-btn / hover / disabled
- .hm-chat-attach-preview / chip / chip-name / chip-remove
- .hm-chat-input-wrap--dragover(拖拽虚线高亮)
- .hm-chat-msg-attachments / msg-image / msg-image--zoom(点击放大模式)
## i18n
- engine.chatAttach / chatAttachRemove / chatAttachOnlyImage
- chatAttachTooBig / chatAttachTooMany / chatAttachReadFailed
- 3 语言(zh-CN/en/zh-TW)
## 注意
- Web 模式(dev-api 走 SSE)暂不支持 attachments 透传(hermes_agent_run_stream 没改),
原因:Web 模式当前 chat 是 stream-only 路径,需要单独改 dev-api 的 hermes_agent_run_stream handler
- 桌面端 Tauri 模式开箱可用
- 累计变动:6 个文件,~120 行新代码,6 个 i18n 键
- cargo check ✓ + npm build ✓
2026-05-14 04:59:36 +08:00
晴天
112963b2b7
feat(hermes): Batch 1 §E - Sessions 导出(走 dashboard /api/sessions/{id}/messages)
...
校对稿订正:不走 CLI `hermes sessions export`,直接调 dashboard 9119 HTTP API。
## 后端
- 新 Tauri 命令 hermes_session_export(session_id):
· GET http://127.0.0.1:{dashboard_port}/api/sessions/{id}/messages
· 拿原始 JSON 返回前端
· 错误提示「请先启动 Dashboard」(dashboard server 必须运行)
## 前端
- tauri-api.js: hermesSessionExport wrapper
- sessions.js: 详情面板「打开会话 / Pin / 导出 / 删除」并列布局
· 点导出 → Blob + URL.createObjectURL + a.download 浏览器下载 hermes-session-{id}.json
· toast 成功/失败
- dev-api.js: Web 模式 handler 同步调 dashboard 端口
## i18n
- sessionsExport / sessionsExportSuccess / sessionsExportFailed × 3 语言
2026-05-14 04:54:25 +08:00
晴天
832bb9a6ef
feat(hermes): Batch 1 §A + §B + P1-3 lazy_deps 优化 - 占位修 + 中文硬编码清 + 自定义 venv 适配
...
## §A channels.js 占位路由处理
- /h/channels 当前是 487 字节 placeholder
- 已确认 sidebar 没挂入口(getNavItems 不含 channels)
- 路由表保留但加注释表明这是 reserved,完整实现见 Batch 3
## §B config.js i18n 化(清理 5 处硬编码)
- "重新加载" / "保存配置" / "saving…" / "loading…" / "raw yaml editor"
- "配置已保存,建议重启 Hermes Gateway 生效" toast
- 抽 7 个新键到 locales/modules/engine.js(3 语言):
· hermesConfigEyebrow / hermesConfigReload / hermesConfigSave
· hermesConfigSaveSuccess / hermesConfigStatusSaving
· hermesConfigStatusLoading / hermesConfigStatusReady
## P1-3 lazy_deps 校对稿优化(commit b852ebb 的补丁)
hermes_venv_python() 增加 HERMES_PYTHON 环境变量优先级:
1. HERMES_PYTHON env var(适配 brew / uv tool / 容器等自定义 venv)
2. ~/.hermes-venv/{bin/python | Scripts/python.exe}(默认)
allow_lazy_installs 守门:经核实内核 tools.lazy_deps.ensure 内部已检查
security.allow_lazy_installs,禁用时抛 FeatureUnavailable,Rust 端已捕捉
并友好返回错误(无需额外代码)。
## 累计
- 3 个修改文件(hermes/index.js + config.js + engine.js + hermes.rs)
- 7 个新 i18n 键 × 3 语言
- cargo check ✓ + npm build ✓
2026-05-14 04:51:16 +08:00
晴天
efade55f61
feat(hermes): Batch 1 §C+§D+§C-bis - Approval Flow + Stop 真中断 + 3 类新事件
...
校对稿(hermes-source-verified)基于真实 Hermes 源码确认了关键事实:
- 真实 SSE 事件 9 类(设计稿推测的 6 个根本不存在)
- 真实 abort 端点:POST /v1/runs/{run_id}/stop(用 run_id 不是 session_id)
- Approval Flow 是 Hermes 重要原生特性,ClawPanel 0% 接入 → 跑代码工具就崩
本 PR 一次解决 3 个必修硬伤:
## 修复 1: Stop 假停(§D)
- 新 Tauri 命令 hermes_run_stop(run_id) → POST /v1/runs/{run_id}/stop
- chat-store: state 新增 currentRunId,来自 hermes-run-started 事件
- stopStreaming() 改为:先调 hermes_run_stop(currentRunId) 通知后端,再 abort 本地 SSE
- 之前 stopStreaming 只 abort 本地 SSE,后端继续跑完 → 是「假停」
## 修复 2: Approval Flow 接入(§C-bis 新增 — 设计稿原本没写)
- 新 Tauri 命令 hermes_run_approval(run_id, choice) → POST /v1/runs/{run_id}/approval
- choice 枚举校验:once / session / always / deny
- chat-store: state.pendingApproval 存待批准信息(tool, args, choices, run_id)
- chat.js: 新增 renderApprovalPanel() 渲染琥珀色气泡 + 4 按钮 + JSON args 预览
- store.respondApproval(choice) 暴露给 UI(乐观清状态 + 失败回滚)
- 用户跑代码工具(terminal/code_execution)时会触发,没接入就会卡死
## 修复 3: SSE 事件白名单补 3 类(§C 校对版)
- normalize_hermes_stream_event 白名单增加:
· approval.request → emit hermes-run-approval-request
· approval.responded → emit hermes-run-approval-responded
· run.cancelled → emit hermes-run-cancelled(终态,返回 Ok(true))
- chat-store 新监听 u5..u9(5 个新事件):
· hermes-run-started → 存 currentRunId
· approval-request → 设 pendingApproval
· approval-responded → 清 pendingApproval
· cancelled → 标记 (stopped) + cleanup
· reasoning → 标记 hasReasoning(设计稿推测的 reasoning.delta 不存在)
- handleStreamEvent(Web 模式)同步加 4 个新分支
## chat.js UI
- renderApprovalPanel:琥珀色边框 + 🔐 emoji + 工具名 + JSON args 预览 + 4 选项按钮
- "deny" 用 btn-secondary(灰色),其他 btn-primary(蓝色)
- 按钮点击 → store.respondApproval(choice) → 后端 POST + 等服务端 approval.responded 作权威清理
- streaming 中显示 aborting 文案当 state.aborting=true
## CSS (.hm-chat-approval*)
- 琥珀色边框 + 半透明背景(明/暗主题各自适配)
- args 单独 monospace 代码块、max-height: 180px 防过长
- 响应式:max-width: 720px,按钮 flex-wrap
## i18n
- engine.chatAborting / chatApprovalTitle / chatApprovalHint
- chatApprovalOnce / chatApprovalSession / chatApprovalAlways / chatApprovalDeny
- chatApprovalFailed
- 3 语言(zh-CN/en/zh-TW),其它语言走 fallback
## 设计稿对照(保留可信细节,砍掉推测)
- ✅ 留:approval.request / approval.responded / run.cancelled / reasoning.available(4 类真实事件)
- ❌ 砍:reasoning.delta / thinking.delta / compression.* / abort.* / usage.updated / run.queued(6 类不存在的事件,hermes-web-ui 内部合成)
- ✅ 修:abort 端点路径 /v1/runs/{run_id}/stop(用 run_id)
## 累计
- Rust: 1 个 helper(read_hermes_api_key) + 2 个新命令 + emit_hermes_stream_event 加 3 分支
- 前端: chat-store 新 4 个 state 字段 + 5 个监听器 + 4 个 handleStreamEvent 分支 + respondApproval API
- chat.js: renderApprovalPanel + 按钮绑定 + aborting 文案
- i18n: +8 个键 × 3 语言
- cargo check ✓ + npm build ✓
2026-05-14 04:48:14 +08:00
晴天
c00b2dbf64
feat(openclaw): P1-6 config.schema RPC 写入校验 - 防小白改坏配置
...
OpenClaw 内核 config.set/patch 写入时已经会校验,但用户要等点保存才看到错误。
本 PR 把校验提前到前端,让用户改完字段立刻看到红字提示。
## 新增工具 src/lib/config-schema.js
- getFieldSchema(path) — 调内核 config.schema.lookup,带 5 分钟缓存
- validateField(path, value) — 拿 schema 后做基础约束校验
- validateFieldSync(schema, value, path) — 已有 schema 时同步校验
- clearSchemaCache(path?) — 清缓存(极少需要)
## 校验维度(不引入 ajv,保持 vanilla JS 体积)
- required — 必填空值检查
- type — string / number / integer / boolean / array / object / null
(含「数字字符串当数字看」的容错)
- enum — 枚举白名单
- minimum / maximum — 数值范围
- pattern — 字符串正则
## 友好错误文案(i18n)
- common.error.schemaRequired / schemaType / schemaEnum / schemaMin / schemaMax / schemaPattern
- 6 个键 × 11 语言全覆盖
- 替换 schema 给的英文 path 后用户看到的是:
「Gateway 端口不能小于 1024」「gateway.port 应该是「integer」类型」
## 集成示范:gateway.js
- saveConfig 开头先 validateField('gateway.port', port)
- 失败 → toast 红字 + focus 回 port 输入框 + early return
- 通过 → 走原流程
- 内核无该 schema 时降级放行(不阻断保存)
## 设计哲学
- 内核仍是最终守门人(config.set/patch 会再校验)
- 本模块的价值是「立即反馈」+「未来动态 UI 渲染」基础
- 容错优先:schema.lookup 失败时静默放行,不影响老内核兼容性
## 累计
- 1 新文件(config-schema.js)
- 2 修改(gateway.js / common.js)
- 6 个新 i18n 键 × 11 语言
- 后续可在 memory/dreaming/security/cron 等页面同样接入
2026-05-14 04:30:23 +08:00
晴天
e717a7a098
feat(openclaw): P1-0 push.web.* 推送通知 - ClawPanel 关掉也能弹系统通知
...
OpenClaw 内核已实现 4 个 push.web.* RPC(vapidPublicKey / subscribe / unsubscribe / test),
但 ClawPanel 完全没接。这次打通整条链路:浏览器 → Service Worker → 内核 → 系统通知中心。
## 收益(用户视角)
- ClawPanel 浏览器标签/桌面应用关掉后,Agent / Cron / 渠道消息仍能弹到
Windows / macOS / iOS / Android 系统通知中心
- 锁屏可见,可离线接收(推送服务由浏览器厂商分发)
- 是下一版主推卖点
## 实施(无需新增 Tauri 命令)
- wsClient.request 直接走 WebSocket 调内核 4 个 RPC
## 前端封装 src/lib/push-web.js
- isPushSupported() / pushPermission() / requestPushPermission()
- ensureServiceWorker() 注册 /push-sw.js(幂等)
- subscribePush() 完整流程:权限 → SW → push.web.vapidPublicKey → PushManager.subscribe → push.web.subscribe 上报内核
- unsubscribePush() 本地取消 + 通知内核清理
- sendTestPush(title, body) 调 push.web.test 广播测试
- getCurrentSubscription() / isLocallySubscribed() 状态查询
- urlBase64ToUint8Array / arrayBufferToBase64Url 工具函数
(VAPID 公钥 base64url ↔ 二进制,订阅 keys 编码)
## Service Worker public/push-sw.js
- skipWaiting + clients.claim 立即激活
- push 事件:解析 JSON payload → showNotification(含 icon / badge / tag / requireInteraction)
- notificationclick:优先聚焦已打开标签 + postMessage 跳转 url;
没有窗口就 openWindow 新开
- 所有路径容错(payload 解析失败 fallback 到默认文案)
## UI 页面 src/pages/notifications.js
- 状态行:通知权限 + 订阅状态(彩色徽章)
- 端点摘要(订阅成功后展示截断的 endpoint,方便用户确认)
- 三个动作按钮(互斥):启用 / 取消订阅 / 发测试通知
- 测试通知会显示「已投递到 N 个订阅」提示
- 不支持环境(Tauri 1.x 桌面壳或老浏览器)显示友好的「Push not supported here」空状态
- 全程走 humanizeError 友好错误提示
## i18n src/locales/modules/notifications.js
- 26 个键 × 11 语言全覆盖
- 含权限徽章 / 操作按钮 / 流程提示 / 不支持环境说明
## 入口
- OpenClaw 引擎「配置」section 新增「推送通知」入口
- sidebar.notifications i18n(短词「推送通知 / Push」)
- 路由 /notifications 注册到 OpenClaw 引擎
- Hermes 引擎暂不注册(push.web.* 是 OpenClaw 内核的 RPC)
## CSS
- 加 .push-status-row / .push-status-item / .push-status-label / .push-status-value
- 复用现有 .lazy-deps-badge.{ok,warn,unknown} 样式
## 待跟进
- iOS Safari 16.4+ 需用户先把 ClawPanel 添加到主屏才能收 push(已知限制,文档跟进)
- 真实流量(不只是 push.web.test)需 OpenClaw 内核侧把通知事件主动 send 出来;
本 PR 把订阅渠道彻底打通,后续内核怎么用现成订阅发送是另一题
- 累计变动:4 新文件 + 4 修改
2026-05-14 04:27:33 +08:00
晴天
b852ebb6ee
feat(hermes): P1-3 lazy_deps 预处理 - 加 IM 渠道不再「首启 Gateway 卡 30 秒后崩」
...
Hermes 内核 tools/lazy_deps.py 维护了一个 allowlist:每个 feature(如 platform.telegram /
tts.elevenlabs / search.exa)对应一组 PyPI 包。原本只有 Gateway 启动 platform 模块时
才会调 ensure() 装包,导致首次启动卡 30 秒甚至超时崩溃。
本 PR 把 lazy_deps 暴露给 ClawPanel UI,让用户能主动预装。
## 后端三个新 Tauri 命令
- hermes_lazy_deps_features() — 列所有 LAZY_DEPS allowlist feature(17 个)
- hermes_lazy_deps_status(features) — 批量查每个 feature 是否已装好
- hermes_lazy_deps_ensure(feature) — 主动调内核 tools.lazy_deps.ensure 装
实现方式:
- 找到 ~/.hermes-venv 的 python 路径(unix: bin/python,windows: Scripts/python.exe)
- 用 tokio::process::Command spawn `python -c "<embedded script>"` 跑临时 Python 脚本
- 脚本走 from tools.lazy_deps import ensure / feature_missing / LAZY_DEPS
- 把结果以 JSON dump 给 stdout,Rust 端解析最后一行
- enhanced_path() 注入 PATH 兼容 macOS Tauri 启动后 PATH 不全
- serde_json::to_string 把字符串和列表序列化为 Python 合法字面量(防注入)
已注册到 lib.rs,前端 wrapper 在 tauri-api.js(features 走 10min 缓存)。
## 前端
- 新页面 src/engines/hermes/pages/lazy-deps.js
- 分类 grid(消息渠道 / TTS / STT / 搜索 / 模型商 / 记忆 / 图像 / 其他),每类有 emoji
- 卡片式:feature 名(友好显示)+ specs 元信息 + 状态徽章(已装✓ / 未装warn / 未知)+ 装/重装按钮
- 装/重装按钮 await ensure,期间「安装中…」disabled,完成后刷新整张表
- 失败走 humanizeError 统一提示
- 17 个 feature 都有友好显示名 i18n(platform.telegram → Telegram,platform.dingtalk → 钉钉 等)
- 完整 11 语言 i18n(hermesLazyDeps 模块),其它语言 fallback 到 en
## sidebar
- Hermes 引擎「管理」section 新增「可选依赖管理」入口
- 路由 /h/lazy-deps
## CSS
- 加 .lazy-deps-grid / .lazy-deps-card / .lazy-deps-badge.{ok,warn,unknown}
- 复用现有 .empty-state / .empty-compact 风格
## Web 模式
- dev-api.js 加三个同名 handler:
- features 返回内置常见 platform 列表
- status 全标 unknown(无法 spawn python)
- ensure 直接 reject,提示走桌面端
## 累计变动
- 2 新文件(lazy-deps.js page + hermesLazyDeps.js i18n)
- 7 修改(dev-api / hermes.rs / lib.rs / hermes/index.js / tauri-api.js / locales/index.js / components.css)
- 11 语言 × ~17 个新 i18n 键
- cargo check ✓ + npm build ✓
2026-05-14 04:18:33 +08:00
晴天
c4bf769eab
feat(hermes): P1-4 hermes_read_config_full 全字段解析 - 解锁 14+ Gateway 高价值配置
...
之前 hermes_read_config 只读 5 字段(model/base_url/provider/api_key/config_exists),
为「快速面板」服务。Hermes Gateway 实际有 14+ 个顶层配置项,ClawPanel 完全没读到。
本次新增 hermes_read_config_full 命令,作为高级配置编辑器的数据源。
## 后端实现
- 加 serde_yaml 0.9 依赖
- 新命令 hermes_read_config_full:
· 用 serde_yaml 完整解析 config.yaml
· 转 JSON 返回 { exists, raw, config, highlights }
· highlights 字段单独抽出 14 个高价值顶层字段:
streaming / stt_enabled / quick_commands / reset_triggers /
default_reset_policy / unauthorized_dm_behavior /
session_store_max_age_days / always_log_local /
group_sessions_per_user / thread_sessions_per_user /
platforms / dashboard / memory / skills
· 已注册到 lib.rs
## 前端
- tauri-api.js 加 hermesReadConfigFull wrapper
## Web 模式
- dev-api.js 加 hermes_read_config_full handler(Web 模式不强制 yaml 解析,
返回 raw + null highlights,前端按需 fallback)
## 后续
- 实际「高级配置编辑器」UI 后续单独开 — 本次仅打通数据通道
- 与轻量版 hermes_read_config 互补共存,model 配置页继续用轻量版
2026-05-14 03:56:17 +08:00
晴天
7eababad4a
feat(ux): toast 智能行动按钮 + 拓展 ⓘ 到 gateway/agents + sidebar 加术语表入口
...
延续上一轮小白 UX 改造的尾声三连:
## 1. toast 智能行动按钮(U2 收尾)
- humanizeError 输出新增 action 字段:{ label, route?, handler?, kind }
- 自动按错误 kind 给默认按钮:
· gatewayDown → [去启动 Gateway] → /services
· cmdMissing / permission → [打开设置] → /settings
· auth → [检查 API Key] → /models
· network / timeout / rateLimit / generic → 不给(重试由用户控制)
- toast 结构化分支渲染 .toast-action-btn 按钮,点击后用 navigate(route) 或调 handler,并自动关闭 toast
- common.js 加 errorAction.* 三个按钮文案 i18n(11 语言)
## 2. ⓘ 拓展到 gateway / agents
- gateway.js: token label 后加 ⓘ(apikey 术语),renderConfig 末尾 attachTermTooltips
- agents.js: addAgent 弹窗 workspace 字段 label 加 ⓘ,setTimeout 扫 document.body 绑定
- term-tooltip.js 精简表新增 4 个术语:workspace / provider / baseurl + scope(已有)
## 3. sidebar 加术语表入口
- 在两个引擎(OpenClaw + Hermes)的最后一个 section 加「术语」条目
- sidebar.js i18n 新增 glossary 键(11 语言)
- 之前只能从 dashboard quick-actions 进入,现在 sidebar 永久可达
## 4. 顺手 bug 修复
- gateway.js 文件末尾历史残留的多余 `}` (line 348) syntax 错误,删除
- 与之前 hermes/cron.js 同类问题,本次改 ⓘ 时被 node --check 暴露
## 累计变动
- 10 个文件修改
- 7 个新 i18n 键(11 语言)
- Build OK
2026-05-14 03:47:25 +08:00
晴天
e710db6ffb
feat(ux): 小白 UX 全面改造 - 错误友好度 + 致命操作强确认 + 空状态 + 新手引导 + 术语表
...
面向小白用户的产品定位重塑,从七大 UX 痛点逐一改造:
## U1 错误友好度(59 处改造)
- 新工具 src/lib/humanize-error.js:自动把后端原始错误(fetch failed、ENETUNREACH、ENOENT 等)
映射成「主行 + hint 行动建议 + 折叠技术详情」三段式结构化对象
- toast 组件升级支持 { message, hint, raw } 结构化入参,向后完全兼容
- 14 个 page 文件中所有 toast(t('xxx.failed') + ': ' + e, 'error') 替换为 toast(humanizeError(e, t(...)), 'error')
- common.js 加 error.* / errorHint.* 共 13 个新 i18n 键(11 语言):
网络/Gateway 未启动/命令缺失/权限/超时/限流/未找到/鉴权/服务繁忙/通用
## U2 致命操作强确认(14 处改造)
- showConfirm 升级支持结构化对象 { message, impact[], title, confirmText, cancelText, variant }
- 加 .modal-impact-list 红边样式(让小白看清楚删了会丢什么)
- 14 处致命操作改造,每处显示影响列表 + 红色「删除/移除/重置」按钮 + 灰色「保留」取消:
· agents.js 删除 Agent(动态显示 N 个绑定影响)
· channels.js 移除平台(动态算 N 个 binding)+ 移除 Agent binding
· memory.js 删除记忆文件
· services.js 卸载 Gateway(3 段影响)+ 删除备份
· models.js 批量删模型
· chat.js 删除会话 + 重置会话
· dreaming.js 重置梦境日记 + 清空 grounded 短期记忆
· agent-detail.js 解除渠道绑定
· cron.js 删除任务(OpenClaw + Hermes 两端)
- skills.js 原生 confirm() 改 showConfirm
- hermes-cron.js 原生 confirm() 改 showConfirm,顺手修末尾多余 `}` 的 syntax 残留
## U3-C 空状态 emoji+CTA(5 页面)
- 通用 .empty-state 组件(大 emoji + 标题 + 副本 + CTA 按钮 + 紧凑变体)
- agents.js: 🤖 + 「+ 新建 Agent」CTA
- memory.js: 🧠 + 「+ 新建记忆文件」CTA(紧凑版)
- cron.js: ⏰ + 「+ 新建任务」CTA
- skills.js: 🛠️ + 「技能商店」CTA(点击切 Tab)
- channels.js: 💬 + 紧凑提示
- CTA 巧妙复用页面顶部已有按钮的 click,零重复逻辑
## U3-B Dashboard 新手任务卡片
- 蓝紫渐变卡片,4 步任务自动检测:启动 Gateway / 添加模型 / 创建 Agent / 第一次聊天
- 已完成:✓ 徽章 + 删除线 + 60% 透明
- 未完成:编号徽章 + 蓝色 CTA 按钮跳对应页面
- 全部完成 → 庆祝条「🎉 全部搞定!」+ 关闭按钮
- localStorage 标记,用户主动关闭后永久隐藏
- 14 个新 i18n 键,文案小白化(Gateway 是「发动机」/ Agent 是「分身」/ 模型给 AI 装「大脑」)
## U3-A 术语表页(/glossary)
- 25 个核心术语 × 4 大分类(核心 8 / 模型 6 / 接入 5 / 进阶 6)
- 搜索框实时过滤 + Tab 切换分类 + 卡片网格布局
- 每条术语:「比喻 + 一句话」描述(避免循环引用)+ 「打开页面 →」CTA 直达配置
- 3 语言(zh-CN / en / zh-TW)完整翻译,其他 8 语言 fallback
- 双引擎(OpenClaw + Hermes)共用路由
- dashboard quick-actions 加「📖 面板术语」入口
## U3-D 术语 ⓘ tooltip
- 通用 src/lib/term-tooltip.js helper:termHelpHtml(id) + attachTermTooltips(root)
- 8 个高频术语精简表(OAuth / Webhook / Bot Token / API Key / Token / Context Window / Binding / Scope)
- channels.js 字段 label 智能匹配关键词自动追加 ⓘ(覆盖 8 个渠道全部敏感字段)
- models.js 添加/编辑 provider 的 API Key label 也加 ⓘ
- 点 ⓘ → 弹小型 modal 含解释 + 「打开术语表 →」CTA
- attachTermTooltips 内部去重,可安全多次调用
## 累计交付
- 4 个新文件(humanize-error.js / term-tooltip.js / glossary.js page / glossary.js i18n)
- 6 个升级文件(toast / modal / components.css / dashboard / channels / models)
- 14 个 page 错误 toast 友好化(59 处)
- 14 处致命操作强确认
- 5 处空状态升级 + Dashboard 新手卡片 + 术语表 + ⓘ tooltip
- 109 个新 i18n 键(11 语言)
- Build 全程通过
2026-05-14 03:38:47 +08:00
晴天
1d6843c4fb
feat(hermes): expose '/v1/capabilities' as the 'hermes_capabilities' Tauri command
...
Hermes 已在 v2026.5.x 暴露 GET /v1/capabilities 给外部 UI 用作机器可读的能力描述,让前端能动态适配可用 endpoint / feature 而无需用版本号硬匹配。ClawPanel 之前完全没利用这层抽象,本 commit 加一条 Tauri 命令 + Web handler + 前端 wrapper,为后续 chat/runs/approval 等动态降级(老版 Gateway 没有的能力优雅隐藏 UI)打底。
2026-05-14 02:31:35 +08:00
晴天
69cce64985
fix(hermes-model-switch): clear stale 'context_length' when switching model in config.yaml
...
When the user switches model via the model picker, hermes_update_model rewrites
model.default and model.provider in config.yaml but historically left model.context_length
untouched. The Hermes kernel (8ac351407, May 2026) now actively clears that field on
model switch because the previous model's context window almost never matches the new
model — leaving the stale value caused 'context too large' errors and silently truncated
output. Mirror the upstream behavior by dropping the context_length line as we walk the
model: block, so Hermes falls back to the new model's default window.
2026-05-14 02:30:53 +08:00
晴天
65e9a4c90c
feat(hermes-provider): rename 'Alibaba Cloud (DashScope)' to 'Qwen Cloud' to match upstream
...
Hermes core 1e01b25e7 (May 2026) renamed the display label across the model picker / wizard / status output but kept the provider slug 'alibaba' and the DASHSCOPE_* env vars unchanged. Mirror the label here so the picker label in ClawPanel matches what users see in the Hermes TUI/CLI; existing configs are not migrated because slug and env vars are stable.
2026-05-14 02:30:34 +08:00
晴天
7d4a423df0
feat(hermes-install): diagnose network failures and add optional Git mirror ( #273 )
...
- Detect git/network failure patterns (failed to connect, could not resolve host,
unable to access, etc.) in install/update output and append a clear hint
pointing users to the proxy or mirror settings instead of leaving them with
raw multi-line git stderr.
- Add optional 'Hermes Install Mirror' setting (panelConfig.gitMirror): when set,
install/upgrade injects GIT_CONFIG_COUNT/KEY_0/VALUE_0 to rewrite
https://github.com/ via the mirror prefix at process scope only — the user's
global ~/.gitconfig is never touched.
- Surface the new mirror field in Settings (works for both engines), with
zh-CN/en/zh-TW copy and a hint explaining how it interacts with the install
flow.
2026-05-14 01:46:55 +08:00