WTStarMark/QAQ
QAQ: a launch resilience guard for DeepSeek Harness (DSH). Supervises dsh web, reads the real DOM via headless Chrome + CDP to catch host crashes and UI red-screens, and auto-rolls-back to the last known-good config. DSH
これは DeepSeek Harness(DSH)プラグインです。当サイトは GitHub README、インストール情報、メンテナンス状況、公開セキュリティシグナルをまとめています。
QAQ — DeepSeek Harness 启动容灾守卫
当 profile 配置损坏导致 DeepSeek Harness(下称 DSH)无法正常启动(宿主崩溃 或 Web UI 红屏)时,QAQ 自动回溯到「上一次成功启动」的配置快照并重启,同时保留被回退的坏配置便于手动还原。
作者:WTStarMark
不侵入 DSH 源码:守卫是独立可执行,只通过 spawn 进程 + CDP 读浏览器真实 DOM;备份插件只读配置不改行为。
它解决什么
DSH Web 存在一种「宿主活、UI 红屏」的失败模式:宿主进程正常、端口可达,但浏览器渲染出 Failed to load plugins。这类失败纯监听宿主进程抓不到、纯 curl 抓空 root 也测不到(服务端 HTML 里 <div id="root"> 是空的,由 React 运行时渲染)。唯一可靠且不侵入的手段,是用 headless 浏览器打开页面、读取真实 DOM。QAQ 的 UI 侦测线正是这么做。
环境要求
- Node.js >= 22
- 机器上有 Chrome/Chromium/Edge(经 CDP 无头驱动;无 Playwright/Puppeteer 依赖)
dsh在PATH,或用QAQ_DSH_CMD/--cwd指定 DSH 启动命令与工作目录
安装 / 快速上手
一键安装(Windows,懒人脚本):双击 bin\qaq-install.zh.cmd(装依赖 + 构建),再双击 bin\qaq-web.zh.cmd 打开交互式守卫控制台——无需记任何命令。(英文版启动器为 bin\qaq-install.cmd / bin\qaq-web.cmd。)
手动安装:
pnpm install
pnpm build # 产出 dist/qaq.mjs 单文件可执行
从可见 CMD 窗口接管 dsh web:
bin\qaq-web.zh.cmd [--port 3080] [--yes]
或直接:
qaq dsh web --port 3080 --yes
用哪个 dsh 启动? 守卫默认执行
dsh web(PATH 解析)。若要从 DSH 源码树启动:QAQ_DSH_CMD="node --import tsx/esm apps/cli/src/bin.ts web" qaq dsh web --cwd /path/to/dsh-checkout
启动前自检:
qaq dsh web(和控制台)会自动发现dsh命令——QAQ_DSH_CMD→--cwd→ 就近的 DSH checkout(当前目录的祖先链,以及与当前目录并排的兄弟 checkout,如 QAQ 与deepseek-harness同目录并列)→PATH——挑选 Chrome/Chromium/Edge 作为 UI 探测浏览器、确认目标端口空闲。发现问题会在拉起任何进程前给出中文可操作提示。
命令面
| 命令 | 作用 |
|---|---|
qaq dsh web [--port N] [--yes] | 接管启动:侦测 host/UI 失败 -> 计数 -> 触发时回滚 -> 重启(带防死循环) |
qaq status | 显示 ~/.dsh/.qaq/state.json 摘要 |
qaq backup [--profile web] | 手动快照当前 profile 为 last-good |
qaq restore --to <snapDir> [--profile web] | 手动从某快照还原 profile |
qaq reset --profile web | 清零失败计数 |
qaq console | 打开交互式菜单(懒人脚本,同 bin\qaq-web.cmd) |
qaq install-plugin [--profile web] | 自动把 dsh-qaq 备份插件挂载进 profile |
全局开关:--yes 自动确认回滚。
一键控制台(qaq console / bin\qaq-web.zh.cmd)
可见 CMD 窗口里的菜单。控制台双语:bin\qaq-web.zh.cmd 显示中文,bin\qaq-web.cmd 显示英文;直接 qaq console 默认中文(可用 --lang en 或 $QAQ_LANG=en 切换):
[1] 一键启动守卫(接管 dsh web) — 每次启动前重新自检
[2] 查看状态 — 计数 / 上次成功 / 最近快照
[3] 手动备份当前配置为 last-good
[4] 手动回滚到 last-good
[5] 重置失败计数
[6] 自动挂载 dsh-qaq 备份插件 — 幂等、失败即撤销(绝不弄坏一次启动)
[7] 查看日志(error / access / host)
[q] 退出
受监督的 dsh web 运行期间,守卫锁会一直持有到它退出(期间拒绝二次启动,也不会被过期的端口检查误导);Ctrl+C 会先杀掉受监督子进程,避免进程残留占住端口。
控制台在每次渲染菜单前自动清屏——窗口永远只保留一屏内容(持久头部 + 上次操作结果 + 菜单),不再堆叠;状态/日志等详情视图会以 [回车返回菜单] 暂停,方便阅读。
操作指南
首次配置(Windows)
- 安装 — 双击
bin\qaq-install.zh.cmd。它会检查 Node.js >= 22、安装依赖(pnpm,失败时回退 npx)、并构建dist/qaq.mjs。 - 挂载备份插件(推荐) — 运行
bin\qaq-web.zh.cmd,选 [6] 自动挂载 dsh-qaq 备份插件。它把dsh-qaq加进 profile 的 bundle 列表,并在 profile 的node_modules里建好模块链接。此后每次干净启动、host 稳定后,插件会自动把配置快照到~/.dsh/.qaq(仅备份,绝不改 DSH 行为)。profile 自己的cordis.patch.yml故意不动——DSH 会从 bundle 声明自动加载插件的 patch 层。 - 启动 — 选 [1] 一键启动守卫。控制台会重新做启动前自检(dsh 命令、浏览器、端口),然后接管
dsh web。UI 稳定通过确认窗口后,配置被记为 last-good,守卫转入后台持续监控(随时可回车回菜单,守卫继续运行)。 - 验证 — 选 [2] 查看状态(或命令行
qaq status):hostFailures/uiFailures应为 0,且存在lastSuccess/lastGoodSnapshot。
日常使用
- 每次都用同一方式启动 DSH:
bin\qaq-web.zh.cmd→ [1]。之后尽量不要再直接跑dsh web——守卫是唯一能发现红屏的监督者。 - 若 UI 连续红屏(或宿主崩溃)3 次,QAQ 会给出回滚确认(带 diff 预览)。接受即可——坏配置会保留在
~/.dsh/.qaq/rolled-back/供事后检查,守卫会自动重启一次。 - 回滚 + 重启成功后,失败计数清零、防死循环栅栏解除;恢复的配置就是坏掉之前的那份。
故障排查
| 现象 | 处理方法 |
|---|---|
启动前自检未通过(找不到 dsh) | 把 dsh 加进 PATH、设置 QAQ_DSH_CMD,或用 --cwd <dir> 指向 DSH 源码目录 |
端口已被占用 | 停掉占用进程,或用 --port N 换端口 |
| 回滚后 UI 仍然红屏 | 看日志与保留的坏配置:qaq console → [7],或直接读 ~/.dsh/.qaq/log/(error.log / access.log / host.log) |
提示 anti-loop fence is active | 5 分钟内已发生过回滚。先手动修复配置(见 rolled-back/),再 qaq reset --profile web 清计数 |
| 想撤销一次回滚 | qaq restore --to <snapDir> --profile web,snapDir 用 ~/.dsh/.qaq/history/(或 rolled-back/)下任意目录 |
| dsh-qaq 不写快照 | 插件只在干净启动、host 稳定时写,失败启动不写。确认它在 profile bundles 里(qaq console → [2] 能看到最近快照),且 install-plugin 报成功 |
数据位置
- 守卫状态、快照、日志:
~/.dsh/.qaq/(或$DSH_HOME/.qaq/) - profile 配置:
$DSH_HOME/profiles/<name>/(package.json+cordis.patch.yml) qaq status会打印你环境下的确切路径。
qaq dsh web 调优参数
| 参数 | 含义 | 默认 |
|---|---|---|
--confirm-ms <ms> | 稳定健康确认窗口(成功判定前的观察时长) | 20000 |
--ui-timeout <ms> | L3 UI 侦测最长等待 | 25000 |
--threshold <n> | 触发回滚的连续同类失败数 | 3 |
--cwd <dir> | 被监督 dsh 的工作目录(源码启动时指向 DSH checkout) | 本进程 cwd |
侦测判据(L3,实证)
- UI 失败:
document.body.innerText含固定文本Failed to load plugins(跨构建稳定);异常详情直接给出缺失插件/服务(如web boot: 1 entry did not activate dsh-x: pending (waiting for service: s))。 - 成功:出现 composer 业务容器(
<textarea>)且无红屏文本,稳定 >=--confirm-ms。 - 不使用 CSS 类选择器:红屏结构类是 CSS Modules 哈希(
_boot_<hash>),跨构建不稳定。
状态与存储(~/.dsh/.qaq/)
state.json—hostFailures/uiFailures/lastSuccess/lastFailure/lastGoodSnapshot/rolledBackAtlatest-good/— 当前「确认成功」的 profile 配置副本(package.json + cordis.patch.yml + manifest)history/<ts>/— 最近 5 份时间戳历史快照rolled-back/<ts>/— 被执行回滚的坏配置(手动还原用)log/— 结构化多文件日志(见下)
绝不纳入快照:凭据、会话、storages、mcp-servers。
日志(供开发者检修)
每条记录一行 JSON({ ts, level, cat, phase?, msg, ...meta }),可机器解析;按 log/ 下四个文件分门别类,各自按大小轮转(256 KB → .1.log,保留 5 份):
| 文件 | 内容 |
|---|---|
qaq.log | 全部(info + warn + error),主记录 |
error.log | 仅 warn/error——快速 grep 问题 |
access.log | 崩溃审计轨迹:启动结论、快照、回滚、重置、插件挂载、手动还原 |
host.log | 被监督 dsh 的原始 stdout/stderr(同时镜像到可见窗口) |
触发与防死循环
- 连续 3 次同类(host 或 ui)失败 -> 触发回滚。
- 例外——确定性宿主崩溃:子进程死亡且输出带启动失败标记(
plugin tree failed to load等)属于确定的配置错误,首次命中即回滚(有效阈值 1,不再等 3 次),无需重复手动启动。防死循环栅栏与 Y/N 确认(除非--yes)仍然生效。 - 默认需用户在窗口确认(Y/N);
--yes全自动。 - 拒绝确认即停手,不自动重启:坏配置保留原位(同时备份到
rolled-back/)供手动还原——守卫绝不会在你背后用 autoConfirm 重启来强行回滚。 - 回滚后进入 5 分钟防死循环栅栏:窗口内再次失败即停手,指引人工检查
rolled-back/。
可靠性增强
- 瞬态失败重试(
retries=1):对疑似瞬时错误(host 未就绪 / bundle 脚本加载失败)自动重试一次,不计入失败计数,避免 Windows 偶发 EBUSY 误伤。带失败标记的确定性宿主崩溃不重试(重试只会复现同样的错误),直接计数并首次即回滚。每次重试前会先杀掉上一次的子进程——失败启动绝不会泄漏进程占住端口或挂住守卫。 - 确认窗口复查:首次健康 DOM 探测后,启动需稳定经过
--confirm-ms,随后再对真实 DOM 复查一次才写 last-good 快照——首次健康后立即劣化的启动绝不会被记为 good。 - PID 感知守卫锁:崩溃残留的陈旧锁在下一次运行自动回收,避免「假占用」。
- 回滚 diff 预览:Y/N 确认前打印当前配置与 last-good 的差异。
- 历史保留确定性:快照按 ISO 时间戳名排序,跨重启保留稳定。
- 宿主失败快速上报:子进程在端口打开前退出(或 spawn 失败,如命令不存在)会立即上报,不再干等完整端口超时。
测试
pnpm test # vitest 单元测试(store / rollback / detector-ui / guard / spawn-dsh / env / install-plugin / log)
pnpm smoke # 一键回归:单测 + 隔离 home 种子/破坏/守卫检测
pnpm smoke 在可用 DSH checkout(QAQ_SMOKE_DSH_HOME)时才会执行真实 DSH 集成段。
CI(.github/workflows/ci.yml)在 ubuntu-latest 与 windows-latest、Node 22、冻结 lockfile 下运行 typecheck + 构建 + 单测 + smoke。
集成验收素材:qaq-test-plugins/dsh-broken-theme(注入永不存在的服务 -> 确定性红屏),配合 tools/rollback-test.ps1 可在真实 DSH 实例上跑通「失败 -> 计数 -> 回滚 -> 还原」闭环。
仓库布局
| 路径 | 作用 |
|---|---|
src/cli.ts | 命令面 + 接管循环 |
src/guard.ts | superviseBoot 编排(host 就绪 -> UI 侦测 -> 计数/回滚) |
src/spawn-dsh.ts | spawn dsh web、继承 env、就绪/退出监听 |
src/cdp.ts | 极简 CDP 客户端(headless Chrome,无 Playwright) |
src/detector-ui.ts | L3 文本判据 |
src/store.ts | ~/.dsh/.qaq 原子读写 + 快照管理 + 锁 |
src/rollback.ts | 回滚 + 坏版备份 + 防死循环 + 成功记账 |
src/env.ts | 环境自动发现 + 启动前自检(dsh / 浏览器 / 端口) |
src/console.ts | 交互式菜单 GUI(懒人脚本,CMD 窗口) |
src/install-plugin.ts | 自动挂载 dsh-qaq 备份插件(失败即撤销,绝不弄坏启动) |
src/paths.ts · src/log.ts | 路径助手;结构化多文件轮转日志 |
packages/dsh-qaq/ | DSH 备份插件(host boot settle 后写快照,仅备份不改行为) |
bin/ | qaq / qaq-web.cmd / qaq-install.cmd 启动入口 |
tools/ · test/ | 集成/smoke 脚本;vitest 测试 |
文档
面向二次开发的专项解析文档:
| 文档 | 内容 |
|---|---|
| architecture.zh.md | 架构总览:模块地图、启动时序、状态机、数据流 |
| guard-lifecycle.zh.md | 守卫生命周期:失败分类、瞬态重试、确认窗口 |
| state-and-rollback.zh.md | 状态存储与回滚:state.json、快照、防循环、守卫锁 |
| ui-detection.zh.md | UI 检测与 CDP:无依赖客户端、L3 判据、探测时序 |
| console-and-env.zh.md | 懒人脚本控制台与环境自动发现、插件挂载 |
| logging.zh.md | 日志系统:结构化格式、四通道、轮转 |
| testing.zh.md | 测试与真实集成:单测矩阵、smoke、故障注入 |
英文版见
docs/*.md(默认命名)。
参与贡献
欢迎一切形式的贡献——Bug 报告、功能建议与 Pull Request 都能让 QAQ 变得更好。
报 Bug / 提需求:在 Issues 提交,附上复现步骤(~/.dsh/.qaq/log/access.log 与 error.log 的关键片段最有帮助)和你的环境(操作系统、Node 版本)。
提交 Pull Request:
- Fork 本仓库并创建功能分支。
- 本地准备:
pnpm install(Node 22+、pnpm 11——见.nvmrc)。 - 修改并补测试——见 testing.zh.md 了解各 spec 覆盖点与新增用例的方式。
- 通过门禁:
pnpm typecheck、pnpm test、pnpm build(CI 会在 Ubuntu 与 Windows 上强制执行)。 - 开 PR,附上简短说明:改了什么、为什么。
入门指引:先读 architecture.zh.md,再深入 docs/ 下各专项文档。
License
MIT
セキュリティとインストールエビデンス
このスコアは公開リポジトリメタデータと当サイトに登録されたインストールエビデンスのみに基づくもので、コードセキュリティ監査とは異なります。
公開プラグインカタログから取得し、公開 GitHub リポジトリにリンクしています。
リポジトリは MIT ライセンスを宣言しています。
過去180日以内にコードの更新があります。
再現可能な正確なインストールメタデータはまだ登録されていません。リポジトリの説明に従って手動で確認してください。
確認したパッケージメタデータにインストールライフサイクルスクリプトは宣言されていません。