@hupan56/wlkj 2.7.12 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/bin/cli.js +1435 -1107
  2. package/package.json +29 -29
  3. package/templates/qoder/agents/insight-planning.md +1 -1
  4. package/templates/qoder/agents/insight-research.md +28 -15
  5. package/templates/qoder/commands/optional/wl-insight.md +161 -161
  6. package/templates/qoder/commands/optional/wl-report.md +20 -39
  7. package/templates/qoder/commands/optional/wl-status.md +4 -4
  8. package/templates/qoder/commands/wl-code.md +2 -2
  9. package/templates/qoder/commands/wl-design.md +6 -6
  10. package/templates/qoder/commands/wl-init.md +3 -3
  11. package/templates/qoder/commands/wl-prd.md +26 -13
  12. package/templates/qoder/commands/wl-req.md +43 -0
  13. package/templates/qoder/commands/wl-search.md +78 -47
  14. package/templates/qoder/commands/wl-task.md +343 -40
  15. package/templates/qoder/commands/wl-test.md +43 -17
  16. package/templates/qoder/config.yaml +52 -14
  17. package/templates/qoder/hooks/post-tool-use.py +181 -0
  18. package/templates/qoder/hooks/session-start.py +94 -23
  19. package/templates/qoder/hooks/stop-eval.py +207 -0
  20. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  21. package/templates/qoder/rules/wl-pipeline.md +85 -49
  22. package/templates/qoder/scripts/README.md +102 -0
  23. package/templates/qoder/scripts/capability/__init__.py +26 -0
  24. package/templates/qoder/scripts/capability/__main__.py +72 -0
  25. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  26. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  27. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  28. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  29. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  30. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  31. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  32. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  33. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  34. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  35. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  36. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  37. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  38. package/templates/qoder/scripts/capability/chain.py +92 -0
  39. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  40. package/templates/qoder/scripts/capability/registry.py +246 -0
  41. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  42. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  43. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  44. package/templates/qoder/scripts/deployment/setup/__init__.py +11 -0
  45. package/templates/qoder/scripts/deployment/setup/carriers.py +669 -0
  46. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  47. package/templates/qoder/scripts/{init_doctor.py → deployment/setup/init_doctor.py} +100 -39
  48. package/templates/qoder/scripts/{install_qoderwork.py → deployment/setup/install_qoderwork.py} +48 -30
  49. package/templates/qoder/scripts/{platform_doctor.py → deployment/setup/platform_doctor.py} +271 -259
  50. package/templates/qoder/scripts/{repo_root.py → deployment/setup/repo_root.py} +9 -2
  51. package/templates/qoder/scripts/{setup.py → deployment/setup/setup.py} +143 -14
  52. package/templates/qoder/scripts/{setup_lanhu.py → deployment/setup/setup_lanhu.py} +979 -963
  53. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  54. package/templates/qoder/scripts/{fill_prototype.py → domain/design/fill_prototype.py} +17 -5
  55. package/templates/qoder/scripts/{gen_design_doc.py → domain/design/gen_design_doc.py} +406 -394
  56. package/templates/qoder/scripts/domain/kg/__init__.py +11 -0
  57. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  58. package/templates/qoder/scripts/domain/kg/build/build_entity_registry.py +201 -0
  59. package/templates/qoder/scripts/domain/kg/build/build_relations.py +132 -0
  60. package/templates/qoder/scripts/{build_style_index.py → domain/kg/build/build_style_index.py} +50 -15
  61. package/templates/qoder/scripts/domain/kg/build/build_workflows.py +149 -0
  62. package/templates/qoder/scripts/{kg_build.py → domain/kg/build/kg_build.py} +685 -612
  63. package/templates/qoder/scripts/{kg_build_db.py → domain/kg/build/kg_build_db.py} +338 -327
  64. package/templates/qoder/scripts/{kg_incremental.py → domain/kg/build/kg_incremental.py} +425 -393
  65. package/templates/qoder/scripts/{learn_aggregate.py → domain/kg/build/learn_aggregate.py} +212 -201
  66. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  68. package/templates/qoder/scripts/domain/kg/extract/test_extract.py +115 -0
  69. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  70. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  71. package/templates/qoder/scripts/{kg_link_db.py → domain/kg/graph/kg_link_db.py} +235 -224
  72. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  73. package/templates/qoder/scripts/{kg.py → domain/kg/kg.py} +871 -708
  74. package/templates/qoder/scripts/domain/kg/kg_capabilities.py +182 -0
  75. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  76. package/templates/qoder/scripts/{context_pack.py → domain/kg/search/context_pack.py} +45 -17
  77. package/templates/qoder/scripts/{enrich_prompt.py → domain/kg/search/enrich_prompt.py} +238 -226
  78. package/templates/qoder/scripts/domain/kg/search/prefetch.py +384 -0
  79. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  80. package/templates/qoder/scripts/{search_index.py → domain/kg/search/search_index.py} +210 -88
  81. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  82. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  83. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  84. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  85. package/templates/qoder/scripts/{kg_duckdb.py → domain/kg/storage/kg_duckdb.py} +70 -45
  86. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  87. package/templates/qoder/scripts/{learn.py → domain/learning/learn.py} +157 -146
  88. package/templates/qoder/scripts/domain/report/__init__.py +11 -0
  89. package/templates/qoder/scripts/{add_session.py → domain/report/add_session.py} +256 -244
  90. package/templates/qoder/scripts/{export.py → domain/report/export.py} +72 -4
  91. package/templates/qoder/scripts/{report.py → domain/report/report.py} +292 -281
  92. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  93. package/templates/qoder/scripts/domain/report/role.py +39 -0
  94. package/templates/qoder/scripts/{status.py → domain/report/status.py} +737 -628
  95. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  96. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  97. package/templates/qoder/scripts/{archive_prd.py → domain/requirement/archive_prd.py} +389 -377
  98. package/templates/qoder/scripts/domain/requirement/req.py +228 -0
  99. package/templates/qoder/scripts/domain/task/__init__.py +11 -0
  100. package/templates/qoder/scripts/{git_sync.py → domain/task/git_sync.py} +90 -50
  101. package/templates/qoder/scripts/{syncgate.py → domain/task/syncgate.py} +18 -7
  102. package/templates/qoder/scripts/domain/task/task.py +229 -0
  103. package/templates/qoder/scripts/domain/task/task_lifecycle.py +606 -0
  104. package/templates/qoder/scripts/domain/task/task_query.py +162 -0
  105. package/templates/qoder/scripts/domain/task/task_relations.py +425 -0
  106. package/templates/qoder/scripts/{team_sync.py → domain/task/team_sync.py} +101 -23
  107. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  108. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  109. package/templates/qoder/scripts/foundation/bootstrap.py +145 -0
  110. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  111. package/templates/qoder/scripts/foundation/core/cmd_registry.py +112 -0
  112. package/templates/qoder/scripts/foundation/core/config.py +187 -0
  113. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -400
  114. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  115. package/templates/qoder/scripts/foundation/data/contract.py +317 -0
  116. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  117. package/templates/qoder/scripts/foundation/data/result.py +223 -0
  118. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -392
  119. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  120. package/templates/qoder/scripts/foundation/identity/check_publish.py +103 -0
  121. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -238
  122. package/templates/qoder/scripts/foundation/identity/guard.py +159 -0
  123. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +132 -9
  124. package/templates/qoder/scripts/foundation/identity/roles.py +60 -0
  125. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  126. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  127. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +11 -10
  128. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  129. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  130. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  131. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  132. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  133. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  134. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  135. package/templates/qoder/scripts/foundation/protocol/mcp_base.py +268 -0
  136. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  137. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  138. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  139. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  140. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  141. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  142. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  143. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  144. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  145. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  146. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  147. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  148. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  153. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  154. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  155. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  156. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  157. package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → protocol/mcp/lanhu_stdio_wrapper.py} +131 -119
  158. package/templates/qoder/scripts/protocol/mcp/mcp_doctor.py +548 -0
  159. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  160. package/templates/qoder/scripts/protocol/mcp/mysql_mcp_server.py +461 -0
  161. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  162. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  163. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  164. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  165. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  166. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  167. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  168. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  169. package/templates/qoder/scripts/validation/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  171. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  172. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  173. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  174. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  175. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  176. package/templates/qoder/scripts/{eval_prd.py → validation/metrics/eval_prd.py} +84 -15
  177. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  178. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  179. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  180. package/templates/qoder/scripts/{autotest.py → validation/test/autotest.py} +1234 -1751
  181. package/templates/qoder/scripts/validation/test/autotest_auth.py +109 -0
  182. package/templates/qoder/scripts/{autotest_batch.py → validation/test/autotest_batch.py} +255 -224
  183. package/templates/qoder/scripts/validation/test/autotest_data.py +680 -0
  184. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  185. package/templates/qoder/scripts/{autotest_run.py → validation/test/autotest_run.py} +323 -297
  186. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  187. package/templates/qoder/scripts/{benchmark.py → validation/test/benchmark.py} +17 -5
  188. package/templates/qoder/scripts/{kg_auto_login.py → validation/test/kg_auto_login.py} +208 -196
  189. package/templates/qoder/scripts/{kg_test_runner.py → validation/test/kg_test_runner.py} +13 -2
  190. package/templates/qoder/scripts/{page_probe.py → validation/test/page_probe.py} +470 -459
  191. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  192. package/templates/qoder/settings.json +23 -2
  193. package/templates/qoder/skills/design-import/SKILL.md +235 -226
  194. package/templates/qoder/skills/design-review/SKILL.md +91 -82
  195. package/templates/qoder/skills/prd-generator/SKILL.md +38 -24
  196. package/templates/qoder/skills/prd-review/SKILL.md +8 -6
  197. package/templates/qoder/skills/prototype-generator/SKILL.md +296 -247
  198. package/templates/qoder/skills/spec-coder/SKILL.md +24 -15
  199. package/templates/qoder/skills/spec-generator/SKILL.md +24 -12
  200. package/templates/qoder/skills/test-generator/SKILL.md +9 -7
  201. package/templates/qoder/skills/wl-code/SKILL.md +25 -13
  202. package/templates/qoder/skills/wl-commit/SKILL.md +10 -9
  203. package/templates/qoder/skills/wl-design/SKILL.md +7 -5
  204. package/templates/qoder/skills/wl-init/SKILL.md +8 -8
  205. package/templates/qoder/skills/wl-insight/SKILL.md +25 -12
  206. package/templates/qoder/skills/wl-prd-full/SKILL.md +59 -8
  207. package/templates/qoder/skills/wl-prd-quick/SKILL.md +7 -7
  208. package/templates/qoder/skills/wl-prd-review/SKILL.md +18 -6
  209. package/templates/qoder/skills/wl-report/SKILL.md +27 -25
  210. package/templates/qoder/skills/wl-search/SKILL.md +151 -80
  211. package/templates/qoder/skills/wl-spec/SKILL.md +9 -7
  212. package/templates/qoder/skills/wl-status/SKILL.md +50 -18
  213. package/templates/qoder/skills/wl-task/SKILL.md +94 -12
  214. package/templates/qoder/skills/wl-test/SKILL.md +154 -45
  215. package/templates/qoder/templates/prd-full-template.md +7 -0
  216. package/templates/root/AGENTS.md +275 -237
  217. package/templates/root/requirements.txt +3 -0
  218. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  219. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  220. package/templates/qoder/hooks/inject-workflow-state.py +0 -169
  221. package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
  222. package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
  223. package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
  224. package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
  225. package/templates/qoder/scripts/check_carriers.py +0 -238
  226. package/templates/qoder/scripts/check_mcp.py +0 -298
  227. package/templates/qoder/scripts/check_mcp_launch.py +0 -183
  228. package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
  229. package/templates/qoder/scripts/collect_prds.py +0 -31
  230. package/templates/qoder/scripts/common/mentions.py +0 -134
  231. package/templates/qoder/scripts/common/utf8.py +0 -38
  232. package/templates/qoder/scripts/extract_api_params.py +0 -246
  233. package/templates/qoder/scripts/extract_routes.py +0 -54
  234. package/templates/qoder/scripts/extract_routes_tree.py +0 -78
  235. package/templates/qoder/scripts/handoff.py +0 -22
  236. package/templates/qoder/scripts/init_developer.py +0 -76
  237. package/templates/qoder/scripts/kg_mcp_server.py +0 -801
  238. package/templates/qoder/scripts/kg_semantic.py +0 -150
  239. package/templates/qoder/scripts/mcp_launcher.py +0 -414
  240. package/templates/qoder/scripts/mysql_mcp_server.py +0 -396
  241. package/templates/qoder/scripts/parse_prds.py +0 -33
  242. package/templates/qoder/scripts/role.py +0 -51
  243. package/templates/qoder/scripts/sync_carriers.py +0 -259
  244. package/templates/qoder/scripts/task.py +0 -1261
  245. package/templates/qoder/scripts/workspace_init.py +0 -102
  246. package/templates/qoder/scripts/zentao_mcp_server.py +0 -424
  247. package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
  248. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  249. /package/templates/qoder/{skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp → scripts/domain/__init__.py} +0 -0
  250. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  251. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  252. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  253. /package/templates/qoder/scripts/{secure-ls.js → validation/test/secure-ls.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-task
3
- description: "任务管理 + RICE 优先级 + 依赖排期。7 站流水线的'任务'站,产品在这里把 PRD 落成任务。Task management with RICE prioritization. 用户说'建任务''排优先级''开始做这个''任务做完了''列一下任务''归档''排期'时触发。"
4
- trigger: "用户说'建任务''建个任务''排优先级''开始做''做完了''看任务''列任务''归档''排期''甘特图''/wl-task'"
3
+ description: "任务管理 + RICE 优先级 + 依赖排期。7 站流水线的'任务'站,产品在这里把 PRD 落成任务。Task management with RICE prioritization. "
4
+ trigger: "user invokes /wl-* command explicitly"
5
5
  ---
6
6
 
7
7
 
@@ -11,7 +11,7 @@ trigger: "用户说'建任务''建个任务''排优先级''开始做''做完了'
11
11
  ```bash
12
12
  R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
13
13
  ```
14
- > `repo_root.py` 从 `~/.qoderwork/mcp.json` 反推仓库根;失败回退 `.`(IDE/CLI 工作目录即仓库根)。找不到时先跑 `python .qoder/scripts/install_qoderwork.py`。
14
+ > `repo_root.py` 从 `~/.qoderwork/mcp.json` 反推仓库根;失败回退 `.`(IDE/CLI 工作目录即仓库根)。找不到时先跑 `python "$R/.qoder/scripts/orchestration/wlkj.py" install-qw`。
15
15
 
16
16
  # wl-task — 任务管理(7 站之「任务」站 · 产品工位)
17
17
 
@@ -25,8 +25,10 @@ R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
25
25
  | 用户说什么 | 动作 | 跑什么 |
26
26
  |-----------|------|--------|
27
27
  | "建个任务 XXX" / "把刚才需求建成任务" / "create" | **create** | `task.py create`(带 PRD 衔接) |
28
- | "列一下任务" / "我的任务" / "有哪些任务" / "list" | **list** | `task.py list` |
29
- | "接下来做啥" / "能做的有哪些" | **list --ready** | 只看能立刻开始的 |
28
+ | "列一下**本地**任务" / "有哪些任务" / "list" | **list** | `task.py list`(本地离线缓存,非禅道) |
29
+ | **"我的任务" / "我的禅道" / "这周干啥" / "我的Bug"** | **自然查询** | ★直接 `my_workbench()`(见下方禅道查询总表),不走本命令工序 |
30
+ | **"看下#301" / "需求#761怎么样了" / "Bug状态"** | **自然查询** | 直接 `get_task` / `get_story_detail` / `get_bug`,自然回答 |
31
+ | "接下来做啥" / "能做的有哪些" | **list --ready** | 只看能立刻开始的(本地依赖视角) |
30
32
  | "卡住的有哪些" / "哪些被阻塞" | **list --blocked** | 只看有未完成依赖的 |
31
33
  | "看下 XXX 任务" / "XXX 怎么样了" / "show" | **show** | `task.py show <名>` |
32
34
  | "开始做 XXX" / "启动 XXX" / "start" | **start** | `task.py start <名>` |
@@ -36,16 +38,96 @@ R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
36
38
  | "排期" / "甘特图" / "排个日期" / "plan" | **plan** | `task.py gantt` + set-due |
37
39
  | 模糊 / 拿不准 | 先 list 给全貌 | 再问要操作哪个 |
38
40
 
41
+ > **边界**:上面"自然查询"行的(我的任务/看进度/Bug状态)—— AI 直接用禅道 MCP 工具回答,**不拉入工序流程**。
42
+ > "PRD发禅道/记工时/改状态"这类**显式操作**才走工序(见 wl-task.md 的 zentao 剧本)。
43
+
44
+ ### 🔌 宿主路由:禅道怎么调(看你在哪个宿主)
45
+
46
+ > ★ 丝滑关键。禅道工具有两条入口,用错就慢/重复 spawn/报错。
47
+
48
+ | 宿主 | 调用入口 | 何时用 |
49
+ |------|---------|--------|
50
+ | **QoderWork** | `qw_mcp_call("工具名", {参数})` | 第一宿主。QoderWork 已起 zentao 进程,直接复用,**省 list/get 两步元调用**。下表工具名确定时直接 call。 |
51
+ | **Qoder IDE / Quest** | `mcp__qoder-zentao__工具名(参数)` | IDE 把 MCP 工具暴露成 `mcp__<server>__<tool>`。 |
52
+ | **CLI / 其他** | `cap.mcp.call("工具名", {参数})` | 无原生 MCP,capability 层 spawn 本地 server。 |
53
+
54
+ **判定宿主**:`QODER_SESSION_ID` 存在 = QoderWork;否则 `detect_host()`。下表统一用 `qw_mcp_call(...)` 示意(CLI 换 `cap.mcp.call`,参数一致)。
55
+
56
+ ### ★★★ 禅道查询总表 + 三铁律(处理任何禅道意图,先查这张表,禁止瞎试)
57
+
58
+ > 这三轮实测的病根:AI 看到"看我的禅道X"找不到路就**瞎试→枚举→调用爆炸/token浪费**。
59
+ > 下面这张表是"宪法"——任何禅道意图,**先匹配表里的行,照着走**。匹配不上再问用户,**绝不逐个枚举**。
60
+
61
+ #### 🔒 三条铁律(违反 = 失败,AI 必读)
62
+
63
+ 1. **禁止枚举扇出**:拿到 list 结果后,**绝不**逐个调 `get_*_detail`。list 返回的 `id+name+status` 已够用;只有用户明确点了某条("看#761详情"),才单独 `get_story_detail(story_id=761)` 一次。
64
+ 2. **🚫 跨域不冒充(v3.1.5 新增,最重要)**:用户问「任务」就查 task 域,问「需求」查 story 域,问「Bug」查 bug 域。**查不到如实说"没有指派给你的任务"+贴查询证据,绝不拿需求/Bug 顶替任务来回答**。用户问"我的任务"却收到需求列表 = 严重失败。
65
+ 3. **写操作要确认**:改/删需求、执行、版本这类**无归属校验**的工具,调之前先把要操作的项列出来让用户确认(防改错队友/全局资源)。任务/Bug 的 start/finish/resolve 等有 `_assert_owner` 兜底,但仍建议先 get 一次确认是我的。
66
+
67
+ #### 意图路由总表(用户说什么 → 调什么 → 调几次)
68
+
69
+ | 用户说的意图 | 直达工具 | 调用次数 | 关键约束 |
70
+ |------------|---------|:---:|---------|
71
+ | **看我的禅道任务/这周干啥/我手头有啥** | ★`my_workbench()` | **1** | 跨执行/产品全量聚合,一行拿全!不再逐执行查 |
72
+ | 看我未开始/进行中的任务 | `list_my_tasks(status='wait')` / `list_my_tasks(status='doing')` | 1 | 跨执行全量 |
73
+ | **看我的禅道需求** / "我的需求" | `my_workbench()` 看需求段(或逐产品 `list_stories`) | 1 | 🚫**禁逐个 get_story_detail** |
74
+ | **看我的Bug** | ★`list_my_bugs()` | **1** | 跨产品全量,不再逐产品查 |
75
+ | 看某执行任务(已知eid) | `list_execution_tasks(eid)` | 1 | 默认只看我的 |
76
+ | 看全队任务/需求/Bug | 对应工具 + `all=true` | 1 | ★**必须用户明说"全队"才加** |
77
+ | 看某条详情("#761怎么样") | `get_story_detail` / `get_task` / `get_bug` (该 id) | 1 | 用户**点了具体 ID** 才调 |
78
+ | 看有哪些产品/执行/版本 | `list_products` / `list_executions` / `list_builds(project_id=9)` | 1 | 导航类,可自由调(公开结构) |
79
+ | 建需求 / PRD发禅道 | `create_story` → 然后**主动问关联版本**(见下) | 1+ | 不知产品先 `list_products` 勾选 |
80
+ | 关联版本 | `list_builds(project_id=9)` → `link_story_to_build` | 2 | 多选 = 一个需求进当前+未来版本 |
81
+ | 拆需求为任务 | `list_executions` 选 → `create_task` | 2 | 不填 assignedTo 默认指派给我 |
82
+ | 开始/完成/记工时任务 | `start_task` / `finish_task` / `log_effort` (task_id) | 1 | 有归属校验;finish 要问消耗工时 |
83
+
84
+ #### 「看我的工作」统一范式(v3.1.5 升级)
85
+
86
+ ```
87
+ ★ 首选: my_workbench() —— 一次返回任务+需求+Bug 三域全量聚合, 跨所有执行/产品不漏。
88
+ 这是回答"我手头有什么活/我的任务/我的禅道"的默认工具, 调用次数从原来的 N(逐执行) 降到 1。
89
+
90
+ 单域查询: list_my_tasks(status=...) / list_my_bugs() —— 跨执行/产品全量, 只看我的。
91
+
92
+ 旧的逐执行/逐产品查法 (list_execution_tasks 逐个执行、list_stories 逐个产品) 仍可用,
93
+ 但只用于"已知具体执行/产品ID"的场景。查"我的全部"会被漏数据(实测 61 执行逐个查会漏)。
94
+ ```
95
+
96
+ #### 归属账号未识别(v3.1.5 起工具层直接拒绝)
97
+
98
+ 若 `my_workbench` / `list_my_tasks` / `list_my_bugs` / `list_execution_tasks`(默认) 返回:
99
+ `🚫 未识别禅道身份: member.json 缺 zentao_account...`
100
+ → 这是**工具层主动拒绝**(不再静默降级)。原样把提示转述给用户,引导跑 `/wl-init` 配置。
101
+ **绝不绕过**(不传 all=true 去看全队当我的,不拿别的域顶替)。配好后重启 MCP 生效。
102
+
103
+
104
+ #### 建需求后主动问版本(★ 你们的版本=项目级 build)
105
+
106
+ > 你们的「版本」是**项目级 build**(项目#9 下按周 `V+日期`,如 `V20260625`),不是产品级 plan/release。一个需求可能**同时进当前+未来版本**,所以**显式让 PM 多选**,不自动关联。
107
+
108
+ 建需求/评审通过后,AI **主动**列最近 build 让 PM 勾选:
109
+ ```
110
+ AI: 要关联到哪个版本?(最近 6 个 build):
111
+ [1] #22 V20260625 (本周) [2] #21 V20260618 (上周) [3] #16 V20260604 ...
112
+ PM> 1,3 ← 多选 = 一个需求进当前版本(本周发)+未来版本
113
+ AI: ✅ 需求#761 已关联 build#22(本周) + #16(未来)
114
+ ```
115
+ - 候选:`list_builds(project_id=9)` 取最近 6 个,按时间倒序编号。
116
+ - 关联:`link_story_to_build(build_id=<选中>, stories=[<需求ID>])`,**逐个 build 调一次**。
117
+ - PM 也可主动触发:"把#761 关联到本周版本" → AI 查本周 build 再关联。
118
+
39
119
  ## ⚙️ 自取上下文(Quest / QoderWork 无 hook 注入,必须自读)
40
120
 
41
- - `.qoder/.developer` 当前开发者(assignee 默认值)
42
- - `.qoder/.current-task` — 当前活动任务("开始做""完成了"默认对它操作)
43
- - 列出已有任务:`python "$R/.qoder/scripts/task.py" list`
121
+ - **当前身份**:当前开发者(assignee 默认值)。读法:先 `R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.` 定位仓库根,
122
+ `python "$R/.qoder/scripts/foundation/core/paths.py" whoami`(输出开发者名;空=未初始化)。
123
+ ⚠️ 勿用裸相对路径 `.qoder/.developer`(QoderWork 桌面端 cwd 不在仓库根,会读不到而误报未初始化)。
124
+ - **活动任务**:当前活动任务("开始做""完成了"默认对它操作)。读法 `python "$R/.qoder/scripts/foundation/core/paths.py" current-task`(输出任务路径;空=无活动任务)。
125
+ - 列出已有任务:`cap.mcp.call("list_tasks", {})`
44
126
  - 衔接 PRD:扫 `workspace/members/{dev}/drafts/REQ-*.md` + `data/docs/prd/REQ-*.md`
45
127
 
46
128
  ## 🔒 三道前置检查(任何动作前先做,保证健壮)
47
129
 
48
- 1. **身份检查**:`.developer` 缺失 → 停下,提示先 `/wl-init`,不继续(否则 create 会把 assignee 写空)。
130
+ 1. **身份检查**:跑 `python "$R/.qoder/scripts/foundation/core/paths.py" whoami`,无输出/退出码1 = 未初始化 → 停下,提示先 `/wl-init`(否则 create 会把 assignee 写空)。
49
131
  2. **空数据兜底**:tasks 目录不存在/空 → 读操作友好提示"还没有任务",不报错;create 直接建。
50
132
  3. **脚本退出码**:`task.py` 返回非 0 → 原样读 stderr 告诉用户。`4`=权限不足(零信任 ACL),`1`=任务不存在/JSON 缺失。**绝不绕过 ACL。**
51
133
 
@@ -56,7 +138,7 @@ R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
56
138
  **create(最高频)—— PRD 衔接不丢字段:**
57
139
  - 有 PRD → 从 PRD 提取标题/模块/验收点,**别让用户重述**;把 REQ-ID 记进 task.json 的 `tags`。
58
140
  - 无 PRD → 用用户给的一句话当标题。
59
- - 建完 push:`python "$R/.qoder/scripts/team_sync.py" push`
141
+ - 建完 push:`cap.mcp.call("sync", {"direction": "push"})`
60
142
 
61
143
  **rank(RICE)—— 一次取全,别逐个问:**
62
144
  1. `task.py list --status planning` 拿全待排任务
@@ -105,7 +187,7 @@ RICE = Reach × Impact × Confidence ÷ Effort
105
187
 
106
188
  `create` / `finish` / `archive` 改了任务状态,都要推给团队(用户永不碰 git):
107
189
  ```bash
108
- python "$R/.qoder/scripts/team_sync.py" push
190
+ cap.mcp.call("sync", {"direction": "push"})
109
191
  ```
110
192
 
111
193
  ## finish 后:自动生成测试交接画像(可选增强)
@@ -124,7 +206,7 @@ python "$R/.qoder/scripts/team_sync.py" push
124
206
 
125
207
  ## 🧩 QoderWork 增强:待办双向同步(可选 · 无连接器则自动回退)
126
208
 
127
- > 依赖 **QoderWork 桌面端连接器**(Settings → Connectors,授权 Microsoft 365 待办 / OneNote,或 macOS 提醒事项)。
209
+ > 通过 capability 层自动路由(Settings → Connectors,授权 Microsoft 365 待办 / OneNote,或 macOS 提醒事项)。
128
210
  > **纯 Qoder IDE / CLI 没有连接器 → 本段不生效,任务只在本地 task.json 管理,完全够用。**
129
211
  > 探测方式:仅当运行环境提供了「待办 / To-Do」工具可直接读写时才用。
130
212
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-test
3
3
  description: "测试工作流: 意图式用例 + Playwright MCP 执行 + 锚点缓存。触发: /wl-test 命令; 或自然语言里带'功能验证点'(如'测一下XX支不支持YY''验一下XX能不能ZZ''XX对不对')。纯随手看('打开XX页''看看登录')→不走本工作流。需确认(DANGEROUS)。"
4
- trigger: "/wl-test 命令; 或自然语言带具体功能验证点: '测一下XX支不支持YY''验一下XX能不能''XX功能对不对''回归XX'。仅'打开/看看/瞄一眼'等无验证点的不触发。"
4
+ trigger: "user invokes /wl-* command explicitly"
5
5
  ---
6
6
 
7
7
  # wl-test — 测试工作流(/wl-test 命令 或 带功能验证点的自然语言触发)
@@ -32,9 +32,9 @@ trigger: "/wl-test 命令; 或自然语言带具体功能验证点: '测一下XX
32
32
 
33
33
  **① 必须用意图式格式(intent+anchor),禁止旧 action+selector 格式。**
34
34
  ```json
35
- // ✅ 对: 意图式, anchor 来自 recall
35
+ // ✅ 对: 意图式, anchor 来自 recall 或 snapshot
36
36
  {"intent":"fill","desc":"账号输入框","value":"{{ask:登录账号}}","anchor":{"role":"textbox","name":"尊敬的管理员"}}
37
- // ❌ 错: 旧 action+CSS selector (脆弱, recall 锚点白沉淀)
37
+ // ❌ 错: 旧 action+CSS selector (脆弱, 脆弱, recall 锚点白沉淀)
38
38
  {"action":"form_input","target":"input[placeholder*='账号']","value":"{{ask:测试账号}}"}
39
39
  ```
40
40
 
@@ -46,20 +46,48 @@ trigger: "/wl-test 命令; 或自然语言带具体功能验证点: '测一下XX
46
46
  **③ 用例 JSON 必须用 `--cases-file` 传文件,禁止内联 `--cases`。**
47
47
  ```bash
48
48
  # ✅ 对: 写文件再传路径(不截断)
49
- python "$R/.qoder/scripts/autotest.py" quick --cases-file <文件路径> --env test --platform web
49
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test quick --cases-file <文件路径> --env test --platform web
50
50
  # ❌ 错: 内联(长JSON截断, 多条用例必丢)
51
- python "$R/.qoder/scripts/autotest.py" quick --cases '[{"case_id"...(超长)...}]'
51
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test quick --cases '[{"case_id"...(超长)...}]'
52
52
  ```
53
53
 
54
- **④ 执行前必须 recall 查锚点。有锚点 直接填进 anchor,不调 LLM 匹配。**
54
+ **④ 无锚点时必须先 snapshot 拿真实 anchor 再填,禁止预猜 CSS selector。**
55
55
  ```bash
56
- python "$R/.qoder/scripts/autotest.py" recall --url "/auth/login"
56
+ # recall 空时 → 不预猜! 先 navigate + snapshot 拿到真实 a11y 树
57
+ # 再把 snapshot 里看到的 role+name 填进 step.anchor
57
58
  ```
58
- recall 返回的每个锚点,直接用它的 role+name 填进 step.anchor。这步是**省模型调用**的根本。
59
+ - recall 命中 直接用 recall 的 anchor(确定性命中,零 LLM)
60
+ - recall 空(首次)→ **navigate + browser_snapshot → 从 a11y 树提取 anchor → 填进用例**
61
+ - **绝不**在没看页面的情况下凭"登录页一般有账号框"去猜 selector
59
62
 
60
- **⑤ 验证码必须用 Playwright MCP 的 `browser_take_screenshot` 截图 → QoderWork 自带视觉识别 → `browser_type` 填入 → 删图。禁止用 Computer 截图(实测反复失败超时)、禁止瞎蒙默认值。**
61
- - `{{ask:}}` 占位符里**绝不出现验证码**——验证码不存个人文档,执行时实时识别。
62
- - 截图工具不可用时 用 JS 提取 base64 → 存图 → Read 看 → 算答案 → 填入 → **删图**。
63
+ **⑤ URL 必须写成 `{{base_url}}/auth/login`(带斜杠)。**
64
+ - base_url 已去尾斜杠(脚本行为),写 `{{base_url}}auth/login` 会拼成 `https://xxxauth/login` 坏地址。
65
+ - 脚本会检测并告警,但 AI 应一次写对。
66
+
67
+ **⑥ recall 的 `--url` 必须用相对路径(无前导斜杠),避开 Git-bash/MSYS 路径转换坑。**
68
+ ```bash
69
+ # ✅ 对: 相对路径 (MSYS 不转换)
70
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test recall --url auth/login
71
+ # ❌ 错: 前导斜杠会被 Windows Git-bash 转成 /D:/.../Git/auth/login
72
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test recall --url /auth/login
73
+ ```
74
+ (脚本已加 normalize 兜底能修这个,但别依赖兜底——直接写相对路径最干净。)
75
+
76
+ **⑦ Playwright 工具一次性批量加载,snapshot 结果直接用内存 a11y 树,禁止写文件再 Read。**
77
+ ```bash
78
+ # ✅ 对: 一个回合里并发加载所有要用的 browser_* 工具描述
79
+ # ✅ 对: browser_snapshot 返回的 a11y 树直接在对话里读, 不落地文件
80
+ # ❌ 错: 用一个加载一个(调用数翻倍); snapshot 写 yml 文件 → 再 Read 读回来(每步2次调用)
81
+ ```
82
+
83
+ **⑧ 验证码识别一气呵成(截图→Read→type→删图),不绕路、不预先纠结。**
84
+ - 登录用例里**不写**验证码 step——点登录后若弹验证码,执行循环自动走 5 步。
85
+ - 固定 5 步连发:`browser_snapshot` 找验证码图 → `browser_take_screenshot` 存图 → Read 看图算 → `browser_type` 填 → 删图。
86
+ - 验证码有时效(1-2分钟),所以**填完立刻点登录**,别在中间插别的操作。
87
+ - 自识别连失 2 次才交人。
88
+
89
+ **⑨ 用例必须一次生成全部(正向+异常),禁止一条一条生成。**
90
+ - 每生成一条 = 一次模型调用。一次写完 Q-1(正向) + Q-2(异常) + ... 全部。
63
91
 
64
92
  ## ⚙️ 自取上下文(Quest / QoderWork 无 hook 注入,必须自读)
65
93
 
@@ -70,8 +98,8 @@ recall 返回的每个锚点,直接用它的 role+name 填进 step.anchor。
70
98
  > R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
71
99
  > ```
72
100
  > `repo_root.py` 从 `~/.qoderwork/mcp.json` 反推仓库根;失败回退 `.`(IDE/CLI 工作目录即仓库根)。
73
- > **读到 1 次记住,后续所有脚本统一用 `python "$R/.qoder/scripts/xxx.py"`,不要再搜!**
74
- > 如果 `repo_root.py` 报错找不到,先在仓库里跑 `python "$R/.qoder/scripts/install_qoderwork.py"`。
101
+ > **后续脚本统一用 `python "$R/.qoder/scripts/orchestration/wlkj.py" <命令>`,不要再搜!**
102
+ > 如果 `repo_root.py` 报错找不到,先在仓库里跑 `python "$R/.qoder/scripts/orchestration/wlkj.py" install-qw`。
75
103
 
76
104
  - `<R>/.qoder/.developer` — 当前开发者
77
105
  - `<R>/.qoder/config.yaml` 的 `autotest:` 段 — 环境/域名
@@ -84,7 +112,7 @@ recall 返回的每个锚点,直接用它的 role+name 填进 step.anchor。
84
112
 
85
113
  **唯一正确做法**——1 条命令查 MySQL sys_menu 真实路由:
86
114
  ```bash
87
- python "$R/.qoder/scripts/search_index.py" --routes 保险
115
+ python "$R/.qoder/scripts/orchestration/wlkj.py" search --routes 保险
88
116
  # → 保险管理 -> /veh/vehicle/vehAffair/insurance
89
117
  ```
90
118
  - 数据来自 MySQL `sys_menu` 表(后台动态菜单,**唯一事实源**)
@@ -93,10 +121,10 @@ python "$R/.qoder/scripts/search_index.py" --routes 保险
93
121
 
94
122
  ### 生成用例时用 MySQL MCP 补真实数据(少手填、覆盖边界)
95
123
 
96
- 1. **取真实测试数据**:需要业务单号/账号时 `mcp__qoder-mysql__query_data(table='表名', columns='id,单号列', where='条件', limit=5)`
124
+ 1. **取真实测试数据**:需要业务单号/账号时 `cap.mcp.call("query_data", {"table": "表名", "columns": "id", "单号列", "where": "条件", "limit": "5"})`
97
125
  - 拿测试库真实可用的数据,别编造。填进用例的 data 里。
98
126
  - [QAS环境] 数据行仅参考格式,不代表线上。
99
- 2. **枚举边界覆盖**:涉及状态/类型字段时 `mcp__qoder-mysql__query_distinct(table='表名', column='状态列')`
127
+ 2. **枚举边界覆盖**:涉及状态/类型字段时 `cap.mcp.call("query_distinct", {"table": "表名", "column": "状态列"})`
100
128
  - 查真实取值范围(如 case_status = 1/2/3/4),按每个值造边界用例。
101
129
  - 取值范围可信 → 用例枚举全覆盖,不漏分支。
102
130
 
@@ -131,30 +159,66 @@ coverage_matrix()
131
159
 
132
160
  **不要任务/PRD。零搜索。** 用意图+锚点格式(A方案),observe-act-extract 执行。
133
161
 
134
- ### Step 0:先 recall 查有没有现成锚点(跳过 LLM)
162
+ ### Step 0 + 0.5:recall 查锚点 + context_pack 取全(两者无依赖,同回合并发)
163
+
164
+ > Step0(recall 锚点)和 Step0.5(context_pack 上下文)互不依赖 → **同一条消息并发发**,别先跑0再跑0.5。
165
+
166
+ **Step 0:recall 查锚点**(用相对 URL,避开 MSYS 坑)
135
167
  ```bash
136
- python "$R/.qoder/scripts/autotest.py" recall --url "/auth/login"
168
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test recall --url auth/login
137
169
  ```
138
170
  - **有锚点** → 生成用例时直接把 anchor 填进 step(确定性命中,快、零 LLM)
139
- - **无锚点**用意图式生成(首次会调 LLM 匹配,执行后 learn 沉淀,下次就快)
171
+ - **无锚点(首次)****先 navigate + snapshot 拿真实锚点,再生成用例**(见 Step 0.6)
140
172
 
141
- ### Step 0.5:用知识图谱 MCP 增强用例(1 次调用取全)
173
+ **Step 0.5:用知识图谱 MCP 增强用例**(1 次调用取全,与 recall 并发)
174
+ ```python
175
+ context_pack(keyword='功能名', platform='web', role='test')
176
+ ```
177
+ - 返回(role=test 裁剪): 代码落点 + 相关历史 PRD 标题 + API + 字段
178
+ - 拿到后用于: API→断言点, 字段→fill 步骤更准
142
179
 
143
- **只调 1 次** `context_pack(keyword='功能名', platform='web', role='test')`:
144
- - 返回(role=test 裁剪): 代码 + PRD验收标准 + API + 数据库表结构(第8段)
145
- - 拿到后用于: PRD验收标准→用例expected, API→断言点, 字段→fill步骤更准
180
+ > ⚠️ **注意:context_pack 不抓 PRD 验收标准正文**(它只取 PRD 的 title+keywords,
181
+ > 不解析「## 验收标准」章节)。**业务规则断言不要指望 context_pack**,它给不了 expected。
182
+ > 要把 PRD 验收标准翻译成可执行断言,用 `assertion-gen` 子命令(见下方专节)。
146
183
 
147
184
  > 图谱无数据 → 跳过,按通用模式生成。**不要再单独调 feature_overview**(信息重叠,浪费一轮)。
148
185
 
186
+ ### Step 0.6:recall 空时,先 snapshot 拿真实锚点(🔴 首次跑关键,禁止预猜 selector)
187
+
188
+ **recall 返回空 = 第一次测这页。此时绝不能凭"登录页一般有账号框"去猜 CSS selector。**
189
+ 正确做法:先用 Playwright 打开页面拿一次 a11y 树,从里面提取真实 anchor:
190
+
191
+ ```bash
192
+ # 1. 批量加载要用的 browser_* 工具描述 (一次并发, 别一个一个加载)
193
+ # 最少: browser_navigate, browser_snapshot, browser_click, browser_type,
194
+ # browser_take_screenshot, browser_evaluate
195
+
196
+ # 2. browser_navigate 到 {{base_url}}/auth/login (base_url 从 config 取, 已去尾斜杠)
197
+ # 3. browser_snapshot 一次 → 拿到 a11y 树 (直接读对话里的内容, 不写文件)
198
+ ```
199
+ snapshot 返回形如:
200
+ ```
201
+ - textbox "尊敬的管理员,请输入您的账号" [ref=e36]
202
+ - textbox "请输入您的密码" [ref=e42]
203
+ - textbox "验证码" [ref=e56]
204
+ - button "login" [ref=e64]: 登录
205
+ ```
206
+ **把这里的 role+name 直接填进用例的 anchor**:
207
+ ```json
208
+ {"intent":"fill","desc":"账号输入框","value":"{{ask:登录账号}}","anchor":{"role":"textbox","name":"尊敬的管理员,请输入您的账号"}}
209
+ ```
210
+ > 这一步把"首次跑要靠 LLM 兜底匹配"变成"确定性命中",是省调用的根本。
211
+ > 拿到锚点后继续 Step 1。
212
+
149
213
  **🎯 知道页面名/URL 时,AI 先查按钮+接口画像(最精准,1 条命令拿到所有交互点):**
150
214
  ```bash
151
- python "$R/.qoder/scripts/autotest.py" page --kw 保险 # 按业务名查
152
- python "$R/.qoder/scripts/autotest.py" page --url /veh/insurance # 按URL查
215
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test page --kw 保险 # 按业务名查
216
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test page --url /veh/insurance # 按URL查
153
217
  ```
154
218
  (这是 AI 在 `/wl-test` 流程内部自动调用的工具,**用户只用 `/wl-test`,不碰此命令**。)
155
219
  输出每个按钮的 handler + 调用接口 + HTTP 方法 + 置信度,**直接对应到用例的 click→assert 断言点**。开发 `finish` 任务时也会自动生成 `test-handoff.md`,内容同此画像——交接场景直接读那份即可,不必重查。
156
220
 
157
- ### Step 1:AI 据用户描述 + 图谱信息生成意图式用例 JSON(**一次生成全部用例**)
221
+ ### Step 1:AI 据用户描述 + 锚点生成意图式用例 JSON(**一次生成全部用例**)
158
222
  **意图+锚点格式**(A方案核心):用 `intent` 表达"做什么",用 `anchor` 精确定位(有锚点则确定性命中,无则 LLM 兜底)。
159
223
  ```json
160
224
  [{"case_id":"Q-1","title":"正确账号密码登录","platform":"web","env":"test",
@@ -181,7 +245,7 @@ python "$R/.qoder/scripts/autotest.py" page --url /veh/insurance # 按URL查
181
245
  # AI 先写文件:
182
246
  # 写 workspace/members/{dev}/drafts/_autotest-cases.json
183
247
  # 再调:
184
- python "$R/.qoder/scripts/autotest.py" quick \
248
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test quick \
185
249
  --cases-file workspace/members/{dev}/drafts/_autotest-cases.json \
186
250
  --desc "<用户描述>" --platform <web|app>
187
251
  ```
@@ -220,32 +284,40 @@ python "$R/.qoder/scripts/autotest.py" quick \
220
284
  > ⚠️ **导航是 `browser_navigate`(不是 BrowserNavigate / navigate)**。
221
285
  > 调用前对照上面清单,名字写错 = 工具不存在 = 整个测试失败。
222
286
 
287
+ **🔴 调用效率(实测:一次登录测试不该超过 12 步调用):**
288
+ 1. **工具批量加载**:进入执行阶段时,在一个回合里并发加载所有要用的 `browser_*` 工具描述(navigate/snapshot/click/type/take_screenshot/evaluate),不要用一个加载一个。
289
+ 2. **snapshot 不落地**:`browser_snapshot` 返回的 a11y 树**直接在对话里读**,禁止写 yml 文件再 Read 回来(每步省一次调用)。
290
+ 3. **有 anchor 连发不思考**:锚点已确定,`browser_type`/`browser_click` 直接按 role+name 操作,零模型调用。
291
+
223
292
  **对每个 step(用 Playwright MCP 工具,连着发,别每步深度思考):**
224
293
  1. **intent=goto** → `browser_navigate`(1 次)
225
- 2. **首次到新页面** → `browser_snapshot` **1 次**拿 a11y
294
+ 2. **首次到新页面** → `browser_snapshot` **1 次**拿 a11y 树(直接读,不写文件)
226
295
  3. **intent=click/fill**(锚点优先,**确定性匹配不思考**):
227
296
  - **有 anchor** → snapshot 结果里按 `role+name`/`placeholder` 直接匹配 → 拿到元素 → `browser_type`/`browser_click`(**零模型调用,连着发**)
228
297
  - **无 anchor** → 用 `desc` 语义匹配(1 次模型调用)
229
298
  - 匹配失败 → self-heal:重新 `browser_snapshot` + 重试,最多 2 次
230
- 4. **intent=extract** → 看 URL / read_page 判断(1 次模型调用)
299
+ 4. **intent=extract** → 看 URL / 当前页面判断(1 次模型调用)
231
300
  5. **intent=ask_human** → 暂停等人
232
301
  6. **intent=assert** → 确定性校验(零模型调用)
233
302
 
234
- ### Step 3.5:验证码识别一条龙(数学题)
303
+ ### Step 3.5:验证码识别一条龙(数学题)— 一气呵成,别绕路
235
304
 
236
305
  > **🔴 验证码铁律(实测反复踩坑):**
237
306
  > - **禁止用 Computer 截图 / zoom 截验证码**——实测反复失败、超时、浪费 5-6 步。
238
307
  > - **禁止填默认值/瞎蒙**(如 000000)。
239
308
  > - **唯一正确路径**:JS 提取 base64 → 存图 → Read 看 → 算答案 → 填 → 删图。固定 5 步,不偏离。
309
+ > - **验证码有时效(1-2 分钟),所以填完立刻点登录,中间别插别的操作。**
240
310
 
241
- 按这个**固定顺序**一次走完(用 Playwright MCP 工具,约 30 秒):
242
- 1. **`browser_snapshot`** 看页面元素,找到验证码图片元素
311
+ 按这个**固定顺序**一次走完(用 Playwright MCP 工具,约 30 秒,**连发不思考**):
312
+ 1. **`browser_snapshot`**(如果刚才已经 snapshot 过且页面没变,可跳过)看页面元素,找到验证码图片元素
243
313
  2. **`browser_take_screenshot`** 截验证码图片 → 存临时文件(稳定,不像 Computer 截图会失败)
244
314
  3. **Read 工具看图 → 算出答案**(QoderWork 自带视觉,1 次模型调用,数学题识别率高)
245
315
  4. **`browser_type`** 填答案到验证码输入框
246
- 5. **删掉临时图片**(bash `del _captcha.png`)
247
- > 验证码有时效(1-2 分钟),所以要快。过期了刷新重走一遍。
316
+ 5. **立刻 `browser_click` 点登录**(验证码刚填、还没过期,抓住窗口)
317
+ 6. **删掉临时图片**(bash `del _captcha.png`)
318
+ > 验证码过期了(提示"验证码已失效")→ 别纠结,直接刷新重走 1-5 步。
248
319
  > 识别完**必须删图**,不留垃圾。
320
+ > 自识别连续失败 2 次或明显是短信/扫码类 → 才交人(见 Step A 铁律⑤)。
249
321
 
250
322
  ### Step 4:回收结果 + 自学习沉淀(🔴 必须,不做完不出报告)
251
323
 
@@ -254,7 +326,7 @@ python "$R/.qoder/scripts/autotest.py" quick \
254
326
 
255
327
  **执行方式**:把测试结果 + 测试中 `browser_snapshot` 看到的页面元素一起回传:
256
328
  ```bash
257
- python "$R/.qoder/scripts/autotest.py" quick \
329
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test quick \
258
330
  --cases-file <之前的cases文件> \
259
331
  --record '{"Q-1":"pass","Q-2":"pass","Q-3":"pass"}' \
260
332
  --page-json '{"url":"/veh/vehicle/vehAffair/insurance","elements":[{"role":"textbox","name":"车牌号"},{"role":"button","name":"搜索"},{"role":"button","name":"新增"}]}'
@@ -275,11 +347,11 @@ python "$R/.qoder/scripts/autotest.py" quick \
275
347
  ## browser 基于任务的浏览器测试(用户明确给了任务名时)
276
348
 
277
349
  ```bash
278
- python "$R/.qoder/scripts/task.py" list # 确认任务存在
279
- python "$R/.qoder/scripts/autotest.py" generate <task> # 生成骨架到 autotest-cases.jsonl
350
+ cap.mcp.call("list_tasks", {}) # 确认任务存在
351
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test generate <task> # 生成骨架到 autotest-cases.jsonl
280
352
  # AI 读任务 PRD「验收标准」补全 steps/expected (真实数据用 {{ask:}}, 不搜源码)
281
- python "$R/.qoder/scripts/autotest.py" run <task> # 注入+出执行计划
282
- python "$R/.qoder/scripts/autotest.py" run <task> --record '{"..":"pass"}' # 回收结果
353
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test run <task> # 注入+出执行计划
354
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test run <task> --record '{"..":"pass"}' # 回收结果
283
355
  ```
284
356
 
285
357
  **回归测试增强(图谱 MCP)**:测接口改动时,用 `get_impact` 查影响范围,自动覆盖受影响页面:
@@ -300,6 +372,43 @@ JUnit 测试(Mock + MockMvc,Given-When-Then,`@DisplayName`,AssertJ)→
300
372
 
301
373
  ---
302
374
 
375
+ ## 📋 断言生成 assertion-gen(业务规则断言 · 第三档专用)
376
+
377
+ > 解决痛点:quick 模式的 `_check_expect` 能执行 `{fetch, jsonpath, equals}` 断言,
378
+ > 但那个 **equals 期望值从哪来** 没人管——靠 LLM 瞎编不可信。
379
+ > `assertion-gen` 把"PRD 验收标准 → 可执行断言"这条断链接上。
380
+
381
+ **分工(呼应图谱边界三条红线):**
382
+ - **人补语义**:PRD 里写结构化验收(Given-When-Then,或"条件-操作-预期"带接口名/状态码/字段值)
383
+ - **图谱补字段**:`page_probe` 查按钮→接口,`field_map` 查中文标题→字段名
384
+ - **真跑定对错**:assertion-gen 只产断言 JSON,跑不跑交给 quick/webaccess
385
+
386
+ **什么时候用**:业务规则断言(保险延期要审批、退保校验、状态流转)——这是 quick 通用模式
387
+ 搞不定的第三档。冒烟(页面没崩)、CRUD 流(新增→列表出现)用 quick 就够,不需要这个。
388
+
389
+ ```bash
390
+ # 从任务 PRD 的验收标准章节抿断言
391
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test assertion-gen --task <任务名> --page 保险
392
+
393
+ # 临时用 GWT 文本兜底(PRD 没写验收标准时)
394
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test assertion-gen \
395
+ --gwt "Given 已登录保险页 When 点击延期提交 Then 接口 /api/insurance/delay 返回 code=200 且 状态列显示审批中" \
396
+ --page 保险
397
+ ```
398
+
399
+ **输出**:`workspace/tasks/<task>/assertions.json`,每条断言带 `source` 置信度标记:
400
+ - `规则·句中含接口` / `图谱·按钮画像` = 可信(接口路径已确定)
401
+ - `需确认·字段未命中` = 待补(字段表查不到,留 `{{ask:}}` 占位)
402
+
403
+ **两条铁律(assertion-gen 内置):**
404
+ 1. **抽不到就老实说**:PRD 验收标准为空/纯描述 → 输出"无可抽取的结构化断言",**绝不编造**断言。
405
+ 2. **语义不背书**:字段补全命中标 `[图谱]`,查不到留占位标 `[需确认]`,不让图谱假装懂业务。
406
+
407
+ **下一步**:把 `assertions.json` 的 assertions 数组并进 quick 用例的 steps(`intent:"assert"`),
408
+ 用 webaccess 或 quick 执行真跑验证。**assertion-gen 自己不执行、不真跑。**
409
+
410
+ ---
411
+
303
412
  ## 🔐 测试数据处理原则(个人 vs 团队隔离)
304
413
 
305
414
  - **绝不编造**:账号/密码/手机号用 `{{ask:描述}}` 占位,问用户要。
@@ -307,9 +416,9 @@ JUnit 测试(Mock + MockMvc,Given-When-Then,`@DisplayName`,AssertJ)→
307
416
  域名才放 config(全团队一致)。账号密码每人不同 → 个人文档。
308
417
  - **个人文档**:`workspace/members/{你的名字}/autotest-data.yaml`(gitignored,永不 push)
309
418
  ```bash
310
- python "$R/.qoder/scripts/autotest.py" init-data # 生成模板
311
- python "$R/.qoder/scripts/autotest.py" set-data 登录账号 test --env test # 填(按环境/平台分块)
312
- python "$R/.qoder/scripts/autotest.py" list-data --env test # 查看(密码脱敏)
419
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test init-data # 生成模板
420
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test set-data 登录账号 test --env test # 填(按环境/平台分块)
421
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test list-data --env test # 查看(密码脱敏)
313
422
  ```
314
423
  run/quick 时按 env/platform 自动取最精确的值;`--data` 可临时覆盖。
315
424
 
@@ -319,7 +428,7 @@ run/quick 时按 env/platform 自动取最精确的值;`--data` 可临时覆
319
428
 
320
429
  **Step A:查登录态**
321
430
  ```bash
322
- python "$R/.qoder/scripts/autotest.py" login-state show
431
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test login-state show
323
432
  ```
324
433
 
325
434
  **Step B:按登录态决定行为**
@@ -340,8 +449,8 @@ python "$R/.qoder/scripts/autotest.py" login-state show
340
449
 
341
450
  ```bash
342
451
  # 手动操作(一般不用,AI 会自动):
343
- python "$R/.qoder/scripts/autotest.py" login-state mark --env pre --platform web # 标记已登录
344
- python "$R/.qoder/scripts/autotest.py" login-state clear --env pre # 清除(强制重登录)
452
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test login-state mark --env pre --platform web # 标记已登录
453
+ python "$R/.qoder/scripts/orchestration/wlkj.py" test login-state clear --env pre # 清除(强制重登录)
345
454
  ```
346
455
 
347
456
  ## 🧩 QoderWork 增强:浏览器自动执行(可选 · 无连接器则自动回退)
@@ -76,6 +76,13 @@
76
76
  #### 原型地址
77
77
  {prototype-{feature}.html 的路径;两端需求分别给 -web/-app 两个文件}
78
78
 
79
+ > **原型可选(v3.1)**:若本需求为纯规则/接口/定时/参数下发/计算类(无 UI 变化),
80
+ > 经用户在「轻反思+批量确认」环节明确同意不画原型后,本节写:
81
+ > `无({原因},经用户确认豁免)`
82
+ > 并在 PRD 第 1 行 `@contract` 头标记 `prototype: none`。
83
+ > 下游 `/wl-design` 读到 `prototype: none` 跳过原型环节;`/wl-code` 直接以 PRD 字段表为准。
84
+ > eval_prd 检测到 `prototype: none` 时 A2 自动跳过(满分从 100 降到 70,照样能 PASS)。
85
+
79
86
  ## 非功能性需求
80
87
  {性能(响应时间/并发)、安全(权限)、兼容性(浏览器/系统版本)、可用性}
81
88