小
小程序 AI Skills 校验修复
作者:鹿Sir开发工具v1
对微信小程序 AI Skills 产物执行静态校验、原子接口执行、原子组件渲染与交付文档输出的闭环校验,并按错误类型分类就地修复 skill 源文件,依托微信开发者工具完成真机验证。当用户需要校验小程序 skills 目录、跑通原子接口、验证组件渲染、修复校验报错或输出交付文档时触发。
下载量
404
点赞
98
价格
免费
技能文档
---
name: wxa-skills-validate
title: 小程序 AI Skills 校验修复
category: 开发工具
description: 对微信小程序 AI Skills 产物执行静态校验、原子接口执行、原子组件渲染与交付文档输出的闭环校验,并按错误类型分类就地修复 skill 源文件,依托微信开发者工具完成真机验证。当用户需要校验小程序 skills 目录、跑通原子接口、验证组件渲染、修复校验报错或输出交付文档时触发。
---
# 小程序 AI Skills 校验修复
对小程序 AI SKILLs 产物执行"**静态校验 → 原子接口执行 → 原子组件渲染 → 交付文档**"的闭环校验,并在每一步失败时按错误类型分类就地修复 skill 源文件。
## 依赖
- Node.js ≥ 18(`scripts/*.mjs` 用到 `node:crypto` / 原生 `fetch`)
- 微信开发者工具(Nightly Electron Build 最新版)已安装,CLI 可执行:`<DEVTOOLS_APP_PATH>/Contents/MacOS/cli -h`(macOS 默认 `<DEVTOOLS_APP_PATH>=/Applications/wechatwebdevtools.app`)
- **开发者工具的服务端口必须开启**:手动打开工具 → 设置 → 安全设置 → 打开「服务端口」。未开启时 CLI 连不上,execute / render 全部失败
- 调试基础库 ≥ 3.16.2;项目 AppID 已在「微信公众平台 - 基础功能 - AI 能力」申请通过「开发模式」
- 项目 `project.config.json` 含 `appid`;`app.json` 含 `agent.skills`;每个 skill 目录含 `mcp.json` + `SKILL.md`
> 运行过程中开发者工具可能弹授权窗,需手动授权;未授权会导致原子接口执行失败。
## 触发条件
出现下列任一情况时启动本技能:
- 显式要求对 skills 目录做 "校验 / 跑通 / 渲染 / 出交付文档" 中任一项
- 已有 skills 产物(无论来源)需要进入验证阶段
- 跑出 skills 的校验报错需要修复
## 必需信息
| 项 | 说明 | 缺失时动作 |
|---|---|---|
| `<project-path>` | 小程序项目根目录(含 `project.config.json` + `app.json`;`app.json` 的 `agent.skills[].path` 指向 skill 分包) | 向用户询问 |
| `<DEVTOOLS_APP_PATH>` | 微信开发者工具应用路径 | macOS 默认 `/Applications/wechatwebdevtools.app`,用户可覆盖 |
| `<AUTO_PORT>` | auto WebSocket 端口 | 默认 `9420` |
> 注:`<skills-path>` 已**不再作为入参**,脚本自动从 `app.json` 发现分包。
## 参考资料(按需加载)
进入"步骤 4:真机闭环"时**必须**先读 `references/CLI_AGENT_REFERENCE.md`,内含脚本用法、产物结构、读产物后的下一步动作、5 项核对对照表、失败回溯流程。
| 文件 | 用途 | 加载时机 |
|------|------|---------|
| `references/CLI_AGENT_REFERENCE.md` | CLI `agent` 命令参考 | 步骤 4 执行前 |
| `references/VALIDATE_RULES.md` | validate.mjs 内置的 V001~V021 规则详解 | 出现校验报错需定位 id 时 |
| `references/DELIVERY_TEMPLATE.md` | `DELIVERY.md` 交付模板 | 最终交付时 |
---
## 验收目标(不可降级)
- `<project-path>` 下 `app.json` 发现的每个 skill 分包,其 `mcp.json` 声明的所有原子接口必须跑通 execute(`status === "ok"` 且 `invokeResult.isError !== true`)。**例外:敏感接口不真实执行**——命中敏感关键词的接口由 V019 落盘 `cli-agent-run/destructive-manifest.json`,execute.mjs 读该 manifest 拦截(`--confirm-destructive` 放行)——只做静态校验,验收时视为「已跳过执行」而非未通过,需在报告标注 `skipped_destructive`。
- 所有带 `_meta.ui.componentPath` 的原子接口,必须跑通 render 且通过 5 项核对(见 `references/CLI_AGENT_REFERENCE.md` 第 2.3 节)。
- 单接口连续修复 3 轮仍不通过才允许挂起。不得跳过任何一项(敏感接口的执行跳过除外)。
- 静态/编译通过 ≠ 验收通过:须真机 execute + render 5 项核对;execute 未跑成时不得判通过、不产出 `DELIVERY.md`(见「不可修复类」与「终止条件 4」)。
---
## 技能工作流
按以下阶段逐项完成(可复制清单勾选):
```
阶段 1 — 静态校验 + 编译校验
- [ ] 运行 `node validate.mjs <project-path>`(单参数,脚本自动发现 skill 分包并决定是否跑 preview)
- [ ] summary.errors === 0(含 V001~V021),否则按 T1~T9 分类修复后重跑
- [ ] summary.buildStatus === "pass"(静态 0 error 时 preview 会自动运行;
若为 "skipped" 说明静态未过,先按上一项修复)
- [ ] 阅读 Build 行:若 stage=compile + FAIL,说明有语法/编译错误,必须修复
阶段 2 — 准备
- [ ] 确认 CLI 可执行:<DEVTOOLS_APP_PATH>/Contents/MacOS/cli -h
- [ ] (可选)显式启动 cli auto
阶段 3 — 构建执行计划
- [ ] 解析每个 <skill>/mcp.json 的 apis[],按书写顺序 + 参数依赖做拓扑排序
- [ ] 建立"已知数据池"(空)
阶段 4 — execute 与 render(可独立执行)
对每个 {name}:
- [ ] execute 成功(status=ok 且 !isError)
- [ ] 若 mcp.json 有 _meta.ui.componentPath,render 可在任何时间点执行(不要求紧跟 execute)
- [ ] render 通过 --from-execute 复用最新的 execute 产物(args 取自 invokeResult.structuredContent);
structuredContent 缺失时必须先重跑 execute
- [ ] 5 项核对全部通过(主要依据:`consoleMessages.snapshotCard` 中的生命周期日志 + `[ai-mode] ... overflow monitor=on` 基线日志 + 不出现 `overflowed=true`;仅在具备图像读取能力时再辅助读截图)
阶段 5 — 交付
- [ ] 写 ./cli-agent-run/report.md
- [ ] 若全部通过,按 references/DELIVERY_TEMPLATE.md 写 ./DELIVERY.md 并回贴内容
```
---
## 工作目录
在 `<project-path>` 同级建 `./cli-agent-run/` 统一存放产物:
```
cli-agent-run/
├── validate-report.json # 阶段 1 产物
├── execute-result.<apiName>.json # 阶段 4 execute 产物(含 invokeResult.structuredContent 供 render 继承)
├── render-result.<apiName>.json # 阶段 4 render 产物(snapshot 摘要 + consoleMessages + elementTree)
├── render-result.<apiName>.snapshot.png # 阶段 4 render 截图
├── execute-trace.json # 每次尝试的回溯日志
└── report.md # 阶段 5 执行报告
项目根目录/
└── DELIVERY.md # 全部通过时的最终交付文档
```
同一接口重跑时必须复用 `--output`(文件会被覆盖);不同接口必须用不同文件名。
---
### 步骤1:静态校验 + 编译校验(合并为一次运行)
**运行**:
```bash
node <skill-dir>/scripts/validate.mjs <miniprogram-project-path>
```
**入参只需要一个——小程序项目根目录**(含 `project.config.json` + `app.json`)。脚本自动:
1. 读 `app.json` 的 `agent.skills[].path` 发现 skill 分包(没配置时回退到顶层 `metaServicePkg/` 或 `skills/`)
2. 静态规则只在 **skill 分包目录内** 执行,不触及主包代码
3. 把校验产物目录 `cli-agent-run/` 写入 `project.config.json` 的 `packOptions.ignore`(打包忽略)和 `watchOptions.ignore`(监听忽略),避免开发者工具持续监听产物变更触发循环编译(已存在不会重复追加;产物落盘前完成同步,结果挂在报告 `ignoreSync` 字段)
4. 静态校验通过(`errors === 0`)后自动调用 `cli preview` 做编译校验;有 error 则跳过 preview
5. 报告落盘到 `<project>/cli-agent-run/validate-report.json`(可用 `--output` 覆盖)
可选参数:`--rules <自定义规则 json>` / `--cli-path <CLI 路径>` / `--build-timeout <ms>` / `--output <path>`。
**退出码**:`0` 通过;`1` 存在 error 或 build 失败;`2` 运行异常。
**通过判据**:
- `summary.errors === 0`(warning 允许带着进入阶段 2)
- `summary.buildStatus === "pass"`(静态 0 error 后会自动触发 build;`"skipped"` 意味着静态未过,先按修复决策表修复)
- Build 行 `stage=compile + FAIL` 说明有语法/编译错,必须修复
**Build 编译报错时:优先检查集成配置,再动源码**。对照 wxa-skills-generate `SKILL.md` 的"阶段 6 — 配置集成"与 `references/CODE_TEMPLATES.md` 的"六、app.json + project.config.json 配置"核对 `app.json`(`agent.skills` / `subPackages`)与 `project.config.json`(`appid` / `packOptions.include`)。集成无误后才按日志改源码,**禁止用注释/删除源码的方式绕过集成问题**。
**CLI 未找到时的处理**:若输出 `Build: SKIPPED - 跳过:未找到微信开发者工具 CLI`,说明脚本未能自动定位到 `cli`。自动探测顺序为:`--cli-path` > 环境变量 `WECHAT_DEVTOOLS_CLI` / `WXA_CLI` > macOS `/Applications/wechatwebdevtools.app/Contents/MacOS/cli` > 同路径的用户目录变体 > Windows `C:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat`。此时应主动向用户询问微信开发者工具的安装路径,然后:
- 重跑:`node validate.mjs <project-path> --cli-path <用户提供的绝对 cli 路径>`
- 或建议用户设置环境变量:`export WECHAT_DEVTOOLS_CLI=<绝对路径>` 后重跑
CLI 缺失不影响静态规则的输出,只会让 build 阶段被 skip。
**执行顺序**(脚本内部闭环):
1. 同步 `project.config.json` 的 `packOptions.ignore` + `watchOptions.ignore`(追加 `cli-agent-run/`)
2. 发现 skill 分包 → 只在分包内跑 V001~V021
3. 有 error → build=`skipped`(节省 preview 成本);0 error → 调 `cli preview`
4. 到达 `upload` 阶段视为编译通过;即便上传失败(服务端校验、网络等),也不标记 build 失败
**失败时的修复决策表**(读完 `validate-report.json` 中 `results[].id` / `message` / `fix` 后匹配):
| 错误类型 | 识别特征 | 修复范围 | 动作 |
|---------|---------|---------|------|
| **T1 命名拼写** | 字段大小写/拼写错 | 单文件单行 | 直接改 |
| **T2 Schema 不一致** | `structuredContent` 与 `outputSchema.properties` 字段不匹配(V009) | `apis/{name}.js` + `mcp.json` | 对齐字段 |
| **T3 组件绑定不一致** | WXML `{{}}` 与 `setData` 字段对不上(V011) | `components/{x}/index.{js,wxml}` | 对齐绑定 |
| **T4 组件取值路径错** | `result.structuredContent.xxx` 与接口返回字段不符(V010) | `components/{x}/index.js` | 修访问路径 |
| **T5 合规性违规** | 非白名单 WXML 标签 / 事件 / 图片格式 / CSS 属性(V003/V005/V006) | 单文件改写 | 用白名单实现替换:`collapsible-view` 是允许的;`transition` / `animation` / `overflow` / `-webkit-line-clamp` 一律删除(改 `-wx-line-clamp`);非 tap 事件删除 |
| **T6 注册缺失** | `mcp.json` 的 `name` 在 `index.js` 未 `registerAPI`,或反之(V007/V008) | `index.js` | 补/删注册 |
| **T7 依赖链路问题** | storage key 写入方/读取方对不上 | 跨接口 + `utils/util.js` | 跨文件调整 |
| **T8 原子接口粒度错** | 接口职责重叠 | `mcp.json` + `index.js` + `apis/*.js` | 拆分/合并 `apis[]` |
| **T-mcp-size** | `mcp.json` 去除 outputSchema 后超过 24000 字符(V013;后台也会拒绝) | `mcp.json` 的 description/title/inputSchema;或重划 skill 分包 | 压缩描述文字;接口多到难以精简时按职责拆分为多个 skill 分包,**不要把示例/枚举硬塞进 outputSchema** |
| **T-auth 鉴权缺失** | `401` / `unauthorized` / `token 无效` 等(静态阶段通常由 V007/V008 连带触发) | `utils/util.js` / `apis/{name}.js` | **读主包**还原登录流程 |
| **T-wx-jsapi 非白名单** | 运行时 `wx.<xxx> is not a function` / `wx.<ns>` 为 undefined | `apis/{name}.js` / `components/{x}/index.js` | 对照 wxa-skills-generate `SKILL.md` D.1/D.2 白名单(**完整清单**见 `wxa-skills-generate/references/JSAPI_WHITELIST.md`),按 D.7 替换或改网络请求;无替代标 T9(详见阶段 4 C 类) |
| **T-build 编译失败** | Build 行显示 FAIL 且 stage=compile | 项目集成 / `.js` / `.wxml` / `.wxss` | 先对照 wxa-skills-generate `SKILL.md` 阶段 6 "配置集成" 核对 `app.json` / `project.config.json`,集成无误后再按日志修源码 |
| **T-skill-description** | `app.json` 的 `agent.skills[].description` 缺失或为空(V016) | `app.json` | 在该条目中补充非空的 `description` 字段 |
| **T-handoff** | 接力页 `_meta.ui.pagePath` 格式错/页面不存在/带 query,或声明了 pagePath 却未返回 `handoff`(V017) | `mcp.json` + `apis/{name}.js` | pagePath 以 `/` 开头、不含 query、页面真实存在;返回值顶层补 `handoff: { query, payload? }`(详见 wxa-skills-generate `SKILL.md` D.6) |
| **T-handoff-query** | `handoff.query` 的参数名与接力页 `onLoad` 读取的参数名不匹配(V018) | `apis/{name}.js` | 读接力页 `<pagePath>.js` 的 `onLoad(param)` 确认其读取的 `param.xxx` 名称,将 `handoff.query` 的参数名改为页面实际读取的名称 |
| **T-destructive** | 接口命中敏感关键词,V019 待模型判断(V019,`destructive:null`) | `cli-agent-run/destructive-manifest.json` | 编辑 manifest 填 `destructive=true`+`destructiveReason`(真敏感)或 `false`+`destructiveReason`(误判如只读查询) |
| **T-relatedPage** | 组件未在 `components[]` 声明,或 `relatedPage` 缺失 / 缺前导 `/` / 页面不存在(V015) | `mcp.json` + `components/{x}/index.js` | 在 `components[]` 补 `{ path, relatedPage }`(`path` 与接口 `_meta.ui.componentPath` 严格相等,`relatedPage` 以 `/` 开头且页面真实存在,无对应业务页时填首页);运行时在收到 `Result` 后调 `setRelatedPage({ query })` |
| **T-limits** | `SKILL.md` / `AGENTS.md` / `page-meta.json` 超字节上限,或 SKILL 数超 30(V020) | 对应文件 / `app.json` | 精简内容(`SKILL.md` 只留 5 节结构,接口契约回 `mcp.json`);SKILL 过多时合并职责相近的 |
| **T-dynamic** | 静态原子组件或其相对 JavaScript 依赖里用了 `wx.login` / `wx.checkSession` / `wx.request` / `setTimeout` / `setInterval`,或任意组件代码路径用了云开发(V021) | `<componentPath>.js`、其相对 JavaScript 依赖或 `mcp.json` | 静态组件确有实时需求才在 `components[]` 该条目加 `permissions["scope.dynamic"]`;云开发一律移到原子接口并经 `NotificationType.Result` 下发数据 |
| **T9 能力无法实现** | 所有候选都违反硬约束 | — | ⛔ 终止,告知用户 |
V001~V021 规则详情见 `references/VALIDATE_RULES.md`。
**判别口诀**:文件内能改完 → T1~T6;需改 storage 清单或接口划分 → T7/T8;连修复方案都违规 → T9。
**迭代规则**:
| 情况 | 动作 |
|------|------|
| `summary.errors === 0` | ✅ 进入阶段 2 |
| errors 数较上一轮减少 | 继续修复,重跑 |
| 连续 3 轮相同 finding id | 升级为 T7/T8 跨文件调整 |
| 累计 5 轮仍未通过 | ⛔ 终止,请求人工介入 |
---
### 步骤2:准备 CLI agent 命令
**确认 CLI 可执行**:
```bash
<DEVTOOLS_APP_PATH>/Contents/MacOS/cli -h
```
失败则告知用户 "确认微信开发者工具已安装" 后停止,不要强行绕过。
**(推荐)先 open 预热再 auto**(约 10s,大项目可延长),减少 websocket 超时:
```bash
<DEVTOOLS_APP_PATH>/Contents/MacOS/cli open --project <PROJECT_PATH>
<DEVTOOLS_APP_PATH>/Contents/MacOS/cli auto \
--project <PROJECT_PATH> --auto-port <AUTO_PORT> --trust-project
```
跳过此步时脚本会自动拉起 auto;遇超时或 `agent compile mode is disabled` 时按「不可修复类 / 工具不稳定」处理。
---
### 步骤3:构建执行计划
读取 `<project-path>` 下 `app.json` 发现的每个 skill 分包的 `mcp.json`(`validate-report.json` 中的 `skillDirs` 字段给出了具体分包路径):
1. **敏感接口初筛+模型判断(V019,execute 前必做)**:阶段 1 静态校验的 V019 脚本初筛所有 mcp.json,把 name/description 命中敏感关键词的接口写入 `cli-agent-run/destructive-manifest.json`(`destructive:null` 待判断),报 error 阻断 build。模型逐个判断后编辑 manifest 填 `destructive:true`(真敏感,execute 跳过)或 `false`(误判,execute 放行)+ `destructiveReason`,重跑 validate 至 V019 pass。execute.mjs 读 manifest:`true` 拦截 / `false` 放行 / `null` 拦截(待判断)/ 不在 manifest 放行。生成侧阶段 2 已规定敏感接口默认不收集;V019 是兜底,catch 漏网的敏感接口名。
2. 汇总 `apis[]` 的 `name` / `description` / `inputSchema` / `outputSchema` / `_meta.ui.componentPath`。
3. **按入参依赖排序**(拓扑序):
- 无参接口(`inputSchema.properties` 为空或无 `required`)→ **最先执行**
- 有参接口 → 排在其参数来源接口之后
- `description` 或 `inputSchema` 含 "需要先调用 X" 类表述时,将 X 前置
4. 维护"已知数据池":每个接口成功后把 `structuredContent` 存入池中,供下游参数引用。
5. **有参接口的参数填充优先级**:先查已知数据池(上游接口 `structuredContent` 的同义字段),池中没有才考虑用户指定或默认值——**禁止在有数据池可用时直接用默认值测试有参接口**。
---
### 步骤4:execute 与 render
> **术语澄清**:execute 是**校验阶段名**(本阶段),用 **CLI agent tool** 调用 skills 分包的注册接口;**不要与 probe 混淆**——probe 是 generate 阶段 3.7 用 **automator** 在源项目上抓请求响应。两者工具不同(CLI agent vs automator)、对象不同(skills 分包 vs 源项目)、阶段不同(校验 vs 生成)。
`execute` 和 `render` 是**两个独立可重入**的命令:
- `execute` 调用原子接口,产出业务数据(`invokeResult.structuredContent`)。
- `render` 通过 `--from-execute` 把 execute 的 `invokeResult.structuredContent` 作为渲染数据源喂给组件;
也可以 `--name` + `--args` 独立指定。CLI 内部每次 render 会自动生成一次性 toolCallId / sessionId,
不依赖 execute 的运行时上下文。
**执行灵活度**:
- 可以一次 execute 所有原子接口、再统一批量 render
- 也可以"单接口 execute → render"交替进行
- render 的数据来源优先级:`--args` 显式指定 > `--from-execute` 读到的 `invokeResult.structuredContent`
**硬约束**(仅保留真正必要的):
- **敏感接口默认不执行**——会产生不可逆副作用的接口**默认拒绝执行**。判定来源:优先读 `cli-agent-run/destructive-manifest.json`(V019 初筛+模型判断),`destructive=true` 拦截 / `false` 放行 / `null` 拦截(待判断,安全第一)/ 接口不在 manifest 放行;manifest 不存在时回退关键词判定。`execute.mjs` 未带 `--confirm-destructive` 时对判定的敏感接口直接拒绝(退出码 3、不落盘)。全量 execute / loop 排查中**必须跳过**这些接口(只做阶段 1 静态校验),报告标 `skipped_destructive`。**严禁**批量放行。仅当用户明确要求执行某个具体敏感接口时,才带 `--confirm-destructive` 单独执行,且执行前应向用户说明后果。
- **执行顺序:先无参后有参**——无参接口先批量 execute 成功,其 `structuredContent` 入数据池后,有参接口再从池中取参数值 execute。禁止在有数据池可用时直接用默认值测试有参接口
- 按 `apis[]` 顺序依赖关系准备好入参(下游接口的 args 若依赖上游 `structuredContent`,仍需先 execute 上游)
- 每个带 `componentPath` 的接口最终都要 render 通过;完整通过的判据仍然是"execute 成功 + render 5 项核对通过"
- 同一条 CLI 调用内,`render.mjs` 不能并发执行(CLI 后台 auto 是串行的)
- `--from-execute` 的 execute 产物必须含 `invokeResult.structuredContent`;若缺失,`render.mjs` 会直接报错,需先重新 execute 成功后再 render
### 4.1 execute
**运行**:
```bash
node <skill-dir>/scripts/execute.mjs \
--project <PROJECT_PATH> \
--name <name> \
[--args '{"query":"..."}'] \
[--auto-port <AUTO_PORT>] \
[--skill <skill-name-or-path>] \
[--timeout <ms>] \
--output ./cli-agent-run/execute-result.<name>.json
```
`execute.mjs` **只接受** 上述参数;toolCallId / sessionId / auto 相关票据由 CLI 内部自动处理,脚本不再暴露。
**入参来源优先级**:
1. 用户指定
2. **已知数据池**(上游接口 `structuredContent` 的同义字段)——有参接口必须先尝试从已成功执行的无参/上游接口的 `structuredContent` 中提取参数值,而非直接用默认值。例:`getOrderDetail` 需要 `orderId` → 先跑 `listOrders`(无参),从其 `structuredContent.orders[0].id` 取 `orderId`
3. `inputSchema` 允许为空 → 省略 `--args`
4. 类型默认值(string `""`、number `0`、array `[]`、object `{}`),日志标注"使用默认值"——**仅当数据池无对应字段且用户未指定时才用**
**成功判据**:`status === "ok"` 且 `invokeResult.isError !== true` 且 `invokeResult.structuredContent` 为非空对象
(后者是 render `--from-execute` 的前置条件)。
**空结果排查(success 但 structuredContent 业务数据为空)**:`isError !== true` 但返回的 `structuredContent` 是空列表 / 空对象 / `total: 0` / 只有 `error` 字段时,**不能直接判通过**——这通常是请求参数错误、鉴权未生效、URL 拼错或响应拆包路径错的症状,而非业务上真的无数据。按以下顺序排查:
1. **读 consoleMessages 的 `[ai-mode]` 日志**:确认请求实际发出的 URL / 参数 / header 是否正确(入口日志 → 请求前日志 → 请求后日志)
2. **读主包源码定位真实请求**:找到该接口在主包中对应的页面/请求封装,确认真实 URL / method / 参数名 / 鉴权头 / 响应拆包路径
3. **对比主包真实请求与 `apis/<name>.js` 实际发出的请求**:URL / method / 参数名 / 鉴权头是否一致?不一致 → 回 `apis/<name>.js` 或 `utils/request.js` 修正
4. **鉴权排查**:主包请求封装需要的登录态/token,`apis/<name>.js` 入口是否补齐 `await ensureLogin()` 等 → 鉴权缺失会导致后端返回空而非报错
5. 排查后修正 → 重跑 execute;仍空且确认请求与主包真实请求完全一致 → 可能是后端环境差异(测试账号无数据),在 trace 记录"已排查请求正确,疑似环境无数据",允许带声明通过
**execute 失败**:先检查产物 `_meta.diagnosis` 是否为不可修复类(若是则立即停止),否则按下方"阶段 4 失败分类"的 A/B/C/D 类处理。
### 4.2 render(仅当 mcp.json 中该 api 有 `_meta.ui.componentPath` 时执行)
只要给对的 `name` + `args`(渲染数据源)就能渲染。CLI 的 render **不会重新执行原子接口**,而是把 `--args`
作为 `structuredContent` 直接喂给组件渲染;`--from-execute` 只是一个语法糖,用来把 execute 产物里的
`invokeResult.structuredContent` 直接喂给 render。
**推荐运行方式**(从 execute 产物继承 `name` / `args`,args 来源为 `invokeResult.structuredContent`):
```bash
node <skill-dir>/scripts/render.mjs \
--project <PROJECT_PATH> \
--from-execute ./cli-agent-run/execute-result.<name>.json \
[--timeout 90000] \
--output ./cli-agent-run/render-result.<name>.json
```
> 若 execute 产物缺 `invokeResult.structuredContent`,脚本会直接 exit 2 报错——
> 此时必须先重跑 execute 并确认 `status=ok` + `invokeResult.isError!==true` + `structuredContent` 为非空对象。
**独立指定上下文**(没有 execute 产物,或需要手动指定 args):
```bash
node <skill-dir>/scripts/render.mjs \
--project <PROJECT_PATH> \
--name <tool-name> \
--args '{"<字段>":"..."}' \
[--timeout 90000] \
--output ./cli-agent-run/render-result.<name>.json
```
`render.mjs` 自动从 `--from-execute` 继承 `name` / `args`;任一字段被 `--name` / `--args`
等显式参数提供时以显式值为准。CLI 下发的参数仅限 `--project / --name / --args / --output / --trust-project`
(及必要时的 `--timeout`),其它上下文由 CLI 内部自动生成,无需也无法从脚本显式传入。
> render cold start 通常比 execute 慢(需要创建 container + 渲染组件),首次调用或 CI 环境建议 `--timeout 90000`。
> 详细参数、产物结构、读产物后下一步动作见 `references/CLI_AGENT_REFERENCE.md` 第 2 节。
**必须读取的产物**(仅靠 `render.mjs` 退出码 `0` 不足以判通过):
- **console 日志(主要依据)**:`render-result.<name>.json` 的 `consoleMessages.snapshotCard`。必看:
- `[ai-mode] ... created` → `[ai-mode] ... 收到接口返回` → `[ai-mode] ... setData` 三条生命周期日志(缺任何一条 → 组件初始化或 Result 监听有问题)
- `[ai-mode] <component> overflow monitor=on`(**基线日志,必存在**):组件已绑定 `NotificationType.Overflow` 监听。缺失 → 视为未接入监听,回 wxa-skill-generate 的组件 JS 骨架补齐
- `[ai-mode] <component> overflow overflowed=true data=<JSON>`(或 `data.overflowHeight > 0`):有裁剪,核对 ③ 不通过。只要出现一次就判失败;只有 `monitor=on`、没有 `overflowed=true` 记录则视为未裁剪通过
- 任何 `ERROR` 级日志基本意味着业务组件初始化失败,截图会是空白
- **组件树 `elementTree`**(辅助核对,原样透传):`render-result.<name>.json` 的 `elementTree` 完全由 CLI render
返回,是一段缩进格式的**字符串**(非 JSON 对象),序列化了卡片的 shadow tree,形如
`<view:view class="addr-row">...`、`<text:default-component class="temp">... 28°`、
`<(virtual):wx:if>` 等节点。`render.mjs` / `lib.mjs` 不做任何加工或占位回填——CLI 没下发就没有该字段。
它**不参与 pass/fail 判定**,仅作为辅助信号:用来核对字段文案是否命中绑定、列表节点数量、
`wx:if` 空状态是否生效等(对字符串做 `grep` 即可)
- **截图(辅助)**:`render-result.<name>.snapshot.png`。**仅在当前运行环境具备图像读取能力**时,以图像方式 `read_file` 读入,辅助核对样式还原度(核对 ④)。若当前环境不具备图像读取能力,**跳过**截图读取,不视为失败;核对 ③(裁剪)完全以 `overflow` 日志为准,不回退到基于截图的视觉判断
**5 项核对**见 `references/CLI_AGENT_REFERENCE.md` 第 2.3 节。任一不通过 → 留在本接口继续修复。
### 4.3 闭环自检(整体判通过前的硬门闩)
每个带 `componentPath` 的接口都满足下列全部才允许标为通过:
- [ ] 存在 `execute-result.<name>.json`,其 `status === "ok"` 且 `invokeResult.isError !== true`
- [ ] 存在 `render-result.<name>.json`
- [ ] 5 项核对全部通过(含 `consoleMessages.snapshotCard` 中存在 `[ai-mode] ... overflow monitor=on` 基线日志、且不出现 `overflowed=true`;截图仅在具备图像读取能力时作为辅助信号)
---
## 步骤4失败分类与修复流程
按错误类型分类的完整修复手册见 [references/FAILURE_PLAYBOOK.md](references/FAILURE_PLAYBOOK.md)。
## 回溯记录
每次 execute / render 追加写入 `./cli-agent-run/execute-trace.json`:
```json
{
"skill": "<skill-dir>",
"api": "<name>",
"attempt": 1,
"argumentsUsed": { },
"argumentsSource": "user | upstream:<apiName> | default | empty",
"executeStatus": "ok | error",
"executeError": null,
"renderChecks": { "rendered": true, "fieldsComplete": true, "overflow": false, "style": true, "ellipsis": true },
"renderFailReason": null,
"recovery": null
}
```
---
## 终止条件
满足任一即终止:
1. 阶段 1 通过 + 每个声明的 `api` execute 成功 + 有 `componentPath` 的接口 5 项核对全部通过
2. 阶段 1 连续 5 轮未通过 → 停止,输出失败报告
3. 阶段 4 累计 5 轮仍有接口未通过 → 停止,输出失败报告
4. 不可修复类(`_meta.diagnosis` 非 null)或工具不稳定经预热/加 timeout/重启仍失败 → 停止,转述 `hint`,不产出 `DELIVERY.md`
5. T9 类问题 → 立即终止,告知用户
---
### 步骤5:交付产物
### 1. 执行报告 `./cli-agent-run/report.md`(每次终止都输出)
```markdown
# CLI `agent` 命令校验报告
- 执行时间:<ISO>
- project-path:<abs-path>
- skill 分包:<metaServicePkg, ...>(validate-report.json 中 skillDirs 字段)
- devtools:<DEVTOOLS_APP_PATH>
## 接口结果
| skill | api | componentPath | execute | render 5 项 | 产物 |
|-------|-----|---------------|---------|------------|------|
| business | searchItems | components/item-list/index | ✔ | ✔✔✔✔✔ | execute-result.searchItems.json / render-result.searchItems.snapshot.png |
## 未通过接口
- <apiName>:<原因简述>,详见 <产物路径>
## 修复摘要
- `skills/<skill>/apis/<name>.js`:<一行摘要>
```
### 2. 交付文档 `./DELIVERY.md`(仅终止条件 1 成立时产出)
终止条件 1 成立时必须产出:
- 写入路径:`./DELIVERY.md`(项目根;用户指定其它路径时以用户为准,但必须是 `.md`)
- 模板:严格套用 `references/DELIVERY_TEMPLATE.md`,所有 `{占位符}` 必须替换为实际值
- `execute-trace.json` 存在时在"已知限制"节引用
- 写入后**必须在对话中同时贴出完整 MD 内容**,不能只说"文件已生成"
- 无法写入(权限)→ 将 MD 内容直接输出在对话中作为替代
**仅输出 `report.md` 不算任务完成;`DELIVERY.md` 才是最终交付物。**
### 3. 未通过时的修复建议(追加到 report.md 末尾)
- **阶段 4 不可修复类 / 工具不稳定** → 禁止改代码,按 `diagnosis.hint` 转述;提示用户工具恢复后重跑 execute,不产出 `DELIVERY.md`
- 阶段 1 T1~T6 → 直接修对应文件,重跑 validate
- 阶段 1 T7/T8 → 调整 `mcp.json` 的 `apis[]` / `utils/util.js` 的 storage 逻辑 / `index.js` 的 `registerAPI`,重跑 validate
- 阶段 4 A/B 类 → 修 `apis/<name>.js` 入参拼装或 `utils/util.js` 的 `ensureStorageInit`,重跑 execute
- 阶段 4 C 类 → 对照主包源码修 `apis/<name>.js` / `utils/util.js`,必要时调整 `mcp.json` 的 `outputSchema` 与组件取值路径,重跑 execute
- 阶段 4 D 类 → 修 `components/<name>/` 的 wxml/wxss/js,重跑 render
- T9 → 终止,告知用户功能不支持或建议更换实现路径
---
## 关键约束(再次强调)
- 验收目标不可降级:所有原子接口与带 `componentPath` 的原子组件都必须通过;挂起仅限"连续 5 轮仍未通过"硬上限
- render 必须读取 `consoleMessages.snapshotCard` 做判断,不能只看 `execute-result`;具备图像读取能力时再辅助读截图
- "未裁剪 + 样式还原"是硬判据:**未裁剪**以 `consoleMessages.snapshotCard` 中存在 `[ai-mode] ... overflow monitor=on` 基线日志且不出现 `overflowed=true` 为准(缺 `monitor=on` = 未接入监听,按不通过处理);**样式还原度**在具备图像读取能力时再读 `snapshot.png` 作为辅助信号,否则以 `elementTree` 字段完整性兜底
- 修复必须跨主包 + 分包联动,真相只在主包里
- 根据 `mcp.json` 的 `apis[]` 依赖关系安排 execute 顺序;存在上游依赖时,上游 execute 必须先于下游。render 无此顺序约束
- 不要新增依赖、不要重写整个文件使用说明
# 小程序 AI Skills 校验修复 一句话:对小程序 AI Skills 产物做「静态校验 → 原子接口执行 → 原子组件渲染 → 交付文档」闭环验证,失败自动分类修复。 ## 使用 直接对话,例如: - 「校验一下这个小程序项目的 skills 目录」 - 「跑通这些 skill 的原子接口并验证渲染,输出交付文档」 ## 工作原理 技能依赖微信开发者工具 CLI 与调试基础库:先用 validate.mjs 做静态与编译校验(V001~V021 规则),再经 WebSocket 驱动开发者工具执行原子接口与组件渲染,失败时按错误类型对照修复手册就地修复 skill 源文件,最后按模板输出 DELIVERY.md 交付文档。
支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手