Chuyển đến nội dung chính

dsh-mp-automator

Đã xác minh

dsh-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 插件:选择器寻址、构建新鲜度门、面向纯文

Cài đặt

dsh plugin add dsh-mp-automator

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Thẻ

Tác giả

Readme

dsh-mp-automator

WeChat Mini Program automated testing for DeepSeek Harness (dsh) 微信小程序自动化测试 · DeepSeek Harness 插件

npm license tests

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:

  1. 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.
  2. Stale builds. If the compiled .js is older than its .ts, every assertion runs against code nobody intends to ship.
  3. 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 actionsmp_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 === true is 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