WTStarMark/QAQ--packages-dsh-qaq ↗★ 3
dsh-qaq
QAQ backup plugin: snapshots the profile's startup config to ~/.dsh/.qaq once the host boot settles. Backup-only; does not detect failure, roll back, or alter DSH behavior.
AI 分析
核心用途是在 DSH 成功启动且确认可用后,自动将当前配置备份至本地目录。适合作为 QAQ 守护进程的辅助插件,保障配置安全,不改变 DSH 运行逻辑。
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:WTStarMark/QAQ#548e41dacc05ebb375bb22f74ed89f05a4e59e4e&path:packages/dsh-qaqドキュメント
README 全文を読む ↗QAQ — DeepSeek Harness Launch Resilience Guard
QAQ is a launch resilience guard for DeepSeek Harness (DSH). When a disrupted profile configuration prevents DSH from starting normally — a crashed host or a red-screened Web UI — QAQ automatically restores the configuration snapshot from the last successful boot and restarts, while preserving the broken config for manual recovery.
Author: WTStarMark
Non-invasive: QAQ never edits DSH source. The guard is a standalone executable that supervises the dsh web process and reads the browser's real DOM over CDP; the backup plugin only reads configuration and never changes behavior.


What it solves
DSH's Web surface has a failure mode where the host is alive but the UI red-screens: the host process runs, the port responds, yet the browser renders Failed to load plugins. Such failures are invisible to host-process monitoring and cannot be detected by curl (the server-side HTML ships an empty , rendered client-side). The only reliable non-invasive probe is to open the page in a headless browser and read the actual DOM. QAQ's UI-detection line is exactly that.
Requirements
- Node.js >= 22
- A Chrome/Chromium/Edge binary on the machine (used headlessly via CDP; no Playwright/Puppeteer dependency)
- The
dshcommand onPATH, or an explicitQAQ_DSH_CMD/--cwd
Install / Quick start
One command: qaq setup installs dependencies + builds, then qaq tui opens the full-screen live guard dashboard.
Or manually:
pnpm install
pnpm build # bundles dist/qaq.mjs AND regenerates packages/dsh-qaq/lib (the plugin)
bin/qaq.cmdruns the CLI through tsx for development; the globalqaqcommand (frompnpm build) runs the bundleddist/qaq.mjs. Both share the same CLI surface.qaq console/qaq tuiopens the full-screen dashboard on a TTY, or a compact menu otherwise.
Take over dsh web from a visible CMD window:
qaq tui --port 3080
# or a single supervised boot without the dashboard:
qaq dsh web --port 3080 --yes
or directly:
qaq dsh web --port 3080 --yes
Which
dshruns? The guard defaults todsh web(PATHresolution). To run from the DSH source tree instead:QAQ_DSH_CMD="node --import tsx/esm apps/cli/src/bin.ts web" qaq dsh web --cwd /path/to/dsh-checkout
Pre-launch self-check:
qaq dsh web(and the console) auto-discover thedshcommand —QAQ_DSH_CMD→--cwd→ a nearby DSH checkout (ancestors of the current directory, plus a sibling checkout sitting next to it, e.g. QAQ anddeepseek-harnessside by side) →PATH— pick a Chrome/Chromium/Edge binary for the UI probe, and verify the target port is free. Problems are reported with actionable Chinese hints before anything is spawned.
Commands
| Command | Purpose |
|---|---|
qaq dsh web [--port N] [--yes] | supervised startup: detect host/UI failure -> count -> roll back when triggered -> restart (with anti-loop) |
qaq status | print a summary of ~/.dsh/.qaq/state.json |
qaq backup [--profile web] | snapshot the current profile into the MANUAL backup set (independent 3-snapshot quota) |
qaq restore --to [--profile web] | restore a profile from a snapshot directory |
qaq reset --profile web | zero the failure counters |
qaq tui / qaq console | open the full-screen live dashboard (or a compact menu on non-TTY) |
qaq setup | install dependencies + build (one command) |
qaq install-plugin [--profile web] | auto-mount the dsh-qaq backup plugin into a profile |
Global: --yes auto-confirms rollbacks.
Dashboard (qaq tui / qaq console)
On a terminal (qaq tui) QAQ shows a full-screen, auto-refreshing dashboard — the all-in-one entry for launching, watching, browsing logs, and managing plugins. It shows guard status, the current operating mode (launcher / sideload / idle), failure counters, last-good snapshot, plugin mount state, a log viewer, and a plugin manager. On a non-TTY it falls back to a one-screen menu (qaq console). The interface is bilingual — press 10 in the TUI to toggle en/zh (a bare qaq console defaults to Chinese; $QAQ_LANG or --lang overrides). The actions available are:
[1] supervise a dsh web boot (guard) — fresh preflight each time, rollback + restart (launcher mode)
[2] refresh state panel — also auto-refreshes every ~1s
[3] back up the current profile into the MANUAL backup set
[4] backup/rollback list — open the backup manager: auto vs manual groups, pick one to restore
[5] reset failure counters
[6] mount the dsh-qaq backup plugin — idempotent, rollback-safe
[7] manage plugins — install / uninstall / enable / disable
[8] view logs — full-screen log viewer (error/access/host/qaq)
[9] sideload watch — run a continuous sideload guard on an external DSH (toggle)
[10] toggle en / zh
[11] quit
Navigation: ↑/↓ (or j/k) move the selection, Enter/Space run the action, digits 1..N jump straight to an action, q/Esc/Ctrl+C quit.
- Log viewer (
[8]):1–4switch betweenerror.log/access.log/host.log/qaq.log,↑/↓scroll,q/Esc/Enterreturn to the menu. - Plugin manager (
[7]): manages the real DeepSeek Harness plugins. It auto-discovers the DSH installation (home + source checkout, detected running process via heartbeat), scans the checkout'spackages/for the installable@deepseek-ai/dsh-*bundle packages, lists what's installed/enabled in the active profile, and lets you↑/↓select theneenable,ddisable,uuninstall,iinstall. Disabling keeps the module installed but removes it from the profile's boot bundle; uninstalling removes both. It never touches QAQ's own repository. - Operating modes: the status line shows which integration mode is active — launcher (QAQ owns a supervised
dsh web), sideload (an external DSH is up, or a continuous sideload guard is watching it), or idle. - Backup manager (
[4]): the backup-list sub-screen, split into auto backups (written by the guard on confirmed health / the plugin after a real conversation; independent 10-snapshot quota) and manual backups (written by[3]/qaq backup; independent 3-snapshot quota).↑/↓move the selection,Enterrestores the chosen backup,q/Escreturns. - Sideload guard (
[9]): a toggle. First press resolves the external DSH (the--portyou gaveqaq tui, else the dsh-qaq plugin heartbeat), pins that port, then keeps probing the real DOM every ~15s — counting host/UI failures and rolling back at threshold (auto-confirm, CLI-owned), exactly likeqaq watch. Press[9]again (or quit) to stop. The status line shows the watched URL and the last probe outcome.
The panel auto-refreshes while a supervised dsh web runs; the guard lock is held until it exits (a second launch is refused and a stale port check never misfires). q/Esc/Ctrl+C quit the dashboard; a supervised child is killed so no process is left holding the port.
Operations guide
First-time setup (Windows)
- Install — run
qaq setup. It checks Node.js >= 22, installs dependencies (pnpm, with an npx fallback), and buildsdist/qaq.mjs+ the plugin lib. - Mount the backup plugin (recommended) — run
qaq tui, pressi(mount the dsh-qaq backup plugin). This addsdsh-qaqto the profile's bundle list and links the module into the profile'snode_modules. From then on, the plugin snapshots the config once a real user conversation has happened — the strongest proof the boot is actually usable. A host that settles but renders a web red screen never lets the user talk, so it is never recorded as last-good (backup-only; it never changes DSH behavior). The profile's owncordis.patch.ymlis intentionally left untouched — DSH auto-loads the plugin's patch from its bundle declaration. - Launch — press
1(start the guard). The dashboard re-runs the pre-launch self-check (dsh command, browser, port), then supervisesdsh web. Once the UI has been healthy for the confirmation window, the config is recorded as last-good and the guard keeps monitoring in the background. - Verify —
qaq status:hostFailures/uiFailuresshould be 0 andlastSuccess/lastGoodSnapshotpresent.
Everyday use
- Start DSH the same way every time:
qaq tui→ press1. Prefer not to startdsh webdirectly anymore — the guard owns the supervised process and is the only one that can detect a red screen. - If the UI red-screens (or the host crashes) 3 times in a row, QAQ offers a rollback to the last-good config with a diff preview. Accept it — the broken config is preserved under
~/.dsh/.qaq/rolled-back/for later inspection, and the guard restarts once automatically. - After a successful rollback + restart, the counters are zeroed and the anti-loop fence is cleared; the restored profile is the one you had before it broke.
Troubleshooting
| Symptom | What to do |
|---|---|
Pre-launch self-check failed — dsh not found | Put dsh on PATH, set QAQ_DSH_CMD, or pass --cwd pointing at the DSH checkout |
Port already in use — port busy | Stop the other process, or pick another port: --port N |
| UI red-screens again after a rollback | Inspect the logs and the preserved bad config: qaq tui (logs are shown in the dashboard) or read, or read ~/.dsh/.qaq/log/ (error.log, access.log, host.log) |
Guard says anti-loop fence is active | A rollback already happened within the last 5 minutes. Fix the config manually (see rolled-back/), then qaq reset --profile web to clear the counters |
| Want to undo a rollback | qaq restore --to --profile web with any directory under ~/.dsh/.qaq/history/auto/ (or history/manual/, rolled-back/) |
| dsh-qaq not snapshotting | The plugin only writes last-good after a real user conversation — a host that settles but red-screens, or a boot nobody talked to, is never snapshotted. Confirm dsh-qaq is in the profile bundles (the dashboard shows the last snapshot) and that install-plugin reported success |
Data locations
- Guard state, snapshots, and logs:
~/.dsh/.qaq/(or$DSH_HOME/.qaq/) - Profile configs:
$DSH_HOME/profiles//(package.json+cordis.patch.yml) qaq statusprints the exact paths for your environment.
Supervised dsh web options
| Option | Meaning | Default |
|---|---|---|
--confirm-ms | stable-healthy confirmation window before snapshotting | 20000 |
--ui-timeout | max wait for the UI to settle during the L3 probe | 25000 |
--threshold | consecutive same-kind failures that trigger a rollback | 3 |
--cwd | working directory for the supervised dsh (set to the checkout for source launch) | process cwd |
Detection criteria (L3, empirically verified)
- UI failure:
document.body.innerTextcontains the pinned textFailed to load plugins(stable across builds). The failure detail even names the missing plugin/service (e.g.web boot: 1 entry did not activate dsh-x: pending (waiting for service: s)). - Success: a composer business container (``) is present and the failure marker is absent, stable for >=
--confirm-ms. - No CSS class selectors: the red-screen structural classes are CSS-Module hashes (
_boot_) that change between builds.
State & storage (~/.dsh/.qaq/)
state.json—hostFailures,uiFailures,lastSuccess,lastFailure,lastGoodSnapshot,rolledBackAtlatest-good/— the last confirmed-good profile config (package.json+cordis.patch.yml+manifest.json)history/auto//— auto backup set (guard confirm / plugin real conversation; independent 10-snapshot quota)history/manual//— manual backup set (qaq backup/ TUI[3]; independent 3-snapshot quota)rolled-back//— the broken config saved before a rollback (for manual recovery)log/— structured multi-file logs (see below)
Never snapshotted: credentials, sessions, storages, mcp-servers.
Logging (for developer troubleshooting)
Every record is one JSON line ({ ts, level, cat, phase?, msg, ...meta }) so the trail is machine-parseable, split across four files under log/, each rotating by size (256 KB → .1.log, keeping 5 copies):
| File | Content |
|---|---|
qaq.log | everything (info + warn + error), the canonical record |
error.log | warn/error only — grep for trouble fast |
access.log | crash-audit trail: boot verdicts, snapshots, rollbacks, resets, plugin mounts, manual restore |
host.log | raw supervised dsh stdout/stderr (mirrored to the visible window) |
Trigger & anti-loop
- 3 consecutive failures of the same kind (host or UI) trigger a rollback.
- Exception — definitive host crash: when the child process dies and its output carries a fail-loud boot marker (`plugin tree failed