@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,182 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ kg_capabilities.py - 知识图谱共享查询能力 (Strategy 模式, 消除 CLI↔MCP 重复)
4
+
5
+ v3.0 f3: kg.py (CLI) 和 kg_mcp_server.py (MCP) 有近字重复的查询逻辑
6
+ (workflow/hop/wiki/design_system 等)。本模块提取共享查询, 两边都调它,
7
+ 消除重复, 且保证 CLI 和 MCP 行为完全一致。
8
+
9
+ 核心 API (都接收已打开的 duckdb con, 由调用方管理连接):
10
+ workflow_query(con, q) -> str 业务流程链查询
11
+ # hop_query / wiki_query / design_system_query 后续添加
12
+
13
+ 设计: 查询逻辑 (数据清洗/SQL/格式化) 在此单一真源;
14
+ kg.py 和 kg_mcp_server 只负责"开连接 + 调本模块 + 返回"。
15
+ """
16
+
17
+ __all__ = ["workflow_query", "hop_query", "wiki_query"]
18
+
19
+
20
+ def workflow_query(con, q):
21
+ """workflows 表查询 + 脏数据清洗 + 中文兜底。
22
+
23
+ Args:
24
+ con: 已打开的 duckdb 连接 (read_only)
25
+ q: 模块名 (英文 assets/cost/hr 或中文触发兜底)
26
+
27
+ Returns:
28
+ 格式化的业务流程链文本
29
+ """
30
+ q = (q or '').strip()
31
+ # 1) 精确 + 模糊匹配 workflows.module(英文)
32
+ hits = con.execute(
33
+ "SELECT DISTINCT module FROM workflows WHERE module = ? OR module LIKE '%' || ? || '%' ORDER BY module",
34
+ [q.lower(), q.lower()]
35
+ ).fetchall()
36
+ if not hits:
37
+ # 2) 中文兜底: 查 entities.cn 返回英文候选
38
+ cn_hits = con.execute(
39
+ "SELECT canonical, cn FROM entities WHERE type IN ('FEATURE','MODULE') AND cn <> '' AND (cn LIKE '%' || ? OR cn LIKE '%' || ? || '%')",
40
+ [q, q]
41
+ ).fetchall()
42
+ if cn_hits:
43
+ cands = ', '.join('%s(%s)' % (c[0], c[1]) for c in cn_hits[:8])
44
+ return "未在 workflows 表找到模块 '%s'。但 entities 表有相近中文名,可换这些英文模块名重试:\n %s" % (q, cands)
45
+ all_mods = [r[0] for r in con.execute("SELECT DISTINCT module FROM workflows ORDER BY module").fetchall()]
46
+ return "未找到模块 '%s'。现有模块: %s" % (q, ', '.join(all_mods))
47
+
48
+ out = []
49
+ for (mod,) in hits:
50
+ # 清洗: 过滤空端点和模板泄漏按钮
51
+ rows = con.execute("""
52
+ SELECT state, seq, button, endpoint FROM workflows
53
+ WHERE module = ?
54
+ AND endpoint <> 'None' AND endpoint <> ''
55
+ AND button NOT LIKE '{{%'
56
+ ORDER BY seq, state
57
+ """, [mod]).fetchall()
58
+ if not rows:
59
+ continue
60
+ out.append('=== %s (%d 步, 已清洗脏数据) ===' % (mod, len(rows)))
61
+ cur_seq = -1
62
+ for st, sq, btn, ep in rows:
63
+ if sq != cur_seq:
64
+ out.append(' [%d] %s' % (sq, st))
65
+ cur_seq = sq
66
+ out.append(' %-16s -> %s' % (btn, ep))
67
+ out.append('')
68
+ return '\n'.join(out).strip() or "模块 '%s' 清洗后无有效操作链" % q
69
+
70
+
71
+ def hop_query(con, symbol, depth, multi_hop_fn=None):
72
+ """多跳遍历: 别名解析(三级兜底) + 递归CTE + 按depth分组展示。
73
+
74
+ Args:
75
+ con: duckdb 连接
76
+ symbol: 起始符号 (中文/端点/函数名, 自动别名解析)
77
+ depth: 最大跳数 1-5
78
+ multi_hop_fn: kg_duckdb.multi_hop 函数 (避免硬依赖)
79
+ Returns:
80
+ 格式化的多跳遍历文本
81
+ """
82
+ # 1) 别名解析(三级兜底)
83
+ start_id = symbol
84
+ resolved = con.execute(
85
+ "SELECT entity_id FROM aliases WHERE alias = ?", [symbol.lower()]
86
+ ).fetchone()
87
+ if resolved:
88
+ start_id = resolved[0]
89
+ else:
90
+ fuzzy = con.execute(
91
+ "SELECT id FROM entities WHERE id = ? OR id LIKE '%' || ? || '%' LIMIT 1",
92
+ [symbol, symbol]
93
+ ).fetchone()
94
+ if fuzzy:
95
+ start_id = fuzzy[0]
96
+ else:
97
+ edge_hit = con.execute(
98
+ "SELECT from_id FROM edges WHERE from_id LIKE '%' || ? || '%' LIMIT 1",
99
+ [symbol]
100
+ ).fetchone()
101
+ if edge_hit:
102
+ start_id = edge_hit[0]
103
+
104
+ # 2) 递归 CTE 遍历
105
+ if multi_hop_fn is None:
106
+ from domain.kg.storage import kg_duckdb as K
107
+ multi_hop_fn = K.multi_hop
108
+ try:
109
+ hops = multi_hop_fn(con, start_id, max_depth=depth)
110
+ except Exception as e:
111
+ return "遍历出错 (起点=%s): %s" % (start_id, str(e))
112
+
113
+ if not hops or (len(hops) == 1 and hops[0][1] == 0):
114
+ return "从 '%s' (解析为 %s) 出发无可达节点。可能该符号不在图谱中,或无出边。" % (symbol, start_id)
115
+
116
+ # 3) 按 depth 分组展示
117
+ from collections import defaultdict
118
+ by_depth = defaultdict(list)
119
+ for eid, d in hops:
120
+ by_depth[d].append(eid)
121
+
122
+ out = ['=== 多跳遍历: %s (解析为 %s) ===' % (symbol, start_id)]
123
+ out.append('可达 %d 个实体, 最大 %d 跳:' % (len(hops), max(by_depth.keys())))
124
+ out.append('')
125
+ for d in sorted(by_depth.keys()):
126
+ eids = by_depth[d]
127
+ out.append('[第 %d 跳] %d 个实体:' % (d, len(eids)))
128
+ shown = 0
129
+ for eid in eids:
130
+ if shown >= 12:
131
+ out.append(' ... 还有 %d 个' % (len(eids) - 12))
132
+ break
133
+ info = con.execute(
134
+ "SELECT type, canonical, cn FROM entities WHERE id = ?", [eid]
135
+ ).fetchone()
136
+ if info:
137
+ t, c, cn = info
138
+ label = '%s / %s' % (c, cn) if cn and cn != c else c
139
+ out.append(' %-14s %-12s %s' % ('[%s]' % t, eid[:40], label))
140
+ else:
141
+ out.append(' %-14s %s' % ('[edge]', eid[:60]))
142
+ shown += 1
143
+ out.append('')
144
+ return '\n'.join(out).strip()
145
+
146
+ def wiki_query(kw):
147
+ """Repo Wiki 搜索 + 格式化 (CLI/MCP 共用)。
148
+
149
+ Args:
150
+ kw: 搜索关键词
151
+ Returns:
152
+ 格式化的 wiki 匹配结果文本
153
+ """
154
+ import os
155
+ from foundation.core.paths import DATA_INDEX_DIR as _idx, PROJECT_ROOT as _base
156
+ wiki_path = os.path.join(str(_idx), 'wiki-index.json')
157
+ if not os.path.isfile(wiki_path):
158
+ return ("wiki-index.json 不存在。请手动构建(一次性):\n"
159
+ " python .qoder/scripts/domain/kg/search/search_index.py wiki")
160
+ try:
161
+ from repowiki import search_wiki
162
+ from foundation.integrations.terms import get_cn_map_with_auto
163
+ except ImportError as e:
164
+ return "Wiki 搜索模块缺失: %s" % str(e)
165
+ code_dir = os.path.join(_base, 'data', 'code')
166
+ try:
167
+ cn_map = get_cn_map_with_auto()
168
+ results = search_wiki(kw, str(_idx), code_dir, cn_map)
169
+ except Exception as e:
170
+ return "Wiki 搜索出错: %s" % str(e)
171
+ if not results:
172
+ return "No wiki pages match: %s" % kw
173
+ out = ['Wiki pages matching: %s (%d found)' % (kw, len(results)), '']
174
+ for i, r in enumerate(results, 1):
175
+ out.append(' %d. [%s] %s' % (i, r.get('project', '?'), r.get('title', '')))
176
+ deps = r.get('dependent_files') or []
177
+ if deps:
178
+ out.append(' 依赖: %s%s' % (', '.join(deps[:2]),
179
+ (' (共 %d 个文件)' % len(deps)) if len(deps) > 2 else ''))
180
+ if r.get('md_path'):
181
+ out.append(' 文档: %s' % r['md_path'])
182
+ return '\n'.join(out)
@@ -1,5 +1,17 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
+ # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
4
+ import os as _o, sys as _s
5
+ _f = _o.path.abspath(__file__)
6
+ for _ in range(10):
7
+ _f = _o.path.dirname(_f)
8
+ _cp = _o.path.join(_f, 'foundation')
9
+ if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
10
+ break
11
+ if _cp not in _s.path: _s.path.insert(0, _cp)
12
+ from bootstrap import setup; setup()
13
+ from foundation.core.paths import get_repo_root
14
+
3
15
  """
4
16
  QODER Context Pack - 一次调用返回写 PRD/原型所需的全部上下文
5
17
 
@@ -19,7 +31,7 @@ Usage:
19
31
  """
20
32
 
21
33
  import os
22
- from common.paths import BUILD_CACHE_DIR
34
+ from foundation.core.paths import BUILD_CACHE_DIR
23
35
  import sys
24
36
  import json
25
37
  import time
@@ -34,9 +46,9 @@ except (AttributeError, TypeError, OSError, IOError):
34
46
  pass
35
47
 
36
48
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
37
- from common.terms import CN_MAP, BUSINESS_PATH_MAP, CN_TO_EN, get_platform_map
49
+ from foundation.integrations.terms import CN_MAP, BUSINESS_PATH_MAP, CN_TO_EN, get_platform_map, expand_chinese_query
38
50
 
39
- BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
51
+ BASE = get_repo_root()
40
52
  INDEX_DIR = os.path.join(BASE, 'data', 'index')
41
53
  PLATFORM_MAP = get_platform_map()
42
54
  MIN_FUZZY_LEN = 4
@@ -45,7 +57,7 @@ MIN_FUZZY_LEN = 4
45
57
  def load(filename):
46
58
  """Load index from DuckDB (preferred) or JSON fallback."""
47
59
  try:
48
- from search_index import _duckdb_load
60
+ from domain.kg.search.search_index import _duckdb_load
49
61
  result = _duckdb_load(filename)
50
62
  if result is not None:
51
63
  return result
@@ -62,11 +74,14 @@ def load(filename):
62
74
 
63
75
 
64
76
  def expand_query(query):
65
- words = []
66
- if query in CN_MAP:
67
- words.extend(CN_MAP[query].split())
68
- if query in BUSINESS_PATH_MAP:
69
- words.extend(p.strip('/-').lower() for p in BUSINESS_PATH_MAP[query])
77
+ """词扩展: 委托给 expand_chinese_query (三级匹配: 精确/分词/兜底)。
78
+
79
+ 旧版只查精确匹配, 复合词如 "保险单OCR" / "异常记录" 查不到就 0 命中。
80
+ 现在用 expand_chinese_query, 能拆 "保险单OCR" → "保险" + "ocr",
81
+ "异常记录" "异常" + "记录", 大幅减少单词查询的 0 命中。
82
+ """
83
+ words = expand_chinese_query(query)
84
+ # 兜底: 拆不出词就用原词小写 (让英文索引做子串匹配)
70
85
  return sorted(set(w.lower() for w in words)) or [query.lower()]
71
86
 
72
87
 
@@ -132,7 +147,7 @@ def _save_cache(key, content):
132
147
  os.replace(tmp, cache_path)
133
148
  # LRU 清理: 保留最新 30 个, 删更老的
134
149
  try:
135
- from search_index import _cleanup_cache_dir
150
+ from domain.kg.search.search_index import _cleanup_cache_dir
136
151
  _cleanup_cache_dir(cache_dir, 'ctx-cache-', max_files=30)
137
152
  except Exception:
138
153
  pass
@@ -212,6 +227,21 @@ def _compute_and_print(query, platform, page_type):
212
227
  print('- {} (命中: {}) -> {}'.format(f, ','.join(sorted(kws)[:3]), full))
213
228
  if not hits:
214
229
  print('- (无命中 — 换业务词重试, 或该功能为全新)')
230
+ # 语义补充: 关键词命中稀疏时, 用 bge-small-zh 向量检索补一轮 (中→英跨语言)。
231
+ # 模型未装/无 embedding → 静默跳过, 不报错。
232
+ if len(hits) <= 2:
233
+ try:
234
+ from domain.kg.graph.kg_semantic import semantic_search_files, filter_semantic_by_platform
235
+ sem = semantic_search_files(query, top_k=8)
236
+ if sem:
237
+ filtered = filter_semantic_by_platform(sem, platform, BASE)
238
+ if filtered:
239
+ print('- [语义补充] (关键词命中少, 用向量检索跨语言补充):')
240
+ for fp, cn, score in filtered[:6]:
241
+ full = 'data/code/' + fp
242
+ print(' - %.2f %s -> %s' % (score, cn[:20], full))
243
+ except Exception:
244
+ pass
215
245
 
216
246
  # ---- 2. 同类型页面真实示例 ----
217
247
  si = load('ui-style.json') or {}
@@ -279,8 +309,8 @@ def _compute_and_print(query, platform, page_type):
279
309
  code_dir = os.path.join(BASE, 'data', 'code')
280
310
  wiki_results = []
281
311
  try:
282
- from common.repowiki import search_wiki, build_wiki_index
283
- from common.terms import get_cn_map_with_auto
312
+ from repowiki import search_wiki, build_wiki_index
313
+ from foundation.integrations.terms import get_cn_map_with_auto
284
314
  wiki_idx_path = os.path.join(BUILD_CACHE_DIR, 'wiki-index.json')
285
315
  if not os.path.isfile(wiki_idx_path):
286
316
  build_wiki_index(code_dir, wiki_idx_path)
@@ -315,10 +345,9 @@ def _compute_and_print(query, platform, page_type):
315
345
 
316
346
  # ── 8. 数据库表结构 (从 kg_db.duckdb, 合并了原来要单独调 MCP 的查询) ──
317
347
  try:
318
- import duckdb as _ddb2
319
- db_path = os.path.join(INDEX_DIR, 'kg_db.duckdb')
320
- if os.path.isfile(db_path):
321
- con = _ddb2.connect(db_path, read_only=True)
348
+ from domain.kg.search.search_index import _get_kg_db
349
+ con = _get_kg_db() # 惰性缓存的只读连接, 不在此 close (供后续调用复用)
350
+ if con is not None:
322
351
  # 关键词匹配表名 (英文词或snake_case, camelCase自动转)
323
352
  kw_lower = query.lower()
324
353
  # camelCase → snake_case (qualityCase → quality_case)
@@ -349,7 +378,6 @@ def _compute_and_print(query, platform, page_type):
349
378
  if ents:
350
379
  print(' {} → Entity: {}'.format(
351
380
  tn, ', '.join(e[0] for e in ents)))
352
- con.close()
353
381
  except Exception:
354
382
  pass # kg_db不存在/被占用 → 跳过, 不影响其它段
355
383