Files
clawpanel/scripts/dev-api.js
晴天 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

371 KiB