dsh-mp-automator
Verifieddsh-mp-automator · v0.3.0 · MIT
WeChat Mini Program automated testing for DeepSeek Harness (dsh): selector-addressed actions, build-freshness gates, geometry-first assertions that work on text-only models, and screenshot image blocks on vision routes. 微信小程序自动化测试 dsh 插件:选择器寻址、构建新鲜度门、面向纯文
Install
dsh plugin add dsh-mp-automator Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-mp-automator
WeChat Mini Program automated testing for DeepSeek Harness (dsh) 微信小程序自动化测试 · DeepSeek Harness 插件
Eight mp_* tools that let a dsh agent drive a real Mini Program in WeChat
DevTools — inspect pages, act on elements, capture screenshots, read the
console — with the correctness discipline built into the tools instead of
into prompts the model may ignore.
让 dsh 智能体驱动微信开发者工具里真实运行的小程序:读取页面、操作元素、截图、 看控制台。正确性纪律内建在工具里,而不是写在模型可能无视的提示词里。
Why this exists · 为什么做这个
Testing a Mini Program through an LLM agent fails in three quiet ways, and each one produces a green result that means nothing:
- Stale element handles. The DevTools automation layer renumbers element uids on reconnect, navigation, snapshot, and whenever a second client touches it — invisibly. An agent that replays a remembered uid taps the wrong element, and nothing errors.
- Stale builds. If the compiled
.jsis older than its.ts, every assertion runs against code nobody intends to ship. - Invisible screenshots. A text-only model "takes" a screenshot it can never see, then quietly describes what it imagines.
三种静默失败,每一种都产出毫无意义的绿色结果:uid 被运行时无声重编号(点错 元素不报错);编译产物比源码旧(断言的是没人要发布的代码);纯文本模型"截"了一张 自己永远看不见的图(然后凭想象描述它)。
This plugin's answer, respectively · 对应的三个答案:
| Failure · 失败 | Mechanism · 机制 |
|---|---|
| stale uid | Selector-addressed actions — mp_act re-resolves the element inside one exclusive tool call; no uid ever crosses a call boundary. 选择器寻址:查找与操作在同一次独占调用内背靠背完成,uid 永不跨调用存活 |
| stale build | Freshness gate — act-class tools refuse when .js is older than .ts, and say honestly when freshness is unknowable (plain-JS projects) instead of pretending. 新鲜度门:产物过期直接拒绝执行;无从判断时如实警告,绝不伪装 |
| invisible screenshot | Dual path — every screenshot yields a geometry fact table (works on ANY model); vision-declared routes additionally get the real PNG as an image block, and the result always says which happened (<imageStatus>). 双路径:几何事实表全模型可用;声明视觉的路由额外附真图,结果永远写明发生了哪种 |
Install · 安装
# 1. the automation CLI this plugin drives (owns the DevTools connection)
npm i -g vince-mp-cli
# 2. the plugin, into your dsh profile
dsh plugin --profile web add dsh-mp-automator
Requirements · 前置:macOS + WeChat DevTools (automation/CLI port enabled in 设置→安全设置) · Node ≥ 20 · dsh ≥ 0.1.0-rc.5.
Open a dsh session inside your Mini Program project (the directory with
project.config.json) — the tools resolve the project from the session's
working directory. 会话必须开在小程序项目目录内。
The tools · 工具
| tool | what it does · 作用 |
|---|---|
mp_session |
start / status / stop / restart / reconnect the persistent DevTools session(其余工具会自动起会话) |
mp_doctor |
project health: DevTools cli, tsc --noEmit, compiled-JS freshness — feeds the gate · 健康检查,喂给新鲜度门 |
mp_inspect |
page / stack / data(+path) / sysinfo / snapshot(元素事实表) |
mp_query |
selector → geometry fact table: fully-visible / partial / offscreen / read-failed flags + overlap candidates(0.2.0 起相对当前滚动窗口判定,事实表披露 scrollTop=;scroll-aware since 0.2.0) |
mp_act |
tap / input / longpress by selector · nav / switchTab / reLaunch · camera-less scan |
mp_screenshot |
PNG to captures/ + fact table; real image block on vision routes; <imageStatus> says which path fired |
mp_console |
errors first, then the most recent entries(自动翻到缓冲区尾部) |
mp_eval |
escape hatch: evaluate JS in the page context — freshness-gated, config kill-switch |
Every result is byte-clamped under the host's compaction pruner and is self-contained — long test sessions survive context compaction without the results rotting into "see above". 所有结果自带字节上限且自包含,长会话压缩后依然可读。
A test run looks like · 一次测试长这样
you › 测试首页的"立刻开始"按钮能进入扫码页
agent › mp_doctor → freshness: fresh — freshness verified: 12 .ts/.js pair(s) checked, typecheck passed
agent › mp_query .start-btn → matched=1 · button_3 | button | 24,180,342,96 | fully-visible | 立刻开始 简单扫码
agent › mp_act tap .start-btn → tap on .start-btn[0] (resolved button_3, 1 match(es)) | route now: pages/scan/index
agent › mp_console → console: total=2 errors=0
agent › ✅ 按钮可见、可点、路由跳转正确、无控制台错误
And when the build is stale · 构建过期时:
agent › mp_act tap .start-btn
✗ refusing to act on this runtime: 1 compiled file(s) are older than their
TypeScript source (e.g. utils/debounce.ts) — rebuild the project (or let
DevTools finish compiling) so the runtime matches the source
Vision routes · 视觉路由
Declare input: [text, image] on any pi-ai provider model and
mp_screenshot attaches the real PNG — verified live with
kimi-k2.7-code, which read button text and page colors straight from the
pixels (evidence). Text-only routes (e.g.
DeepSeek V4) get the same geometry table plus an explicit "the PNG is on
disk but NOT in context" note, so the model can never pretend it saw one.
给任意 pi-ai provider 的模型声明 input: [text, image],截图就会作为真实
image block 进入上下文(已用 kimi-k2.7-code 实测:从像素读出按钮文字与配色)。
纯文本路由拿到同样的几何表 + 一行明示"图在磁盘、不在上下文",模型无法假装看过图。
Provider template · 配置模板:docs/PROVIDER-TEMPLATE.yaml
Configuration · 配置
# in your profile's cordis.patch.yml
- id: mp-automator
config:
freshnessMode: block # block(默认) | warn | off
enableEval: true # mp_eval kill-switch
imageBudget: 3 # max ATTACHED screenshots per session (vision routes) — each
# attached image keeps billing on every later request; unchanged
# screens are never re-attached · 视觉路由的图片附加预算
screenshotDir: captures
binPath: vince-mp # absolute path if not on PATH
Design notes · 设计笔记
This plugin was built by adversarial iteration: a five-lens attack battery
(plus a cross-vendor DeepSeek attacker) destroyed the first design — 9 P1
findings, four root causes — and v3 eliminated the root causes structurally
rather than patching symptoms. The full ledger, the red→green test evidence,
and the live test matrix live in the repo's docs/ (kept out of the npm tarball to stay lean).
本插件经对抗性迭代产出:五透镜攻击电池(外加跨厂商 DeepSeek 攻击手)击穿了第一版
设计(9 个 P1、四个根因),v3 用结构性设计消灭根因而非打补丁。完整台账、红绿测试
证据与真机测试矩阵见仓库 docs/(未打进 npm 包以保持精简)。
The four structural decisions · 四个结构性决策:
- Don't mirror shared state — change the addressing model. The uid map is daemon-owned and renumbers invisibly; no plugin-side counter can win. 不镜像共享状态,改寻址模型。
- Fail closed everywhere. Only strict
ok === trueis success; a missing doctor document refuses instead of assuming. 一切解析默认失败。 - stderr is half the contract. The CLI prints thrown errors to stderr; both streams are parsed. stderr 是契约的另一半。
- Budgets live in code. Byte-clamps with disclosed truncation, not prose promises. 预算写进代码,截断必声明。
Companion skill · 配套技能
skill/mp-testing/SKILL.md carries the
judgment layer (inspect→act→verify rhythm, selector discipline, the
assertion recipe). Load it into any skill root dsh reads — the tools work
without it, but test quality comes from doctrine.
工具携带能力与门,技能携带打法(先看后动再验证、选择器纪律、断言配方)。
Relationship to vince-mp-cli · 与 CLI 的关系
This plugin is a thin shell: vince-mp-cli
owns the automation truth (DevTools connection, element resolution, path
policy); the plugin owns agent-facing discipline. Version negotiation is
explicit — the plugin verifies vince-mp-cli >=0.2.0 <0.3.0 at first use
and refuses with an upgrade hint outside that window.
薄壳架构:CLI 拥有自动化事实,插件拥有面向智能体的纪律;首次调用时协商版本, 窗口外拒绝并给出升级指引。
License
MIT © Vincent Jiang