dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
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 启动容灾守卫,检测宿主崩溃与 UI 红屏,自动回滚到最近一次成功配置。非侵入、一键懒人脚本、结构化日志。
PROJECT TOPICS
PROJECT README
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.
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 <div id="root">, 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.
dsh command on PATH, or an explicit QAQ_DSH_CMD / --cwdOne-click (Windows): double-click bin\qaq-install.cmd (installs deps + builds), then double-click bin\qaq-web.cmd to open the interactive guard console — no commands to remember. (Chinese launcher variants: bin\qaq-web.zh.cmd / bin\qaq-install.zh.cmd.)
Or manually:
pnpm install
pnpm build # emits a single-file executable at dist/qaq.mjs
Take over dsh web from a visible CMD window:
bin\qaq-web.cmd [--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.
| 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 as last-good |
qaq restore --to <snapDir> [--profile web] |
restore a profile from a snapshot directory |
qaq reset --profile web |
zero the failure counters |
qaq console |
open the interactive menu (lazy launcher, same as bin\qaq-web.cmd) |
qaq install-plugin [--profile web] |
auto-mount the dsh-qaq backup plugin into a profile |
Global: --yes auto-confirms rollbacks.
qaq console / bin\qaq-web.cmd)A menu in a visible CMD window. The console is bilingual: bin\qaq-web.cmd shows English, bin\qaq-web.zh.cmd shows Chinese; a bare qaq console defaults to Chinese (--lang en or $QAQ_LANG=en switches). The menu items correspond to:
[1] Start the guard (take over dsh web) — supervised launch (fresh preflight each time)
[2] View status — counters / last success / last snapshot
[3] Back up the current profile as last-good
[4] Roll back to last-good
[5] Reset failure counters
[6] Mount the dsh-qaq backup plugin — idempotent, rollback-safe (never breaks a boot)
[7] View logs (error / access / host)
[q] Quit
While a supervised dsh web is running, the guard lock is held until it exits (a second launch is refused and a stale port check can never misfire); Ctrl+C kills the supervised child so no process is left holding the port.
The console clears the screen before every menu render — the window always shows one screen (persistent header + last action result + menu) instead of stacking stale output. Detailed views (status / logs) pause with an Enter-to-return prompt.
bin\qaq-install.cmd. It checks Node.js >= 22, installs dependencies (pnpm, with an npx fallback), and builds dist/qaq.mjs.bin\qaq-web.cmd, pick [6] (mount the dsh-qaq backup plugin). This adds dsh-qaq to the profile's bundle list and links the module into the profile's node_modules. From then on, the plugin snapshots the config every time a clean host boot settles (backup-only; it never changes DSH behavior). The profile's own cordis.patch.yml is intentionally left untouched — DSH auto-loads the plugin's patch from its bundle declaration.dsh 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 (return to the menu anytime; the guard keeps running).qaq status: hostFailures / uiFailures should be 0 and lastSuccess / lastGoodSnapshot present.bin\qaq-web.cmd → [1]. Prefer not to start dsh web directly anymore — the guard owns the supervised process and is the only one that can detect a red screen.~/.dsh/.qaq/rolled-back/ for later inspection, and the guard restarts once automatically.| Symptom | What to do |
|---|---|
Pre-launch self-check failed — dsh not found |
Put dsh on PATH, set QAQ_DSH_CMD, or pass --cwd <dir> 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 console → [7], 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 <snapDir> --profile web with any directory under ~/.dsh/.qaq/history/ (or rolled-back/) |
| dsh-qaq not snapshotting | The plugin only writes on a clean host settle; it does not write on a failed boot. Confirm it is listed in the profile bundles (qaq console → [2] shows the last snapshot) and that install-plugin reported success |
~/.dsh/.qaq/ (or $DSH_HOME/.qaq/)$DSH_HOME/profiles/<name>/ (package.json + cordis.patch.yml)qaq status prints the exact paths for your environment.dsh web options| Option | Meaning | Default |
|---|---|---|
--confirm-ms <ms> |
stable-healthy confirmation window before snapshotting | 20000 |
--ui-timeout <ms> |
max wait for the UI to settle during the L3 probe | 25000 |
--threshold <n> |
consecutive same-kind failures that trigger a rollback | 3 |
--cwd <dir> |
working directory for the supervised dsh (set to the checkout for source launch) |
process cwd |
document.body.innerText contains the pinned text Failed 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)).<textarea>) is present and the failure marker is absent, stable for >= --confirm-ms._boot_<hash>) that change between builds.~/.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/<ts>/ — up to 5 timestamped historical snapshotsrolled-back/<ts>/ — the broken config saved before a rollback (for manual recovery)log/ — structured multi-file logs (see below)Never snapshotted: credentials, sessions, storages, mcp-servers.
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) |
plugin tree failed to load etc.), it is a deterministic config error: QAQ rolls back on the first hit (effective threshold 1) instead of waiting for 3 manual runs. The anti-loop fence and the Y/N confirmation (unless --yes) still apply.Y/N); --yes makes it fully automatic.rolled-back/ too) for manual recovery — the guard never restarts with an auto-confirmed rollback behind your back.rolled-back/.retries=1): suspected one-off flakes (host not ready, a client bundle that transiently fails to load) are retried once and not counted, so a Windows EBUSY does not corrupt the strike counter. A definitive host crash (death + fail-loud marker) is not retried — a retry only reproduces the same deterministic error — and it rolls back on the first hit. Every retried attempt kills its child first, so a failed boot never leaks a process that would hold the port or hang the guard.--confirm-ms, then the real DOM is probed once more before a last-good snapshot is written — a boot that degrades right after first health is never recorded as good.Y/N.pnpm test # vitest unit tests (store / rollback / detector-ui / guard / spawn-dsh / env / install-plugin / log)
pnpm smoke # one-shot regression: unit tests + seed/broken/detect in an isolated home
pnpm smoke performs a real-DSH integration segment only when a checkout is available (set QAQ_SMOKE_DSH_HOME).
CI (.github/workflows/ci.yml) runs typecheck + build + unit tests + smoke on ubuntu-latest and windows-latest with Node 22 and a frozen lockfile.
Integration fixture: qaq-test-plugins/dsh-broken-theme (injects a service that never arrives -> deterministic red screen), used with tools/rollback-test.ps1 to exercise the full fail->count->rollback->recover loop on a real DSH instance.
| Path | Purpose |
|---|---|
src/cli.ts |
command surface + supervised loop |
src/guard.ts |
superviseBoot orchestration (host ready -> UI detect -> count/rollback) |
src/spawn-dsh.ts |
spawn dsh web, inherit env, readiness/exit tracking |
src/cdp.ts |
minimal CDP client (headless Chrome, no Playwright) |
src/detector-ui.ts |
L3 text criteria |
src/store.ts |
atomic ~/.dsh/.qaq read/write + snapshot management + lock |
src/rollback.ts |
rollback + broken-config backup + anti-loop + success bookkeeping |
src/env.ts |
auto-discovery + pre-launch self-check (dsh / browser / port) |
src/console.ts |
interactive menu GUI (lazy launcher, CMD window) |
src/install-plugin.ts |
auto-mount the dsh-qaq backup plugin (rollback-safe) |
src/paths.ts · src/log.ts |
path helpers; structured multi-file rotating logger |
packages/dsh-qaq/ |
DSH backup plugin (snapshots after host boot settles; backup-only) |
bin/ |
qaq / qaq-web.cmd / qaq-install.cmd launchers (+ qaq-web.zh.cmd / qaq-install.zh.cmd Chinese variants) |
tools/ · test/ |
integration/smoke scripts; vitest specs |
Developer-oriented deep-dives for secondary development:
| Document | Covers |
|---|---|
| architecture.md | module map, boot sequence, state machine, data flow |
| guard-lifecycle.md | supervised boot flow, failure classification, transient retry, confirmation window |
| state-and-rollback.md | state.json, snapshots, anti-loop fence, guard lock |
| ui-detection.md | headless-Chrome CDP client, L3 text criteria, probe timing |
| console-and-env.md | lazy launcher console, environment auto-discovery, plugin mounting |
| logging.md | structured log format, four channels, rotation |
| testing.md | unit-test matrix, smoke, real-DSH integration, fault injection |
Chinese versions:
docs/*.zh.md(default-named files are English).
Contributions are welcome — bug reports, feature requests, and pull requests all help make QAQ better.
Report a bug / request a feature: open an issue with reproduction steps (excerpts from ~/.dsh/.qaq/log/access.log and error.log go a long way) and your environment (OS, Node version).
Send a pull request:
pnpm install (Node 22+, pnpm 11 — see .nvmrc).pnpm typecheck && pnpm test && pnpm build (CI enforces these on Ubuntu + Windows).Orientation: start with architecture.md, then the topic documents under docs/.
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。