@hupan56/wlkj 3.0.0 → 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 (237) hide show
  1. package/bin/cli.js +1435 -1373
  2. package/package.json +1 -1
  3. package/templates/qoder/commands/optional/wl-insight.md +6 -4
  4. package/templates/qoder/commands/optional/wl-report.md +20 -39
  5. package/templates/qoder/commands/optional/wl-status.md +4 -4
  6. package/templates/qoder/commands/wl-code.md +2 -2
  7. package/templates/qoder/commands/wl-design.md +5 -5
  8. package/templates/qoder/commands/wl-init.md +3 -3
  9. package/templates/qoder/commands/wl-prd.md +26 -13
  10. package/templates/qoder/commands/wl-req.md +3 -3
  11. package/templates/qoder/commands/wl-search.md +78 -47
  12. package/templates/qoder/commands/wl-task.md +343 -40
  13. package/templates/qoder/commands/wl-test.md +10 -10
  14. package/templates/qoder/config.yaml +35 -13
  15. package/templates/qoder/hooks/post-tool-use.py +181 -0
  16. package/templates/qoder/hooks/session-start.py +82 -1
  17. package/templates/qoder/hooks/stop-eval.py +207 -0
  18. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  19. package/templates/qoder/rules/wl-pipeline.md +70 -8
  20. package/templates/qoder/scripts/README.md +78 -115
  21. package/templates/qoder/scripts/capability/__init__.py +26 -0
  22. package/templates/qoder/scripts/capability/__main__.py +72 -0
  23. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  24. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  25. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  26. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  27. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  28. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  29. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  30. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  31. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  32. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  33. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  34. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  35. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  36. package/templates/qoder/scripts/capability/chain.py +92 -0
  37. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  38. package/templates/qoder/scripts/capability/registry.py +246 -0
  39. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  40. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  41. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  42. package/templates/qoder/scripts/{report → deployment/setup}/__init__.py +11 -11
  43. package/templates/qoder/scripts/{setup → deployment/setup}/carriers.py +33 -26
  44. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  45. package/templates/qoder/scripts/{setup → deployment/setup}/init_doctor.py +40 -16
  46. package/templates/qoder/scripts/{setup → deployment/setup}/install_qoderwork.py +20 -12
  47. package/templates/qoder/scripts/{setup → deployment/setup}/platform_doctor.py +8 -2
  48. package/templates/qoder/scripts/{setup → deployment/setup}/repo_root.py +113 -112
  49. package/templates/qoder/scripts/{setup → deployment/setup}/setup.py +31 -11
  50. package/templates/qoder/scripts/{setup → deployment/setup}/setup_lanhu.py +13 -7
  51. package/templates/qoder/scripts/domain/__init__.py +0 -0
  52. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  53. package/templates/qoder/scripts/{report → domain/design}/fill_prototype.py +12 -6
  54. package/templates/qoder/scripts/{report → domain/design}/gen_design_doc.py +8 -2
  55. package/templates/qoder/scripts/{setup → domain/kg}/__init__.py +11 -11
  56. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  57. package/templates/qoder/scripts/{kg → domain/kg/build}/build_entity_registry.py +7 -2
  58. package/templates/qoder/scripts/{kg → domain/kg/build}/build_relations.py +7 -2
  59. package/templates/qoder/scripts/{kg → domain/kg/build}/build_style_index.py +13 -7
  60. package/templates/qoder/scripts/{kg → domain/kg/build}/build_workflows.py +7 -2
  61. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build.py +76 -9
  62. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build_db.py +7 -2
  63. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_incremental.py +11 -6
  64. package/templates/qoder/scripts/{report → domain/kg/build}/learn_aggregate.py +9 -4
  65. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  66. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/test_extract.py +115 -115
  68. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  69. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  70. package/templates/qoder/scripts/{kg → domain/kg/graph}/kg_link_db.py +7 -2
  71. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  72. package/templates/qoder/scripts/{kg → domain/kg}/kg.py +263 -30
  73. package/templates/qoder/scripts/{common → domain/kg}/kg_capabilities.py +182 -182
  74. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  75. package/templates/qoder/scripts/{kg → domain/kg/search}/context_pack.py +30 -9
  76. package/templates/qoder/scripts/{kg → domain/kg/search}/enrich_prompt.py +10 -4
  77. package/templates/qoder/scripts/{kg → domain/kg/search}/prefetch.py +33 -8
  78. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  79. package/templates/qoder/scripts/{kg → domain/kg/search}/search_index.py +143 -77
  80. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  81. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  82. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  83. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  84. package/templates/qoder/scripts/{kg → domain/kg/storage}/kg_duckdb.py +38 -14
  85. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  86. package/templates/qoder/scripts/{report → domain/learning}/learn.py +8 -3
  87. package/templates/qoder/scripts/{mcp → domain/report}/__init__.py +11 -11
  88. package/templates/qoder/scripts/{report → domain/report}/add_session.py +9 -3
  89. package/templates/qoder/scripts/{report → domain/report}/export.py +10 -5
  90. package/templates/qoder/scripts/{report → domain/report}/report.py +9 -4
  91. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  92. package/templates/qoder/scripts/{report → domain/report}/role.py +10 -4
  93. package/templates/qoder/scripts/{report → domain/report}/status.py +112 -9
  94. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  95. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  96. package/templates/qoder/scripts/{report → domain/requirement}/archive_prd.py +8 -2
  97. package/templates/qoder/scripts/{report → domain/requirement}/req.py +228 -222
  98. package/templates/qoder/scripts/{kg → domain/task}/__init__.py +11 -11
  99. package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
  100. package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
  101. package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
  102. package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
  103. package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
  104. package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
  105. package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
  106. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  107. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  108. package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
  109. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  110. package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
  111. package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
  112. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
  113. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  114. package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
  115. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  116. package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
  117. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
  118. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  119. package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
  120. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
  121. package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
  122. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
  123. package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
  124. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  125. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  126. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
  127. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  128. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  129. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  130. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  131. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  132. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  133. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  134. package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
  135. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  136. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  137. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  138. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  139. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  140. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  141. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  142. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  143. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  144. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  145. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  146. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  147. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  148. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  153. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  154. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  155. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  156. package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
  157. package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
  158. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  159. package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
  160. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  161. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  162. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  163. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  164. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  165. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  166. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  167. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  168. package/templates/qoder/scripts/validation/__init__.py +0 -0
  169. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  171. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  172. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  173. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  174. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  175. package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
  176. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  177. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  178. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  179. package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
  180. package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
  181. package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
  182. package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
  183. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  184. package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
  185. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  186. package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
  187. package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
  188. package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
  189. package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
  190. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  191. package/templates/qoder/settings.json +30 -0
  192. package/templates/qoder/skills/design-import/SKILL.md +22 -13
  193. package/templates/qoder/skills/design-review/SKILL.md +19 -10
  194. package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
  195. package/templates/qoder/skills/prd-review/SKILL.md +6 -4
  196. package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
  197. package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
  198. package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
  199. package/templates/qoder/skills/test-generator/SKILL.md +7 -5
  200. package/templates/qoder/skills/wl-code/SKILL.md +23 -11
  201. package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
  202. package/templates/qoder/skills/wl-design/SKILL.md +5 -3
  203. package/templates/qoder/skills/wl-init/SKILL.md +6 -6
  204. package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
  205. package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
  206. package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
  207. package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
  208. package/templates/qoder/skills/wl-report/SKILL.md +25 -23
  209. package/templates/qoder/skills/wl-search/SKILL.md +149 -78
  210. package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
  211. package/templates/qoder/skills/wl-status/SKILL.md +48 -16
  212. package/templates/qoder/skills/wl-task/SKILL.md +92 -10
  213. package/templates/qoder/skills/wl-test/SKILL.md +75 -29
  214. package/templates/qoder/templates/prd-full-template.md +7 -0
  215. package/templates/root/AGENTS.md +275 -236
  216. package/templates/root/requirements.txt +3 -0
  217. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  218. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  219. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
  220. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
  221. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
  222. package/templates/.qoder/learning/eval-history.jsonl +0 -28
  223. package/templates/data/index/wiki-index.json +0 -8
  224. package/templates/qoder/nul +0 -4
  225. package/templates/qoder/scripts/kg/extract.py +0 -398
  226. package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
  227. package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
  228. package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
  229. package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
  230. package/templates/qoder/scripts/task/__init__.py +0 -11
  231. package/templates/qoder/scripts/test/__init__.py +0 -11
  232. package/templates/qoder/scripts/wlkj.py +0 -116
  233. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  234. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  235. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  236. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  237. /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
@@ -1,384 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
4
- import os as _o, sys as _s
5
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
6
- if _cp not in _s.path: _s.path.insert(0, _cp)
7
- from bootstrap import setup; setup()
8
-
9
- """ZenTao (禅道) MCP Server - 对接禅道项目管理, 替代本地 task。
10
-
11
- 禅道自建内网开源版 REST API。
12
- /wl-task 的底层从本地 task.json 切换到禅道。
13
-
14
- 工具:
15
- - list_products: 列产品(找到需求的归属)
16
- - list_stories: 列需求(PRD→禅道需求)
17
- - create_story: 创建需求(PRD发布→自动建禅道需求)
18
- - list_execution_tasks: 列执行的任务(谁在做什么)
19
- - get_story_detail: 查需求详情
20
-
21
- 认证: 用户名密码 → token (config.yaml zentao 段配, 团队共享)
22
- """
23
- import os
24
- import sys
25
- import json
26
- import socket
27
-
28
- try:
29
- sys.stdout.reconfigure(encoding='utf-8', errors='replace')
30
- sys.stderr.reconfigure(encoding='utf-8', errors='replace')
31
- except Exception:
32
- pass
33
-
34
- # 配置 (从环境变量或 config.yaml)
35
- ZENTAO_URL = os.environ.get('ZENTAO_URL', 'http://10.89.2.91/zentao')
36
- ZENTAO_USER = os.environ.get('ZENTAO_USER', 'hupan')
37
- ZENTAO_PASSWORD = os.environ.get('ZENTAO_PASSWORD', 'Aa123456')
38
- PING_HOST = ZENTAO_URL.replace('http://', '').replace('https://', '').split('/')[0]
39
- PING_PORT = 80 if '://' not in ZENTAO_URL or ':80' in ZENTAO_URL else (
40
- int(ZENTAO_URL.split(':')[2].split('/')[0]) if ZENTAO_URL.count(':') >= 2 else 80
41
- )
42
-
43
- # stdout 重定向 + 协议层由 BaseMCPServer 接管 (v3.0 重构)
44
- # 注意: requests 在 run() 内才需要 (延迟 import, 避免没装时启动即崩)
45
-
46
- _TOKEN = None
47
- _SESSION = None
48
-
49
-
50
- def check_intranet():
51
- """内网连通性校验。"""
52
- try:
53
- host = PING_HOST
54
- port = PING_PORT
55
- with socket.create_connection((host, port), timeout=3):
56
- return True, ''
57
- except Exception as e:
58
- return False, '无法连接禅道 (%s): %s。请确认已连接内网。' % (ZENTAO_URL, str(e)[:60])
59
-
60
-
61
- def _get_token():
62
- """登录拿 token (缓存)。"""
63
- global _TOKEN
64
- if _TOKEN:
65
- return _TOKEN
66
- r = requests.post(
67
- ZENTAO_URL.rstrip('/') + '/api.php/v1/tokens',
68
- json={'account': ZENTAO_USER, 'password': ZENTAO_PASSWORD},
69
- timeout=10
70
- )
71
- if r.status_code in (200, 201):
72
- _TOKEN = r.json().get('token')
73
- return _TOKEN
74
- raise RuntimeError('禅道登录失败: %s %s' % (r.status_code, r.text[:100]))
75
-
76
-
77
- def _api(method, path, data=None):
78
- """调禅道 API。"""
79
- token = _get_token()
80
- url = ZENTAO_URL.rstrip('/') + '/api.php/v1' + path
81
- r = requests.request(method, url, headers={'Token': token},
82
- json=data if method in ('POST', 'PUT') else None,
83
- params=data if method == 'GET' else None,
84
- timeout=15)
85
- if r.status_code == 401:
86
- global _TOKEN
87
- _TOKEN = None
88
- token = _get_token()
89
- r = requests.request(method, url, headers={'Token': token},
90
- json=data if method in ('POST', 'PUT') else None,
91
- params=data if method == 'GET' else None,
92
- timeout=15)
93
- return r
94
-
95
-
96
- TOOLS = [
97
- {
98
- "name": "list_products",
99
- "description": "列禅道产品(找到需求归属)。例: list_products()",
100
- "inputSchema": {"type": "object", "properties": {}},
101
- },
102
- {
103
- "name": "list_stories",
104
- "description": "查某产品的需求列表。例: list_stories(product_id=1, limit=10)",
105
- "inputSchema": {
106
- "type": "object",
107
- "properties": {
108
- "product_id": {"type": "integer", "description": "产品ID"},
109
- "limit": {"type": "integer", "description": "返回数量(默认20)"},
110
- },
111
- "required": ["product_id"],
112
- },
113
- },
114
- {
115
- "name": "create_story",
116
- "description": "在禅道创建需求(PRD发布→禅道需求)。权限不足会返回友好提示不报错。例: create_story(product_id=1, title='品质案件催办', spec='需求详情', pri=3, module=104)",
117
- "inputSchema": {
118
- "type": "object",
119
- "properties": {
120
- "product_id": {"type": "integer", "description": "产品ID"},
121
- "title": {"type": "string", "description": "需求标题"},
122
- "spec": {"type": "string", "description": "需求描述"},
123
- "pri": {"type": "integer", "description": "优先级 1-4(1最高, 默认3)"},
124
- "module": {"type": "integer", "description": "模块ID(可选)"},
125
- "category": {"type": "string", "description": "类别(feature/interface/optimization, 默认feature)"},
126
- },
127
- "required": ["product_id", "title", "spec"],
128
- },
129
- },
130
- {
131
- "name": "list_plans",
132
- "description": "查某产品的计划/迭代列表(让用户选归属)。例: list_plans(product_id=1)",
133
- "inputSchema": {
134
- "type": "object",
135
- "properties": {
136
- "product_id": {"type": "integer", "description": "产品ID"},
137
- },
138
- "required": ["product_id"],
139
- },
140
- },
141
- {
142
- "name": "list_executions",
143
- "description": "查活跃的执行/迭代(按周划分的后端/前端/移动端)。例: list_executions(limit=5)",
144
- "inputSchema": {
145
- "type": "object",
146
- "properties": {
147
- "limit": {"type": "integer", "description": "返回数量(默认10)"},
148
- },
149
- },
150
- },
151
- {
152
- "name": "link_story_to_execution",
153
- "description": "把需求关联到执行/迭代(让开发能看到)。权限不足返回提示不报错。例: link_story_to_execution(story_id=761, execution_id=73)",
154
- "inputSchema": {
155
- "type": "object",
156
- "properties": {
157
- "story_id": {"type": "integer", "description": "需求ID"},
158
- "execution_id": {"type": "integer", "description": "执行ID"},
159
- },
160
- "required": ["story_id", "execution_id"],
161
- },
162
- },
163
- {
164
- "name": "assign_story",
165
- "description": "指派需求给某人(设负责人)。权限不足返回提示不报错。例: assign_story(story_id=761, account='hupan')",
166
- "inputSchema": {
167
- "type": "object",
168
- "properties": {
169
- "story_id": {"type": "integer", "description": "需求ID"},
170
- "account": {"type": "string", "description": "禅道账号"},
171
- },
172
- "required": ["story_id", "account"],
173
- },
174
- },
175
- {
176
- "name": "change_story_status",
177
- "description": "变更需求状态(draft→reviewing→active→closed)。权限不足返回提示不报错。例: change_story_status(story_id=761, status='active')",
178
- "inputSchema": {
179
- "type": "object",
180
- "properties": {
181
- "story_id": {"type": "integer", "description": "需求ID"},
182
- "status": {"type": "string", "description": "目标状态(draft/reviewing/active/closed)"},
183
- },
184
- "required": ["story_id", "status"],
185
- },
186
- },
187
- {
188
- "name": "list_execution_tasks",
189
- "description": "查某执行的任务列表(谁在做什么)。例: list_execution_tasks(execution_id=73)",
190
- "inputSchema": {
191
- "type": "object",
192
- "properties": {
193
- "execution_id": {"type": "integer", "description": "执行ID"},
194
- "limit": {"type": "integer", "description": "返回数量"},
195
- },
196
- "required": ["execution_id"],
197
- },
198
- },
199
- {
200
- "name": "get_story_detail",
201
- "description": "查需求详情(完整描述+状态+关联)。例: get_story_detail(story_id=761)",
202
- "inputSchema": {
203
- "type": "object",
204
- "properties": {
205
- "story_id": {"type": "integer", "description": "需求ID"},
206
- },
207
- "required": ["story_id"],
208
- },
209
- },
210
- ]
211
-
212
-
213
- def _execute_tool(name, args):
214
- args = args or {}
215
- ok, msg = check_intranet()
216
- if not ok:
217
- return msg
218
-
219
- if name == 'list_products':
220
- r = _api('GET', '/products')
221
- if r.status_code != 200:
222
- return '查询失败: %s' % r.text[:100]
223
- products = r.json().get('products', [])
224
- lines = ['禅道产品 (%d 个):' % len(products)]
225
- for p in products:
226
- lines.append(' [%s] %s' % (p.get('id'), p.get('name', '')[:20]))
227
- return '\n'.join(lines)
228
-
229
- if name == 'list_stories':
230
- pid = args.get('product_id', 1)
231
- limit = args.get('limit', 20)
232
- r = _api('GET', '/products/%s/stories' % pid, {'limit': limit})
233
- if r.status_code not in (200, 201):
234
- return '查询失败: %s' % r.text[:100]
235
- stories = r.json().get('stories', [])
236
- lines = ['产品 %s 的需求 (%d 个):' % (pid, len(stories))]
237
- for s in stories[:limit]:
238
- lines.append(' [#%s] %s (pri=%s status=%s)' % (
239
- s.get('id'), s.get('title', '')[:30], s.get('pri'), s.get('status')))
240
- return '\n'.join(lines)
241
-
242
- if name == 'create_story':
243
- pid = args.get('product_id', 1)
244
- payload = {
245
- 'title': args.get('title', ''),
246
- 'spec': args.get('spec', ''),
247
- 'category': args.get('category', 'feature'),
248
- 'pri': args.get('pri', 3),
249
- }
250
- if args.get('module'):
251
- payload['module'] = args['module']
252
- r = _api('POST', '/products/%s/stories' % pid, payload)
253
- if r.status_code in (200, 201):
254
- d = r.json()
255
- sid = d.get('id', '?')
256
- return '✅ 需求已创建! ID=%s\n禅道地址: %s/story-view-%s.html' % (
257
- sid, ZENTAO_URL.rstrip('/'), sid)
258
- # 权限不足或字段错误, 友好返回不崩
259
- try:
260
- err = r.json().get('error', r.text[:100])
261
- except Exception:
262
- err = r.text[:100]
263
- return '⚠️ 需求创建失败: %s\n(可能权限不足或字段缺失, 不影响其它操作)' % err
264
-
265
- if name == 'list_plans':
266
- pid = args.get('product_id', 1)
267
- r = _api('GET', '/products/%s/plans' % pid)
268
- if r.status_code != 200:
269
- return '查询计划失败: %s' % r.text[:100]
270
- plans = r.json().get('plans', [])
271
- if not plans:
272
- return '产品 %s 暂无计划。可在禅道里创建计划/迭代。' % pid
273
- lines = ['产品 %s 的计划 (%d 个):' % (pid, len(plans))]
274
- for p in plans:
275
- lines.append(' [%s] %s (%s~%s)' % (
276
- p.get('id'), str(p.get('title', ''))[:20], p.get('begin', ''), p.get('end', '')))
277
- return '\n'.join(lines)
278
-
279
- if name == 'list_executions':
280
- limit = args.get('limit', 10)
281
- r = _api('GET', '/executions', {'limit': limit})
282
- if r.status_code != 200:
283
- return '查询执行失败: %s' % r.text[:100]
284
- execs = r.json().get('executions', [])
285
- lines = ['活跃执行/迭代 (%d 个):' % len(execs)]
286
- for ex in execs[:limit]:
287
- lines.append(' [%s] %s (%s~%s project=%s)' % (
288
- ex.get('id'), str(ex.get('name', ''))[:15],
289
- ex.get('begin', ''), ex.get('end', ''), ex.get('project', '')))
290
- return '\n'.join(lines)
291
-
292
- if name == 'link_story_to_execution':
293
- sid = args.get('story_id', 0)
294
- eid = args.get('execution_id', 0)
295
- r = _api('POST', '/executions/%s/stories' % eid, {'stories': [sid]})
296
- if r.status_code in (200, 201):
297
- return '✅ 需求 #%s 已关联到执行 #%s' % (sid, eid)
298
- try:
299
- err = r.json().get('error', r.text[:100])
300
- except Exception:
301
- err = r.text[:100]
302
- return '⚠️ 关联失败: %s\n(可能权限不足, 需在禅道手动关联)' % err
303
-
304
- if name == 'assign_story':
305
- sid = args.get('story_id', 0)
306
- account = args.get('account', '')
307
- r = _api('POST', '/stories/%s/assign' % sid, {'assignedTo': account})
308
- if r.status_code in (200, 201):
309
- return '✅ 需求 #%s 已指派给 %s' % (sid, account)
310
- try:
311
- err = r.json().get('error', r.text[:100])
312
- except Exception:
313
- err = r.text[:100]
314
- return '⚠️ 指派失败: %s\n(可能权限不足, 需在禅道手动指派)' % err
315
-
316
- if name == 'change_story_status':
317
- sid = args.get('story_id', 0)
318
- status = args.get('status', '')
319
- r = _api('POST', '/stories/%s/change' % sid, {'status': status})
320
- if r.status_code in (200, 201):
321
- return '✅ 需求 #%s 状态变更为 %s' % (sid, status)
322
- try:
323
- err = r.json().get('error', r.text[:100])
324
- except Exception:
325
- err = r.text[:100]
326
- return '⚠️ 状态变更失败: %s\n(可能权限不足或状态转换不合法)' % err
327
-
328
- if name == 'list_execution_tasks':
329
- eid = args.get('execution_id', 1)
330
- r = _api('GET', '/executions/%s/tasks' % eid)
331
- if r.status_code != 200:
332
- return '查询失败: %s' % r.text[:100]
333
- tasks = r.json().get('tasks', [])
334
- lines = ['执行 %s 的任务 (%d 个):' % (eid, len(tasks))]
335
- for t in tasks[:20]:
336
- if isinstance(t, dict):
337
- lines.append(' [#%s] %s (assignedTo=%s status=%s)' % (
338
- t.get('id'), str(t.get('name', ''))[:25],
339
- t.get('assignedTo', ''), t.get('status', '')))
340
- return '\n'.join(lines)
341
-
342
- if name == 'get_story_detail':
343
- sid = args.get('story_id', 0)
344
- r = _api('GET', '/stories/%s' % sid)
345
- if r.status_code != 200:
346
- return '查询失败: %s' % r.text[:100]
347
- s = r.json()
348
- return '需求 #%s: %s\n状态: %s\n优先级: %s\n描述: %s' % (
349
- sid, s.get('title', ''), s.get('status', ''),
350
- s.get('pri', ''), str(s.get('spec', ''))[:200])
351
-
352
- return '未知工具: %s' % name
353
-
354
-
355
- # ── MCP Server (继承 BaseMCPServer, 协议层由基类接管) ──────────────────
356
- # v3.0 重构: 删除 _send/_handle/main 三段逐字复制代码 (~69行),
357
- # 改为继承 BaseMCPServer (Template Method), 只填差异点。
358
-
359
- def _bootstrap_base():
360
- """延迟 import BaseMCPServer (scripts/ 在 sys.path)。"""
361
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
362
- from common.mcp_base import BaseMCPServer
363
- return BaseMCPServer
364
-
365
-
366
- class ZentaoMCPServer(_bootstrap_base()):
367
- """禅道 MCP Server。继承基类协议层, 只填工具逻辑。"""
368
-
369
- SERVER_NAME = "qoder-zentao"
370
- SERVER_VERSION = "1.0.0"
371
- TOOLS = TOOLS # 引用上方模块级 TOOLS
372
-
373
- def handle_tool(self, name, args):
374
- return _execute_tool(name, args)
375
-
376
- def on_initialize_hook(self, info):
377
- # 启动时内网校验, 不通塞 warning (与旧版行为一致)
378
- ok, msg = check_intranet()
379
- if not ok:
380
- info['warning'] = msg
381
-
382
-
383
- if __name__ == '__main__':
384
- ZentaoMCPServer().run()
@@ -1,11 +0,0 @@
1
- # 子包初始化: 注入 scripts/根 + 所有子包到 sys.path
2
- # 让跨包 import (旧式不带前缀) 仍可用, 兼容现有代码
3
- import os as _os, sys as _sys
4
- _root = _os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))
5
- if _root not in _sys.path:
6
- _sys.path.insert(0, _root)
7
- # 注入所有子包目录 (兼容旧式 import xxx)
8
- for _sub in ('kg', 'build', 'test', 'setup', 'io'):
9
- _subdir = _os.path.join(_root, _sub)
10
- if _os.path.isdir(_subdir) and _subdir not in _sys.path:
11
- _sys.path.insert(0, _subdir)
@@ -1,11 +0,0 @@
1
- # 子包初始化: 注入 scripts/根 + 所有子包到 sys.path
2
- # 让跨包 import (旧式不带前缀) 仍可用, 兼容现有代码
3
- import os as _os, sys as _sys
4
- _root = _os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))
5
- if _root not in _sys.path:
6
- _sys.path.insert(0, _root)
7
- # 注入所有子包目录 (兼容旧式 import xxx)
8
- for _sub in ('kg', 'build', 'test', 'setup', 'io'):
9
- _subdir = _os.path.join(_root, _sub)
10
- if _os.path.isdir(_subdir) and _subdir not in _sys.path:
11
- _sys.path.insert(0, _subdir)
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- wlkj.py - 工作流顶层调度器 (统一入口, 兼容旧调用)
5
-
6
- v3.0 引入: 把分散的脚本调用收敛到一个入口, 提供"逻辑分组"体验,
7
- 而不需要物理分子目录 (避免 170+ 处路径改写 + 40 处 sys.path 风险)。
8
-
9
- 用法 (与旧 python .qoder/scripts/xxx.py 等价):
10
- python .qoder/scripts/wlkj.py kg search 保险 --platform web
11
- python .qoder/scripts/wlkj.py task list
12
- python .qoder/scripts/wlkj.py doctor --fix
13
- python .qoder/scripts/wlkj.py search 考勤
14
- python .qoder/scripts/wlkj.py status
15
-
16
- 分组 (逻辑导航, 非物理目录):
17
- kg/* 知识图谱 (kg.py 的子命令直接透传)
18
- task 任务系统
19
- search 代码搜索
20
- doctor 环境体检
21
- status 项目状态
22
- sync 团队同步
23
- ...
24
-
25
- 设计:
26
- - 透明转发: 不改变任何子脚本的行为, 只是把 argv 转过去
27
- - 兼容: 旧的 `python .qoder/scripts/kg.py` 仍可用 (脚本都还在原位)
28
- - 零维护: 加新命令只需在 DISPATCH 表加一行
29
- """
30
-
31
- import os
32
- import subprocess
33
- import sys
34
-
35
- # 命令 → 脚本 映射 (加新命令只需在此加一行)
36
- # v3.0: 脚本已分子目录, 路径更新为 子包/脚本
37
- DISPATCH = {
38
- 'kg': 'kg/kg.py',
39
- 'task': 'task/task.py',
40
- 'sync': 'task/team_sync.py',
41
- 'team-sync': 'task/team_sync.py',
42
- 'git-sync': 'task/git_sync.py',
43
- 'search': 'kg/search_index.py',
44
- 'context': 'kg/context_pack.py',
45
- 'prefetch': 'kg/prefetch.py',
46
- 'status': 'report/status.py',
47
- 'report': 'report/report.py',
48
- 'doctor': 'setup/init_doctor.py',
49
- 'init': 'setup/setup.py',
50
- 'test': 'test/autotest.py',
51
- 'autotest': 'test/autotest.py',
52
- 'eval': 'report/eval_prd.py',
53
- 'eva': 'report/eval_prd.py',
54
- 'export': 'report/export.py',
55
- 'style': 'kg/build_style_index.py',
56
- 'role': 'report/role.py',
57
- }
58
-
59
-
60
- def _usage():
61
- lines = [
62
- 'wlkj.py — 工作流顶层调度器',
63
- '',
64
- '用法: python .qoder/scripts/wlkj.py <命令> [参数...]',
65
- '',
66
- '命令分组 (转发到对应脚本):',
67
- ' 知识图谱: kg <子命令> (kg.py, 13+ 能力)',
68
- ' 任务: task <子命令> (task.py, create/list/start/finish)',
69
- ' 同步: sync pull|push (team_sync.py)',
70
- ' 搜索: search <词> (search_index.py)',
71
- ' 上下文: context <词> (context_pack.py)',
72
- ' 体检: doctor [--fix] (init_doctor.py)',
73
- ' 状态: status (status.py)',
74
- ' 报告: report daily|weekly (report.py)',
75
- ' 测试: test <子命令> (autotest.py)',
76
- ' 评估: eval <prd.md> (eval_prd.py)',
77
- ' 导出: export <格式> (export.py)',
78
- '',
79
- '示例:',
80
- ' wlkj.py kg search 保险 --platform web',
81
- ' wlkj.py task create "登录优化"',
82
- ' wlkj.py doctor --fix',
83
- '',
84
- '注: 旧的 python .qoder/scripts/kg.py 形式仍可用 (脚本在原位)。',
85
- ]
86
- return '\n'.join(lines)
87
-
88
-
89
- def main():
90
- argv = sys.argv[1:]
91
- if not argv or argv[0] in ('-h', '--help', 'help'):
92
- print(_usage())
93
- return 0
94
-
95
- cmd = argv[0]
96
- rest = argv[1:]
97
-
98
- script = DISPATCH.get(cmd)
99
- if not script:
100
- # 未知命令: 提示 + 退出
101
- sys.stderr.write('未知命令: %s\n' % cmd)
102
- sys.stderr.write('可用命令: %s\n' % ', '.join(sorted(DISPATCH.keys())))
103
- return 1
104
-
105
- script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), script)
106
- if not os.path.isfile(script_path):
107
- sys.stderr.write('脚本不存在: %s\n' % script_path)
108
- return 1
109
-
110
- # 透明转发: 用当前 python 跑目标脚本, 透传所有参数和 exit code
111
- r = subprocess.run([sys.executable, script_path] + rest)
112
- return r.returncode
113
-
114
-
115
- if __name__ == '__main__':
116
- sys.exit(main())