Skip to content
dsh.fish
Bundle

dsh-mp-automator

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 插件:选择器寻址、构建新鲜度门、面向纯文本模型的几何断言、视觉路由附真实截图。

Source
VincentJiang06
License
MIT
Updated
Updated 7 days ago

Readme

# dsh-mp-automator

**微信小程序自动化测试 · [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) 插件**
**WeChat Mini Program automated testing for dsh agents**

[![npm](https://img.shields.io/badge/npm-dsh--mp--automator-cb3837)](https://www.npmjs.com/package/dsh-mp-automator)
[![license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/VincentJiang06/dsh-mp-automator/blob/main/LICENSE)
[![tests](https://img.shields.io/badge/tests-51%2F51-brightgreen)](https://github.com/VincentJiang06/dsh-mp-automator/blob/main/docs/evidence/green-run.txt)

让 dsh 智能体驱动微信开发者工具里**真实运行**的小程序:读页面、点元素、截图、看控制台。
你只需要在小程序项目目录里开一个 dsh 会话,然后用自然语言下测试任务:

> **你**:测试首页的"立刻开始"按钮能进入扫码页
> **agent**:*(mp_query 确认按钮可见 → mp_act 点击 → 验证路由已跳转 → mp_console 确认无报错)*
> ✅ 按钮可见、可点、路由跳转正确、无控制台错误

Eight `mp_*` tools let a dsh agent drive a real Mini Program in WeChat DevTools.
The correctness discipline is built **into the tools** — not into prompts the
model may ignore.

---

## 目录 · Contents

1. [工作原理 · How it works](#1-工作原理--how-it-works)
2. [快速开始 · Quick start](#2-快速开始--quick-start)
3. [八个工具 · The eight tools](#3-八个工具--the-eight-tools)
4. [为什么可信:三种静默失败与对应的门 · Why trust it](#4-为什么可信三种静默失败与对应的门--why-trust-it)
5. [截图:双路径与图片经济 · Screenshots](#5-截图双路径与图片经济--screenshots)
6. [配置 · Configuration](#6-配置--configuration)
7. [配套技能 · Companion skill](#7-配套技能--companion-skill)
8. [排障 · Troubleshooting](#8-排障--troubleshooting)
9. [设计笔记 · Design notes](#9-设计笔记--design-notes)

---

## 1. 工作原理 · How it works

```
  dsh agent(任意模型;视觉能力可选)
    │
    │  调用 mp_* 工具 —— 纪律层:新鲜度门、选择器寻址、字节预算、图片经济
    ▼
  dsh-mp-automator(本插件)
    │
    │  驱动 vince-mp CLI —— 全 JSON 契约,首次调用协商版本 >=0.2.0 <0.3.0
    ▼
  微信开发者工具 自动化端口
    ▼
  你的小程序(真实运行时、真实 WXML)
```

分层职责 · Layering:[`vince-mp-cli`](https://www.npmjs.com/package/vince-mp-cli)
拥有自动化事实(DevTools 连接、元素解析、路径策略);本插件拥有**面向智能体的纪律**
(什么时候拒绝执行、输出多少字节、图片何时该进上下文)。The CLI owns automation
truth; this plugin owns agent-facing discipline.

## 2. 快速开始 · Quick start

**前置 · Prerequisites**:macOS ·
[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)
(在 设置 → 安全设置 里开启**服务端口**)· Node ≥ 20 · dsh ≥ 0.1.0-rc.5

```bash
# ① 安装本插件驱动的自动化 CLI(拥有 DevTools 连接)
npm i -g vince-mp-cli

# ② 把插件装进你的 dsh profile
dsh plugin --profile web add dsh-mp-automator
```

```bash
# ③ 在小程序项目目录里(有 project.config.json 的那层)开 dsh 会话
cd your-miniprogram-project && dsh
```

④ 直接下测试任务。其余 mp_* 工具会自动起会话;模型不需要任何前置仪式。
Open the session **inside the Mini Program project** — tools resolve the
project from the session's working directory — then just describe the test.

## 3. 八个工具 · The eight tools

| 工具 | 作用 · What it does |
|---|---|
| `mp_session` | start / status / stop / restart / reconnect 持久 DevTools 会话(其余工具自动起会话,主要用 restart 自救)|
| `mp_doctor` | 项目体检:DevTools cli、`tsc --noEmit`、编译产物新鲜度 —— 结果喂给新鲜度门 |
| `mp_inspect` | page / stack / data(+path) / sysinfo / snapshot(元素事实表)|
| `mp_query` | 选择器 → 几何事实表:`fully-visible / partial / offscreen / read-failed` 标志 + 遮挡候选对,相对**当前滚动窗口**判定(披露 `scrollTop=`)|
| `mp_act` | **按选择器**执行 tap / input / longpress · 导航 nav / switchTab / reLaunch · 免摄像头 `scan` 注入 |
| `mp_screenshot` | PNG 落盘 `captures/` + 几何事实表;视觉路由额外附真图;`<imageStatus>` 永远写明发生了哪种(见 [§5](#5-截图双路径与图片经济--screenshots))|
| `mp_console` | 报错优先,然后是**最新**的日志(自动翻到缓冲区尾部)|
| `mp_eval` | 逃生舱:在页面 appservice VM 里执行 JS —— 受新鲜度门管,配置可一键关闭 |

所有结果自带字节上限且自包含——长测试会话经历上下文压缩后依然可读,不会烂成
"见上文"。Every result is byte-clamped and self-contained, so long sessions
survive context compaction.

## 4. 为什么可信:三种静默失败与对应的门 · Why trust it

用 LLM 测小程序会以三种**安静**的方式失败——每种都产出毫无意义的绿色结果。
本插件对每一种都有结构性回答,而不是提示词层面的叮嘱:

| 静默失败 · Silent failure | 结构性回答 · Structural answer |
|---|---|
| **uid 过期**:DevTools 自动化层在重连/导航/快照/第二客户端接入时**无声重编号**元素 uid,重放旧 uid 会点到错误元素且*不报错* | **选择器寻址** —— `mp_act` 在*同一次独占调用内*重新解析元素;uid 永不跨调用存活。Selector-addressed actions: no uid ever crosses a call boundary |
| **构建过期**:编译出的 `.js` 比 `.ts` 源码旧,所有断言跑在没人打算发布的代码上 | **新鲜度门(G1)** —— 每次执行前跑真实的快速体检(实测 0.10–0.18s,无缓存窗口),产物过期直接拒绝;纯 JS 项目无从判断时**如实警告**而不是假装通过 |
| **看不见的截图**:纯文本模型"截"了一张自己永远看不见的图,然后凭想象描述它 | **双路径** —— 每张截图都产出几何事实表(任何模型可用);视觉路由额外附真 PNG;`<imageStatus>` 一行永远写明到底发生了哪种,模型无法假装看过图 |

失败时的输出也是纪律的一部分:每个 CLI 错误码都映射到**下一步该做什么**
(见 [§8 排障](#8-排障--troubleshooting)),解析一律 fail-closed——只有严格的
`ok === true` 算成功。Failure output is part of the contract: every CLI error
code maps to a remedy, and parsing fails closed.

## 5. 截图:双路径与图片经济 · Screenshots

**双路径 · Dual path** — 每次 `mp_screenshot`:

- **任何模型**都拿到:PNG 落盘 + 几何事实表(元素、坐标、可见性标志)。
  纯文本路由(如 DeepSeek V4)额外得到一行明示:*"图在磁盘、不在你的上下文"*。
- **视觉路由**(provider 声明了 `input: [text, image]`,模板见
  [`docs/PROVIDER-TEMPLATE.yaml`](./docs/PROVIDER-TEMPLATE.yaml))额外把真实
  PNG 作为 image block 附进上下文——已用 kimi-k2.7-code 实测从像素读出按钮文字
  与页面文案([证据](https://github.com/VincentJiang06/dsh-mp-automator/blob/main/docs/evidence/live-matrix.md))。

**图片经济 · Image economy**(0.3.0)— 视觉路由上每张附加的图片会在**之后的每次
请求上持续计费**,所以附加是被预算管理的:

- `imageBudget`(默认 3):每个**会话**最多附加 3 张——预算按会话对象隔离,
  多个会话共享插件实例也互不泄漏
- **sha256 去重**:画面没变就不重复附加(免费,披露为"deliberate economy")
- **预算耗尽是诚实的**:超预算后照常给几何事实表 + 计费原因说明,绝不静默跳过
- 实测全链路:attach → dedupe → attach → attach → exhausted,API 请求里恰好
  3 个 image block

已实测的边界 · A proven boundary:`wx.showLoading` / toast 这类**原生浮层不进
DevTools 截图**(浮层前后 PNG 字节级相同)——不要用截图断言 toast 出现过,
配套技能会教模型这条。

## 6. 配置 · Configuration

```yaml
# 你的 profile 的 cordis.patch.yml 里
- id: mp-automator
  config:
    freshnessMode: block   # block(默认) | warn | off —— 新鲜度门行为
    enableEval: true       # mp_eval 逃生舱开关
    imageBudget: 3         # 每会话最多附加的截图数(视觉路由);0 = 完全禁用附图
    screenshotDir: captures  # 截图落盘目录(项目内相对路径)
    binPath: vince-mp      # CLI 不在 PATH 上时给绝对路径
```

| 键 | 默认 | 说明 |
|---|---|---|
| `freshnessMode` | `block` | `block` 产物过期拒绝执行;`warn` 只警告;`off` 完全关闭(不跑体检进程)|
| `enableEval` | `true` | 关掉后 `mp_eval` 拒绝一切调用 |
| `imageBudget` | `3` | 钳制为非负整数;`0` 显式禁用附图 |
| `screenshotDir` | `captures` | 始终被约束在项目目录内 |
| `binPath` | `vince-mp` | 版本窗口 `>=0.2.0 <0.3.0`,窗口外拒绝并给升级指引 |

## 7. 配套技能 · Companion skill

[`skill/mp-testing/SKILL.md`](./skill/mp-testing/SKILL.md) 是判断力层:
inspect→act→verify 三拍节奏、选择器纪律、断言配方(`fully-visible` 才算可见、
`partial` 不算)、截图经济纪律、诚实的 `mp_eval` 边界。装进 dsh 读取的任意
skill 根即可——没有它工具照常能用,但测试的*质量*来自打法。
Tools carry capability and gates; the skill carries judgment.

## 8. 排障 · Troubleshooting

工具的错误输出自带 remedy 行,下面是最常见的几条 · Most-seen failures and
their built-in remedies:

| 错误码 | 含义 → 该做什么 |
|---|---|
| `AUTOMATION_PORT_TIMEOUT` | 自动化端口没开 → 开发者工具 设置→安全设置 开启服务端口,然后 `mp_session restart` |
| `APP_NOT_RUNNING` | 小程序没在模拟器里跑 → 先看 DevTools 控制台有没有**编译错误**,不要盲目重试 |
| `STEP_TIMEOUT` | 单步超时 → `mp_session restart`;若**只有截图**反复超时,是 DevTools 渲染进程卡死(实测存在)→ 退出重启开发者工具本体 |
| `NOT_INSTALLED` | 缺 CLI → `npm i -g vince-mp-cli` |
| `NO_PROJECT_CWD` / `INVALID_PROJECT` | 会话不在小程序项目目录里 → 到有 `project.config.json` 的目录重开会话 |
| 门拒绝:`stale` | 编译产物比源码旧 → 重新编译(或等 DevTools 编译完)再测;**不要**为了绿而把门关掉 |

## 9. 设计笔记 · Design notes

本插件经对抗性迭代产出:五透镜攻击电池(外加跨厂商 DeepSeek 攻击手)击穿第一版
设计(9 个 P1、四个根因),重铸后的版本用结构性设计消灭根因;每个版本发布前由
独立审查 + fix-audit 双重把关。完整台账、红→绿测试证据与四路由真机测试矩阵见
[`docs/`](./docs/)(未打进 npm 包)。Built by adversarial iteration; the full
ledger and live-test matrix live in the repo.

四个结构性决策 · Four structural decisions:

1. **不镜像共享状态,改寻址模型** —— uid 表归 daemon 所有且会不可见地重编号,
   插件侧任何计数器都必输;所以让选择器成为唯一句柄。
2. **处处 fail closed** —— 只有严格 `ok === true` 算成功;缺失的体检文档导致
   拒绝,而不是假定通过。
3. **stderr 是契约的另一半** —— CLI 把抛出的错误打到 stderr,两条流都要解析。
4. **预算写进代码** —— 字节上限、行数上限、图片预算全部是代码里的钳制 +
   显式披露,不是文档里的承诺。

状态归属准则(0.3.0 审查沉淀):**项目属性按项目键控(新鲜度、类型检查),
上下文属性按会话键控(图片预算)**——键选错一个维度,正确的缓存就变成跨会话
的谎言。State keyed by what it is a property OF: the project, or the session.

## License

MIT © Vincent Jiang

Install

dsh plugin --profile web add github:VincentJiang06/dsh-mp-automator

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source