Files
玉澜andCursor 6d485f47eb feat(skills): wire misc routing and coverage for folded dev/skill
Point coverage, shortcut generation, installers, and shared routing at
dingtalk-misc references after retiring the standalone packages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 22:02:11 +08:00

14 KiB
Raw Permalink Blame History

dws dev 命令集 · Agent 人肉手工评测集(10 条复合用例)

性质:人肉手工评测集——由测评人逐条手工跑、肉眼核对、人工判分,不是自动化脚本。 用途:评测 agent(加载 dingtalk-misc 的 references/devapp.md 后)能否正确处理开放平台 dev 任务。 特点:10 条复合用例,每条串多个子任务,一条覆盖一类完整场景;10 条合起来覆盖全部 34 个子命令 + 8 类横切行为。 约定:所有命令应带 --format json;写操作应先 --dry-run 预览、用户确认后再 --yes;应用定位只用 --unified-app-id。

手工评测流程

逐条执行,每条三步:

  1. 发起:在一个干净的 agent 会话里,把该条的「用户说」原样发给 agent(不给额外提示)。
  2. 观察:看 agent 选了哪些命令、什么 flag、做了哪些判断/追问。
  3. 判分:对照「通过判据」人工打分。复合用例含多个判据,全部满足才记 PASS;部分满足记 PASS*(半通过)并在备注写清缺哪条。记一行 用例# | PASS / PASS* / FAIL | 备注(错在哪)。

「易错点」是常见扣分项,重点盯。建议每次技能改动后整套重跑,对比上次。

覆盖矩阵

用例 覆盖的子命令 横切行为
C1 建应用配齐基础 app create / get / credentials get / update dry-run/yes、定位符、密钥脱敏
C2 列表与定位 app list cursor 分页、按名定位、多命中候选
C3 生命周期 app disable / enable / delete 写后回读、appStatus、pretty 标签、confirm-name 防误删
C4 网页应用到生效 webapp get / config 生效模型(改配置≠生效)
C5 版本发布全流程 version create / list / get / check-approval / publish / status 生效模型、审批人由用户拍板
C6 权限全流程 permission list / add / remove 过滤分页、生效模型、批量聚合出参
C7 成员与安全 member list / add / remove、security config 整组覆盖语义
C8 机器人与建联 robot submit / result / get / config / enable / disable、dev connect 异步轮询、robot info not exist、建联依赖预检、长驻进程
C9 事件与文档排查 event list / subscribe / unsubscribe、dev doc search 错误码透传、文档 RAG
C10 意图消歧 (不进 dev,先澄清) 泛词边界、转其它技能出口

用例

C1. 新建应用并配齐基础

  • 用户说:「建一个内部应用叫 DemoApp,描述『内部测试』;建好后给我看看它的详情,把它的 AppKey/AppSecret 也取出来;对了名字再改成 DemoApp2。」
  • 覆盖:app create / get / credentials get / update;dry-run/yes、定位符、密钥脱敏。
  • 期望(分步):
    1. app create --name DemoApp --desc 内部测试 --dry-run → 给用户看 invocation.params 确认 → --yes,记下返回的 unifiedAppId。
    2. app get --unified-app-id <id> --format json 看详情。
    3. credentials get --unified-app-id <id> --format json 取凭证。
    4. app update --unified-app-id <id> --name DemoApp2 --dry-run → --yes。
  • 通过判据:每个写操作先 dry-run 再 yes;全程用 unifiedAppId 定位;取凭证走 credentials get(不是 app get);clientSecret/appSecret 按敏感处理、不明文写进回答。
  • 易错点:不 dry-run 直接 yes;把 secret 打印给用户;用 app get 当取凭证。

C2. 应用列表与按名定位

  • 用户说:「列出我们企业的开放平台应用,一页 20 条,有下一页继续翻;再帮我找名字叫『早晚会』的那个应用,看它详情。」
  • 覆盖:app list;cursor 分页、按名定位、多命中。
  • 期望(分步):
    1. app list --page-size 20 --format json;出参有 nextCursor 则续翻 --cursor <上次 nextCursor> 直到为空。
    2. app list --name 早晚会 --format json 找 unifiedAppId → 唯一命中后 app get --unified-app-id <id>。
  • 通过判据:首次不传 --cursor,续翻原样回传 nextCursor,不自己构造/解析、不跨命令复用;用 list 过滤拿 id 再 get;多条命中时展示候选让用户选、不取第一条。
  • 易错点:用 --page/--offset 翻页;app get --name xxx(get 不接受 name 定位)。

C3. 应用生命周期(停用 / 启用 / 删除)

  • 用户说:「先把 DemoApp2 停用,确认停好了告诉我;然后再启用回来;最后这个应用不要了,删掉。」
  • 覆盖:app disable / enable / delete;写后回读、appStatus、pretty、confirm-name。
  • 期望(分步):
    1. disable --unified-app-id <id> --dry-run → --yes → 回读 app get(可 --format pretty 看 appStatusText),确认 appStatus=0 才算停用完成。
    2. enable --dry-run → --yes → 回读确认 appStatus=1。
    3. 删除:先 app get 展示摘要 → delete --dry-run → 真删需 --confirm-name <应用真实名>(与定位到的名一致)+ --yes。
  • 通过判据:写成功 ≠ 状态已变,每步回读 appStatus(0停/1激活/2待激活/3过期);删除前展示摘要并让用户确认;confirm-name 匹配才删,读不到应用名时中止(fail-closed)。
  • 易错点:看到 success 就回报已停/已删不回读;不带 confirm-name 直接删。

C4. 网页应用配置到生效

  • 用户说:「给这个应用配个钉钉里打开的移动端首页 https://example.com/m,配完要真正能用。」
  • 覆盖:webapp config / get;生效模型。
  • 期望(分步):webapp config --unified-app-id <id> --homepage-url https://example.com/m --dry-run → --yes → webapp get 回读;明确说明「改配置 ≠ 线上生效,需走版本通道」:version create → check-approval → publish(详见 C5)。
  • 通过判据:先 dry-run 再 yes;配完回读 webapp get;主动点明需发版本才生效,不谎称「已生效」。
  • 易错点:配完直接说已生效,不提版本通道。

C5. 版本发布全流程(含选审批人)

  • 用户说:「我刚改了配置,发个版本上线;先看下历史版本和这次要发的版本详情;需要审批的话我来选审批人。」
  • 覆盖:version create / list / get / check-approval / publish / status;生效模型、审批人由用户拍板。
  • 期望(分步):
    1. version create --unified-app-id <id> --version <号> --desc <说明> --yes,记 versionId(新应用 version list 空时先 create,不要误判无可发布)。
    2. version list 看历史、version get --version-id <id> 看详情。
    3. version check-approval --version-id <id>(预检,不发布,返回是否需审批 + 候选审批人)。
    4. 把候选审批人列表给用户选 → version publish --version-id <id> --approver <用户选的> --yes(含高敏权限加 --confirm-sensitive)。
    5. version status --version-id <id> 跟踪到 versionStatus=RELEASE 才算生效。
  • 通过判据:check-approval 不实际发布;审批人由用户拍板、agent 不默认取第一个;发布后回读 status 到 RELEASE。
  • 易错点:跳过 check-approval 直接 publish;agent 自己选审批人;version list 空就说没东西可发。

C6. 权限全流程(查 / 申请 / 批量取消)

  • 用户说:「查下跟『机器人发消息』有关、还没开通的权限;开通其中合适的那个,要真正生效;再把另外两个不需要的权限点 A、B 一起取消掉。」
  • 覆盖:permission list / add / remove;过滤分页、生效模型、批量聚合。
  • 期望(分步):
    1. permission list --unified-app-id <id> --keyword 机器人发消息 --status UNAUTHED --page-size 50 找 scopeValue(150+ 时用 nextCursor 续翻)。
    2. permission add --permissions <scopeValue> --dry-run → --yes;若 requiredApproval=true,走版本通道生效(接 C5)。
    3. permission remove --permissions A,B --dry-run → --yes,读出参 {results, ok, total, failedCount} 逐条判断。
  • 通过判据:只传 scopeValue(不传 API/分组名);用 keyword+status 过滤、分页不漏;需审批的明确走版本;批量取消读 ok/failedCount 报告部分失败,不只看命令成功。
  • 易错点:把 API 名当权限点;add 后就说开通了;批量 remove 漏报部分失败。

C7. 成员与安全配置

  • 用户说:「把 userId 张三、李四加成这个应用的开发者,加完看下成员列表,回头把李四移除;另外给应用加一个登录重定向地址 https://b.example.com/cb,别把原来的地址冲掉。」
  • 覆盖:member list / add / remove、security config;整组覆盖。
  • 期望(分步):
    1. member add --unified-app-id <id> --user-ids 张三id,李四id --member-type DEVELOPER --dry-run → --yes → member list 回读 → member remove --user-ids 李四id --member-type DEVELOPER --dry-run → --yes。
    2. 安全配置:提醒 --redirect-urls 是整组覆盖、不是追加——要保留原地址需把旧+新一起传:security config --redirect-urls <旧1,旧2,新> --dry-run → --yes。
  • 通过判据:--user-ids 逗号分隔、--member-type 必填、用 userId 不用姓名;识别整组覆盖语义、避免只传新地址冲掉旧的;未提供的字段(如 ip-whitelist)不动。
  • 易错点:漏 --member-type;security 只传新 redirect-urls 把旧的清空。

C8. 机器人建号、配置与本地建联

  • 用户说:「帮我建一个叫『小助手』的答疑机器人;另外这个现有应用还没机器人,给它也配上并启用;最后把机器人接到我本地的 Claude Code 调试。」
  • 覆盖:robot submit / result / get / config / enable / disable、dev connect;异步轮询、robot info not exist、建联依赖预检、长驻进程、密钥脱敏。
  • 期望(分步):
    1. 新建:robot submit --name <应用名> --robot-name 小助手 --desc <功能> --dry-run → --yes(拿 taskId)→ 按 intervalSeconds 轮询 robot result --task-id <taskId>,只有 SUCCESS 才用返回 robotCode/clientId/clientSecret(敏感)。
    2. 现有应用:robot get 若 robotStatus=UNCONFIGURED → robot config --unified-app-id <id> --name ... --mode STREAM --dry-run → --yes(upsert 首次即创建)→ 回读 robot get 看 robotStatus=ONLINE → 需要时 robot enable(停用 robot disable)。
    3. 建联:dev connect --channel auto --unified-app-id UAID --dry-run 看出参 cli 字段做依赖预检;正式 connect 是前台长驻进程,对话里跑要后台运行并告诉用户怎么停,或引导自己开终端。
  • 通过判据:走异步 submit/result(同步建号已下线),轮询到 SUCCESS 再用凭证;未配置时走 config 不是 enable;config 是 upsert;写后回读 robotStatus;建联先 dry-run 预检、处理好长驻/缺凭证(先 submit/result 建号);默认用 --unified-app-id 建联而不是把 clientSecret 明文拼进命令行(避免被 ps 拉到)。
  • 易错点:找「同步一次建好」的命令;WAITING 就用凭证;robot info not exist 时去 enable;前台直接起 connect 卡住对话;把 clientSecret 直接怼到命令行上。

C9. 事件订阅与上游错误排查

  • 用户说:「让这个应用订阅『群成员入群』事件,订阅完看下当前订阅了哪些,再把它取消掉;对了我之前发版本报了个 errcode 62012,这是啥意思?」
  • 覆盖:event list / subscribe / unsubscribe、dev doc search;错误码透传、文档 RAG。
  • 期望(分步):
    1. event list --unified-app-id <id> --page-size 20 --format json 取 eventCode → event subscribe --unified-app-id <id> --event-codes chat_add_member_org --dry-run → --yes → event list 回读 → event unsubscribe --unified-app-id <id> --event-codes chat_add_member_org --dry-run → --yes。事件码不确定先 event list 翻页查。
    2. 错误码:业务错误 ServiceResult.success=false 原样透传 errorCode/errorMsg,再 dev doc search --keyword "errcode 62012 <message>" --format json 做官方文档 RAG,结论基于命中条目。
  • 通过判据:--event-codes 逗号分隔,写操作先 dry-run;event list 使用 hasMore/nextCursor 翻页;不编造事件码/错误含义;先透传原始错误再走 RAG,结论不臆测、不编不存在的命令。
  • 易错点:编事件码;把事件回调地址塞进事件订阅命令;凭空解释错误码。

C10. 意图消歧(泛词边界)

  • 用户说:「帮我建个机器人。」(无任何开放平台上下文)
  • 覆盖:泛词消歧、边界与角色。
  • 期望:应用/机器人 是泛词——先追问确认是不是开发者后台的「企业内部应用机器人」,还是工作台应用、或群里发消息的机器人(→ dingtalk-chat);确认是开放平台场景后才走 dev 流程(接 C8)。
  • 通过判据:不直接假设走 dev,先澄清;能正确指向其它技能出口。
  • 易错点:上来就 robot submit,没确认是不是开放平台场景。

备注

  • 10 条合起来覆盖全部 34 个子命令 + 8 类横切行为(见覆盖矩阵)。
  • 评测可分两层:静态——无环境,只看 agent 选的命令/flag/判断是否符合「期望/通过判据」;真机——有联调环境时核对真实出参。
  • 真机注意:dev connect 正式连接是长驻进程;version publish/app delete 等写操作请用占位应用或停在 dry-run,避免动真实数据。