xiayuhkust
dsh-visual-probe
Visual-verification tools for DeepSeek Harness (dsh): flicker, visual regression, and WCAG contrast as numbers a text-only agent can read.
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
dsh-plugin-browser-probe
English | 中文
Visual-verification tools for DeepSeek Harness (dsh). It runs a headless browser and turns three kinds of UI check into numbers, so a text-only agent can verify them by reading metrics instead of seeing the page:
| Tool | Question it answers | Returns |
|---|---|---|
flicker_detect | Does the page flicker? | how many frame pairs change, and by how much |
visual_diff | Did my edit change anything unintended? | how much differs, and which screen zones |
contrast_probe | Is any text too light to read? | WCAG contrast ratio per text element, and which fail |
Each returns data, not an image — the agent reads the numbers and decides. Built on Playwright + pngjs.
Runtime: dsh 0.1.x developer preview; interfaces may shift with dsh.
Install
Heavy dependency (Playwright downloads a browser), so it is a standalone package.
dsh plugin --profile web add -w dsh-plugin-browser-probe
npx playwright install chromium-headless-shell # one-time browser download
Mount it in the profile's cordis.patch.yml (use - insert: to add a new row, not a bare - id:):
- insert:
- id: browser-probe
name: dsh-plugin-browser-probe
config:
frames: 10 # flicker: frames to capture (default 10)
intervalMs: 150 # flicker: ms between frames (default 150)
settleMs: 400 # wait after load before capturing (default 400)
Restart dsh web to take effect. dsh --profile web --dump-config confirms the row is present.
Tools
flicker_detect
Captures consecutive frames of a page and measures the fraction of pixels that change between them. A verdict is FLICKER only when change recurs (≥2 frame pairs over threshold) — a single changed pair is a one-off load transition, not flicker.
| Parameter | Description |
|---|---|
url | Page to inspect (file:// or http://). |
frames | Frames to capture. Default 10. |
intervalMs | Milliseconds between frames. Default 150. |
settleMs | Wait after load before the first frame. Default 400. |
selector | Optional CSS selector; crops the measurement to that element's box — the reliable way to catch flicker in a small widget. |
region | Optional {x, y, width, height} rectangle; values ≤1 are viewport fractions, otherwise pixels. |
Whole-frame measurement reliably catches flicker over ~8% of the screen. For a small flickering element (a caret, a thin line), pass selector or region so the ratio is computed inside that area.
Returns hotPairs/totalPairs, maxChangedRatio, isFlickering, scope, verdict.
visual_diff
Compares two rendered states — two URLs, or two saved PNG paths — and reports how much and where they differ. The frame is split into an 8×6 grid; changed zones are reported as top/middle/bottom × left/center/right, so a small change still surfaces with its location.
| Parameter | Description |
|---|---|
a | Baseline state: an http/file URL, or a path to a saved .png. |
b | Comparison state: same. |
settleMs | For URL inputs, wait after load before capturing. Default 400. |
Returns changedRatio, changedZones, changedCells (worst first), dimensionsMatch, verdict. Typical use: keep a known-good URL (or capture before your edit), then diff the after-state and confirm only the intended zones changed.
contrast_probe
Reads each text element's color and effective background from the DOM and computes the objective WCAG contrast ratio, reporting which text fails the standard (AA needs 4.5:1 for normal text, 3:1 for large). Large text is detected by font size/weight; semi-transparent text is blended over its background first.
| Parameter | Description |
|---|---|
url | Page to inspect (file:// or http://). |
selector | Optional CSS selector to limit the scan to one area. Omit to scan the whole page. |
standard | AA (default, 4.5/3) or AAA (7/4.5). |
settleMs | Wait after load before reading styles. Default 400. |
Returns checked (count), worstRatio, failures (each with the ratio, required ratio, and actual fg/bg colors), verdict.
Command line
Each tool's core also runs standalone, useful for a quick check or CI:
node src/flicker-detect.mjs <url> [frames] [intervalMs] [settleMs] [region:x,y,w,h | sel:CSS]
node src/visual-diff.mjs <a-url-or-png> <b-url-or-png> [settleMs]
node src/contrast-probe.mjs <url> [selector] [AA|AAA]
testpages/ holds fixtures you can point them at (a flickering page, a before/after pair, graded-contrast text).
Notes
- Zero
@deepseek-ai/dsh-*import: dsh 0.1.x-rc's loader does not resolve host internal imports for third-party plugins, so tools are registered by constructing the tool object directly withctx.tools.register. networkidleis not used before capture — a live app that polls may never go idle; a fixedsettleMswait is used instead.