mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-07-16 18:14:03 +08:00
按全量代码审查(8 角度 × 对抗验证)修复 10 项确认问题并完成收口: 安全: - 媒体资产下载仅对与服务商 Base URL 同主机的地址携带 API Key,防止密钥外泄 - 助手媒体工具默认关闭需显式开启;付费图片/视频生成在任何模式下强制确认 数据与容错: - 媒体数据统一存放 openclaw 数据目录下,便携迁移后配置与历史直接生效 - 视频轮询 429/5xx 瞬时错误不再永久标记失败;失败任务可重新轮询找回 - 创建视频任务无法识别任务 ID 时保留任务记录与原始响应(可能已计费) - 便携迁移失败时正确显示错误状态;便携命令加入 Web 模式 ALWAYS_LOCAL 性能与体验: - 任务记录落盘前裁剪 base64 等超大字段,媒体历史文件不再膨胀 - 资产预览 stat 预检 + 64MB 上限 + 缓存淘汰;轮询并行化(后端 jobs 加锁) - 初始设置页两阶段渲染:本地检测先出首屏,版本网络查询异步补充 - 创作中心删除改用统一确认弹窗(原生 confirm 在 macOS WebView 失效) - 检查配置/获取模型列表放行 http:// 自建网关;桌面/Web 状态解析对齐 - 统一三处路径包含检查为 utils 共享 helper(Linux 大小写误判修复) - 补充便携模式 hermes-cli-missing 警告翻译(简/繁/英) 其他:修复 web-headless-reload-policy 陈旧断言(e16ff2b 后 ws-client 已无隐式 reload) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
67 lines
2.5 KiB
JavaScript
67 lines
2.5 KiB
JavaScript
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { readFileSync } from 'node:fs'
|
||
|
||
const tauriApi = readFileSync(new URL('../src/lib/tauri-api.js', import.meta.url), 'utf8')
|
||
const wsClient = readFileSync(new URL('../src/lib/ws-client.js', import.meta.url), 'utf8')
|
||
const main = readFileSync(new URL('../src/main.js', import.meta.url), 'utf8')
|
||
const chat = readFileSync(new URL('../src/pages/chat.js', import.meta.url), 'utf8')
|
||
|
||
test('Web/headless 模式配置写入不能隐式 reload Gateway', () => {
|
||
assert.match(
|
||
tauriApi,
|
||
/function\s+_debouncedReloadGateway\(\)\s*\{[\s\S]*?if\s*\(\s*!isTauriRuntime\(\)\s*\)\s*return/,
|
||
'tauri-api 的防抖 reload 必须在 Web/headless 模式直接跳过',
|
||
)
|
||
})
|
||
|
||
test('Web/headless 模式自动配对重连不能隐式 reload Gateway', () => {
|
||
assert.match(
|
||
wsClient,
|
||
/import\s+\{\s*api\s*,\s*isTauriRuntime\s*\}\s+from\s+['"]\.\/tauri-api\.js['"]/,
|
||
'ws-client 必须能判断当前是否为 Tauri 桌面端',
|
||
)
|
||
// e16ff2b 起自动配对后不再隐式 reload(任何平台):连接层不得触发 Gateway 重载
|
||
assert.doesNotMatch(
|
||
wsClient,
|
||
/api\.reloadGateway\(/,
|
||
'ws-client 不得隐式 reload Gateway(自动配对重连由上层显式处理)',
|
||
)
|
||
})
|
||
|
||
test('Web/headless 模式启动自动连接不能隐式 reload Gateway', () => {
|
||
assert.match(
|
||
main,
|
||
/if\s*\(\s*needReload\s*&&\s*isTauriRuntime\(\)\s*\)\s*\{[\s\S]*?await\s+api\.reloadGateway\(\)/,
|
||
'启动自动连接合并 reload 只能在 Tauri 桌面端执行',
|
||
)
|
||
})
|
||
|
||
test('Web/headless 模式聊天连接修复不自动 reload Gateway', () => {
|
||
assert.match(
|
||
chat,
|
||
/if\s*\(\s*isTauriRuntime\(\)\s*\)\s*\{[\s\S]*?await\s+api\.reloadGateway\(\)/,
|
||
'聊天页连接修复按钮只能在 Tauri 桌面端自动 reload',
|
||
)
|
||
})
|
||
|
||
test('聊天发送按钮会在输入状态变化时重新同步 disabled 状态', () => {
|
||
assert.match(
|
||
chat,
|
||
/<button class="chat-send-btn" id="chat-send-btn" type="button" disabled>/,
|
||
'发送按钮必须是普通按钮,避免表单/浏览器默认行为干扰点击状态',
|
||
)
|
||
for (const eventName of ['compositionend', 'change', 'keyup']) {
|
||
assert.match(
|
||
chat,
|
||
new RegExp(`_textarea\\.addEventListener\\('${eventName}',\\s*updateSendState\\)`),
|
||
`textarea ${eventName} 事件必须同步发送按钮状态`,
|
||
)
|
||
}
|
||
assert.match(
|
||
chat,
|
||
/requestAnimationFrame\(updateSendState\)/,
|
||
'页面初始化后需要再同步一次发送按钮状态,覆盖自动填充或恢复输入内容',
|
||
)
|
||
})
|