Commit Graph

105 Commits

Author SHA1 Message Date
晴天
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
晴天
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
晴天
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
晴天
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
晴天
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
晴天
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
晴天
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
晴天
d0d6950628 fix(web-mode): consolidate Tauri event subscription helper to silence transformCallback errors (#256)
- Add shared safeTauriListen helper in tauri-api.js that returns a noop
  unsubscriber when running outside Tauri, so dynamic-importing
  @tauri-apps/api/event in the browser no longer throws
  'Cannot read properties of undefined (reading transformCallback)'.
- Replace 4 bare 'await import(@tauri-apps/api/event)' call sites
  (about.js hermes upgrade button + channels.js three install/action flows)
  that previously crashed the page on web mode.
- Drop the duplicated local tauriListen helpers in hermes dashboard / chat
  store and route them through the shared helper.
2026-05-14 01:31:58 +08:00
晴天
31dcf64426 fix(ws): friendlier error when Gateway kernel does not support v3 handshake (#272)
- Detect 'device signature invalid' / 'protocol mismatch' on WebSocket close (code 1008)
- Detect DEVICE_AUTH_SIGNATURE_INVALID/PROTOCOL_VERSION_MISMATCH on connect failure after auto-pair
- Replace cryptic English reason with kernel.tooOldForProtocol message (zh-CN + en)
- Suggest upgrading Gateway kernel to recommended version (2026.5.x)
- Stop auto-reconnect loop in these unrecoverable cases
2026-05-14 01:16:33 +08:00
friendfish
1584d53bf9 fix: 修复批量测试模型时误触发 Gateway 重启 (#270)
Fixes #271
2026-05-14 01:12:04 +08:00
晴天
81c42dbfe2 chore: release v0.15.1 2026-05-10 21:30:36 +08:00
晴天
328624cf03 chore: release v0.15.0
发布 0.15.0:
- 新增内核版本兼容层、特性门控、低版本阻断和升级提示
- 新增 PATH 中 OpenClaw CLI 冲突检测、隔离与恢复
- 修复 Hermes Gateway loopback 自动拉起与 /v1/runs 诊断
- 修复 standalone 一键安装包在 About/仪表盘显示未知版本
- 同步 OpenClaw 2026.5.6 推荐版本和热更新 minAppVersion
- 补齐本地 JS/Rust 测试与发布前检查说明

验证:
- npm run build
- node --test tests/*.test.js
- node --check src/scripts JS 文件
- cargo fmt --all -- --check
- cargo check
- cargo clippy --all-targets -- -D warnings
- cargo test
2026-05-08 04:39:36 +08:00
晴天
9ee99ead24 chore: release v0.14.0
集中发版:

新功能(10)
- 心甜Claw 引擎入口(第 3 个引擎模式)
- Hermes 22 个 Provider 注册表 + 安装/仪表盘动态加载
- Hermes .env 高级编辑(拒绝触碰托管 Provider 密钥)
- Hermes 会话与用量分析增强
- Hermes Dashboard 自动拉起 + Windows POSIX-only 兼容模态
- Hermes Skills 工具集面板
- 官网 Hermes Agent 黑金特色区 + 图文指南
- Boot Manifest 启动页(双语 + 错峰动画)
- 官网 Markdown 阅读器图片 lightbox
- Hermes Memory 概览卡

改进(9)
- Hermes 仪表盘/扩展页全面本地化
- 记忆编辑大尺寸模态
- 日志下载 Web/桌面分流
- 侧边栏导航补全
- 模型备选管理 UI(PR #232)
- 模型加载错误 UX 重做(错误卡 + 详情 + 重试)
- .page 布局 clamp + .page-narrow
- Memory 单列断点提早到 1100px
- Web 模式跳过前端热更新检查

修复(12)
- Gateway 启动 platforms.api_server.enabled 自修复(含 7 unit test)
- Memory 页 overview 卡穿模(旧 flex 列约束 → 自然块流)
- Skills 页 hero/toolsets 被压缩(flex-shrink:0)
- Web 模式 Skills ReferenceError(补 _readHermesDisabledSkills)
- 日志/记忆下载行为分流
- src/pages/models.js 5 处 typo
- 删除 56 行 .hm-memory-* 死代码 + line-clamp 标准属性
- Dependabot rustls-webpki / postcss / rand
2026-04-25 23:47:22 +08:00
晴天
3ed59fcb2b feat(hermes): align dashboard APIs and add xintian engine 2026-04-25 10:31:32 +08:00
晴天
31936b4779 feat(hermes): add .env editor page for unmanaged env vars (Step 4)
Users may need to configure custom environment variables for Hermes
(e.g. `TAVILY_API_KEY` for the tavily skill, `HTTP_PROXY`, SKILL_*
settings). Previously the only way to set these was to hand-edit
~/.hermes/.env, which risks clobbering the provider keys that
ClawPanel writes through configure_hermes.

This patch adds a dedicated editor UI backed by three new Tauri
commands that refuse to touch managed keys.

Backend (src-tauri/src/commands/hermes.rs):
- `hermes_env_read_unmanaged` — returns every KEY=VALUE pair whose key
  is NOT in `hermes_providers::all_managed_env_keys()` (so provider
  API keys, base URLs, `GATEWAY_ALLOW_ALL_USERS`, `API_SERVER_KEY`
  stay hidden). Preserves file order, dedups.
- `hermes_env_set(key, value)` — validates key against `^[A-Z0-9_]+$`,
  refuses managed keys, updates first occurrence or appends,
  preserves comments/blanks.
- `hermes_env_delete(key)` — refuses managed keys, removes first
  matching line, preserves other structure.

All three commands registered in `src-tauri/src/lib.rs`.

Frontend:
- New page `src/engines/hermes/pages/env-editor.js`:
  - Header with "back to dashboard" link and warning banner listing
    which keys are managed by ClawPanel.
  - Table with Key / Value / Actions columns.
  - Inline edit mode per row (save / cancel).
  - "Add variable" button for new entries.
  - Value column masks long secrets (`sk-a…xyz9`) so glances don't
    leak credentials.
  - Toast feedback on save / delete / validation errors.
  - Inline Chinese copy (TODO: wire up i18n when the locales module
    lands).
- Route registered at `/h/env` in `src/engines/hermes/index.js`.
- Dashboard "Model config" section now has a subtle link
  ".env 高级编辑 →" pointing to the new page.

API wiring:
- `src/lib/tauri-api.js`: added `hermesEnvReadUnmanaged`,
  `hermesEnvSet`, `hermesEnvDelete`.
- `scripts/dev-api.js`: mirrors the three commands in Web mode with
  a duplicated managed-key list (keep in sync with Rust's
  `hermes_providers::all_managed_env_keys` as new providers land).

Verified: cargo fmt / cargo clippy -D warnings / cargo test / npm run
build all green. Dashboard chunk unchanged (24.30 kB); new env-editor
chunk is ~7 kB gzip.
2026-04-24 20:50:29 +08:00
晴天
42d6758eb4 feat(hermes): dynamically load provider registry in setup & dashboard (Step 2)
Wire the new Rust `hermes_list_providers` command into the frontend and
replace the hardcoded OpenClaw PROVIDER_PRESETS usage with the
authoritative Hermes registry. Closes the G4 gap from the v3 design.

New module `src/engines/hermes/lib/providers.js`:
- Async `loadHermesProviders()` with per-session cache.
- `groupProviders()` buckets by authType + region: apiKeyIntl,
  apiKeyCn, aggregators, oauth, externalProc, custom.
- Lookup helpers: `findProviderById`, `inferProviderByBaseUrl`,
  `defaultModelFor`, plus cache reset for hot-reload scenarios.
- Exported auth_type / transport string constants mirroring Rust.

Refactored `src/engines/hermes/pages/setup.js`:
- Drops `PROVIDER_PRESETS` import; loads registry before first paint.
- Provider buttons are grouped under labeled sections (International,
  China, Aggregators), with an OAuth hint block listing the CLI
  commands users must run (e.g. `hermes auth login nous`).
- Selected provider detail panel now shows target env var
  (`ANTHROPIC_API_KEY`, `DEEPSEEK_API_KEY`, etc.) and model catalog
  size.
- `doSaveConfig` sends the provider id (not preset key) through
  `api.configureHermes`; falls back to `custom` when the base URL
  doesn't match any registered provider.
- `doFetchModels` maps provider.transport → apiType.
- Graceful fallback: when the registry is empty (Web mode), UI
  degrades to manual Base URL + API Key entry.

Refactored `src/engines/hermes/pages/dashboard.js`:
- Loads provider registry in parallel with gateway refresh.
- Preset buttons filter out the `custom` placeholder and source
  data from the async-loaded list.
- Uses `inferProviderByBaseUrl` consistently for highlight / fetch /
  save flows.

Frontend API wiring:
- `src/lib/tauri-api.js`:
  - Added `hermesListProviders` (10-minute cache).
  - Extended `hermesFetchModels` and `hermesUpdateModel` with
    optional `provider` param.
- `scripts/dev-api.js`:
  - `hermes_list_providers`: Web-mode stub returning [] (triggers
    frontend fallback UI).
  - `hermes_fetch_models` / `hermes_update_model` accept provider
    param (no-op in fetch; full YAML rewrite in update_model matching
    Rust behavior).

Verified: `npm run build` green (1.04s). Setup chunk 24.34 kB,
dashboard chunk 24.30 kB. No new warnings.
2026-04-24 20:41:06 +08:00
晴天
11cd6218dc feat(diagnose): detect and inform about @homebridge/ciao cmd popup bug (#250)
* feat(diagnose): detect and inform about @homebridge/ciao cmd popup bug

On Windows, OpenClaw's transitive dependency @homebridge/ciao (<=1.3.6)
calls child_process.exec('arp -a ...') every 15-30 seconds without
passing windowsHide:true, causing a cmd.exe popup to flash.

This is an upstream library bug:
- Issue: homebridge/ciao#64
- PR:    homebridge/ciao#65 (open, not merged)

ClawPanel deliberately chooses 'detect and inform' rather than silently
patching the user's node_modules. We respect the user's control over
their own machine.

Changes:
- src-tauri/src/commands/diagnose.rs: new check_ciao_windowshide_bug
  command; scans openclaw's @homebridge/ciao/lib/NetworkManager.js and
  reports whether the buggy exec pattern is present
- src-tauri/src/lib.rs: register the new command
- scripts/dev-api.js: Web-mode stub (returns affected:false since the
  bug does not manifest off-Windows)
- src/lib/tauri-api.js: add api.checkCiaoWindowsHideBug
- src/lib/ciao-bug-warning.js: new module with toast + modal flow,
  version-scoped dismiss (localStorage)
- src/locales/modules/ciaoBug.js: translations in 5 primary languages
- src/locales/index.js: register the ciaoBug module
- src/main.js: call checker 3s after splash hides

Non-Windows users see nothing; Windows users see a single warning toast
(version-dismissible) linking to three fix paths: wait for upstream,
apply patch-package, or edit NetworkManager.js manually.

* fix(diagnose): gate helper with cfg(windows), drop unneeded return

CI failures on Linux + macOS:
- openclaw_module_root was dead code when target_os != windows
  since the only caller is the #[cfg(target_os = "windows")] block
  inside check_ciao_windowshide_bug
- Explicit `return CiaoCheckResult {...};` in the non-Windows branch
  triggered clippy::needless_return

Fix:
- Add #[cfg(target_os = "windows")] to openclaw_module_root so it
  is not compiled on other platforms
- Convert the non-Windows early exit to a tail expression
2026-04-24 19:36:20 +08:00
晴天
5235853373 fix(gateway): debounce restart with single-flight queue (#248)
Root cause for #243 / #244 / #240: model edits trigger
api.restartGateway() with only 300ms debounce. Fast consecutive
edits stack up restart calls, creating zombie Gateway processes,
failed restarts, and CPU fan spikes.

Layer A (frontend):
- New src/lib/gateway-restart-queue.js: 3s debounce + single-flight
  lock + reschedule on in-flight request
- Refactor src/pages/models.js doAutoSave: write config immediately,
  schedule restart via queue with 'Apply now' toast button
- Subscribe to queue state for unified success/failure toast
- Add i18n: models.configQueued, models.applyNow

Layer B (backend):
- src-tauri/src/commands/config.rs: wrap restart_gateway /
  reload_gateway with tokio::sync::Mutex + 2s cooldown
- Cargo.toml: add tokio 'sync' feature
- scripts/dev-api.js: same guard for Web mode (inflight promise
  reuse + 2s cooldown)

Effects:
- 10 rapid edits within 3s -> 1 restart (was 10+ with races)
- Backend serializes concurrent restart calls, no zombie spawns
- User sees single 'Apply now' toast instead of restart storm

Refs #243 #244 #240
2026-04-24 19:35:39 +08:00
晴天
7c63438c0e feat(assistant): 识别本地 LLM 服务端常见错误并给出修复指引
用户反馈:切本地 vLLM(Qwen/Qwen3-30B-A3B)后在助手里调用工具报错:
  "auto" tool choice requires --enable-auto-tool-choice and
  --tool-call-parser to be set

这是 vLLM 0.6+ 的默认安全策略 —— 必须在启动参数显式开启工具调用
才允许客户端在 body 里带 tools 字段。ClawPanel 发的请求符合 OpenAI
规范,不是我们的 bug,但用户面对这个原始报错字面上看不出是 vLLM
配置问题也不知道怎么修。

## 解决

新增 src/lib/model-error-diagnosis.js,提供 enhanceModelCallError:
保留原始错误文本 + 附加中文修复指引。目前覆盖 5 类常见本地部署错误:

1. **vLLM tool choice 限制**(本次用户实际踩的)
   - 给出 --enable-auto-tool-choice + --tool-call-parser 启动命令
   - Qwen / Mistral / Llama 各系列推荐的 parser 值
   - 建议临时切到"聊天"模式规避

2. **llama.cpp / LM Studio 旧版本不支持 tools**
3. **Ollama 模型不支持 tools**
4. **模型 ID 不存在 / 404**
5. **上下文超长 / token limit**

在 assistant.js 的 5 个错误抛出点统一接入:
- callChatCompletions(OpenAI 聊天模式)
- callResponsesAPI(新 /v1/responses 接口)
- callAnthropicMessages(Claude)
- callGeminiGenerate(Gemini)
- callAIWithTools(工具模式,就是用户踩坑的那条路径)

## 验证

- npm run build 通过
- assistant chunk 从 153.98KB → 156.24KB(gzip +0.86KB),合理
- 所有增强都走 try { parseJSON } 之后,不会影响原有错误处理路径

## 相关

- #Compat-5 系列的一部分(运行时错误诊断)
- 用户场景:vLLM + Qwen3 MoE,切换到本地模型后调工具
- 用户侧实际修复命令:
  vllm serve <model> --enable-auto-tool-choice --tool-call-parser hermes
2026-04-20 13:02:05 +08:00
晴天
e39233f2c1 fix(lifecycle): 卸载/升级 OpenClaw 后同步刷新 Rust 缓存与前端缓存
这是 #Compat-4(安装不识别修复)的收尾补丁。除了 setup 安装场景,
OpenClaw 的卸载和升级场景也存在类似的缓存失效问题。

## Rust 端:uninstall_openclaw_inner 卸载后刷缓存

卸载完成时只 emit 了 "upgrade-progress 100",但没有刷 enhanced_path
和 CLI 检测缓存。后果:

- `is_cli_installed`(60s TTL)在卸载后 60 秒内仍返回 true,UI 显示
  「CLI 已安装」
- 服务状态页 gateway 被误判为还在运行

在 emit 进度 100 之后立刻调用:
- `super::refresh_enhanced_path()`
- `crate::commands::service::invalidate_cli_detection_cache()`

## 前端:upgrade/uninstall/installGateway/uninstallGateway 清前端缓存

`upgrade_openclaw` / `uninstall_openclaw` / `install_gateway` /
`uninstall_gateway` 这四个 API 会改变 CLI 状态或 Gateway 状态,但
原先直接 invoke,没有清前端的 cachedInvoke 缓存。Rust 端自己刷了
缓存没用,前端仍吃旧的 `check_installation` / `get_services_status`
/ `get_version_info` 缓存(60s / 10s / 30s TTL)。

统一在调用前 invalidate 相关缓存:

- upgrade/uninstall OpenClaw → 清 check_installation / check_node /
  check_git / get_services_status / get_status_summary / get_version_info
- install/uninstall Gateway → 清 get_services_status / get_status_summary

## 验证

- `cargo check` 通过
- `npm run build` 通过
2026-04-20 12:46:06 +08:00
晴天
dfb81066b4 feat(assistant): 备用模型组 failover + 测试按钮走 Rust 后端(修 status 0)
解决用户反馈的两个问题:晴辰助手设置里"测试"按钮在某些 provider
(如 gpt.qt.cool)上显示 Response Status: 0、Body 空,以及只能配
一个模型、挂了就没法用。

## 1. 测试按钮 status 0 根因 & 修复

**根因**:Tauri 桌面端以前走 webview 的 `fetch()` 直打外部 API,
受 Chromium 网络栈限制 —— 某些 provider 的 HTTP/2 分块编码、TLS
握手、CORS 预检、或特殊响应头会被静默拒绝并抛 TypeError: Failed
to fetch,前端 catch 后把 `respStatus` 写死 0、`respBody` 空。这
不是 provider 的问题,也不是 key 的问题,是 Chromium net stack 的
兼容性问题。

**修复**:新增 Rust 命令 `test_model_verbose`(基于已有的 reqwest
HTTP 客户端),返回结构化 JSON
  `{success, status, reqUrl, reqBody, respBody, reply, error,
   elapsedMs, usedApi}`。

  前端测试按钮无论 Tauri/Web 模式,一律调 `api.testModelVerbose()`:
  - Tauri → `invoke('test_model_verbose')` → 走原生 reqwest
  - Web → `fetch('/__api/test_model_verbose')` → 走 dev-api.js 服务端
    fetch

  这样绕过了 webview net stack 所有兼容性陷阱,拿到的永远是真实
  HTTP status(含 401/429/5xx)和原始 body,debug 面板展示完整信息。

  相比旧的 `test_model` 命令,`test_model_verbose` 不会因 400/422/429
  就吞错误返回 "连接正常",而是如实回传,便于用户排查。

## 2. 备用模型组 failover(参考 OpenClaw)

**新增配置**:`_config.fallbackModels: Array<{label, baseUrl, apiKey,
model, apiType, enabled}>`,存在 localStorage 里。

**callAI 改造**:
- 旧的 `callAI` 改名为 `_callAIOnce`,保持不变
- 新增 `callAIWithSlot(slot, messages, onChunk)`:临时把 slot 注入
  到 `_config`,调 `_callAIOnce`,finally 恢复(单线程安全,因为
  `_isStreaming` 防并发)
- 新的 `callAI`:`buildActiveSlots()` 收集主模型 + 启用且配置完整
  的 fallback,按序尝试
  - 成功 → return
  - `AbortError`(用户中止)→ 直抛,不 failover
  - 鉴权错误 401/403/`unauthorized`/`invalid api key` → 直抛,不
    failover(切也白切)
  - 其他可重试错误(网络/超时/5xx/429/400 请求错/模型不存在)→ 在
    聊天里插入 `⚠ 模型「X」失败,切换到备用「Y」` 引用块,继续下
    一个 slot
  - 全部 slot 都失败 → 抛最后一个错误,触发既有 retry bar + circuit
    breaker 流程

**UI**:设置面板 API 标签页,在晴辰云 promo 卡片下方新增一个默认
折叠的 `<details>` 区块"备用模型组":
- 顶部 summary 显示启用数量 + 折叠箭头
- 每张卡片:label / baseUrl / apiType / apiKey / model(紧凑 2 列
  栅格)+ enabled 开关 + 删除按钮
- 顶部 "添加备用模型" 按钮:默认继承主模型的 apiType,减少配置项
- 编辑态用 fallbackDrafts(深拷贝),保存按钮才过滤空卡片写回
  `_config.fallbackModels`
- 单个 input 变化时只同步 drafts + 更新计数,不重渲染列表(保持
  输入框焦点)

**文件改动**:
- `src-tauri/src/commands/config.rs`:+175 行 `test_model_verbose`
- `src-tauri/src/lib.rs`:注册新命令
- `src/lib/tauri-api.js`:+1 行 `testModelVerbose` 封装
- `scripts/dev-api.js`:+75 行 Web 模式 test_model_verbose handler
- `src/pages/assistant.js`:
  - `loadConfig`: 新增 `fallbackModels = []` 默认值
  - `callAI` 重构为 failover loop(+80 行)
  - 测试按钮:移除 90 行的 webview fetch 双分支,统一调 verbose
    API(净减 ~60 行)
  - `showSettings`: 新增备用模型 UI + 事件绑定(+85 行)
  - 保存按钮:收集 fallbackDrafts 写回 _config
- `src/locales/modules/assistant.js`:11 语言翻译(slotPrimary /
  failoverNotice / fallbackModelsTitle / fallbackModelsDesc /
  fallbackEnabledSuffix / fallbackEmpty / fallbackAdd /
  fallbackRemove / fallbackEnabled / placeholders)

## 验证

- `npm run build` 通过(assistant chunk 149.85 → 153.98 kB)
- `cargo fmt --check` 通过
- `cargo clippy --all-targets -- -D warnings` 通过
- 向后兼容:旧用户的 `localStorage` 无 `fallbackModels` 字段,
  loadConfig 会初始化空数组,既有行为不变

Refs: 模型兼容性优化 + 多模型 failover 需求
2026-04-20 03:43:43 +08:00
晴天
36eaa64bf4 chore(release): v0.13.3
- 修复 #212 AI 消息气泡空白
- 修复 #215 HTTPS 下 WebSocket Mixed Content
- 修复 #219 多实例版本检测错误
- 修复引擎切换后仪表盘无限加载
- 修复热更新假更新循环(macOS/Linux)
- CI release 构建前自动同步版本号
2026-04-16 13:55:26 +08:00
晴天
55e8365cab chore: release v0.13.2 2026-04-13 15:10:20 +08:00
晴天
549801e007 fix: sidebar menu not updating after engine switch + dashboard loading skeleton
1. engine-manager: activateEngine 切换时调用 engine.boot() 检测状态
2. main.js: onEngineChange 监听器重绑 state/ready 回调,确保新引擎
   状态变化时侧边栏自动刷新
3. Hermes 仪表盘: loading 期间显示骨架屏动画,消除空白等待
4. components.css: 新增 .skeleton-line 通用骨架行样式
2026-04-13 11:08:55 +08:00
晴天
5575566806 feat: Hermes Agent 多引擎架构核心代码
- 新增 src/engines/hermes/ 完整引擎(仪表盘/服务管理/模型配置/Agent管理/对话)
- 新增 src/lib/engine-manager.js 引擎管理器(切换/检测/状态)
- 新增 src-tauri/src/commands/hermes.rs 后端命令(Gateway控制/配置读写/Agent Run SSE)
- sidebar 引擎切换器 UI
- i18n 新增 engine 模块(中/英/繁体)
- 多安装清理工具(gateway-ownership.js)
- 晴辰助手文件访问开关
- Hermes 对话工具调用可视化、SSE 流式输出
- Cargo.lock / dev-api.js 同步更新
2026-04-13 04:09:09 +08:00
晴天
271dc93b08 feat: OpenClaw 4.9 全面适配 (v0.12.0)
- 推荐内核统一升级至 2026.4.9 / 2026.4.9-zh.2
- standalone 安装兼容 edition 格式 latest.json + openclaw-zh- 文件名前缀
- standalone 三级降级: R2 CDN → GitHub Releases → npm
- pre_install_cleanup 所有命令加 10s 超时保护(修复安装卡死)
- npm uninstall 加 30s 超时保护
- wmic 全部迁移到 PowerShell(兼容 Windows 11)
- standalone 下载增加文字进度显示
2026-04-11 04:42:36 +08:00
晴天
70d768be17 feat: new pages + dashboard enhancements + backend improvements
New pages:
- Plugin Hub: grid cards, search, install/toggle/enable plugins
- Route Map: SVG visualization of channels→agents bindings with legends
- Diagnose: gateway connectivity diagnosis with step-by-step checks

Dashboard enhancements:
- WebSocket status indicator (connected/handshaking/reconnecting/disconnected)
- Connected channels overview with platform icons
- Colored log level badges (ERROR/WARN/INFO/DEBUG) with timestamps
- Channels data loading in dashboard secondary fetch

Splash screen:
- Multi-stage boot detection (JS not loaded vs boot slow vs timeout)
- 15s: WebView2/resource load failure
- 20s: "initializing..." hint with elapsed counter
- 90s: true timeout error

Backend (Rust):
- diagnose.rs: gateway connectivity diagnosis command
- messaging.rs: plugin management commands
- service.rs: improvements
- lib.rs: register new commands

Frontend libs:
- feature-gates.js: feature flag system
- ws-client.js: reconnect state tracking
- tauri-api.js: new API bindings
- model-presets.js: provider fixes
- Remove gateway-guardian-policy.js (unused)

Dev API (scripts/dev-api.js):
- list_all_plugins, toggle_plugin, install_plugin handlers
- probe_gateway_port, diagnose_gateway_connection handlers

i18n: dashboard, sidebar, diagnose, extensions, routeMap locale modules
CSS: plugin-hub cards, route-map SVG styles
2026-04-11 00:44:06 +08:00
晴天
3c5a0d252b chore: release v0.11.6
feat: Skills multi-agent support — agent selector + per-agent skills directory (Rust/Node.js/frontend)
feat: Assistant tool mode streaming — typewriter effect + tool_calls chunk accumulation
improve: OpenClaw 4.5 compatibility — full agent event stream handling + 3-min ultimate timeout
improve: Replace hot-update with stable download links (website/GitHub)
fix: Gateway status flapping — dashboard throttle + TCP retry + debounce threshold
fix: Assistant empty gray bubbles — SSE 0-chunk detection + stream error capture + render filter
2026-04-07 16:17:09 +08:00
晴天
ad00ffef3d chore: release v0.11.5
feat: SkillHub skill store (SDK-based, no CLI dependency)
- Rust SDK (skillhub.rs): HTTP search, index fetch, zip download+extract
- Node.js SDK (skillhub-sdk.js): mirrors Rust SDK for Web/Docker mode
- Skills page: new "Store" tab with full index browse + client-side filter
- Remove 6 old CLI-dependent commands, add 3 SDK commands
- Migrate assistant.js skill tools from ClawHub CLI to SkillHub SDK
- Fix index decode error ({total,skills} wrapper vs bare array)
- Fix skill name display (API field 'name' vs 'display_name')
- Clean up 13 dead CSS rules from old skills hero/tips UI
2026-04-07 03:25:26 +08:00
晴天
9ff91f74d8 feat: IME-aware chat input, message copy button, Git path scanning
- Fix IME composition issue: Enter during Chinese/Japanese/Korean input
  method composition no longer prematurely sends messages (assistant.js)
  Uses e.isComposing + keyCode 229 guard on keydown handler
- Add one-click copy button to chat message bubbles (both chat.js and
  assistant.js), with hover-reveal animation and checkmark feedback
- Add 'copy' icon to SVG icon library (Lucide style)
- Add CSS for msg-copy-btn in chat.css and assistant.css
- Implement scan_git_paths Rust command: scans common Git installation
  locations on Windows/macOS/Linux (Program Files, Scoop, Chocolatey,
  GitHub Desktop, VS Code, MSYS2, Homebrew, Xcode CLT, etc.)
- Register scan_git_paths in lib.rs, tauri-api.js, dev-api.js
- Add scan button + results UI in settings.js Git path section
- Add i18n keys: gitScan, gitScanning, gitScanEmpty, gitScanUse
2026-04-06 00:14:18 +08:00
晴天
42aeb8b077 fix: Gateway status discrepancy — foreign detection, claim action, banner sync
- Services page: foreign Gateway now shows warning dot (yellow) instead of green
- Add claim_gateway command (Rust + dev-api + frontend API) to adopt foreign Gateway
- Services page: add "Claim Gateway" button for foreign Gateway instances
- Top banner: distinguish foreign Gateway (warning + claim) vs stopped (info + start)
- app-state: expose isGatewayForeign(), pass foreign flag to onGatewayChange listeners
- Services page actions now immediately sync global Gateway state (no 15s poll wait)
- Relax owner matching: cli_path missing on either side no longer triggers foreign
- Add i18n keys: foreignGatewayBanner, claimGateway, claimSuccess, claimFailed, processing
2026-04-05 23:12:16 +08:00
晴天
ce4e9ee8b0 chore: release v0.11.3 2026-04-03 00:16:50 +08:00
晴天
aad8043196 feat(config): add config calibration repair flow 2026-04-01 22:46:36 +08:00
晴天
b427a6b000 feat: improve gateway compatibility and complete i18n cleanup 2026-04-01 15:06:25 +08:00
晴天
f5d32c377c fix: 修复多个高优 Issue (#160, #165, #156, #159, #151)
- #160 Gateway 死循環: _autoPairAndReconnect 后不调用 reconnect() 避免重置计数器
- #165 readConfig 未定义: 替换为内联 fs.readFileSync/writeFileSync
- #156 systemd PATH: findOpenclawBin 添加 npm 全局路径, systemd 服务注入 PATH
- #159 Docker 双容器冲突: 新增 DISABLE_GATEWAY_SPAWN 环境变量开关
- #151 Gateway 检测冲突: linuxCheckGateway 验证进程名, 拒绝操作非 OpenClaw 进程
2026-03-30 23:13:24 +08:00
Octopus
61bfd56865 feat: upgrade MiniMax provider to api.minimax.io and add M2.7/M2.5 model presets (#163)
- Fix MiniMax API base URL from api.minimax.chat to api.minimax.io
- Add MiniMax model presets (M2.7, M2.7-highspeed, M2.5, M2.5-highspeed)
  with correct context window sizes (1M for M2.7, 204K for M2.5)
- Update MiniMax description to reflect latest M2.7/M2.5 model series
- Add MiniMax to README provider tables (Chinese + English)
- Add 12 unit tests for model presets validation

Co-authored-by: PR Bot <pr-bot@minimaxi.com>
2026-03-30 22:50:00 +08:00
晴天
540da00b91 feat: 渠道插件安装自动 pin 版本,兼容旧版 OpenClaw
- messaging.rs: install_channel_plugin/install_qqbot_plugin/run_channel_action 新增 version 参数
- 微信插件 npx 安装也支持版本 pin(@tencent-weixin/openclaw-weixin-cli@{version})
- channels.js: 安装前自动获取用户 OpenClaw 版本,pin 到基础版本号
- tauri-api.js/dev-api.js: 同步支持 version 参数传递
2026-03-26 02:57:43 +08:00
晴天
985d263dc6 feat: i18n 11 languages + website update + fix #139 #140 #141
i18n:
- Add 9 new locale files (ja/ko/de/es/fr/pt/ru/vi/zh-TW)
- Add multilingual README files for all 11 languages
- Add locale helper, index, and modular translation system
- Add translation generation scripts

Website (docs/index.html):
- Replace 公益AI接口 branding with 晴辰云AI接口
- Remove OpenClaw 独立安装包 promotion block
- Update SEO meta tags (description, keywords, OG, Twitter, JSON-LD)
- Add 11-language README links to footer
- Update 元宝派 link to new URL

Bug fixes:
- fix(cron): delivery format mode:'push' → mode:'announce', remove invalid 'to' field (fixes #141)
- fix(cron): allow single-channel users to select delivery channel
- fix(cron): preserve delivery field in job state for editing
- fix(models): add 'ollama' as recognized API type, prevent overwriting native ollama config (fixes #140)
- fix(models): skip /v1 append for ollama native API baseUrl
- fix(assistant): normalize 'google-generative-ai' consistently, add ollama hints
- fix(version): use CLI path classification for source detection on Windows (fixes #139)
- fix(version): default to 'official' instead of 'chinese' when source unknown
- fix(version): reorder npm global package check based on active CLI
2026-03-24 22:31:11 +08:00
晴天
0c062e93e0 feat: multi-OpenClaw CLI detection/binding + i18n infrastructure
Multi-OpenClaw Detection & Binding:
- Add resolve_openclaw_cli_path() and classify_cli_source() in utils.rs
- Support openclawCliPath binding in clawpanel.json (user selects CLI)
- VersionInfo now includes cli_path, cli_source, all_installations
- scan_all_installations() detects all OpenClaw installs on system
- Dashboard shows CLI source label + multi-install warning
- Settings page: CLI binding UI with auto-detect and manual selection
- dev-api.js synced with cli_path/cli_source fields for Web mode

i18n Infrastructure:
- Create src/lib/i18n.js core module (t(), setLang(), initI18n())
- Create src/locales/zh-CN.json and src/locales/en.json
- Sidebar fully i18n-ized (nav labels, sections, instance switcher)
- Dashboard stat cards fully i18n-ized
- Settings page: language switcher UI (live reload)
- initI18n() called in main.js on startup
2026-03-24 11:57:40 +08:00