@hupan56/wlkj 3.0.0 → 3.1.3

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 (247) 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 +55 -23
  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 +35 -12
  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/domain/task/__pycache__/syncgate.cpython-39.pyc +0 -0
  100. package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
  101. package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
  102. package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
  103. package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
  104. package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
  105. package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
  106. package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
  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/__pycache__/__init__.cpython-39.pyc +0 -0
  110. package/templates/qoder/scripts/foundation/__pycache__/bootstrap.cpython-39.pyc +0 -0
  111. package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
  112. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  113. package/templates/qoder/scripts/foundation/core/__pycache__/__init__.cpython-39.pyc +0 -0
  114. package/templates/qoder/scripts/foundation/core/__pycache__/paths.cpython-39.pyc +0 -0
  115. package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
  116. package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
  117. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
  118. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  119. package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
  120. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  121. package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
  122. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
  123. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  124. package/templates/qoder/scripts/foundation/identity/__pycache__/__init__.cpython-39.pyc +0 -0
  125. package/templates/qoder/scripts/foundation/identity/__pycache__/identity.cpython-39.pyc +0 -0
  126. package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
  127. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
  128. package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
  129. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
  130. package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
  131. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  132. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  133. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
  134. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  135. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  136. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  137. package/templates/qoder/scripts/foundation/io/__pycache__/__init__.cpython-39.pyc +0 -0
  138. package/templates/qoder/scripts/foundation/io/__pycache__/atomicio.cpython-39.pyc +0 -0
  139. package/templates/qoder/scripts/foundation/io/__pycache__/filelock.cpython-39.pyc +0 -0
  140. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  141. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  142. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  143. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  144. package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
  145. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  146. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  147. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  148. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  149. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  150. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  151. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  152. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  153. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  154. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  155. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  156. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  157. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  158. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  159. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  160. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  161. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  162. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  163. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  164. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  165. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  166. package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
  167. package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
  168. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  169. package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
  170. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  171. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  172. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  173. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  174. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  175. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  176. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  177. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  178. package/templates/qoder/scripts/validation/__init__.py +0 -0
  179. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  180. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  181. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  182. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  183. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  184. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  185. package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
  186. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  187. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  188. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  189. package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
  190. package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
  191. package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
  192. package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
  193. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  194. package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
  195. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  196. package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
  197. package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
  198. package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
  199. package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
  200. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  201. package/templates/qoder/settings.json +30 -0
  202. package/templates/qoder/skills/design-import/SKILL.md +22 -13
  203. package/templates/qoder/skills/design-review/SKILL.md +19 -10
  204. package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
  205. package/templates/qoder/skills/prd-review/SKILL.md +6 -4
  206. package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
  207. package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
  208. package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
  209. package/templates/qoder/skills/test-generator/SKILL.md +7 -5
  210. package/templates/qoder/skills/wl-code/SKILL.md +23 -11
  211. package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
  212. package/templates/qoder/skills/wl-design/SKILL.md +5 -3
  213. package/templates/qoder/skills/wl-init/SKILL.md +6 -6
  214. package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
  215. package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
  216. package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
  217. package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
  218. package/templates/qoder/skills/wl-report/SKILL.md +25 -23
  219. package/templates/qoder/skills/wl-search/SKILL.md +149 -78
  220. package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
  221. package/templates/qoder/skills/wl-status/SKILL.md +48 -16
  222. package/templates/qoder/skills/wl-task/SKILL.md +92 -10
  223. package/templates/qoder/skills/wl-test/SKILL.md +75 -29
  224. package/templates/qoder/templates/prd-full-template.md +7 -0
  225. package/templates/root/AGENTS.md +275 -236
  226. package/templates/root/requirements.txt +3 -0
  227. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  228. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  229. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
  230. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
  231. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
  232. package/templates/.qoder/learning/eval-history.jsonl +0 -28
  233. package/templates/data/index/wiki-index.json +0 -8
  234. package/templates/qoder/nul +0 -4
  235. package/templates/qoder/scripts/kg/extract.py +0 -398
  236. package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
  237. package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
  238. package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
  239. package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
  240. package/templates/qoder/scripts/task/__init__.py +0 -11
  241. package/templates/qoder/scripts/test/__init__.py +0 -11
  242. package/templates/qoder/scripts/wlkj.py +0 -116
  243. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  244. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  245. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  246. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  247. /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
@@ -1,9 +1,15 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
3
3
  import os as _o, sys as _s
4
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
4
+ _f = _o.path.abspath(__file__)
5
+ for _ in range(10):
6
+ _f = _o.path.dirname(_f)
7
+ _cp = _o.path.join(_f, 'foundation')
8
+ if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
9
+ break
5
10
  if _cp not in _s.path: _s.path.insert(0, _cp)
6
11
  from bootstrap import setup; setup()
12
+ from foundation.core.paths import get_repo_root
7
13
 
8
14
  """
9
15
  kg.py — QODER 知识图谱统一 CLI 入口(全系列通用)
@@ -16,7 +22,7 @@ kg.py — QODER 知识图谱统一 CLI 入口(全系列通用)
16
22
  1. 不复制逻辑 — 调底层: search_index / context_pack / graph_traverse /
17
23
  kg_duckdb / repowiki / fill_prototype / gen_design_doc
18
24
  2. 全容错 — DuckDB/索引缺失优雅降级,给修复提示,绝不抛栈给用户
19
- 3. 参数统一 — 13 个子命令风格一致,对标 MCP 工具名
25
+ 3. 参数统一 — 15 个子命令风格一致,对标 MCP 工具名
20
26
  4. 纯文本输出 — UTF-8,无日志噪音,AI 直接读
21
27
 
22
28
  用法:
@@ -40,8 +46,8 @@ try:
40
46
  except Exception:
41
47
  pass
42
48
 
43
- SCRIPTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 子包→scripts/根
44
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPTS_DIR))) # 多一层: 子包→scripts→repo # repo root
49
+ SCRIPTS_DIR = get_repo_root()
50
+ BASE_DIR = get_repo_root()
45
51
  sys.path.insert(0, SCRIPTS_DIR)
46
52
  _KG_DIR = os.path.dirname(os.path.abspath(__file__))
47
53
  if _KG_DIR not in sys.path: sys.path.insert(0, _KG_DIR) # 同包import
@@ -51,7 +57,7 @@ if _KG_DIR not in sys.path: sys.path.insert(0, _KG_DIR) # 同包import
51
57
  def _index_dir():
52
58
  """获取 data/index 目录(延迟导入,避免顶层崩)。"""
53
59
  try:
54
- from common.paths import DATA_INDEX_DIR
60
+ from foundation.core.paths import DATA_INDEX_DIR
55
61
  return str(DATA_INDEX_DIR)
56
62
  except Exception:
57
63
  # 兜底: 常规布局
@@ -89,7 +95,7 @@ def cmd_search(args):
89
95
  kw, plat = _split_kw_platform(args)
90
96
  if not kw:
91
97
  return "请提供搜索关键词"
92
- import search_index as S
98
+ from domain.kg.search import search_index as S
93
99
  # search_keywords(query, platform=None) 自带中文扩展,不需外层 expand
94
100
  return _capture(S.search_keywords, kw, plat) or "无匹配结果"
95
101
 
@@ -98,7 +104,7 @@ def cmd_api(args):
98
104
  """搜 API 端点。"""
99
105
  if not args:
100
106
  return "用法: kg.py api <关键词>"
101
- import search_index as S
107
+ from domain.kg.search import search_index as S
102
108
  return _capture(S.search_api, args[0]) or "无匹配 API"
103
109
 
104
110
 
@@ -106,7 +112,7 @@ def cmd_prd(args):
106
112
  """搜 PRD(防重复造轮子)。"""
107
113
  if not args:
108
114
  return "用法: kg.py prd <关键词>"
109
- import search_index as S
115
+ from domain.kg.search import search_index as S
110
116
  return _capture(S.search_prds, args[0]) or "无匹配 PRD"
111
117
 
112
118
 
@@ -114,7 +120,7 @@ def cmd_impact(args):
114
120
  """影响分析: 改某接口影响哪些前端页面/按钮。"""
115
121
  if not args:
116
122
  return "用法: kg.py impact <端点或关键词> 例: /asset 或 export"
117
- import search_index as S
123
+ from domain.kg.search import search_index as S
118
124
  return _capture(S.search_impact, args[0]) or "未找到匹配端点"
119
125
 
120
126
 
@@ -122,7 +128,7 @@ def cmd_context360(args):
122
128
  """符号 360 度视图: 端点/函数/处理器的全部关联。"""
123
129
  if not args:
124
130
  return "用法: kg.py context360 <符号> 例: handleExport 或 /system/role"
125
- import search_index as S
131
+ from domain.kg.search import search_index as S
126
132
  return _capture(S.search_context360, args[0]) or "未找到匹配符号"
127
133
 
128
134
 
@@ -147,7 +153,7 @@ def cmd_context(args):
147
153
  kw = rest2[0] if rest2 else ''
148
154
  if not kw:
149
155
  return "请提供业务关键词"
150
- import context_pack as C
156
+ from domain.kg.search import context_pack as C
151
157
  full = _capture(C._compute_and_print, kw, plat, '')
152
158
  if not full:
153
159
  return "无匹配上下文"
@@ -177,11 +183,11 @@ def cmd_prefetch(args):
177
183
  query = ' '.join(rest2) if rest2 else ''
178
184
  if not query:
179
185
  return "请提供需求描述(一句话)"
180
- import prefetch as P
186
+ from domain.kg.search import prefetch as P
181
187
  primary_cn, en_words = P.predict_words(query)
182
188
  if not en_words:
183
189
  # 降级: 预测不出词 → 单词 context_pack
184
- import context_pack as C
190
+ from domain.kg.search import context_pack as C
185
191
  return _capture(C._compute_and_print, query, plat, '') or "无匹配上下文"
186
192
  targets = []
187
193
  if plat and plat.lower() not in ('both', '两端'):
@@ -194,7 +200,7 @@ def cmd_prefetch(args):
194
200
 
195
201
  def cmd_coverage(args):
196
202
  """功能×测试覆盖矩阵: 哪些功能有测试,哪些是盲区。"""
197
- from common.graph_traverse import CodeGraph
203
+ from domain.kg.graph.graph_traverse import CodeGraph
198
204
  g = CodeGraph(_index_dir())
199
205
  return g.coverage_matrix() or "无法生成覆盖矩阵(索引可能为空)"
200
206
 
@@ -222,7 +228,7 @@ def cmd_feature(args):
222
228
  try: con.close()
223
229
  except Exception: pass
224
230
  # 回退: CodeGraph 的 JSON 实现(entity-registry.json 通常不存在)
225
- from common.graph_traverse import CodeGraph
231
+ from domain.kg.graph.graph_traverse import CodeGraph
226
232
  g = CodeGraph(_index_dir())
227
233
  return g.feature_overview(feat) or "未找到功能 '%s'" % feat
228
234
 
@@ -386,7 +392,7 @@ def cmd_workflow(args):
386
392
 
387
393
  def _workflow_query(con, q):
388
394
  """workflows 表查询 — v3.0 f3: 转发到 common.kg_capabilities (单一真源, CLI/MCP共用)。"""
389
- from common.kg_capabilities import workflow_query
395
+ from domain.kg.kg_capabilities import workflow_query
390
396
  return workflow_query(con, q)
391
397
 
392
398
 
@@ -404,11 +410,11 @@ def cmd_hop(args):
404
410
  import duckdb
405
411
  except ImportError:
406
412
  return "未安装 duckdb。请运行: pip install duckdb"
407
- import kg_duckdb as K
413
+ from domain.kg.storage import kg_duckdb as K
408
414
  con = duckdb.connect(_kg_db_path(), read_only=True)
409
415
  try:
410
416
  # v3.0 f3: 核心查询转发到 common.kg_capabilities.hop_query (CLI/MCP共用)
411
- from common.kg_capabilities import hop_query
417
+ from domain.kg.kg_capabilities import hop_query
412
418
  return hop_query(con, symbol, depth, multi_hop_fn=K.multi_hop)
413
419
  finally:
414
420
  try: con.close()
@@ -419,7 +425,7 @@ def cmd_wiki(args):
419
425
  """Repo Wiki 搜索 — v3.0 f3: 转发到 common.kg_capabilities.wiki_query (CLI/MCP共用)。"""
420
426
  if not args:
421
427
  return "用法: kg.py wiki <关键词>"
422
- from common.kg_capabilities import wiki_query
428
+ from domain.kg.kg_capabilities import wiki_query
423
429
  result = wiki_query(args[0])
424
430
  # CLI 额外提示
425
431
  if 'matching' in result:
@@ -434,13 +440,14 @@ def cmd_fill_prototype(args):
434
440
  kw, plat = _split_kw_platform(args)
435
441
  plat = plat or 'web'
436
442
  import subprocess as _sp
437
- script = os.path.join(SCRIPTS_DIR, 'fill_prototype.py')
438
- if not os.path.isfile(script):
439
- return "fill_prototype.py 不存在"
443
+ from foundation.core.paths import find_script
444
+ script = find_script('fill_prototype.py')
445
+ if script is None:
446
+ return "fill_prototype.py 未找到 (脚本迁移后路径未更新)"
440
447
  try:
441
- r = _sp.run([sys.executable, script, kw, '--platform', plat],
448
+ r = _sp.run([sys.executable, str(script), kw, '--platform', plat],
442
449
  capture_output=True, text=True, encoding='utf-8',
443
- errors='replace', timeout=30, cwd=SCRIPTS_DIR)
450
+ errors='replace', timeout=30, cwd=str(script.parent))
444
451
  return r.stdout or "fill_prototype 无输出(可能索引缺失)"
445
452
  except Exception as e:
446
453
  return "[error] fill_prototype: %s" % str(e)
@@ -454,9 +461,10 @@ def cmd_design_system(args):
454
461
  import subprocess as _sp
455
462
  design_md = os.path.join(BASE_DIR, 'data', 'design', 'DESIGN.md')
456
463
  if not os.path.isfile(design_md):
457
- gen_script = os.path.join(SCRIPTS_DIR, 'gen_design_doc.py')
458
- if os.path.isfile(gen_script):
459
- _sp.run([sys.executable, gen_script], capture_output=True, timeout=30)
464
+ from foundation.core.paths import find_script
465
+ gen_script = find_script('gen_design_doc.py')
466
+ if gen_script is not None:
467
+ _sp.run([sys.executable, str(gen_script)], capture_output=True, timeout=30)
460
468
  if os.path.isfile(design_md):
461
469
  content = open(design_md, encoding='utf-8').read()
462
470
  if plat:
@@ -472,7 +480,193 @@ def cmd_design_system(args):
472
480
  result.append(line)
473
481
  return '\n'.join(result) if result else content
474
482
  return content
475
- return "DESIGN.md 不存在且生成失败。请手动跑: python .qoder/scripts/gen_design_doc.py"
483
+ return "DESIGN.md 不存在且生成失败。请手动跑: python .qoder/scripts/design/gen_design_doc.py"
484
+
485
+
486
+ def cmd_semantic(args):
487
+ """语义搜索: 用自然语言找代码/API (概念检索, 不依赖精确关键词)。
488
+
489
+ 需先构建 embedding 向量 (管理员): kg_semantic.py build-embeddings。
490
+ 模型未装时给出安装提示, 不崩溃。
491
+ """
492
+ if not args:
493
+ return ("用法: kg.py semantic <自然语言查询> [--top N]\n"
494
+ " 语义检索: 查'报销'能命中 expense/reimburse\n"
495
+ " 需先构建: python .qoder/scripts/domain/kg/graph/kg_semantic.py build-embeddings")
496
+ query = args[0]
497
+ top_k = 10
498
+ if '--top' in args:
499
+ idx = args.index('--top')
500
+ if idx + 1 < len(args):
501
+ try:
502
+ top_k = int(args[idx + 1])
503
+ except ValueError:
504
+ pass
505
+ from domain.kg.graph.kg_semantic import semantic_search, embedding_status
506
+ results = semantic_search(query, top_k=top_k)
507
+ if results is None:
508
+ st = embedding_status()
509
+ if not st['available']:
510
+ return ("语义检索未启用: sentence-transformers 未安装。\n"
511
+ "启用: pip install sentence-transformers (95MB模型首次自动下载)")
512
+ elif st['embeddings_count'] == 0:
513
+ return ("语义检索未构建向量。请管理员运行:\n"
514
+ " python .qoder/scripts/domain/kg/graph/kg_semantic.py build-embeddings")
515
+ if not results:
516
+ return "无匹配结果"
517
+ out = ["语义搜索: %s (top %d)" % (query, len(results))]
518
+ for eid, text, score in results:
519
+ out.append(" %.3f %s" % (score, text[:70]))
520
+ return '\n'.join(out)
521
+
522
+
523
+ # ── 中文文案/报错溯源 (grep-text): 单进程安全兜底, 替代 findstr/s 全盘扫描 ──
524
+ # 设计动机: 用户查"车辆不存在""项目车号"这类中文文案时, kg.py 的代码标识符索引
525
+ # 天然查不到 (索引按英文标识符建)。AI 若兜底去 findstr /s 或 os.walk 全库
526
+ # (8973+ 文件) → Windows 卡死 + 疯狂弹 cmd 窗口。本命令是这类需求的唯一安全通道:
527
+ # 单进程、限定 data/code、限定扩展名、有行数上限, 绝不递归弹子进程。
528
+ _GREP_EXTS = ('.java', '.vue', '.ts', '.tsx', '.js', '.jsx', '.xml', '.html',
529
+ '.json', '.sql', '.properties', '.yml', '.yaml', '.ftl', '.txt')
530
+
531
+
532
+ def cmd_grep_text(args):
533
+ """中文文案/报错溯源: 在 data/code 里搜中文短语 (报错文案/字段标签/业务词)。
534
+
535
+ 单进程 Python, 限定扩展名, 上限 200 命中 + 30 文件。绝不弹子进程窗口。
536
+ 用法: kg.py grep-text <中文短语> [--ext java,vue] [--limit N] [--platform web|app]
537
+ """
538
+ if not args:
539
+ return ("用法: kg.py grep-text <中文短语> [选项]\n"
540
+ " 在 data/code 里搜中文文案/报错/字段标签 (kg.py search 查不到中文时用这个)\n"
541
+ " --ext java,vue 限定文件类型 (默认: java/vue/ts/xml/json...)\n"
542
+ " --limit N 最多返回 N 条命中 (默认 50)\n"
543
+ " --platform web|app 只搜某平台源码\n"
544
+ "示例: kg.py grep-text 车辆不存在")
545
+ import os as _os
546
+ # kg.py 在 .qoder/scripts/domain/kg/ 下, 往上 4 级到 repo 根
547
+ here = _os.path.dirname(_os.path.abspath(__file__)) # .../domain/kg/
548
+ base = _os.path.dirname(_os.path.dirname(_os.path.dirname(_os.path.dirname(here)))) # repo 根
549
+ code_root = _os.path.join(base, 'data', 'code')
550
+ if not _os.path.isdir(code_root):
551
+ return ('data/code 不存在 (源码未克隆)。跑 python .qoder/scripts/deployment/setup/init_doctor.py --fix')
552
+
553
+ query = args[0]
554
+ # 解析选项
555
+ exts = set(_GREP_EXTS)
556
+ limit = 50
557
+ user_limit = None # 记录用户是否显式传了 --limit (决定是否启用 early_stop)
558
+ plat = ''
559
+ i = 1
560
+ while i < len(args):
561
+ a = args[i]
562
+ if a == '--ext' and i + 1 < len(args):
563
+ exts = set('.' + e.lstrip('.') for e in args[i + 1].split(',') if e.strip())
564
+ i += 2; continue
565
+ if a == '--limit' and i + 1 < len(args):
566
+ try:
567
+ limit = max(1, int(args[i + 1]))
568
+ user_limit = limit # 用户显式指定了, early_stop 不再介入
569
+ except ValueError: pass
570
+ i += 2; continue
571
+ if a == '--platform' and i + 1 < len(args):
572
+ plat = args[i + 1]; i += 2; continue
573
+ i += 1
574
+
575
+ # 平台 → 子目录过滤
576
+ proj_dirs = []
577
+ if not plat:
578
+ for d in sorted(_os.listdir(code_root)):
579
+ if _os.path.isdir(_os.path.join(code_root, d)) and not d.startswith('.'):
580
+ proj_dirs.append(d)
581
+ elif plat in ('web', 'pc'):
582
+ proj_dirs = [d for d in ('fywl-ui',) if _os.path.isdir(_os.path.join(code_root, d))]
583
+ elif plat in ('app', 'h5'):
584
+ proj_dirs = [d for d in ('Carmg-H5',) if _os.path.isdir(_os.path.join(code_root, d))]
585
+ else:
586
+ proj_dirs = [d for d in sorted(_os.listdir(code_root))
587
+ if _os.path.isdir(_os.path.join(code_root, d)) and not d.startswith('.')]
588
+
589
+ hits = []
590
+ files_hit = 0
591
+ scanned = 0
592
+ import time as _time
593
+ deadline = _time.monotonic() + 15 # 硬超时 15s: data/code 大目录上避免 30s+ 卡死
594
+ timed_out = False
595
+ # 够用即停阈值: 仅当用户没显式指定 --limit 时启用 (默认场景快速溯源)。
596
+ # 用户传了 --limit 就完全尊重它, 不被 early_stop 截断 (原 max(10,min(limit,30))
597
+ # 会把 --limit 50 截成 30、把 --limit 5 抬到 10, 违背用户契约)。
598
+ early_stop = 30 if user_limit is None else None
599
+ for proj in proj_dirs:
600
+ proj_path = _os.path.join(code_root, proj)
601
+ for dirpath, dirnames, filenames in _os.walk(proj_path):
602
+ # 跳过明显的依赖/构建目录, 加速
603
+ dirnames[:] = [d for d in dirnames if d not in
604
+ ('node_modules', '.git', 'target', 'dist', 'build', '.idea', '__pycache__')]
605
+ for fn in filenames:
606
+ # 文件级超时检查: 避免单个大文件卡死目录内循环 (15s 硬超时在目录级
607
+ # 检查时形同虚设)。已找到结果才超时退出, 没找到继续扫。
608
+ if hits and _time.monotonic() > deadline:
609
+ timed_out = True
610
+ break
611
+ ext = _os.path.splitext(fn)[1].lower()
612
+ if ext not in exts:
613
+ continue
614
+ fp = _os.path.join(dirpath, fn)
615
+ # 跳过大文件 (>500KB 多半是生成/压缩文件, 拖慢扫描)
616
+ try:
617
+ if _os.path.getsize(fp) > 500_000:
618
+ continue
619
+ except OSError:
620
+ continue
621
+ scanned += 1
622
+ done = False
623
+ try:
624
+ with open(fp, 'r', encoding='utf-8', errors='ignore') as fh:
625
+ for lineno, line in enumerate(fh, 1):
626
+ # 逐文件行级超时检查: 极大文件逐行读也能及时退出
627
+ if lineno % 20000 == 0 and hits and _time.monotonic() > deadline:
628
+ timed_out = True
629
+ done = True
630
+ break
631
+ if query in line:
632
+ rel = _os.path.relpath(fp, code_root).replace('\\', '/')
633
+ snippet = line.strip()[:120]
634
+ hits.append((rel, lineno, snippet))
635
+ if len(hits) >= limit:
636
+ done = True
637
+ break
638
+ # 够用即停 (仅默认场景): 与 limit 同级行内检查,
639
+ # 避免单文件多行命中跨过 early_stop (原34>30问题)
640
+ if early_stop is not None and len(hits) >= early_stop:
641
+ done = True
642
+ break
643
+ except (OSError, UnicodeDecodeError):
644
+ pass
645
+ if done or len(hits) >= limit:
646
+ break
647
+ # 够用即停 (仅默认场景; 用户显式 limit 时 early_stop=None 跳过)
648
+ if early_stop is not None and len(hits) >= early_stop:
649
+ break
650
+ if timed_out or len(hits) >= limit or (early_stop is not None and len(hits) >= early_stop):
651
+ break
652
+ if timed_out or len(hits) >= limit or (early_stop is not None and len(hits) >= early_stop):
653
+ break
654
+
655
+ # 统计命中文件数 (去重)
656
+ files_hit = len(set(h[0] for h in hits))
657
+ if not hits:
658
+ return ('未找到 "%s" (扫描 %d 个文件, %s)\n'
659
+ '提示: 换近义词, 或用 kg.py semantic "%s" 语义检索' % (
660
+ query, scanned, '/'.join(proj_dirs) or 'data/code', query))
661
+ out = ['grep-text: "%s" → %d 命中 / %d 文件 (扫描 %d 文件%s)' % (
662
+ query, len(hits), files_hit, scanned, ', ⏱15s超时已返回部分结果' if timed_out else '')]
663
+ last_file = ''
664
+ for rel, lineno, snippet in hits:
665
+ if rel != last_file:
666
+ out.append('\n■ %s' % rel)
667
+ last_file = rel
668
+ out.append(' L%d: %s' % (lineno, snippet))
669
+ return '\n'.join(out)
476
670
 
477
671
 
478
672
  # ── 工具函数 ──────────────────────────────────────────────────────────
@@ -525,7 +719,7 @@ def _split_symbol_depth(args):
525
719
  # Role-based section filtering for context_pack output
526
720
  # v3.0: 单一真源移到 common/roles.py, 消除与 kg_mcp_server.py 的逐字重复
527
721
  try:
528
- from common.roles import ROLE_SECTIONS, filter_by_role as _filter_by_role_imported
722
+ from foundation.identity.roles import ROLE_SECTIONS, filter_by_role as _filter_by_role_imported
529
723
  _filter_by_role = _filter_by_role_imported # 保持旧调用名 _filter_by_role 兼容
530
724
  except Exception:
531
725
  # 回退: 内联定义 (common 不可用时, 与 common/roles.py 保持一致)
@@ -574,6 +768,8 @@ COMMANDS = [
574
768
  ('wiki', cmd_wiki, 'Repo Wiki 搜索(模块语义文档)'),
575
769
  ('fill-prototype', cmd_fill_prototype, '原型预填(真实数据填模板,输出 80% HTML)'),
576
770
  ('design-system', cmd_design_system, '设计系统查询(布局指纹/颜色token/组件表)'),
771
+ ('semantic', cmd_semantic, '语义搜索(概念检索:查"报销"命中 expense)'),
772
+ ('grep-text', cmd_grep_text, '中文文案/报错溯源(findstr 替代,单进程不弹窗)'),
577
773
  ]
578
774
 
579
775
 
@@ -584,7 +780,7 @@ def _usage():
584
780
  '',
585
781
  '用法: python .qoder/scripts/kg.py <子命令> [参数]',
586
782
  '',
587
- '14 个子命令:',
783
+ '16 个子命令:',
588
784
  ]
589
785
  for name, _, desc in COMMANDS:
590
786
  lines.append(' %-16s %s' % (name, desc))
@@ -599,14 +795,41 @@ def _usage():
599
795
  ' kg.py workflow assets # 资产模块业务流程',
600
796
  ' kg.py hop 资产管理 --depth 3 # 从资产管理出发 3 跳遍历',
601
797
  ' kg.py context 车辆 --role pm # PM 视角的上下文打包',
798
+ ' kg.py grep-text 车辆不存在 # 中文报错文案溯源 (findstr 安全替代)',
602
799
  '',
603
800
  'QoderWork 环境: AI 也会直接调 MCP 工具(mcp__qoder-knowledge-graph__*),功能等价。',
604
801
  ]
605
802
  return '\n'.join(lines)
606
803
 
607
804
 
805
+ def _try_daemon(cmd, rest):
806
+ """尝试走 daemon 热路径。命中返回 True (已输出结果), 未命中返回 False (回退冷路径)。
807
+
808
+ daemon 常驻模型+连接, semantic 26.8s→0.08s。连不上/出错则透明回退。
809
+ """
810
+ try:
811
+ from kgd import kgd_client, DAEMON_COMMANDS
812
+ except Exception:
813
+ return False # kgd 模块不可用 → 回退
814
+ if cmd not in DAEMON_COMMANDS:
815
+ return False # 该命令不走 daemon
816
+ res = kgd_client.call(cmd, rest)
817
+ if res is None:
818
+ return False # daemon 不在线/出错 → 回退
819
+ text, _secs = res
820
+ print(text)
821
+ return True
822
+
823
+
608
824
  def main(argv=None):
609
825
  argv = argv if argv is not None else sys.argv[1:]
826
+
827
+ # 解析 --no-daemon: 强制冷路径 (调试用)。剥离后不影响后续参数解析。
828
+ use_daemon = True
829
+ if '--no-daemon' in argv:
830
+ use_daemon = False
831
+ argv = [a for a in argv if a != '--no-daemon']
832
+
610
833
  if not argv or argv[0] in ('-h', '--help', 'help'):
611
834
  print(_usage())
612
835
  return 0
@@ -622,6 +845,16 @@ def main(argv=None):
622
845
  print("未知子命令: %s" % cmd)
623
846
  print(_usage())
624
847
  return 1
848
+
849
+ # ⚡ 优先走 daemon 热路径 (模型/连接已常驻, 秒回)
850
+ if use_daemon and _try_daemon(cmd, rest):
851
+ return 0
852
+
853
+ # 冷路径: 直接执行 handler (daemon 不在线 / --no-daemon / 不支持的命令)
854
+ # semantic 在 daemon 不在线时给加速提示 (它单次要 ~27s)
855
+ if cmd == 'semantic' and use_daemon:
856
+ print('[提示] daemon 未运行, semantic 将冷启动 (~27s)。')
857
+ print(' 加速: python .qoder/scripts/domain/kg/server/kgd.py start (常驻后 semantic → 0.08s)')
625
858
  # 执行(全容错,绝不抛栈)
626
859
  try:
627
860
  result = handler(rest)