@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
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ nexus CLI 入口 —— 诊断当前宿主能力。
5
+
6
+ 用法:
7
+ python .qoder/scripts/capability # 打印宿主 + 各能力 available
8
+ python -m nexus # 等价(需 scripts 在 sys.path)
9
+
10
+ 输出 JSON,便于人或脚本消费。
11
+ """
12
+ import json
13
+ import os
14
+ import sys
15
+
16
+
17
+ def _ensure_scripts_on_path():
18
+ """确保父目录 scripts/ 在 sys.path,使 nexus 包可被 import。"""
19
+ here = os.path.dirname(os.path.abspath(__file__))
20
+ scripts_dir = os.path.dirname(here)
21
+ if scripts_dir not in sys.path:
22
+ sys.path.insert(0, scripts_dir)
23
+
24
+
25
+ def main() -> int:
26
+ _ensure_scripts_on_path()
27
+ from capability.registry import resolve
28
+
29
+ cap = resolve()
30
+ desc = cap.describe()
31
+
32
+ # MCP server 详情
33
+ mcp_desc = cap.mcp.describe() if hasattr(cap.mcp, "describe") else {}
34
+
35
+ # memory 职责链详情
36
+ memory_chain = []
37
+ if hasattr(cap.memory, "providers_status"):
38
+ memory_chain = cap.memory.providers_status()
39
+ desc["memory_chain"] = memory_chain
40
+
41
+ # 格式化输出
42
+ print("宿主: %s" % desc.get("host", "?"))
43
+ print()
44
+ print("能力:")
45
+ for name, avail in desc.get("capabilities", {}).items():
46
+ icon = "✅" if avail else "❌"
47
+ print(" %s %s" % (icon, name))
48
+
49
+ if mcp_desc.get("servers"):
50
+ print()
51
+ print("MCP servers (tools=%d):" % mcp_desc.get("total_tools", 0))
52
+ for name, info in mcp_desc["servers"].items():
53
+ icon = "✅" if info.get("available") else "❌"
54
+ pid = " pid=%s" % info["spawn_pid"] if info.get("spawn_pid") else ""
55
+ latency = " latency=%sms" % info["latency_ms"] if info.get("latency_ms") is not None else ""
56
+ print(" %s %s: tools=%d%s%s" % (
57
+ icon, name, info.get("tools_indexed", 0), latency, pid))
58
+
59
+ if memory_chain:
60
+ print()
61
+ print("Memory 职责链:")
62
+ for p in memory_chain:
63
+ hit = " ← ACTIVE" if p.get("hit") else ""
64
+ print(" %s: available=%s%s" % (p["provider"], p["available"], hit))
65
+
66
+ print()
67
+ print(json.dumps(desc, ensure_ascii=False, indent=2))
68
+ return 0
69
+
70
+
71
+ if __name__ == "__main__":
72
+ sys.exit(main())
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ nexus.adapters —— 各宿主/降级路径的 Cap 实现。
4
+
5
+ 设计模式: Adapter + Bridge(Cap 抽象 × 宿主实现 正交)
6
+
7
+ 新增宿主(扩展场景 D)= 新建一个文件(如 devin.py)实现其提供的 Cap,
8
+ 在 registry 的 _resolve_xxx 里按宿主名装配。
9
+ 核心 Facade、工作流代码零改动。
10
+
11
+ 文件:
12
+ mcp.py —— L1 MCP 统一入口(复用禅道/知识图谱等已有 MCP)+ McpMemoryProvider(未来)
13
+ qw.py —— QoderWork 原生能力
14
+ cli.py —— 纯文件降级(核心能力兜底,无宿主依赖)
15
+ """
16
+ from .mcp import McpCap, McpMemoryProvider
17
+ from .qw import QwMemoryCap, is_qoderwork
18
+ from .cli import (
19
+ FileRepoCap,
20
+ FileIdentityCap,
21
+ FileContextCap,
22
+ FileMemoryCap,
23
+ )
24
+
25
+ __all__ = [
26
+ "McpCap", "McpMemoryProvider",
27
+ "QwMemoryCap", "is_qoderwork",
28
+ "FileRepoCap", "FileIdentityCap", "FileContextCap", "FileMemoryCap",
29
+ ]
@@ -0,0 +1,316 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ adapters.cli —— 纯文件降级 Adapter。
4
+
5
+ 设计模式: Adapter(纯 Python 文件实现,无任何宿主依赖)
6
+
7
+ 核心能力的兜底实现,保证纯 CLI / 任意宿主环境也能跑。
8
+ 这是"外挂式"的底牌:即便宿主什么能力都不给,工作流仍可用。
9
+
10
+ 实现:
11
+ - FileRepoCap: 向上找含 .qoder/scripts/ 的目录(复用 common.paths)
12
+ - FileIdentityCap: 读 .developer(复用 common.paths.get_developer)
13
+ - FileContextCap: 读配置/偏好文件
14
+ - FileMemoryCap: journal 文件记忆(纯文本追加,无语义检索)
15
+ """
16
+ from __future__ import annotations
17
+
18
+ from datetime import datetime
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+
23
+ def _import_paths():
24
+ """延迟导入 common.paths,避免循环依赖与硬失败。
25
+
26
+ Returns:
27
+ (get_repo_root, get_developer, get_developer_journal_dir) 元组,
28
+ 任一不可用则对应位为 None。
29
+ """
30
+ try:
31
+ from foundation.core.paths import (
32
+ get_repo_root,
33
+ get_developer,
34
+ get_developer_journal_dir,
35
+ )
36
+ return get_repo_root, get_developer, get_developer_journal_dir
37
+ except ImportError:
38
+ return None, None, None
39
+
40
+
41
+ class FileRepoCap:
42
+ """仓库根发现 —— 向上找含 .qoder/scripts/ 的目录。无 ~/.qoderwork/ 依赖。"""
43
+
44
+ available = True # 核心能力,永远可用
45
+
46
+ def root(self) -> Path:
47
+ get_repo_root, _, _ = _import_paths()
48
+ if get_repo_root:
49
+ try:
50
+ return get_repo_root()
51
+ except Exception:
52
+ pass
53
+ # 兜底:__file__ 向上找
54
+ current = Path(__file__).resolve()
55
+ for _ in range(10):
56
+ if (current / ".qoder" / "scripts").is_dir():
57
+ return current
58
+ parent = current.parent
59
+ if parent == current:
60
+ break
61
+ current = parent
62
+ return Path.cwd()
63
+
64
+
65
+ class FileIdentityCap:
66
+ """身份 —— 读 .developer 文件。"""
67
+
68
+ available = True
69
+
70
+ def who(self) -> str | None:
71
+ _, get_developer, _ = _import_paths()
72
+ if get_developer:
73
+ try:
74
+ dev = get_developer()
75
+ if dev:
76
+ return dev
77
+ except Exception:
78
+ pass
79
+ # 兜底:直接读 .developer
80
+ dev_file = FileRepoCap().root() / ".developer"
81
+ if dev_file.is_file():
82
+ return dev_file.read_text(encoding="utf-8").strip() or None
83
+ return None
84
+
85
+ def role(self) -> str | None:
86
+ """从 member.json 读取角色(pm/dev/qa/test/admin)。"""
87
+ try:
88
+ from foundation.identity.identity import get_role
89
+ return get_role(self.who())
90
+ except Exception:
91
+ return None
92
+
93
+ def zentao_account(self) -> str | None:
94
+ """从 member.json 读取禅道账号映射。"""
95
+ try:
96
+ from foundation.identity.identity import get_member
97
+ member = get_member(self.who() or "")
98
+ if member:
99
+ return member.get("zentao_account") or None
100
+ except Exception:
101
+ pass
102
+ return None
103
+
104
+
105
+ class FileContextCap:
106
+ """上下文 —— 读配置/偏好文件。"""
107
+
108
+ available = True
109
+
110
+ def preferences(self) -> dict:
111
+ """读 .qoder/settings.json 或 .qoder/config.yaml 中的偏好。"""
112
+ try:
113
+ repo = FileRepoCap().root()
114
+ import json as _json
115
+ # settings.json 优先
116
+ sf = repo / ".qoder" / "settings.json"
117
+ if sf.is_file():
118
+ with open(sf, encoding="utf-8") as f:
119
+ return _json.load(f)
120
+ # config.yaml 降级
121
+ import yaml
122
+ cf = repo / ".qoder" / "config.yaml"
123
+ if cf.is_file():
124
+ with open(cf, encoding="utf-8") as f:
125
+ return yaml.safe_load(f) or {}
126
+ except Exception:
127
+ pass
128
+ return {}
129
+
130
+ def recent_learnings(self, limit: int = 5) -> list[dict]:
131
+ """读当前开发者的 feedback.jsonl 最近 N 条学习事件。"""
132
+ try:
133
+ _, get_developer, get_journal = _import_paths()
134
+ if not (get_developer and get_journal):
135
+ return []
136
+ dev = get_developer()
137
+ if not dev:
138
+ return []
139
+ fb = get_journal(dev) / "feedback.jsonl"
140
+ if not fb.is_file():
141
+ return []
142
+ import json as _json
143
+ with open(fb, encoding="utf-8") as f:
144
+ lines = [l.strip() for l in f if l.strip()]
145
+ results = []
146
+ for line in reversed(lines[-limit:]):
147
+ try:
148
+ results.append(_json.loads(line))
149
+ except _json.JSONDecodeError:
150
+ continue
151
+ return results
152
+ except Exception:
153
+ return []
154
+
155
+
156
+ class FileMemoryCap:
157
+ """记忆 —— journal 文件降级(feedback.jsonl + memory.md)。
158
+
159
+ 存储位置: workspace/members/{dev}/journal/(复用 common.paths)。
160
+ available 探测到 journal 目录可写时为 True。
161
+
162
+ 实现:
163
+ - remember: 追加到 memory.md(带 key 标题)
164
+ - recall: 扫 memory.md + feedback.jsonl 关键词匹配(非语义,纯子串)
165
+ - get_fact: 精确匹配 memory.md 的 key 标题块
166
+ - list_recent: 返回最近 N 条(memory.md 最新 + feedback.jsonl 最新)
167
+ """
168
+
169
+ def __init__(self):
170
+ self._available = self._probe()
171
+
172
+ def _probe(self) -> bool:
173
+ try:
174
+ _, get_developer, get_journal = _import_paths()
175
+ if not (get_developer and get_journal):
176
+ return False
177
+ dev = get_developer()
178
+ if not dev:
179
+ return False
180
+ journal_dir = get_journal(dev)
181
+ journal_dir.mkdir(parents=True, exist_ok=True)
182
+ return journal_dir.is_dir()
183
+ except Exception:
184
+ return False
185
+
186
+ def _journal_dir(self):
187
+ _, get_developer, get_journal = _import_paths()
188
+ if not (get_developer and get_journal):
189
+ return None
190
+ try:
191
+ dev = get_developer()
192
+ if not dev:
193
+ return None
194
+ return get_journal(dev)
195
+ except Exception:
196
+ return None
197
+
198
+ @property
199
+ def available(self) -> bool:
200
+ return self._available
201
+
202
+ def recall(self, query: str) -> list[dict]:
203
+ """关键词检索:扫 memory.md + feedback.jsonl,返回含 query 的条目。"""
204
+ if not self._available or not query:
205
+ return []
206
+ jdir = self._journal_dir()
207
+ if jdir is None:
208
+ return []
209
+ results = []
210
+
211
+ # 1) memory.md 关键词匹配
212
+ mem_file = jdir / "memory.md"
213
+ if mem_file.is_file():
214
+ try:
215
+ content = mem_file.read_text(encoding="utf-8")
216
+ for block in content.split("\n## "):
217
+ if query.lower() in block.lower():
218
+ results.append({"source": "memory.md", "text": block.strip()})
219
+ except Exception:
220
+ pass
221
+
222
+ # 2) feedback.jsonl 关键词匹配
223
+ fb_file = jdir / "feedback.jsonl"
224
+ if fb_file.is_file():
225
+ import json as _json
226
+ try:
227
+ with open(fb_file, encoding="utf-8") as f:
228
+ for line in f:
229
+ line = line.strip()
230
+ if not line:
231
+ continue
232
+ try:
233
+ entry = _json.loads(line)
234
+ text = _json.dumps(entry, ensure_ascii=False)
235
+ if query.lower() in text.lower():
236
+ results.append({"source": "feedback.jsonl", "data": entry})
237
+ except _json.JSONDecodeError:
238
+ continue
239
+ except Exception:
240
+ pass
241
+
242
+ return results[:20] # 限制返回数
243
+
244
+ def remember(self, key: str, content: str) -> None:
245
+ if not self._available:
246
+ return
247
+ _, get_developer, get_journal = _import_paths()
248
+ if not (get_developer and get_journal):
249
+ return
250
+ try:
251
+ dev = get_developer()
252
+ journal_dir = get_journal(dev)
253
+ ts = datetime.now().strftime("%Y-%m-%d %H:%M")
254
+ entry = f"\n## [{ts}] {key}\n{content}\n"
255
+ with open(journal_dir / "memory.md", "a", encoding="utf-8") as f:
256
+ f.write(entry)
257
+ except Exception:
258
+ pass
259
+
260
+ def get_fact(self, key: str) -> str | None:
261
+ """精确匹配 memory.md 中以 key 为标题的块。"""
262
+ if not self._available or not key:
263
+ return None
264
+ jdir = self._journal_dir()
265
+ if jdir is None:
266
+ return None
267
+ mem_file = jdir / "memory.md"
268
+ if not mem_file.is_file():
269
+ return None
270
+ try:
271
+ content = mem_file.read_text(encoding="utf-8")
272
+ for block in content.split("\n## "):
273
+ # 块标题形如 "[2026-06-18 12:30] 某key"
274
+ if "] " + key in block or block.strip().endswith(key):
275
+ return block.strip()
276
+ except Exception:
277
+ pass
278
+ return None
279
+
280
+ def list_recent(self, limit: int = 10) -> list[dict]:
281
+ """返回最近 N 条记忆(memory.md 倒序 + feedback.jsonl 倒序)。"""
282
+ if not self._available:
283
+ return []
284
+ jdir = self._journal_dir()
285
+ if jdir is None:
286
+ return []
287
+ results = []
288
+
289
+ # memory.md 块倒序
290
+ mem_file = jdir / "memory.md"
291
+ if mem_file.is_file():
292
+ try:
293
+ content = mem_file.read_text(encoding="utf-8")
294
+ blocks = [b.strip() for b in content.split("\n## ") if b.strip()]
295
+ for b in reversed(blocks[-limit:]):
296
+ results.append({"source": "memory.md", "text": b})
297
+ except Exception:
298
+ pass
299
+
300
+ # feedback.jsonl 最后 N 条
301
+ fb_file = jdir / "feedback.jsonl"
302
+ if fb_file.is_file():
303
+ import json as _json
304
+ try:
305
+ with open(fb_file, encoding="utf-8") as f:
306
+ lines = [l.strip() for l in f if l.strip()]
307
+ for line in reversed(lines[-limit:]):
308
+ try:
309
+ entry = _json.loads(line)
310
+ results.append({"source": "feedback.jsonl", "data": entry})
311
+ except _json.JSONDecodeError:
312
+ continue
313
+ except Exception:
314
+ pass
315
+
316
+ return results[:limit]