/** * @homebridge/ciao Windows cmd 弹窗 bug 检测与提示 * * 背景:openclaw 的依赖 @homebridge/ciao (<= 1.3.6) 在 Windows 上每 15-30 秒 * 调用 `child_process.exec("arp -a ...")` 时未传 `windowsHide: true`, * 导致 cmd.exe / conhost.exe 窗口闪烁。这是上游库的 bug, * 不在 ClawPanel 控制范围内。上游 issue #64 和 PR #65 尚未合并。 * * 我们只做两件事:检测 + 给用户展示修复指引。不触碰用户 node_modules。 */ import { api } from './tauri-api.js' import { toast } from '../components/toast.js' import { t } from './i18n.js' const DISMISS_KEY_PREFIX = 'clawpanel_ciao_bug_dismissed_v' function dismissKey(version) { return `${DISMISS_KEY_PREFIX}${version || 'unknown'}` } function isDismissed(version) { try { return localStorage.getItem(dismissKey(version)) === '1' } catch (_) { return false } } function markDismissed(version) { try { localStorage.setItem(dismissKey(version), '1') } catch (_) { /* quota 等异常忽略 */ } } /** * 启动后异步检测;若确实受影响,展示一个可 dismiss 的 toast。 * 用户点"详情"会打开带修复步骤和官方链接的 modal。 */ export async function checkAndWarnCiaoBug() { let result try { result = await api.checkCiaoWindowsHideBug() } catch (err) { console.debug('[ciao-bug] check failed:', err) return } if (!result || !result.affected) return if (isDismissed(result.version)) return const detailBtn = document.createElement('button') detailBtn.className = 'btn btn-sm btn-primary' detailBtn.textContent = t('ciaoBug.viewDetail') detailBtn.style.marginLeft = '8px' detailBtn.onclick = () => openCiaoBugModal(result) toast( t('ciaoBug.toastTitle'), 'warning', { action: detailBtn, duration: 12000 }, ) } function openCiaoBugModal(result) { const overlay = document.createElement('div') overlay.className = 'modal-overlay' const versionLine = result.version ? `
@homebridge/ciao ${escapeHtml(result.version)}
` : '' const pathLine = result.networkManagerPath ? `
${escapeHtml(t('ciaoBug.pathLabel'))} ${escapeHtml(result.networkManagerPath)}
` : '' overlay.innerHTML = ` ` const close = () => overlay.remove() overlay.addEventListener('click', (e) => { if (e.target === overlay) close() }) overlay.querySelector('[data-action="close"]').onclick = close overlay.querySelector('[data-action="dismiss"]').onclick = () => { markDismissed(result.version) close() toast(t('ciaoBug.dismissed'), 'info') } document.addEventListener('keydown', function onEsc(e) { if (e.key === 'Escape') { close() document.removeEventListener('keydown', onEsc) } }) document.body.appendChild(overlay) } function escapeHtml(raw) { return String(raw || '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') }