@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,27 +1,43 @@
1
1
  # 角色定义 (与 kg.py ROLE_SECTIONS 的 5 角色对齐)
2
2
  # commands: 该角色建议主用的命令 (软引导, 不拦截 —— 任何角色都能跑任何命令)
3
- # permissions: 声明式权限 (当前未强制执行, 留作未来硬权限墙)
3
+ # permissions: 声明式权限 (遗留字段, 向后兼容)
4
+ #
5
+ # ★ 能力边界 (v3.0+ 解耦核心) ★
6
+ # can_produce: 该角色允许产出的契约类型 (guard.py 强制, 越权则降级)
7
+ # can_consume: 该角色允许读取/消费的能力 (越权则只读降级)
8
+ # 契约类型必须与 contracts/schemas/*.schema.json 的 type 对齐:
9
+ # prd / prototype / spec / design-spec / code / unit-test / test-report / task
4
10
  roles:
5
11
  pm:
6
12
  name: 产品经理
7
13
  permissions: [create_task, write_prd, approve_prd, review_spec]
8
- commands: [wl-init, wl-insight, wl-prd-full, wl-prd-quick, wl-prd-review, wl-design, wl-task, wl-search, wl-status, wl-report]
14
+ commands: [wl-init, wl-insight, wl-prd, wl-design, wl-task, wl-search, wl-status, wl-report]
15
+ can_produce: [prd, prototype]
16
+ can_consume: ["*"] # PM 需读代码做现状分析
9
17
  design:
10
18
  name: 设计师
11
19
  permissions: [upload_design, approve_design]
12
20
  commands: [wl-init, wl-design, wl-search, wl-status]
21
+ can_produce: [design-spec, prototype]
22
+ can_consume: [prd, code-search]
13
23
  dev:
14
24
  name: 开发
15
25
  permissions: [write_spec, implement, commit, review_code]
16
26
  commands: [wl-init, wl-spec, wl-code, wl-test, wl-search, wl-commit, wl-status]
27
+ can_produce: [spec, code, unit-test]
28
+ can_consume: [prd, prototype, task]
17
29
  test:
18
30
  name: 测试
19
31
  permissions: [run_test, review_acceptance]
20
32
  commands: [wl-init, wl-test, wl-search, wl-status]
33
+ can_produce: [test-report, test-cases, unit-test]
34
+ can_consume: [prd, task, prototype]
21
35
  admin:
22
36
  name: 管理员
23
37
  permissions: [manage_index, manage_members, all]
24
38
  commands: [wl-init, wl-status, wl-search, wl-report]
39
+ can_produce: ["*"]
40
+ can_consume: ["*"]
25
41
 
26
42
  pipeline:
27
43
  workspace_dir: workspace
@@ -32,20 +48,42 @@ pipeline:
32
48
  auto_spec_on_prd_push: true
33
49
  req_id_start: 1
34
50
 
35
- # ── MySQL 只读 MCP (QAS 测试环境, 团队共享) ──
51
+ # ── MySQL 只读 MCP (团队共享, 多环境) ──
52
+ # AI 查数据库时会先问"查哪个环境",用这里的标签让用户选。
53
+ # 标签名自定义 (test/pre/prod 或 qa/staging...),对应 environments 下的 key。
54
+ # 没配 environments (旧扁平结构) 时兼容:当作只有 default_env 一个环境。
36
55
  mysql:
37
- host: 10.54.6.9
38
- port: 3306
39
- user: fywl_ics_test
40
- password: Fywl_ics_test56476
41
- env_name: "QAS 测试环境"
56
+ default_env: test # AI 不指定 / 用户不选时的默认环境
57
+ environments:
58
+ test: # 测试环境
59
+ host: 10.54.6.9
60
+ port: 3306
61
+ user: fywl_ics_test
62
+ password: Fywl_ics_test56476
63
+ env_name: "QAS 测试环境" # 显示标签,会随查询结果返回提醒 AI 当前在哪个环境
64
+ pre: # 预生产环境 (按需填, 不用可整段删)
65
+ host: 10.54.6.10
66
+ port: 3306
67
+ user: fywl_ics_pre_ro
68
+ password: ""
69
+ env_name: "预生产环境"
70
+ prod: # 生产环境 (⚠️ 只读账号! 配了才能查, 查时 AI 会标红提醒)
71
+ host: fywl-mysql.rwlb.rds.aliyuncs.com
72
+ port: 3306
73
+ user: queryuser
74
+ password: "query2025_ics@infore"
75
+ env_name: "生产环境"
42
76
 
43
- # ── 禅道 MCP (自建内网, 团队共享) ──
44
- # /wl-task 对接禅道: 创建需求/查任务/跟踪状态
77
+ # ── 禅道 MCP (自建内网) ──
78
+ # v3.1.4: 禅道是【每人一个账号】(非团队共享)。
79
+ # - url (服务地址): 团队共享, 留这里。
80
+ # - user/password (个人凭据): 不放这里 (进 git 会泄露)。
81
+ # 每人各自填 workspace/members/{我}/.private/secrets/zentao.env:
82
+ # ZENTAO_USER=<你的禅道账号>
83
+ # ZENTAO_PASSWORD=<你的禅道密码>
84
+ # - 账号名映射: member.json 的 zentao_account (进 git, 用于归属过滤)。
45
85
  zentao:
46
86
  url: http://10.89.2.91/zentao
47
- user: hupan
48
- password: Aa123456
49
87
 
50
88
  # ── Platforms (知识图谱/搜索的平台映射, 换项目改这里即可) ──
51
89
  # search_index.py --platform <key或alias> 会过滤到对应 project 目录
@@ -89,14 +127,14 @@ team_remote:
89
127
 
90
128
  # ── Git Sync (Weekly) ──
91
129
  # 每个项目在 data/code/ 下有自己的 git 仓库
92
- # 运行: python .qoder/scripts/git_sync.py
130
+ # 运行: python .qoder/scripts/orchestration/wlkj.py git-sync
93
131
  # 或设 cron: 每周五 18:00
94
132
  #
95
133
  # ★ 源码仓库配置 (重要) ★
96
134
  # 把下面的 url 改成你团队的 git 地址 (Gitea/GitLab/GitHub 均可)。
97
135
  # branch 改成你的主分支。
98
136
  # 不知道填什么? 注释掉整个 projects 段, 手动把代码放到 data/code/<项目名>/ 即可。
99
- # 填完后跑: python .qoder/scripts/setup.py 会自动克隆+建索引。
137
+ # 填完后跑: python .qoder/scripts/orchestration/wlkj.py doctor --fix 会自动克隆+建索引。
100
138
  git_sync:
101
139
  schedule: "0 18 * * 5"
102
140
  projects:
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """post-tool-use.py - PostToolUse hook: 工具执行后自动埋点 (确定性, 治漏斗断链)
4
+
5
+ 吸收宿主确定性 hook 能力: 把"埋点"从"靠 AI 手动调 learn record"(老忘 → F2 漏斗数据残缺)
6
+ 升级为"宿主在工具执行后自动埋点"。AI 想忘都忘不了。
7
+
8
+ 触发场景 (只埋这几类, 不滥用):
9
+ - Write/Edit 落到 **/prd*.md 或 **/PRD*.md → 记 prd_written
10
+ - Write/Edit/MultiEdit 落到 **/task.json → 记 task_created
11
+ - Bash 跑了 git commit / team_sync push → 记 commit_done (兜底, 主路径在 team_sync.py)
12
+
13
+ 铁律:
14
+ - 永远 exit 0 (埋点绝不阻断工作流)
15
+ - 失败 try/except 静默 (hook 崩溃绝不阻塞会话)
16
+ - 幂等: 同一文件短时间内重复埋点靠 feedback.jsonl append 即可 (统计层去重)
17
+
18
+ 阻断契约: exit 0 放行 (本 hook 不阻断)。
19
+ stdin 字段名官方未公开, 兼容 tool_name/tool_input 等多种写法。
20
+ """
21
+ import json
22
+ import os
23
+ import re
24
+ import sys
25
+ from datetime import datetime
26
+
27
+ if sys.platform == 'win32':
28
+ try:
29
+ sys.stdout.reconfigure(encoding='utf-8')
30
+ sys.stderr.reconfigure(encoding='utf-8')
31
+ except Exception:
32
+ pass
33
+
34
+ BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
35
+ HOOK_ERRORS_LOG = os.path.join(BASE, '.qoder', '.runtime', 'hook-errors.log')
36
+
37
+ # 工具名: 宿主原生工具(大写) + 兼容别名
38
+ WRITE_TOOLS = {'write', 'edit', 'multiedit', 'str_replace_editor', 'create_file'}
39
+ COMMIT_RE = re.compile(r'git\s+commit|team_sync.*push|wlkj\.py\s+sync\s+push', re.IGNORECASE)
40
+
41
+
42
+ def _read_tool_info():
43
+ """从 stdin 读 {tool_name, tool_input}。兼容多种字段名。取不到返回 ({}, None)。"""
44
+ try:
45
+ if sys.stdin.isatty():
46
+ return {}, None
47
+ raw = sys.stdin.read().strip()
48
+ except Exception:
49
+ return {}, None
50
+ if not raw:
51
+ return {}, None
52
+ try:
53
+ data = json.loads(raw)
54
+ except (ValueError, TypeError):
55
+ return {}, None
56
+ if not isinstance(data, dict):
57
+ return {}, None
58
+ # tool_name 兼容
59
+ tool_name = None
60
+ for k in ('tool_name', 'name', 'tool'):
61
+ v = data.get(k)
62
+ if isinstance(v, str) and v.strip():
63
+ tool_name = v.strip()
64
+ break
65
+ # tool_input 兼容
66
+ tool_input = data.get('tool_input') or data.get('input') or data.get('args') or data.get('arguments')
67
+ if not isinstance(tool_input, dict):
68
+ tool_input = {}
69
+ return tool_input, tool_name
70
+
71
+
72
+ def _file_paths_from_input(tool_input, tool_name):
73
+ """从 tool_input 提取涉及的文件路径列表。兼容 Write/Edit/Bash 的不同参数名。"""
74
+ paths = []
75
+ for k in ('file_path', 'path', 'filename', 'filePath'):
76
+ v = tool_input.get(k)
77
+ if isinstance(v, str) and v:
78
+ paths.append(v)
79
+ # MultiEdit 可能多文件
80
+ for k in ('paths', 'files'):
81
+ v = tool_input.get(k)
82
+ if isinstance(v, list):
83
+ paths.extend(x for x in v if isinstance(x, str))
84
+ return paths
85
+
86
+
87
+ def _cmd_from_input(tool_input):
88
+ """Bash 工具的命令文本。"""
89
+ for k in ('command', 'cmd'):
90
+ v = tool_input.get(k)
91
+ if isinstance(v, str):
92
+ return v
93
+ return ''
94
+
95
+
96
+ def _dev():
97
+ """读当前开发者。失败返回 None。"""
98
+ df = os.path.join(BASE, '.qoder', '.developer')
99
+ try:
100
+ if not os.path.isfile(df):
101
+ return None
102
+ for line in open(df, encoding='utf-8'):
103
+ if 'name=' in line:
104
+ return line.split('name=', 1)[1].strip().split()[0]
105
+ except Exception:
106
+ pass
107
+ return None
108
+
109
+
110
+ def _append_event(event, data):
111
+ """best-effort append 一条事件到当前 dev 的 feedback.jsonl。避开 learn import 断链, 直接写文件。"""
112
+ try:
113
+ dev = _dev()
114
+ if not dev:
115
+ return
116
+ fb = os.path.join(BASE, 'workspace', 'members', dev, 'journal', 'feedback.jsonl')
117
+ os.makedirs(os.path.dirname(fb), exist_ok=True)
118
+ entry = {
119
+ 'ts': datetime.now().isoformat(timespec='seconds'),
120
+ 'dev': dev,
121
+ 'event': event,
122
+ 'data': data,
123
+ '_source': 'post-tool-use-hook', # 标记来源, 区别于 AI 主动埋点
124
+ }
125
+ with open(fb, 'a', encoding='utf-8') as f:
126
+ f.write(json.dumps(entry, ensure_ascii=False) + '\n')
127
+ except Exception:
128
+ pass # 铁律: 埋点失败绝不阻塞
129
+
130
+
131
+ def main():
132
+ try:
133
+ tool_input, tool_name = _read_tool_info()
134
+ tn = (tool_name or '').lower()
135
+
136
+ # 1. Write/Edit 落到 PRD / task.json → 埋点
137
+ if tn in WRITE_TOOLS or tn == 'bash':
138
+ paths = _file_paths_from_input(tool_input, tool_name)
139
+ for p in paths:
140
+ plow = p.lower().replace('\\', '/')
141
+ if 'prd' in os.path.basename(plow).lower() and plow.endswith('.md'):
142
+ _append_event('prd_written', {'prd': os.path.basename(p), 'tool': tool_name})
143
+ if plow.endswith('task.json'):
144
+ _append_event('task_touched', {'task_json': os.path.basename(os.path.dirname(p)), 'tool': tool_name})
145
+ # v3.1 软提示: prototype HTML 写完但缺来源锚定 → stderr 提醒(不阻断)
146
+ if 'prototype' in os.path.basename(plow) and plow.endswith('.html'):
147
+ try:
148
+ if os.path.isfile(p):
149
+ with open(p, encoding='utf-8', errors='ignore') as _f:
150
+ _ht = _f.read()[:8192]
151
+ import re as _re
152
+ if not _re.search(r'@prototype-source:|x-source-pages', _ht):
153
+ sys.stderr.write(
154
+ '[prototype 提醒] %s 缺来源锚定注释。\n'
155
+ ' → 在 <head> 加一行: <!-- @prototype-source: fywl-ui/.../index.vue -->\n'
156
+ ' → 没做这一步 = 没读真实代码就手抄模板, eval A2 会扣 5 分。\n' % os.path.basename(p))
157
+ except Exception:
158
+ pass # 软提示, 失败静默
159
+
160
+ # 2. Bash 跑了 commit/push → 兜底埋点 commit_done
161
+ if tn == 'bash':
162
+ cmd = _cmd_from_input(tool_input)
163
+ if cmd and COMMIT_RE.search(cmd):
164
+ _append_event('commit_done', {'source': 'post-tool-use-hook', 'cmd': cmd[:120]})
165
+
166
+ sys.exit(0) # 永远放行
167
+ except SystemExit:
168
+ raise
169
+ except Exception as e:
170
+ try:
171
+ os.makedirs(os.path.dirname(HOOK_ERRORS_LOG), exist_ok=True)
172
+ with open(HOOK_ERRORS_LOG, 'a', encoding='utf-8') as f:
173
+ f.write('[{}] post-tool-use: {}\n'.format(
174
+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str(e)[:200]))
175
+ except Exception:
176
+ pass
177
+ sys.exit(0)
178
+
179
+
180
+ if __name__ == '__main__':
181
+ main()
@@ -62,17 +62,8 @@ def _recent_hook_errors(hours=24, limit=3):
62
62
  except Exception:
63
63
  return []
64
64
 
65
- # Injected as REAL OUTPUT below (a comment here would never reach the AI)
66
- CRITICAL_RULE = NL.join([
67
- '## CRITICAL RULE',
68
- 'When user asks for /wl-prd-full, ALWAYS ask platform FIRST:',
69
- '"这个需求是针对哪个平台?',
70
- ' 1. Web 管理端 (fywl-ui) - Ant Design Vue + VxeGrid 风格',
71
- ' 2. APP 移动端 (Carmg-H5) - Vant 风格',
72
- ' 3. 两端都要',
73
- ' 请选择 (1/2/3):"',
74
- 'DO NOT skip this question. DO NOT auto-detect. ALWAYS ASK.',
75
- ])
65
+ # v3.0 M4: CRITICAL_RULE (会话开始主动推销工作流铁律 非侵入式改造)
66
+ # 平台询问逻辑保留在 wl-pipeline.md 规则1 (命令启动后才生效, 不在会话开头强推)
76
67
 
77
68
 
78
69
  def load_json_safe(path):
@@ -138,14 +129,14 @@ def get_index_info():
138
129
  recent = errors[-10:] # 取最后 10 行检查
139
130
  if len(recent) >= 3:
140
131
  lines.append('[WARN] hook 最近频繁失败 (%d 条错误), 详情见 .qoder/.runtime/hook-errors.log' % len(recent))
141
- lines.append(' 跑 python .qoder/scripts/init_doctor.py --fix 排查')
132
+ lines.append(' 跑 python .qoder/scripts/setup/init_doctor.py --fix 排查')
142
133
  except OSError:
143
134
  pass
144
135
 
145
136
  lines.append('## Knowledge Graph')
146
137
  lines.append('MCP工具 (QoderWork自动调用): search_code / get_impact / coverage_matrix / get_workflow 等11个')
147
- lines.append(' python .qoder/scripts/search_index.py <keyword> [--platform web|app]')
148
- lines.append(' python .qoder/scripts/context_pack.py <keyword> # 一次打包全部上下文')
138
+ lines.append(' python .qoder/scripts/io/search_index.py <keyword> [--platform web|app]')
139
+ lines.append(' python .qoder/scripts/io/context_pack.py <keyword> # 一次打包全部上下文')
149
140
 
150
141
  # DuckDB 知识图谱状态检查
151
142
  # Read role from .developer file
@@ -192,22 +183,23 @@ def get_index_info():
192
183
  # 管理员/开发: 能构建
193
184
  if code_newer or db_age_hours > 168: # 7天 = 168小时
194
185
  lines.append(' [WARN] 知识图谱过期! 代码有新变更.')
195
- lines.append(' → 管理员请运行: python .qoder/scripts/kg_build.py')
196
- lines.append(' → 完成后: python .qoder/scripts/team_sync.py push (共享给团队)')
186
+ lines.append(' → 管理员请运行: python .qoder/scripts/kg/kg_build.py')
187
+ lines.append(' → 完成后: python .qoder/scripts/io/team_sync.py push (共享给团队)')
197
188
  else:
198
189
  lines.append(' ✓ 知识图谱最新')
199
190
  else:
200
191
  # 非管理员: 只拉取
201
192
  if code_newer or db_age_hours > 168:
202
193
  lines.append(' [WARN] 知识图谱可能过期.')
203
- lines.append(' → 运行: python .qoder/scripts/team_sync.py pull (获取管理员最新构建)')
194
+ lines.append(' → 运行: python .qoder/scripts/io/team_sync.py pull (获取管理员最新构建)')
204
195
  else:
205
196
  lines.append(' ✓ 知识图谱最新')
206
197
 
207
198
  # 检查是否有未标注的模块 (提示AI做语义标注)
208
199
  try:
209
200
  import subprocess as _sp
210
- r = _sp.run([sys.executable, os.path.join(BASE, '.qoder', 'scripts', 'kg_semantic.py'), '--check'],
201
+ # v3.x: kg_semantic.py 已迁移到 domain/kg/graph/ (旧扁平路径不存在)
202
+ r = _sp.run([sys.executable, os.path.join(BASE, '.qoder', 'scripts', 'domain', 'kg', 'graph', 'kg_semantic.py'), '--check'],
211
203
  capture_output=True, text=True, encoding='utf-8', timeout=5)
212
204
  if r.stdout and 'semantic_labeling_needed' in r.stdout:
213
205
  import json as _json
@@ -220,9 +212,9 @@ def get_index_info():
220
212
  else:
221
213
  lines.append(' [MISSING] kg.duckdb 不存在!')
222
214
  if role in ('admin', 'dev'):
223
- lines.append(' → 运行: python .qoder/scripts/kg_build.py')
215
+ lines.append(' → 运行: python .qoder/scripts/kg/kg_build.py')
224
216
  else:
225
- lines.append(' → 运行: python .qoder/scripts/team_sync.py pull')
217
+ lines.append(' → 运行: python .qoder/scripts/io/team_sync.py pull')
226
218
 
227
219
  return NL.join(lines)
228
220
 
@@ -235,8 +227,8 @@ def get_style_info():
235
227
 
236
228
  lines = []
237
229
  lines.append('## UI Style Index')
238
- lines.append('Style search: python .qoder/scripts/search_index.py --style <table|form|modal>')
239
- lines.append('Field search: python .qoder/scripts/search_index.py --field <name>')
230
+ lines.append('Style search: python .qoder/scripts/io/search_index.py --style <table|form|modal>')
231
+ lines.append('Field search: python .qoder/scripts/io/search_index.py --field <name>')
240
232
 
241
233
  for proj, d in meta.get('projects', {}).items():
242
234
  vue = d.get('vue_files', 0)
@@ -254,6 +246,81 @@ def get_style_info():
254
246
  return NL.join(lines)
255
247
 
256
248
 
249
+ def get_usability_summary():
250
+ """读工作流可用性指标, 把"不达标"项注入会话上下文。
251
+
252
+ 吸收宿主 SessionStart hook 能力: 不用等用户跑 /wl-status, 每次开会话主动
253
+ 暴露"工作流用没用起来"的红灯项。只展示红/黄 (绿的不打扰), 无数据则不显示。
254
+ (与 usability_score.py 同源逻辑, 但 hook 内联精简版, 避免 import 验证脚本拖慢启动)
255
+ """
256
+ lines = []
257
+ try:
258
+ # U2 一次过审率 (从 eval-history 取首条)
259
+ eval_path = os.path.join(BASE, 'data', 'learning', 'eval-history.jsonl')
260
+ records = []
261
+ if os.path.isfile(eval_path):
262
+ with open(eval_path, encoding='utf-8', errors='replace') as f:
263
+ for ln in f:
264
+ ln = ln.strip()
265
+ if ln:
266
+ try:
267
+ records.append(json.loads(ln))
268
+ except Exception:
269
+ continue
270
+ # 取最近 7 天
271
+ from datetime import datetime, timedelta
272
+ cutoff = datetime.now() - timedelta(days=7)
273
+ recent = []
274
+ for r in records:
275
+ t = r.get('time', '')
276
+ try:
277
+ if datetime.fromisoformat(str(t).split('.')[0]) >= cutoff:
278
+ recent.append(r)
279
+ except Exception:
280
+ continue
281
+
282
+ issues = [] # 只收红/黄
283
+ if recent:
284
+ passed = sum(1 for r in recent if r.get('passed'))
285
+ rate = 100.0 * passed / len(recent)
286
+ if rate < 60: # 黄线 30, 红线 60
287
+ tag = '🔴' if rate < 30 else '🟡'
288
+ issues.append('%s 一次过审率 %.0f%% (<60%% 目标) — PRD 质量需提升' % (tag, rate))
289
+
290
+ # U4 规则违反率 (从 feedback)
291
+ fb_dir = os.path.join(BASE, 'workspace', 'members')
292
+ violations = 0
293
+ prds_gen = 0
294
+ if os.path.isdir(fb_dir):
295
+ for dev in os.listdir(fb_dir):
296
+ fb = os.path.join(fb_dir, dev, 'journal', 'feedback.jsonl')
297
+ if not os.path.isfile(fb):
298
+ continue
299
+ try:
300
+ with open(fb, encoding='utf-8', errors='replace') as f:
301
+ for ln in f:
302
+ if '"rule_violation"' in ln:
303
+ violations += 1
304
+ elif '"prd_accepted"' in ln:
305
+ prds_gen += 1
306
+ except Exception:
307
+ continue
308
+ if prds_gen and violations:
309
+ vrate = 100.0 * violations / prds_gen
310
+ if vrate > 10:
311
+ tag = '🔴' if vrate > 25 else '🟡'
312
+ issues.append('%s 规则违反率 %.0f%% (>10%% 目标) — 关键规则没拦住' % (tag, vrate))
313
+
314
+ if issues:
315
+ lines.append('## Workflow Usability (近7天)')
316
+ lines.append('工作流"用不用得起来"红灯 (详情: wlkj.py usability):')
317
+ for it in issues:
318
+ lines.append(' ' + it)
319
+ except Exception:
320
+ pass # hook 失败绝不阻塞会话
321
+ return NL.join(lines) if lines else ''
322
+
323
+
257
324
  def main():
258
325
  parts = []
259
326
  parts.append('<qoder-context>')
@@ -282,8 +349,12 @@ def main():
282
349
  for t in tasks:
283
350
  parts.append(' [' + t['status'] + '] ' + t['name'] + ' - ' + t['title'])
284
351
 
352
+ usability = get_usability_summary()
353
+ if usability:
354
+ parts.append('')
355
+ parts.append(usability)
356
+
285
357
  parts.append('')
286
- parts.append(CRITICAL_RULE)
287
358
 
288
359
  idx_info = get_index_info()
289
360
  if idx_info: