@hupan56/wlkj 3.0.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/bin/cli.js +1435 -1373
  2. package/package.json +1 -1
  3. package/templates/qoder/commands/optional/wl-insight.md +6 -4
  4. package/templates/qoder/commands/optional/wl-report.md +20 -39
  5. package/templates/qoder/commands/optional/wl-status.md +4 -4
  6. package/templates/qoder/commands/wl-code.md +2 -2
  7. package/templates/qoder/commands/wl-design.md +5 -5
  8. package/templates/qoder/commands/wl-init.md +3 -3
  9. package/templates/qoder/commands/wl-prd.md +26 -13
  10. package/templates/qoder/commands/wl-req.md +3 -3
  11. package/templates/qoder/commands/wl-search.md +78 -47
  12. package/templates/qoder/commands/wl-task.md +343 -40
  13. package/templates/qoder/commands/wl-test.md +10 -10
  14. package/templates/qoder/config.yaml +35 -13
  15. package/templates/qoder/hooks/post-tool-use.py +181 -0
  16. package/templates/qoder/hooks/session-start.py +82 -1
  17. package/templates/qoder/hooks/stop-eval.py +207 -0
  18. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  19. package/templates/qoder/rules/wl-pipeline.md +70 -8
  20. package/templates/qoder/scripts/README.md +78 -115
  21. package/templates/qoder/scripts/capability/__init__.py +26 -0
  22. package/templates/qoder/scripts/capability/__main__.py +72 -0
  23. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  24. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  25. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  26. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  27. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  28. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  29. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  30. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  31. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  32. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  33. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  34. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  35. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  36. package/templates/qoder/scripts/capability/chain.py +92 -0
  37. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  38. package/templates/qoder/scripts/capability/registry.py +246 -0
  39. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  40. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  41. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  42. package/templates/qoder/scripts/{report → deployment/setup}/__init__.py +11 -11
  43. package/templates/qoder/scripts/{setup → deployment/setup}/carriers.py +33 -26
  44. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  45. package/templates/qoder/scripts/{setup → deployment/setup}/init_doctor.py +40 -16
  46. package/templates/qoder/scripts/{setup → deployment/setup}/install_qoderwork.py +20 -12
  47. package/templates/qoder/scripts/{setup → deployment/setup}/platform_doctor.py +8 -2
  48. package/templates/qoder/scripts/{setup → deployment/setup}/repo_root.py +113 -112
  49. package/templates/qoder/scripts/{setup → deployment/setup}/setup.py +31 -11
  50. package/templates/qoder/scripts/{setup → deployment/setup}/setup_lanhu.py +13 -7
  51. package/templates/qoder/scripts/domain/__init__.py +0 -0
  52. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  53. package/templates/qoder/scripts/{report → domain/design}/fill_prototype.py +12 -6
  54. package/templates/qoder/scripts/{report → domain/design}/gen_design_doc.py +8 -2
  55. package/templates/qoder/scripts/{setup → domain/kg}/__init__.py +11 -11
  56. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  57. package/templates/qoder/scripts/{kg → domain/kg/build}/build_entity_registry.py +7 -2
  58. package/templates/qoder/scripts/{kg → domain/kg/build}/build_relations.py +7 -2
  59. package/templates/qoder/scripts/{kg → domain/kg/build}/build_style_index.py +13 -7
  60. package/templates/qoder/scripts/{kg → domain/kg/build}/build_workflows.py +7 -2
  61. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build.py +76 -9
  62. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build_db.py +7 -2
  63. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_incremental.py +11 -6
  64. package/templates/qoder/scripts/{report → domain/kg/build}/learn_aggregate.py +9 -4
  65. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  66. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/test_extract.py +115 -115
  68. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  69. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  70. package/templates/qoder/scripts/{kg → domain/kg/graph}/kg_link_db.py +7 -2
  71. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  72. package/templates/qoder/scripts/{kg → domain/kg}/kg.py +263 -30
  73. package/templates/qoder/scripts/{common → domain/kg}/kg_capabilities.py +182 -182
  74. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  75. package/templates/qoder/scripts/{kg → domain/kg/search}/context_pack.py +30 -9
  76. package/templates/qoder/scripts/{kg → domain/kg/search}/enrich_prompt.py +10 -4
  77. package/templates/qoder/scripts/{kg → domain/kg/search}/prefetch.py +33 -8
  78. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  79. package/templates/qoder/scripts/{kg → domain/kg/search}/search_index.py +143 -77
  80. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  81. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  82. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  83. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  84. package/templates/qoder/scripts/{kg → domain/kg/storage}/kg_duckdb.py +38 -14
  85. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  86. package/templates/qoder/scripts/{report → domain/learning}/learn.py +8 -3
  87. package/templates/qoder/scripts/{mcp → domain/report}/__init__.py +11 -11
  88. package/templates/qoder/scripts/{report → domain/report}/add_session.py +9 -3
  89. package/templates/qoder/scripts/{report → domain/report}/export.py +10 -5
  90. package/templates/qoder/scripts/{report → domain/report}/report.py +9 -4
  91. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  92. package/templates/qoder/scripts/{report → domain/report}/role.py +10 -4
  93. package/templates/qoder/scripts/{report → domain/report}/status.py +112 -9
  94. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  95. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  96. package/templates/qoder/scripts/{report → domain/requirement}/archive_prd.py +8 -2
  97. package/templates/qoder/scripts/{report → domain/requirement}/req.py +228 -222
  98. package/templates/qoder/scripts/{kg → domain/task}/__init__.py +11 -11
  99. package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
  100. package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
  101. package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
  102. package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
  103. package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
  104. package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
  105. package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
  106. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  107. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  108. package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
  109. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  110. package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
  111. package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
  112. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
  113. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  114. package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
  115. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  116. package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
  117. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
  118. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  119. package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
  120. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
  121. package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
  122. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
  123. package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
  124. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  125. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  126. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
  127. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  128. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  129. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  130. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  131. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  132. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  133. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  134. package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
  135. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  136. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  137. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  138. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  139. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  140. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  141. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  142. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  143. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  144. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  145. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  146. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  147. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  148. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  153. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  154. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  155. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  156. package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
  157. package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
  158. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  159. package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
  160. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  161. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  162. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  163. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  164. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  165. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  166. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  167. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  168. package/templates/qoder/scripts/validation/__init__.py +0 -0
  169. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  171. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  172. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  173. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  174. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  175. package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
  176. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  177. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  178. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  179. package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
  180. package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
  181. package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
  182. package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
  183. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  184. package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
  185. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  186. package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
  187. package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
  188. package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
  189. package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
  190. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  191. package/templates/qoder/settings.json +30 -0
  192. package/templates/qoder/skills/design-import/SKILL.md +22 -13
  193. package/templates/qoder/skills/design-review/SKILL.md +19 -10
  194. package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
  195. package/templates/qoder/skills/prd-review/SKILL.md +6 -4
  196. package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
  197. package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
  198. package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
  199. package/templates/qoder/skills/test-generator/SKILL.md +7 -5
  200. package/templates/qoder/skills/wl-code/SKILL.md +23 -11
  201. package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
  202. package/templates/qoder/skills/wl-design/SKILL.md +5 -3
  203. package/templates/qoder/skills/wl-init/SKILL.md +6 -6
  204. package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
  205. package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
  206. package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
  207. package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
  208. package/templates/qoder/skills/wl-report/SKILL.md +25 -23
  209. package/templates/qoder/skills/wl-search/SKILL.md +149 -78
  210. package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
  211. package/templates/qoder/skills/wl-status/SKILL.md +48 -16
  212. package/templates/qoder/skills/wl-task/SKILL.md +92 -10
  213. package/templates/qoder/skills/wl-test/SKILL.md +75 -29
  214. package/templates/qoder/templates/prd-full-template.md +7 -0
  215. package/templates/root/AGENTS.md +275 -236
  216. package/templates/root/requirements.txt +3 -0
  217. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  218. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  219. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
  220. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
  221. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
  222. package/templates/.qoder/learning/eval-history.jsonl +0 -28
  223. package/templates/data/index/wiki-index.json +0 -8
  224. package/templates/qoder/nul +0 -4
  225. package/templates/qoder/scripts/kg/extract.py +0 -398
  226. package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
  227. package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
  228. package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
  229. package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
  230. package/templates/qoder/scripts/task/__init__.py +0 -11
  231. package/templates/qoder/scripts/test/__init__.py +0 -11
  232. package/templates/qoder/scripts/wlkj.py +0 -116
  233. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  234. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  235. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  236. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  237. /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
@@ -1,182 +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
- 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 common.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/search_index.py wiki")
160
- try:
161
- from common.repowiki import search_wiki
162
- from common.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
+ # -*- 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)
@@ -2,9 +2,15 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
4
4
  import os as _o, sys as _s
5
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
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
6
11
  if _cp not in _s.path: _s.path.insert(0, _cp)
7
12
  from bootstrap import setup; setup()
13
+ from foundation.core.paths import get_repo_root
8
14
 
9
15
  """
10
16
  QODER Context Pack - 一次调用返回写 PRD/原型所需的全部上下文
@@ -25,7 +31,7 @@ Usage:
25
31
  """
26
32
 
27
33
  import os
28
- from common.paths import BUILD_CACHE_DIR
34
+ from foundation.core.paths import BUILD_CACHE_DIR
29
35
  import sys
30
36
  import json
31
37
  import time
@@ -40,9 +46,9 @@ except (AttributeError, TypeError, OSError, IOError):
40
46
  pass
41
47
 
42
48
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
43
- from common.terms import CN_MAP, BUSINESS_PATH_MAP, CN_TO_EN, get_platform_map, expand_chinese_query
49
+ from foundation.integrations.terms import CN_MAP, BUSINESS_PATH_MAP, CN_TO_EN, get_platform_map, expand_chinese_query
44
50
 
45
- BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
51
+ BASE = get_repo_root()
46
52
  INDEX_DIR = os.path.join(BASE, 'data', 'index')
47
53
  PLATFORM_MAP = get_platform_map()
48
54
  MIN_FUZZY_LEN = 4
@@ -51,7 +57,7 @@ MIN_FUZZY_LEN = 4
51
57
  def load(filename):
52
58
  """Load index from DuckDB (preferred) or JSON fallback."""
53
59
  try:
54
- from search_index import _duckdb_load
60
+ from domain.kg.search.search_index import _duckdb_load
55
61
  result = _duckdb_load(filename)
56
62
  if result is not None:
57
63
  return result
@@ -141,7 +147,7 @@ def _save_cache(key, content):
141
147
  os.replace(tmp, cache_path)
142
148
  # LRU 清理: 保留最新 30 个, 删更老的
143
149
  try:
144
- from search_index import _cleanup_cache_dir
150
+ from domain.kg.search.search_index import _cleanup_cache_dir
145
151
  _cleanup_cache_dir(cache_dir, 'ctx-cache-', max_files=30)
146
152
  except Exception:
147
153
  pass
@@ -221,6 +227,21 @@ def _compute_and_print(query, platform, page_type):
221
227
  print('- {} (命中: {}) -> {}'.format(f, ','.join(sorted(kws)[:3]), full))
222
228
  if not hits:
223
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
224
245
 
225
246
  # ---- 2. 同类型页面真实示例 ----
226
247
  si = load('ui-style.json') or {}
@@ -288,8 +309,8 @@ def _compute_and_print(query, platform, page_type):
288
309
  code_dir = os.path.join(BASE, 'data', 'code')
289
310
  wiki_results = []
290
311
  try:
291
- from common.repowiki import search_wiki, build_wiki_index
292
- 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
293
314
  wiki_idx_path = os.path.join(BUILD_CACHE_DIR, 'wiki-index.json')
294
315
  if not os.path.isfile(wiki_idx_path):
295
316
  build_wiki_index(code_dir, wiki_idx_path)
@@ -324,7 +345,7 @@ def _compute_and_print(query, platform, page_type):
324
345
 
325
346
  # ── 8. 数据库表结构 (从 kg_db.duckdb, 合并了原来要单独调 MCP 的查询) ──
326
347
  try:
327
- from search_index import _get_kg_db
348
+ from domain.kg.search.search_index import _get_kg_db
328
349
  con = _get_kg_db() # 惰性缓存的只读连接, 不在此 close (供后续调用复用)
329
350
  if con is not None:
330
351
  # 关键词匹配表名 (英文词或snake_case, camelCase自动转)
@@ -2,9 +2,15 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
4
4
  import os as _o, sys as _s
5
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
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
6
11
  if _cp not in _s.path: _s.path.insert(0, _cp)
7
12
  from bootstrap import setup; setup()
13
+ from foundation.core.paths import get_repo_root
8
14
 
9
15
  """enrich_prompt.py - 极速提示词润色 (用户提问后第 0 步)
10
16
 
@@ -38,7 +44,7 @@ if sys.platform == 'win32':
38
44
  except Exception:
39
45
  pass
40
46
 
41
- BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
47
+ BASE = get_repo_root()
42
48
  sys.path.insert(0, os.path.join(BASE, '.qoder', 'scripts'))
43
49
 
44
50
  IDX_DIR = os.path.join(BASE, 'data', 'index')
@@ -51,7 +57,7 @@ def _load(name):
51
57
  if name in _CACHE:
52
58
  return _CACHE[name]
53
59
  try:
54
- from search_index import load_index
60
+ from domain.kg.search.search_index import load_index
55
61
  d = load_index(name) or {}
56
62
  except ImportError:
57
63
  # search_index 不可用时, 直接读 JSON (老逻辑)
@@ -136,7 +142,7 @@ def enrich(query):
136
142
  }
137
143
  """
138
144
  t0 = time.perf_counter()
139
- from common.terms import expand_chinese_query
145
+ from foundation.integrations.terms import expand_chinese_query
140
146
 
141
147
  # 1. 中文分词 → 英文搜索词
142
148
  cn_words = list(dict.fromkeys(expand_chinese_query(query))) # 去重保序
@@ -2,7 +2,12 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
4
4
  import os as _o, sys as _s
5
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
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
6
11
  if _cp not in _s.path: _s.path.insert(0, _cp)
7
12
  from bootstrap import setup; setup()
8
13
 
@@ -40,11 +45,11 @@ except (AttributeError, TypeError, OSError, IOError):
40
45
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
41
46
 
42
47
  # 复用 context_pack 的底层 (单一数据源, 不重复造轮子)
43
- from context_pack import (
48
+ from domain.kg.search.context_pack import (
44
49
  load, match_kw, plat_filter, PLATFORM_MAP, MIN_FUZZY_LEN,
45
50
  BASE, INDEX_DIR, BUILD_CACHE_DIR,
46
51
  )
47
- from common.terms import expand_chinese_query, get_cn_map_with_auto, BUSINESS_PATH_MAP
52
+ from foundation.integrations.terms import expand_chinese_query, get_cn_map_with_auto, BUSINESS_PATH_MAP
48
53
 
49
54
 
50
55
  # ── 词预测 ──────────────────────────────────────────────────────────
@@ -111,11 +116,12 @@ def predict_words(sentence):
111
116
 
112
117
  # ── 批量合并取上下文 ──────────────────────────────────────────────────
113
118
 
114
- def _collect(targets, en_words):
119
+ def _collect(targets, en_words, query=None):
115
120
  """对预测出的所有词, 批量收集 1/3/4/5 段命中, 合并去重。
116
121
 
117
122
  返回 dict: {段名: 合并去重 + 排序后的列表}。
118
123
  排序: 多词命中的项排前面 (被越多词命中越相关)。
124
+ query: 原始需求句 (用于语义补充检索, 中文句比拆词后的英文更准)。
119
125
  """
120
126
  ki = load('code-keyword.json') or {}
121
127
  si = load('ui-style.json') or {}
@@ -156,6 +162,25 @@ def _collect(targets, en_words):
156
162
  # 还原成 fywl-ui/... 形式 (views 里是相对 src/views 的路径)
157
163
  f = 'fywl-ui/apps/ics/src/views/' + vp
158
164
  file_hits.setdefault(f, set()).add(word)
165
+
166
+ # 1c. 语义补充: 若关键词命中稀疏 (<=2 文件), 用 bge-small-zh 向量检索补一轮。
167
+ # 解决"中文业务词→英文代码"的跨语言漏召 (查"报销"命中 reimburse/expense)。
168
+ # 把语义命中的文件按低权重并入 file_hits, 不喧宾夺主 (关键词命中优先)。
169
+ if len(file_hits) <= 2:
170
+ try:
171
+ from domain.kg.graph.kg_semantic import semantic_search_files
172
+ sem = semantic_search_files(query, top_k=8)
173
+ if sem:
174
+ for fp, eid, cn, score in sem:
175
+ if targets:
176
+ matched = any(t.lower() in fp.lower() for t in targets)
177
+ if not matched:
178
+ continue
179
+ # 语义命中标 'sem' 词, 不计入 en_words 命中数 (排序靠后)
180
+ file_hits.setdefault(fp, set()).add('sem')
181
+ except Exception:
182
+ pass # 模型未装/无 embedding → 静默跳过
183
+
159
184
  # 按命中词数排序, 取前 12
160
185
  files_ranked = sorted(file_hits.items(), key=lambda x: len(x[1]), reverse=True)[:12]
161
186
 
@@ -271,7 +296,7 @@ def _print_merged(query, platform, primary_cn, en_words, collected):
271
296
  code_dir = os.path.join(BASE, 'data', 'code')
272
297
  wiki_results = []
273
298
  try:
274
- from common.repowiki import search_wiki, build_wiki_index
299
+ from repowiki import search_wiki, build_wiki_index
275
300
  wiki_idx_path = os.path.join(BUILD_CACHE_DIR, 'wiki-index.json')
276
301
  if not os.path.isfile(wiki_idx_path):
277
302
  build_wiki_index(code_dir, wiki_idx_path)
@@ -293,7 +318,7 @@ def _print_merged(query, platform, primary_cn, en_words, collected):
293
318
 
294
319
  # 8. 数据库表结构 (主词查一次即可)
295
320
  try:
296
- from search_index import _get_kg_db
321
+ from domain.kg.search.search_index import _get_kg_db
297
322
  con = _get_kg_db()
298
323
  if con is not None:
299
324
  tbl_q = primary_cn[0] if primary_cn else query
@@ -338,7 +363,7 @@ def main():
338
363
 
339
364
  # 降级: 预测不出任何英文词 → 回退单词 context_pack (保持兼容)
340
365
  if not en_words:
341
- import context_pack as _cp
366
+ from domain.kg.search import context_pack as _cp
342
367
  # 直接调 context_pack 的计算逻辑 (它会自己 print)
343
368
  _cp._compute_and_print(query, platform, None)
344
369
  return 0
@@ -350,7 +375,7 @@ def main():
350
375
  targets = sorted(set(PLATFORM_MAP.values()))
351
376
 
352
377
  # 批量合并取上下文
353
- collected = _collect(targets, en_words)
378
+ collected = _collect(targets, en_words, query)
354
379
  _print_merged(query, platform, primary_cn, en_words, collected)
355
380
  return 0
356
381