@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
@@ -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
 
@@ -50,12 +55,12 @@ except (AttributeError, TypeError, OSError, IOError):
50
55
  except Exception:
51
56
  pass
52
57
 
53
- SCRIPTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 子包→scripts根
54
- sys.path.insert(0, SCRIPTS_DIR)
58
+ from foundation.core.paths import get_repo_root, get_developer, get_developer_info
55
59
 
56
- from common.paths import get_repo_root, get_developer, get_developer_info
60
+ SCRIPTS_DIR = str(get_repo_root())
61
+ sys.path.insert(0, SCRIPTS_DIR)
57
62
 
58
- BASE = str(get_repo_root())
63
+ BASE = SCRIPTS_DIR
59
64
  CODE_DIR = os.path.join(BASE, 'data', 'code')
60
65
  INDEX_DIR = os.path.join(BASE, 'data', 'index')
61
66
  TPL_DIR = os.path.join(BASE, '.qoder', 'templates')
@@ -101,7 +106,7 @@ def run_script(script, *args, timeout=1800):
101
106
  def load_config():
102
107
  """v3.0: 转发到 Config 单例 (带 mtime 缓存)。"""
103
108
  try:
104
- from common.config import Config
109
+ from foundation.core.config import Config
105
110
  return Config.load().raw
106
111
  except Exception:
107
112
  cfg = os.path.join(BASE, '.qoder', 'config.yaml')
@@ -185,11 +190,29 @@ def check_dependencies(fix=False):
185
190
  req = os.path.join(BASE, 'requirements.txt')
186
191
  if os.path.isfile(req):
187
192
  # 用镜像兜底安装: 默认源失败 → 自动切清华/阿里/腾讯
188
- from common.pip_install import install_with_fallback
193
+ # 注意: install_with_fallback 在 Anaconda 3.9+ Windows 上, pip 长时间编译
194
+ # 退出时偶发 GIL 崩溃 (Python 进程死)。这里 try 兜住: 崩了就用 os.system
195
+ # 跑裸 pip (独立进程, 无 GIL 问题) 兜底, 绝不让 doctor --fix 卡死。
189
196
  print(' → 安装: pip install -r requirements.txt (失败自动切国内镜像)')
190
- result = install_with_fallback(['-r', req])
197
+ result = None
198
+ try:
199
+ from foundation.utils.pip_install import install_with_fallback
200
+ result = install_with_fallback(['-r', req])
201
+ except Exception as _e:
202
+ print(' [WARN] 镜像安装工具异常 (%s), 改用直装' % str(_e)[:60])
203
+ # 工具崩了或返回失败 → 用 os.system 直装 (清华镜像, 独立进程无 GIL 风险)
204
+ if not result or not result.get('ok'):
205
+ print(' → 直装: pip install -r requirements.txt (清华镜像)')
206
+ import subprocess as _sp
207
+ _rc = _sp.call([sys.executable, '-m', 'pip', 'install', '--no-input',
208
+ '--progress-bar', 'off', '-i',
209
+ 'https://pypi.tuna.tsinghua.edu.cn/simple',
210
+ '--trusted-host', 'pypi.tuna.tsinghua.edu.cn',
211
+ '-r', req])
212
+ result = {'ok': _rc == 0, 'source': '清华' if _rc == 0 else None,
213
+ 'missing': [], 'hint': None}
191
214
  if result['ok']:
192
- src = result['source']
215
+ src = result.get('source')
193
216
  say(FIX, '依赖安装成功' + ('' if src == 'default' else ' (镜像源: %s)' % src))
194
217
  # 装完后重新验证 (旧版装完不复查, 会把装失败误报为已装)
195
218
  missing_core = []
@@ -200,7 +223,8 @@ def check_dependencies(fix=False):
200
223
  except ImportError:
201
224
  missing_core.append(pkg)
202
225
  else:
203
- print(' [MISS] ' + result['hint'])
226
+ print(' [MISS] 依赖仍未装齐, 手动: pip install -r requirements.txt '
227
+ '-i https://pypi.tuna.tsinghua.edu.cn/simple')
204
228
  # 重新验证, 看哪些真的还缺
205
229
  missing_core = []
206
230
  for mod, pkg, usage, is_core in PIP_DEPS:
@@ -246,7 +270,7 @@ def check_developer(fix, name=None, role=None):
246
270
  return None
247
271
  if name and (not current or current != name):
248
272
  if fix:
249
- from common.developer import init_developer
273
+ from foundation.identity.developer import init_developer
250
274
  if init_developer(name, role):
251
275
  actions.append('注册/切换开发者: ' + name)
252
276
  return name
@@ -430,11 +454,11 @@ def print_degraded_status():
430
454
  print('=' * 56)
431
455
  print(' 以下功能需要源码, 当前不可用:')
432
456
  print(' /wl-search 搜代码 (无源码 = 搜不到)')
433
- print(' /wl-prd-full 完整 PRD 的字段/API 锚定 (会跳过, 原型可用)')
457
+ print(' /wl-prd 完整 PRD 的字段/API 锚定 (会跳过, 原型可用)')
434
458
  print(' 知识图谱 MCP search_code/api 等工具 (启动但返回空)')
435
459
  print()
436
460
  print(' 以下功能不依赖源码, 当前可用:')
437
- print(' /wl-prd-quick 零星需求 (纯文案/小改动)')
461
+ print(' /wl-prd 零星需求模式 (纯文案/小改动)')
438
462
  print(' /wl-task 任务管理')
439
463
  print(' /wl-report 日报周报')
440
464
  print(' /wl-commit 代码提交 (提交的是工作流本身的改动)')
@@ -730,7 +754,7 @@ def check_lanhu():
730
754
  mcp_file = os.path.join(home, '.qoderwork', 'mcp.json')
731
755
  if not os.path.isfile(mcp_file):
732
756
  say(WARN, '未配置蓝湖 MCP (团队不用蓝湖可忽略)')
733
- print(' 用的话跑: python .qoder/scripts/setup.py 或 setup_lanhu.py')
757
+ print(' 用的话跑: python .qoder/scripts/deployment/setup/setup_lanhu.py')
734
758
  return
735
759
 
736
760
  try:
@@ -742,7 +766,7 @@ def check_lanhu():
742
766
 
743
767
  if 'lanhu' not in servers:
744
768
  say(WARN, '未配置蓝湖 MCP (团队不用蓝湖可忽略)')
745
- print(' 用的话跑: python .qoder/scripts/setup.py 或 setup_lanhu.py')
769
+ print(' 用的话跑: python .qoder/scripts/deployment/setup/setup_lanhu.py')
746
770
  return
747
771
 
748
772
  entry = servers['lanhu']
@@ -818,7 +842,7 @@ def main():
818
842
  print('=' * 56)
819
843
  return 1
820
844
  if _has_source_code():
821
- print('环境健康, 可以开始工作: /wl-prd-full <需求描述>')
845
+ print('环境健康, 可以开始工作: /wl-prd <需求描述>')
822
846
  else:
823
847
  print('工作流核心已就绪 (见上方降级说明补源码)。')
824
848
  print('=' * 56)
@@ -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
  install_qoderwork.py - 把 .qoder/skills/ 安装到 QoderWork 桌面端可识别的位置
@@ -46,7 +52,7 @@ if sys.platform == "win32":
46
52
 
47
53
  # 路径自检:项目根 = 本文件上四级 (v3.0: setup/ -> scripts/ -> .qoder/ -> repo)
48
54
  SCRIPT_DIR = Path(__file__).resolve().parent
49
- PROJECT_ROOT = SCRIPT_DIR.parent.parent.parent # v3.0: setup子包多一层
55
+ PROJECT_ROOT = get_repo_root()
50
56
  SOURCE_SKILLS_DIR = PROJECT_ROOT / ".qoder" / "skills"
51
57
  SOURCE_COMMANDS_DIR = PROJECT_ROOT / ".qoder" / "commands"
52
58
 
@@ -416,10 +422,12 @@ def rewrite_mcp_json_for_launcher():
416
422
  # 绝对路径每次 install 时探测, 换机器重跑 update 自动刷新。
417
423
  # 依赖查找: 先找装了 duckdb 的 python (find_python_with_core_deps),
418
424
  # 找不到回退 detect_python_command。
419
- try:
420
- py_cmd = find_python_with_core_deps()
421
- except Exception:
422
- py_cmd = detect_python_command() or "python"
425
+ # ⚠ find_python_with_core_deps 返回 None (不抛异常) 时, 旧代码因 try/except
426
+ # 捕不到 → py_cmd None → mcp.json 写 "command": null → QoderWork 起 MCP
427
+ # 失败变黄。这里显式 None 判断 + 多级回退, 绝不写 null。
428
+ py_cmd = find_python_with_core_deps()
429
+ if not py_cmd:
430
+ py_cmd = detect_python_command() or sys.executable or "python"
423
431
  launcher = str(_HOME / ".qoderwork" / "mcp_launcher.py")
424
432
  # MCP 名 → launcher 子命令
425
433
  name_map = {
@@ -496,7 +504,7 @@ def main():
496
504
  print("MCP 配置刷新 (--mcp-only)")
497
505
  print("=" * 56)
498
506
  # 1. 复制 launcher
499
- launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "mcp" / "mcp_launcher.py" # v3.0: mcp子包
507
+ launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "protocol" / "mcp" / "mcp_launcher.py" # v3.0: protocol/mcp子包
500
508
  launcher_dst = _HOME / ".qoderwork" / "mcp_launcher.py"
501
509
  try:
502
510
  launcher_dst.parent.mkdir(parents=True, exist_ok=True)
@@ -669,7 +677,7 @@ def main():
669
677
  # QoderWork 桌面端工作目录是临时会话目录, 不是仓库根, 相对路径失效。
670
678
  # repo_root.py 从 mcp.json 反推仓库根, 命令文件靠它定位脚本/模板。
671
679
  if action in ("install", "check"):
672
- repo_root_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "setup" / "repo_root.py" # v3.0: setup子包
680
+ repo_root_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "deployment" / "setup" / "repo_root.py" # v3.0: deployment/setup子包
673
681
  repo_root_dst = _HOME / ".qoderwork" / "repo_root.py"
674
682
  if repo_root_src.is_file():
675
683
  if action == "check":
@@ -694,7 +702,7 @@ def main():
694
702
  # .repo-root 锚点文件让 launcher 能定位仓库根 (不依赖 mcp.json 里的路径)。
695
703
  if action in ("install", "check"):
696
704
  print(f"\n--- mcp_launcher.py (统一 MCP 启动器) ---")
697
- launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "mcp" / "mcp_launcher.py" # v3.0: mcp子包
705
+ launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "protocol" / "mcp" / "mcp_launcher.py" # v3.0: protocol/mcp子包
698
706
  launcher_dst = _HOME / ".qoderwork" / "mcp_launcher.py"
699
707
  anchor_dst = _HOME / ".qoderwork" / ".repo-root"
700
708
  if action == "check":
@@ -765,7 +773,7 @@ def main():
765
773
  elif lh_status == "would-add":
766
774
  print(f" [MISS] 未注册蓝湖 MCP, 安装时会写入 {QODERWORK_MCP_FILE}")
767
775
  # STDIO 模式由 QoderWork 自动管, 不查端口; 只确认 wrapper + 源码就绪
768
- wrapper = PROJECT_ROOT / ".qoder" / "scripts" / "lanhu_stdio_wrapper.py"
776
+ wrapper = PROJECT_ROOT / ".qoder" / "scripts" / "protocol" / "mcp" / "lanhu_stdio_wrapper.py"
769
777
  lanhu_dir = PROJECT_ROOT / "external" / "lanhu-mcp"
770
778
  if wrapper.is_file():
771
779
  print(f" wrapper 就绪: {wrapper.name} (按角色读 cookie)")
@@ -777,8 +785,8 @@ def main():
777
785
  if action == "install" and counts["err"] == 0:
778
786
  print("\n✓ 安装完成。重启 QoderWork(或新建对话)后技能生效。")
779
787
  print(" 在 QoderWork 里直接用自然语言即可,例如:")
780
- print(' "写个保险异常筛选的 PRD" -> /wl-prd-full(正经需求)')
781
- print(' "列表加个导出按钮" -> /wl-prd-quick(小改动)')
788
+ print(' "写个保险异常筛选的 PRD" -> /wl-prd(正经需求, 完整档)')
789
+ print(' "列表加个导出按钮" -> /wl-prd(小改动, 自动走快速档)')
782
790
  print(' "查一下考勤代码在哪" -> /wl-search')
783
791
  elif action == "install" and counts["err"] > 0:
784
792
  print(f"\n⚠ 有 {counts['err']} 个安装失败,见上方 [ERR] 行。")
@@ -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
  platform_doctor.py - 跨平台环境自诊断 (任何 OS 跑, 输出环境真相)
@@ -49,7 +55,7 @@ for candidate in [HERE.parent.parent, HERE.parent, HERE]:
49
55
  BASE = candidate
50
56
  break
51
57
  if BASE is None:
52
- BASE = HERE.parent.parent # 最佳猜测
58
+ BASE = get_repo_root()
53
59
 
54
60
  report = {'platform': {}, 'tools': {}, 'engine': {}, 'mcp': {},
55
61
  'role': {}, 'issues': [], 'verdict': 'UNKNOWN'}
@@ -1,112 +1,113 @@
1
- # -*- coding: utf-8 -*-
2
- # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
3
- import os as _o, sys as _s
4
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
5
- if _cp not in _s.path: _s.path.insert(0, _cp)
6
- from bootstrap import setup; setup()
7
-
8
- """
9
- repo_root.py — 自适应定位 QODER 流水线仓库根(QoderWork 桌面端专用)。
10
-
11
- 为什么需要它:
12
- QoderWork 桌面端的工作目录是临时会话目录(workspace/xxx), 不是仓库根。
13
- 命令文件里的相对路径 .qoder/scripts/xxx.py 全部失效。
14
- 本脚本从 ~/.qoderwork/mcp.json 的 kg_mcp_server.py 绝对路径反推仓库根,
15
- 自适应(换机器重装 install 后 mcp.json 会更新, 无需硬编码)。
16
-
17
- 用法(命令文件里):
18
- python ~/.qoderwork/repo_root.py # 打印仓库根绝对路径
19
- python ~/.qoderwork/repo_root.py --script kg.py # 打印仓库内脚本的绝对路径
20
- python ~/.qoderwork/repo_root.py --template prd-quick-template.md
21
-
22
- R=$(python ~/.qoderwork/repo_root.py) # 在 Bash 里捕获仓库根
23
- python "$R/.qoder/scripts/kg.py" context 保险 --platform web
24
- """
25
- import json
26
- import os
27
- import sys
28
-
29
-
30
- def find_repo_root():
31
- """定位 QODER 仓库根。优先级:
32
- 1. ~/.qoderwork/.repo-root 文件 (install 时写, 主路径)
33
- 2. 环境变量 QODER_REPO
34
- 3. 向上找 .qoder/scripts/ (cwd 在仓库内)
35
- 4. 本脚本所在位置 (开发态)
36
- 失败返回 None。
37
- """
38
- home = os.path.expanduser('~')
39
-
40
- # 方法1: .repo-root 锚点文件 (install_qoderwork 写的, 最可靠)
41
- anchor = os.path.join(home, '.qoderwork', '.repo-root')
42
- if os.path.isfile(anchor):
43
- try:
44
- line = open(anchor, encoding='utf-8').read().strip()
45
- if line and os.path.isdir(os.path.join(line, '.qoder', 'scripts')):
46
- return line
47
- except OSError:
48
- pass
49
-
50
- # 方法2: 环境变量
51
- env_repo = os.environ.get('QODER_REPO')
52
- if env_repo and os.path.isdir(os.path.join(env_repo, '.qoder', 'scripts')):
53
- return env_repo
54
-
55
- # 方法3: 向上找 .qoder 目录(适用于工作目录在仓库内的情况, 如 IDE)
56
- here = os.path.abspath(os.getcwd())
57
- for _ in range(8):
58
- if os.path.isdir(os.path.join(here, '.qoder', 'scripts')):
59
- return here
60
- parent = os.path.dirname(here)
61
- if parent == here:
62
- break
63
- here = parent
64
-
65
- # 方法4: 本脚本所在位置(若它被放到仓库 .qoder/scripts/ 下)
66
- try:
67
- s = os.path.abspath(__file__)
68
- root = os.path.dirname(os.path.dirname(os.path.dirname(s)))
69
- if os.path.isdir(os.path.join(root, '.qoder', 'scripts')):
70
- return root
71
- except Exception:
72
- pass
73
-
74
- return None
75
-
76
-
77
- def main():
78
- root = find_repo_root()
79
- if not root:
80
- print('ERROR: 无法定位 QODER 仓库根。请确认 ~/.qoderwork/mcp.json 存在且指向有效的 kg_mcp_server.py', file=sys.stderr)
81
- return 1
82
-
83
- # 子路径模式: --script / --template
84
- args = sys.argv[1:]
85
- if args and args[0] in ('--script', '--scripts'):
86
- # 打印仓库内 .qoder/scripts/<name> 的绝对路径
87
- name = args[1] if len(args) > 1 else ''
88
- print(os.path.join(root, '.qoder', 'scripts', name))
89
- elif args and args[0] in ('--template', '--templates'):
90
- name = args[1] if len(args) > 1 else ''
91
- print(os.path.join(root, '.qoder', 'templates', name))
92
- elif args and args[0] == '--test':
93
- # 自检: 验证关键文件存在
94
- checks = [
95
- ('kg.py', '.qoder/scripts/kg.py'),
96
- ('eval_prd.py', '.qoder/scripts/eval_prd.py'),
97
- ('quick模板', '.qoder/templates/prd-quick-template.md'),
98
- ('full模板', '.qoder/templates/prd-full-template.md'),
99
- ('kg.duckdb', 'data/index/kg.duckdb'),
100
- ]
101
- print('仓库根: %s' % root)
102
- for label, rel in checks:
103
- ok = os.path.isfile(os.path.join(root, rel))
104
- print(' %s %s' % ('✅' if ok else '❌', label))
105
- else:
106
- # 默认: 只打印仓库根
107
- print(root)
108
- return 0
109
-
110
-
111
- if __name__ == '__main__':
112
- sys.exit(main())
1
+ # -*- coding: utf-8 -*-
2
+ # repo_root.py 自适应定位 QODER 流水线仓库根(QoderWork 桌面端专用)。
3
+ #
4
+ # ⚠️ 本文件被 install_qoderwork.py 复制到 ~/.qoderwork/repo_root.py, 在那里它
5
+ # 独立运行 (不依赖仓库内的任何模块)。所以这里**零 import 依赖**——
6
+ # 不能 from bootstrap import (那是仓库内的模块, 定位器不能依赖被定位的东西)
7
+ # bootstrap 的 sys.path 自举作用对其他被复制脚本有效, 对本定位器是死循环。
8
+
9
+ """
10
+ repo_root.py — 自适应定位 QODER 流水线仓库根(QoderWork 桌面端专用)。
11
+
12
+ 为什么需要它:
13
+ QoderWork 桌面端的工作目录是临时会话目录(workspace/xxx), 不是仓库根。
14
+ 命令文件里的相对路径 .qoder/scripts/xxx.py 全部失效。
15
+ 本脚本从 ~/.qoderwork/mcp.json kg_mcp_server.py 绝对路径反推仓库根,
16
+ 自适应(换机器重装 install 后 mcp.json 会更新, 无需硬编码)。
17
+
18
+ 用法(命令文件里):
19
+ python ~/.qoderwork/repo_root.py # 打印仓库根绝对路径
20
+ python ~/.qoderwork/repo_root.py --script kg.py # 打印仓库内脚本的绝对路径
21
+ python ~/.qoderwork/repo_root.py --template prd-quick-template.md
22
+
23
+ R=$(python ~/.qoderwork/repo_root.py) # Bash 里捕获仓库根
24
+ python "$R/.qoder/scripts/kg.py" context 保险 --platform web
25
+ """
26
+ import json
27
+ import os
28
+ import sys
29
+
30
+
31
+ def find_repo_root():
32
+ """定位 QODER 仓库根。优先级:
33
+ 1. ~/.qoderwork/.repo-root 文件 (install 时写, 主路径)
34
+ 2. 环境变量 QODER_REPO
35
+ 3. 向上找 .qoder/scripts/ (cwd 在仓库内)
36
+ 4. 本脚本所在位置 (开发态)
37
+ 失败返回 None。
38
+ """
39
+ home = os.path.expanduser('~')
40
+
41
+ # 方法1: .repo-root 锚点文件 (install_qoderwork 写的, 最可靠)
42
+ anchor = os.path.join(home, '.qoderwork', '.repo-root')
43
+ if os.path.isfile(anchor):
44
+ try:
45
+ line = open(anchor, encoding='utf-8').read().strip()
46
+ if line and os.path.isdir(os.path.join(line, '.qoder', 'scripts')):
47
+ return line
48
+ except OSError:
49
+ pass
50
+
51
+ # 方法2: 环境变量
52
+ env_repo = os.environ.get('QODER_REPO')
53
+ if env_repo and os.path.isdir(os.path.join(env_repo, '.qoder', 'scripts')):
54
+ return env_repo
55
+
56
+ # 方法3: 向上找 .qoder 目录(适用于工作目录在仓库内的情况, 如 IDE)
57
+ here = os.path.abspath(os.getcwd())
58
+ for _ in range(8):
59
+ if os.path.isdir(os.path.join(here, '.qoder', 'scripts')):
60
+ return here
61
+ parent = os.path.dirname(here)
62
+ if parent == here:
63
+ break
64
+ here = parent
65
+
66
+ # 方法4: 本脚本所在位置(若它被放到仓库 .qoder/scripts/ 下)
67
+ try:
68
+ s = os.path.abspath(__file__)
69
+ root = os.path.dirname(os.path.dirname(os.path.dirname(s)))
70
+ if os.path.isdir(os.path.join(root, '.qoder', 'scripts')):
71
+ return root
72
+ except Exception:
73
+ pass
74
+
75
+ return None
76
+
77
+
78
+ def main():
79
+ root = find_repo_root()
80
+ if not root:
81
+ print('ERROR: 无法定位 QODER 仓库根。请确认 ~/.qoderwork/mcp.json 存在且指向有效的 kg_mcp_server.py', file=sys.stderr)
82
+ return 1
83
+
84
+ # 子路径模式: --script / --template
85
+ args = sys.argv[1:]
86
+ if args and args[0] in ('--script', '--scripts'):
87
+ # 打印仓库内 .qoder/scripts/<name> 的绝对路径
88
+ name = args[1] if len(args) > 1 else ''
89
+ print(os.path.join(root, '.qoder', 'scripts', name))
90
+ elif args and args[0] in ('--template', '--templates'):
91
+ name = args[1] if len(args) > 1 else ''
92
+ print(os.path.join(root, '.qoder', 'templates', name))
93
+ elif args and args[0] == '--test':
94
+ # 自检: 验证关键文件存在
95
+ checks = [
96
+ ('kg.py', '.qoder/scripts/domain/kg/kg.py'),
97
+ ('eval_prd.py', '.qoder/scripts/validation/metrics/eval_prd.py'),
98
+ ('quick模板', '.qoder/templates/prd-quick-template.md'),
99
+ ('full模板', '.qoder/templates/prd-full-template.md'),
100
+ ('kg.duckdb', 'data/index/kg.duckdb'),
101
+ ]
102
+ print('仓库根: %s' % root)
103
+ for label, rel in checks:
104
+ ok = os.path.isfile(os.path.join(root, rel))
105
+ print(' %s %s' % ('✅' if ok else '❌', label))
106
+ else:
107
+ # 默认: 只打印仓库根
108
+ print(root)
109
+ return 0
110
+
111
+
112
+ if __name__ == '__main__':
113
+ sys.exit(main())
@@ -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
  setup.py - 一键就绪 (小而美)
@@ -41,7 +47,7 @@ except (AttributeError, TypeError, OSError):
41
47
  pass
42
48
 
43
49
  THIS_DIR = Path(__file__).resolve().parent
44
- BASE = THIS_DIR.parent.parent # repo root
50
+ BASE = get_repo_root()
45
51
 
46
52
 
47
53
  # ============================================================
@@ -641,10 +647,12 @@ def offer_cron(skip=False):
641
647
  return
642
648
 
643
649
  if ask('注册周五 18:00 自动更新知识图谱? (团队只需一台机器注册)', 'y'):
650
+ # cron 脚本在 scripts/ 根 (THIS_DIR = scripts/deployment/setup/, 上两级)
651
+ cron_dir = THIS_DIR.parent.parent
644
652
  if sys.platform == 'win32':
645
- r = run(['cmd', '/c', str(THIS_DIR / 'setup_weekly_cron.bat')], cwd=str(BASE))
653
+ r = run(['cmd', '/c', str(cron_dir / 'setup_weekly_cron.bat')], cwd=str(BASE))
646
654
  else:
647
- r = run(['bash', str(THIS_DIR / 'setup_weekly_cron.sh')], cwd=str(BASE))
655
+ r = run(['bash', str(cron_dir / 'setup_weekly_cron.sh')], cwd=str(BASE))
648
656
  if r.returncode == 0:
649
657
  ok('cron 已注册 (周五 18:00)')
650
658
  else:
@@ -764,13 +772,25 @@ def print_ready(name, role):
764
772
  if projects:
765
773
  ok(f'源码仓库: {len(projects)} 个项目 ({", ".join(projects[:3])})')
766
774
 
767
- # 索引
768
- ki = BASE / 'data' / 'index' / 'code-keyword.json'
769
- if ki.is_file():
775
+ # 知识图谱 (DuckDB 是唯一事实源; 旧 code-keyword.json 已废弃)
776
+ kg = BASE / 'data' / 'index' / 'kg.duckdb'
777
+ if kg.is_file():
770
778
  try:
771
- import json
772
- data = json.loads(ki.read_text(encoding='utf-8'))
773
- ok(f'知识图谱: {len(data)} keywords')
779
+ size_kb = kg.stat().st_size // 1024
780
+ # 尝试读关键词行数作为"有内容"的证据 (读不到只报大小)
781
+ kw_n = None
782
+ try:
783
+ import duckdb as _ddb
784
+ con = _ddb.connect(str(kg), read_only=True)
785
+ row = con.execute('SELECT COUNT(*) FROM keywords').fetchone()
786
+ con.close()
787
+ kw_n = row[0] if row else None
788
+ except Exception:
789
+ pass
790
+ if kw_n:
791
+ ok(f'知识图谱: {kw_n} keywords (kg.duckdb {size_kb} KB)')
792
+ else:
793
+ ok(f'知识图谱: kg.duckdb {size_kb} KB')
774
794
  except Exception:
775
795
  pass
776
796
 
@@ -793,7 +813,7 @@ def print_ready(name, role):
793
813
 
794
814
  print()
795
815
  print(' 现在可以开始了:')
796
- print(' /wl-prd-full 写需求 /wl-search 查代码 /wl-task 建任务')
816
+ print(' /wl-prd 写需求 /wl-search 查代码 /wl-task 建任务')
797
817
  print(' /wl-status 看进度 /wl-report 出日报 /wl-commit 提交')
798
818
  print()
799
819
  print(' 或直接用自然语言:')
@@ -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
  setup_lanhu.py - 蓝湖 MCP 引导器 (幂等)
@@ -48,7 +54,7 @@ except (AttributeError, TypeError, OSError):
48
54
  pass
49
55
 
50
56
  THIS_DIR = Path(__file__).resolve().parent
51
- BASE = THIS_DIR.parent.parent.parent # repo root (M2子目录化: setup/ → scripts/ → .qoder/ → repo)
57
+ BASE = get_repo_root()
52
58
 
53
59
  LANHU_REPO = 'https://github.com/dsphper/lanhu-mcp.git'
54
60
  EXTERNAL_DIR = BASE / 'external'
@@ -71,7 +77,7 @@ def _current_developer():
71
77
  """读 .qoder/.developer 确定当前用户。没有返回 None。"""
72
78
  try:
73
79
  sys.path.insert(0, str(THIS_DIR))
74
- from common.paths import get_developer
80
+ from foundation.core.paths import get_developer
75
81
  return get_developer(BASE)
76
82
  except Exception:
77
83
  return None
@@ -85,14 +91,14 @@ def lanhu_secrets_dir(developer=None):
85
91
  dev = developer or _current_developer() or 'default'
86
92
  try:
87
93
  sys.path.insert(0, str(BASE / '.qoder' / 'scripts'))
88
- from common.paths import get_secrets_dir
94
+ from foundation.core.paths import get_secrets_dir
89
95
  return Path(get_secrets_dir(dev))
90
96
  except Exception:
91
97
  return BASE / 'workspace' / 'members' / dev / '.secrets'
92
98
 
93
99
 
94
100
  def lanhu_env_file(developer=None):
95
- """当前用户的蓝湖 cookie 文件: workspace/members/{dev}/.secrets/lanhu.env"""
101
+ """当前用户的蓝湖 cookie 文件: workspace/members/{dev}/.private/secrets/lanhu.env"""
96
102
  return lanhu_secrets_dir(developer) / 'lanhu.env'
97
103
 
98
104
 
@@ -349,7 +355,7 @@ def ensure_deps(dry=False, _rebuilt=False):
349
355
 
350
356
 
351
357
  # ============================================================
352
- # Step 3: cookie (按开发者隔离, workspace/members/{dev}/.secrets/lanhu.env)
358
+ # Step 3: cookie (按开发者隔离, workspace/members/{dev}/.private/secrets/lanhu.env)
353
359
  # ============================================================
354
360
  # 为什么不放 external/lanhu-mcp/.env:
355
361
  # 1. cookie 是个人登录凭证, 不该进仓库代码区 (即使 gitignore)
@@ -378,7 +384,7 @@ def _read_env_cookie(developer=None):
378
384
  def _write_env_cookie(cookie, developer=None):
379
385
  """把 LANHU_COOKIE 写进当前用户的 lanhu.env (保留其他行)。
380
386
 
381
- 文件: workspace/members/{dev}/.secrets/lanhu.env (已 gitignore)
387
+ 文件: workspace/members/{dev}/.private/secrets/lanhu.env (已 gitignore)
382
388
  """
383
389
  env_file = lanhu_env_file(developer)
384
390
  try:
File without changes