@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,102 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- QODER Pipeline - Workspace Init
5
-
6
- Creates personal workspace under team workspace:
7
- workspace/members/{developer}/
8
- journal/
9
- drafts/
10
- inbox/
11
-
12
- Also syncs latest from git (git pull).
13
-
14
- Usage:
15
- python .qoder/scripts/workspace_init.py <developer-name>
16
- """
17
-
18
- from __future__ import annotations
19
-
20
- import os
21
- import subprocess
22
- import sys
23
- from datetime import datetime
24
- from pathlib import Path
25
-
26
- # Add scripts to path
27
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
28
-
29
- from common.paths import get_repo_root, get_developer, FILE_DEVELOPER
30
-
31
-
32
- def init_workspace(name: str) -> bool:
33
- """Initialize personal workspace under team workspace."""
34
- if not name:
35
- print("Error: developer name required", file=sys.stderr)
36
- return False
37
-
38
- repo_root = get_repo_root()
39
-
40
- # 1. Create .developer file in .qoder/ (engine)
41
- dev_file = repo_root / ".qoder" / FILE_DEVELOPER
42
- if dev_file.is_file():
43
- existing = get_developer(repo_root)
44
- if existing:
45
- print(f"Developer already: {existing}")
46
- print(f"Workspace: workspace/members/{existing}/")
47
- return True
48
-
49
- dev_file.write_text(
50
- f"name={name}\ninitialized_at={datetime.now().isoformat()}\n",
51
- encoding="utf-8"
52
- )
53
-
54
- # 2. Create personal workspace under team workspace
55
- personal = repo_root / "workspace" / "members" / name
56
- for sub in ["journal", "drafts", "inbox"]:
57
- (personal / sub).mkdir(parents=True, exist_ok=True)
58
-
59
- # 3. Create initial journal
60
- today = datetime.now().strftime("%Y-%m-%d")
61
- journal = personal / "journal" / f"journal-1.md"
62
- if not journal.exists():
63
- journal.write_text(
64
- f"# Journal - {name}\n\n> Started: {today}\n\n---\n\n",
65
- encoding="utf-8"
66
- )
67
-
68
- # 4. Git pull (sync latest)
69
- try:
70
- result = subprocess.run(
71
- ["git", "pull"],
72
- capture_output=True, text=True, cwd=str(repo_root), timeout=30
73
- )
74
- pull_msg = result.stdout.strip() if result.returncode == 0 else "already up to date"
75
- except Exception:
76
- pull_msg = "skipped (no remote)"
77
-
78
- print(f"Developer: {name}")
79
- print(f"Personal workspace: workspace/members/{name}/")
80
- print(f" journal/ session logs")
81
- print(f" drafts/ personal drafts")
82
- print(f" inbox/ pending items")
83
- print(f"Git sync: {pull_msg}")
84
- return True
85
-
86
-
87
- def main():
88
- if len(sys.argv) < 2:
89
- print("Usage: python .qoder/scripts/workspace_init.py <your-name>")
90
- print("Example: python .qoder/scripts/workspace_init.py zhangsan")
91
- sys.exit(1)
92
-
93
- name = sys.argv[1]
94
- if init_workspace(name):
95
- print("\nNext: say 'help me generate PRD' in Qoder to start pipeline")
96
- sys.exit(0)
97
- else:
98
- sys.exit(1)
99
-
100
-
101
- if __name__ == "__main__":
102
- main()
@@ -1,424 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- """ZenTao (禅道) MCP Server - 对接禅道项目管理, 替代本地 task。
4
-
5
- 禅道自建内网开源版 REST API。
6
- /wl-task 的底层从本地 task.json 切换到禅道。
7
-
8
- 工具:
9
- - list_products: 列产品(找到需求的归属)
10
- - list_stories: 列需求(PRD→禅道需求)
11
- - create_story: 创建需求(PRD发布→自动建禅道需求)
12
- - list_execution_tasks: 列执行的任务(谁在做什么)
13
- - get_story_detail: 查需求详情
14
-
15
- 认证: 用户名密码 → token (config.yaml zentao 段配, 团队共享)
16
- """
17
- import os
18
- import sys
19
- import json
20
- import socket
21
-
22
- try:
23
- sys.stdout.reconfigure(encoding='utf-8', errors='replace')
24
- sys.stderr.reconfigure(encoding='utf-8', errors='replace')
25
- except Exception:
26
- pass
27
-
28
- # 配置 (从环境变量或 config.yaml)
29
- ZENTAO_URL = os.environ.get('ZENTAO_URL', 'http://10.89.2.91/zentao')
30
- ZENTAO_USER = os.environ.get('ZENTAO_USER', 'hupan')
31
- ZENTAO_PASSWORD = os.environ.get('ZENTAO_PASSWORD', 'Aa123456')
32
- PING_HOST = ZENTAO_URL.replace('http://', '').replace('https://', '').split('/')[0]
33
- PING_PORT = 80 if '://' not in ZENTAO_URL or ':80' in ZENTAO_URL else (
34
- int(ZENTAO_URL.split(':')[2].split('/')[0]) if ZENTAO_URL.count(':') >= 2 else 80
35
- )
36
-
37
- _real_stdout = sys.stdout
38
- sys.stdout = sys.stderr
39
-
40
- try:
41
- import requests
42
- except ImportError:
43
- sys.stdout = _real_stdout
44
- print('[zentao-mcp] requests 未装, 跑 pip install requests')
45
- sys.exit(1)
46
-
47
- _TOKEN = None
48
- _SESSION = None
49
-
50
-
51
- def check_intranet():
52
- """内网连通性校验。"""
53
- try:
54
- host = PING_HOST
55
- port = PING_PORT
56
- with socket.create_connection((host, port), timeout=3):
57
- return True, ''
58
- except Exception as e:
59
- return False, '无法连接禅道 (%s): %s。请确认已连接内网。' % (ZENTAO_URL, str(e)[:60])
60
-
61
-
62
- def _get_token():
63
- """登录拿 token (缓存)。"""
64
- global _TOKEN
65
- if _TOKEN:
66
- return _TOKEN
67
- r = requests.post(
68
- ZENTAO_URL.rstrip('/') + '/api.php/v1/tokens',
69
- json={'account': ZENTAO_USER, 'password': ZENTAO_PASSWORD},
70
- timeout=10
71
- )
72
- if r.status_code in (200, 201):
73
- _TOKEN = r.json().get('token')
74
- return _TOKEN
75
- raise RuntimeError('禅道登录失败: %s %s' % (r.status_code, r.text[:100]))
76
-
77
-
78
- def _api(method, path, data=None):
79
- """调禅道 API。"""
80
- token = _get_token()
81
- url = ZENTAO_URL.rstrip('/') + '/api.php/v1' + path
82
- r = requests.request(method, url, headers={'Token': token},
83
- json=data if method in ('POST', 'PUT') else None,
84
- params=data if method == 'GET' else None,
85
- timeout=15)
86
- if r.status_code == 401:
87
- global _TOKEN
88
- _TOKEN = None
89
- token = _get_token()
90
- r = requests.request(method, url, headers={'Token': token},
91
- json=data if method in ('POST', 'PUT') else None,
92
- params=data if method == 'GET' else None,
93
- timeout=15)
94
- return r
95
-
96
-
97
- TOOLS = [
98
- {
99
- "name": "list_products",
100
- "description": "列禅道产品(找到需求归属)。例: list_products()",
101
- "inputSchema": {"type": "object", "properties": {}},
102
- },
103
- {
104
- "name": "list_stories",
105
- "description": "查某产品的需求列表。例: list_stories(product_id=1, limit=10)",
106
- "inputSchema": {
107
- "type": "object",
108
- "properties": {
109
- "product_id": {"type": "integer", "description": "产品ID"},
110
- "limit": {"type": "integer", "description": "返回数量(默认20)"},
111
- },
112
- "required": ["product_id"],
113
- },
114
- },
115
- {
116
- "name": "create_story",
117
- "description": "在禅道创建需求(PRD发布→禅道需求)。权限不足会返回友好提示不报错。例: create_story(product_id=1, title='品质案件催办', spec='需求详情', pri=3, module=104)",
118
- "inputSchema": {
119
- "type": "object",
120
- "properties": {
121
- "product_id": {"type": "integer", "description": "产品ID"},
122
- "title": {"type": "string", "description": "需求标题"},
123
- "spec": {"type": "string", "description": "需求描述"},
124
- "pri": {"type": "integer", "description": "优先级 1-4(1最高, 默认3)"},
125
- "module": {"type": "integer", "description": "模块ID(可选)"},
126
- "category": {"type": "string", "description": "类别(feature/interface/optimization, 默认feature)"},
127
- },
128
- "required": ["product_id", "title", "spec"],
129
- },
130
- },
131
- {
132
- "name": "list_plans",
133
- "description": "查某产品的计划/迭代列表(让用户选归属)。例: list_plans(product_id=1)",
134
- "inputSchema": {
135
- "type": "object",
136
- "properties": {
137
- "product_id": {"type": "integer", "description": "产品ID"},
138
- },
139
- "required": ["product_id"],
140
- },
141
- },
142
- {
143
- "name": "list_executions",
144
- "description": "查活跃的执行/迭代(按周划分的后端/前端/移动端)。例: list_executions(limit=5)",
145
- "inputSchema": {
146
- "type": "object",
147
- "properties": {
148
- "limit": {"type": "integer", "description": "返回数量(默认10)"},
149
- },
150
- },
151
- },
152
- {
153
- "name": "link_story_to_execution",
154
- "description": "把需求关联到执行/迭代(让开发能看到)。权限不足返回提示不报错。例: link_story_to_execution(story_id=761, execution_id=73)",
155
- "inputSchema": {
156
- "type": "object",
157
- "properties": {
158
- "story_id": {"type": "integer", "description": "需求ID"},
159
- "execution_id": {"type": "integer", "description": "执行ID"},
160
- },
161
- "required": ["story_id", "execution_id"],
162
- },
163
- },
164
- {
165
- "name": "assign_story",
166
- "description": "指派需求给某人(设负责人)。权限不足返回提示不报错。例: assign_story(story_id=761, account='hupan')",
167
- "inputSchema": {
168
- "type": "object",
169
- "properties": {
170
- "story_id": {"type": "integer", "description": "需求ID"},
171
- "account": {"type": "string", "description": "禅道账号"},
172
- },
173
- "required": ["story_id", "account"],
174
- },
175
- },
176
- {
177
- "name": "change_story_status",
178
- "description": "变更需求状态(draft→reviewing→active→closed)。权限不足返回提示不报错。例: change_story_status(story_id=761, status='active')",
179
- "inputSchema": {
180
- "type": "object",
181
- "properties": {
182
- "story_id": {"type": "integer", "description": "需求ID"},
183
- "status": {"type": "string", "description": "目标状态(draft/reviewing/active/closed)"},
184
- },
185
- "required": ["story_id", "status"],
186
- },
187
- },
188
- {
189
- "name": "list_execution_tasks",
190
- "description": "查某执行的任务列表(谁在做什么)。例: list_execution_tasks(execution_id=73)",
191
- "inputSchema": {
192
- "type": "object",
193
- "properties": {
194
- "execution_id": {"type": "integer", "description": "执行ID"},
195
- "limit": {"type": "integer", "description": "返回数量"},
196
- },
197
- "required": ["execution_id"],
198
- },
199
- },
200
- {
201
- "name": "get_story_detail",
202
- "description": "查需求详情(完整描述+状态+关联)。例: get_story_detail(story_id=761)",
203
- "inputSchema": {
204
- "type": "object",
205
- "properties": {
206
- "story_id": {"type": "integer", "description": "需求ID"},
207
- },
208
- "required": ["story_id"],
209
- },
210
- },
211
- ]
212
-
213
-
214
- def _execute_tool(name, args):
215
- args = args or {}
216
- ok, msg = check_intranet()
217
- if not ok:
218
- return msg
219
-
220
- if name == 'list_products':
221
- r = _api('GET', '/products')
222
- if r.status_code != 200:
223
- return '查询失败: %s' % r.text[:100]
224
- products = r.json().get('products', [])
225
- lines = ['禅道产品 (%d 个):' % len(products)]
226
- for p in products:
227
- lines.append(' [%s] %s' % (p.get('id'), p.get('name', '')[:20]))
228
- return '\n'.join(lines)
229
-
230
- if name == 'list_stories':
231
- pid = args.get('product_id', 1)
232
- limit = args.get('limit', 20)
233
- r = _api('GET', '/products/%s/stories' % pid, {'limit': limit})
234
- if r.status_code not in (200, 201):
235
- return '查询失败: %s' % r.text[:100]
236
- stories = r.json().get('stories', [])
237
- lines = ['产品 %s 的需求 (%d 个):' % (pid, len(stories))]
238
- for s in stories[:limit]:
239
- lines.append(' [#%s] %s (pri=%s status=%s)' % (
240
- s.get('id'), s.get('title', '')[:30], s.get('pri'), s.get('status')))
241
- return '\n'.join(lines)
242
-
243
- if name == 'create_story':
244
- pid = args.get('product_id', 1)
245
- payload = {
246
- 'title': args.get('title', ''),
247
- 'spec': args.get('spec', ''),
248
- 'category': args.get('category', 'feature'),
249
- 'pri': args.get('pri', 3),
250
- }
251
- if args.get('module'):
252
- payload['module'] = args['module']
253
- r = _api('POST', '/products/%s/stories' % pid, payload)
254
- if r.status_code in (200, 201):
255
- d = r.json()
256
- sid = d.get('id', '?')
257
- return '✅ 需求已创建! ID=%s\n禅道地址: %s/story-view-%s.html' % (
258
- sid, ZENTAO_URL.rstrip('/'), sid)
259
- # 权限不足或字段错误, 友好返回不崩
260
- try:
261
- err = r.json().get('error', r.text[:100])
262
- except Exception:
263
- err = r.text[:100]
264
- return '⚠️ 需求创建失败: %s\n(可能权限不足或字段缺失, 不影响其它操作)' % err
265
-
266
- if name == 'list_plans':
267
- pid = args.get('product_id', 1)
268
- r = _api('GET', '/products/%s/plans' % pid)
269
- if r.status_code != 200:
270
- return '查询计划失败: %s' % r.text[:100]
271
- plans = r.json().get('plans', [])
272
- if not plans:
273
- return '产品 %s 暂无计划。可在禅道里创建计划/迭代。' % pid
274
- lines = ['产品 %s 的计划 (%d 个):' % (pid, len(plans))]
275
- for p in plans:
276
- lines.append(' [%s] %s (%s~%s)' % (
277
- p.get('id'), str(p.get('title', ''))[:20], p.get('begin', ''), p.get('end', '')))
278
- return '\n'.join(lines)
279
-
280
- if name == 'list_executions':
281
- limit = args.get('limit', 10)
282
- r = _api('GET', '/executions', {'limit': limit})
283
- if r.status_code != 200:
284
- return '查询执行失败: %s' % r.text[:100]
285
- execs = r.json().get('executions', [])
286
- lines = ['活跃执行/迭代 (%d 个):' % len(execs)]
287
- for ex in execs[:limit]:
288
- lines.append(' [%s] %s (%s~%s project=%s)' % (
289
- ex.get('id'), str(ex.get('name', ''))[:15],
290
- ex.get('begin', ''), ex.get('end', ''), ex.get('project', '')))
291
- return '\n'.join(lines)
292
-
293
- if name == 'link_story_to_execution':
294
- sid = args.get('story_id', 0)
295
- eid = args.get('execution_id', 0)
296
- r = _api('POST', '/executions/%s/stories' % eid, {'stories': [sid]})
297
- if r.status_code in (200, 201):
298
- return '✅ 需求 #%s 已关联到执行 #%s' % (sid, eid)
299
- try:
300
- err = r.json().get('error', r.text[:100])
301
- except Exception:
302
- err = r.text[:100]
303
- return '⚠️ 关联失败: %s\n(可能权限不足, 需在禅道手动关联)' % err
304
-
305
- if name == 'assign_story':
306
- sid = args.get('story_id', 0)
307
- account = args.get('account', '')
308
- r = _api('POST', '/stories/%s/assign' % sid, {'assignedTo': account})
309
- if r.status_code in (200, 201):
310
- return '✅ 需求 #%s 已指派给 %s' % (sid, account)
311
- try:
312
- err = r.json().get('error', r.text[:100])
313
- except Exception:
314
- err = r.text[:100]
315
- return '⚠️ 指派失败: %s\n(可能权限不足, 需在禅道手动指派)' % err
316
-
317
- if name == 'change_story_status':
318
- sid = args.get('story_id', 0)
319
- status = args.get('status', '')
320
- r = _api('POST', '/stories/%s/change' % sid, {'status': status})
321
- if r.status_code in (200, 201):
322
- return '✅ 需求 #%s 状态变更为 %s' % (sid, status)
323
- try:
324
- err = r.json().get('error', r.text[:100])
325
- except Exception:
326
- err = r.text[:100]
327
- return '⚠️ 状态变更失败: %s\n(可能权限不足或状态转换不合法)' % err
328
-
329
- if name == 'list_execution_tasks':
330
- eid = args.get('execution_id', 1)
331
- r = _api('GET', '/executions/%s/tasks' % eid)
332
- if r.status_code != 200:
333
- return '查询失败: %s' % r.text[:100]
334
- tasks = r.json().get('tasks', [])
335
- lines = ['执行 %s 的任务 (%d 个):' % (eid, len(tasks))]
336
- for t in tasks[:20]:
337
- if isinstance(t, dict):
338
- lines.append(' [#%s] %s (assignedTo=%s status=%s)' % (
339
- t.get('id'), str(t.get('name', ''))[:25],
340
- t.get('assignedTo', ''), t.get('status', '')))
341
- return '\n'.join(lines)
342
-
343
- if name == 'get_story_detail':
344
- sid = args.get('story_id', 0)
345
- r = _api('GET', '/stories/%s' % sid)
346
- if r.status_code != 200:
347
- return '查询失败: %s' % r.text[:100]
348
- s = r.json()
349
- return '需求 #%s: %s\n状态: %s\n优先级: %s\n描述: %s' % (
350
- sid, s.get('title', ''), s.get('status', ''),
351
- s.get('pri', ''), str(s.get('spec', ''))[:200])
352
-
353
- return '未知工具: %s' % name
354
-
355
-
356
- # ── MCP Stdio Protocol ──
357
- def _send(msg):
358
- _real_stdout.write(json.dumps(msg, ensure_ascii=False) + '\n')
359
- _real_stdout.flush()
360
-
361
-
362
- async def _handle(req):
363
- method = req.get('method', '')
364
- req_id = req.get('id')
365
- params = req.get('params', {})
366
-
367
- if method == 'initialize':
368
- ok, msg = check_intranet()
369
- info = {"name": "qoder-zentao", "version": "1.0.0"}
370
- if not ok:
371
- info['warning'] = msg
372
- _send({"jsonrpc": "2.0", "id": req_id, "result": {
373
- "protocolVersion": "2024-11-05",
374
- "capabilities": {"tools": {}}, "serverInfo": info}})
375
- elif method == 'notifications/initialized':
376
- pass
377
- elif method == 'tools/list':
378
- _send({"jsonrpc": "2.0", "id": req_id, "result": {"tools": TOOLS}})
379
- elif method == 'tools/call':
380
- import asyncio
381
- try:
382
- result = await asyncio.get_event_loop().run_in_executor(
383
- None, _execute_tool, params.get('name', ''), params.get('arguments', {}))
384
- _send({"jsonrpc": "2.0", "id": req_id, "result": {
385
- "content": [{"type": "text", "text": result}], "isError": False}})
386
- except Exception as e:
387
- _send({"jsonrpc": "2.0", "id": req_id, "result": {
388
- "content": [{"type": "text", "text": "[error] %s" % str(e)[:200]}],
389
- "isError": True}})
390
- elif method == 'ping':
391
- _send({"jsonrpc": "2.0", "id": req_id, "result": {}})
392
- elif req_id is not None:
393
- _send({"jsonrpc": "2.0", "id": req_id,
394
- "error": {"code": -32601, "message": "Method not found"}})
395
-
396
-
397
- def main():
398
- import asyncio
399
- while True:
400
- try:
401
- line = sys.stdin.buffer.readline()
402
- except (EOFError, OSError):
403
- break
404
- if not line:
405
- break
406
- line = line.strip()
407
- if not line:
408
- continue
409
- try:
410
- req = json.loads(line.decode('utf-8'))
411
- loop = asyncio.new_event_loop()
412
- loop.run_until_complete(_handle(req))
413
- loop.close()
414
- except json.JSONDecodeError:
415
- pass
416
- except Exception as e:
417
- print('[zentao-mcp] error: %s' % str(e)[:80])
418
-
419
-
420
- if __name__ == '__main__':
421
- try:
422
- main()
423
- except KeyboardInterrupt:
424
- pass
@@ -1,90 +0,0 @@
1
- ---
2
- name: prompt-enrich
3
- description: "提问润色(第0步): 用户每条消息后先跑极速润色(<10ms), 定位业务上下文, 输出润色结果给用户确认, 再走原命令。触发: 每条含业务词的用户消息。"
4
- trigger: "用户每条消息(含业务关键词时)"
5
- always_apply: true
6
- ---
7
-
8
-
9
- ## 🔧 仓库根定位(QoderWork 桌面端 vs Qoder IDE/CLI)
10
-
11
- **后续脚本里的 `$R` 代表仓库根**,先确定它(QoderWork 桌面端工作目录不是仓库根,相对路径会失效):
12
- ```bash
13
- R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
14
- ```
15
- > `repo_root.py` 从 `~/.qoderwork/mcp.json` 反推仓库根;失败回退 `.`(IDE/CLI 工作目录即仓库根)。找不到时先跑 `python .qoder/scripts/install_qoderwork.py`。
16
-
17
- # prompt-enrich — 提问润色(每个命令的第 0 步)
18
-
19
- > **这是什么**:用户提问后,先极速判断这句话命中哪些业务上下文,输出一个「润色后的提示词」给用户确认,再走原命令。
20
- > **不是什么**:不是独立命令,是内置在每条消息处理前的第 0 步。
21
-
22
- ## 🚦 执行规则(每条用户消息都适用)
23
-
24
- 收到用户消息后,**在做任何其它事之前**,先判断:
25
-
26
- ### 第 0 步:极速润色(必须最先做)
27
-
28
- ```bash
29
- python "$R/.qoder/scripts/enrich_prompt.py" "<用户原话>" --json
30
- ```
31
-
32
- - 脚本纯内存查表,实测 **< 50ms**(冷启动含索引加载;热态 < 10ms)
33
- - 不跑重检索(那个留到确认后)
34
-
35
- **看返回的 `is_business` 字段**:
36
-
37
- | is_business | 意思 | 你怎么做 |
38
- |-------------|------|----------|
39
- | `false` | 非业务消息(谢谢/继续/确认润色等) | **跳过润色**,直接处理用户请求 |
40
- | `true` | 业务消息 | **输出润色块**,等用户确认 |
41
-
42
- ### is_business=true 时,输出润色块(严格按这个格式)
43
-
44
- ```
45
- 🔎 极速润色(Xms)— 直接用或回复「改:xxx」调整
46
- ─────────────────────────────────────
47
- 业务词: insurance, approval, abnormal...
48
- 相关代码: 19 处 (abnormal, anomaly, approval, exception...)
49
- 相关 API: /insurance
50
- ─────────────────────────────────────
51
- 将以此上下文继续。回复「好」接受,或「改: <你的调整>」。
52
- ```
53
-
54
- **然后停下,等用户回复。** 不要继续往下做命令。
55
-
56
- ### 用户确认后
57
-
58
- | 用户回复 | 你怎么做 |
59
- |---------|----------|
60
- | 「好」「继续」「接受」「确认」或任意无"改"字 | 接受润色,继续走原命令(prd/code/test...) |
61
- | 「改: 不要保险,只要批改」 | 按用户调整的上下文继续 |
62
- | 「不要润色」 | 跳过润色,用原话继续 |
63
-
64
- ---
65
-
66
- ## 关键约束
67
-
68
- 1. **必须最先做**:润色是第 0 步,排在平台询问、搜索、读文件之前。
69
- 例外:`/wl-init`、`/wl-search` 这种纯工具命令可跳过润色(它们不产契约)。
70
- 2. **极速**:只用 enrich_prompt.py,不用 context_pack(那是确认后的事)。
71
- 3. **可改可拒**:润色结果是建议,用户有最终决定权。
72
- 4. **不改变意图**:润色只补上下文,不改用户要做的事(还是 /wl-prd-full /wl-code 等)。
73
-
74
- ## 与其它命令的关系
75
-
76
- 润色是**横切关注点**,所有产契约的命令(prd/design/spec/code/test)都先过它:
77
-
78
- ```
79
- 用户: /wl-prd-full 保险批改那个异常统计页加个审批按钮
80
-
81
- 第0步: enrich_prompt → 输出润色块 → 用户确认
82
-
83
- 第1步起: /wl-prd-full 原流程(用确认后的上下文跑 context_pack)
84
- ```
85
-
86
- ## 为什么用脚本而不是靠 AI 自己想
87
-
88
- - **快**:纯内存查表纳秒级,AI 自己推理要秒级
89
- - **准**:复用 common/terms.py 的中文分词 + keyword-index,跟 /wl-search 同源
90
- - **一致**:每次润色逻辑一样,不依赖 AI 心情