@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
@@ -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')
@@ -83,16 +88,24 @@ def problem(msg, hint=None):
83
88
 
84
89
  def run_script(script, *args, timeout=1800):
85
90
  """跑另一个脚本, 实时透传输出。
86
- v3.0: 支持子目录化 — 先在 scripts/根找, 找不到扫各子包。"""
91
+
92
+ v3.x: 脚本已分子目录 (domain/task/, domain/kg/build/, ...), 不再固定在少数子包。
93
+ 用递归 glob 在 scripts/ 下找, 找不到才报错 —— 根治"目录一重组 run_script 就断链"
94
+ (旧版硬扫 io/setup/kg/build/test 这几个子目录, v3.0 重组后全找不到)。
95
+ """
96
+ import glob
97
+ if not script.endswith('.py'):
98
+ script = script + '.py'
87
99
  # 先试 scripts/根
88
100
  cand = os.path.join(SCRIPTS_DIR, script)
89
101
  if not os.path.isfile(cand):
90
- # 扫各子包
91
- for sub in ('io', 'setup', 'kg', 'build', 'test'):
92
- c2 = os.path.join(SCRIPTS_DIR, sub, script)
93
- if os.path.isfile(c2):
94
- cand = c2
95
- break
102
+ # 递归找 scripts/**/<script>
103
+ hits = glob.glob(os.path.join(SCRIPTS_DIR, '**', script), recursive=True)
104
+ if hits:
105
+ cand = hits[0]
106
+ else:
107
+ print('[run_script] 找不到脚本: %s (在 scripts/ 下递归也没找到)' % script)
108
+ return False
96
109
  cmd = [sys.executable, cand] + list(args)
97
110
  r = subprocess.run(cmd, cwd=BASE, timeout=timeout)
98
111
  return r.returncode == 0
@@ -101,7 +114,7 @@ def run_script(script, *args, timeout=1800):
101
114
  def load_config():
102
115
  """v3.0: 转发到 Config 单例 (带 mtime 缓存)。"""
103
116
  try:
104
- from common.config import Config
117
+ from foundation.core.config import Config
105
118
  return Config.load().raw
106
119
  except Exception:
107
120
  cfg = os.path.join(BASE, '.qoder', 'config.yaml')
@@ -185,11 +198,29 @@ def check_dependencies(fix=False):
185
198
  req = os.path.join(BASE, 'requirements.txt')
186
199
  if os.path.isfile(req):
187
200
  # 用镜像兜底安装: 默认源失败 → 自动切清华/阿里/腾讯
188
- from common.pip_install import install_with_fallback
201
+ # 注意: install_with_fallback 在 Anaconda 3.9+ Windows 上, pip 长时间编译
202
+ # 退出时偶发 GIL 崩溃 (Python 进程死)。这里 try 兜住: 崩了就用 os.system
203
+ # 跑裸 pip (独立进程, 无 GIL 问题) 兜底, 绝不让 doctor --fix 卡死。
189
204
  print(' → 安装: pip install -r requirements.txt (失败自动切国内镜像)')
190
- result = install_with_fallback(['-r', req])
205
+ result = None
206
+ try:
207
+ from foundation.utils.pip_install import install_with_fallback
208
+ result = install_with_fallback(['-r', req])
209
+ except Exception as _e:
210
+ print(' [WARN] 镜像安装工具异常 (%s), 改用直装' % str(_e)[:60])
211
+ # 工具崩了或返回失败 → 用 os.system 直装 (清华镜像, 独立进程无 GIL 风险)
212
+ if not result or not result.get('ok'):
213
+ print(' → 直装: pip install -r requirements.txt (清华镜像)')
214
+ import subprocess as _sp
215
+ _rc = _sp.call([sys.executable, '-m', 'pip', 'install', '--no-input',
216
+ '--progress-bar', 'off', '-i',
217
+ 'https://pypi.tuna.tsinghua.edu.cn/simple',
218
+ '--trusted-host', 'pypi.tuna.tsinghua.edu.cn',
219
+ '-r', req])
220
+ result = {'ok': _rc == 0, 'source': '清华' if _rc == 0 else None,
221
+ 'missing': [], 'hint': None}
191
222
  if result['ok']:
192
- src = result['source']
223
+ src = result.get('source')
193
224
  say(FIX, '依赖安装成功' + ('' if src == 'default' else ' (镜像源: %s)' % src))
194
225
  # 装完后重新验证 (旧版装完不复查, 会把装失败误报为已装)
195
226
  missing_core = []
@@ -200,7 +231,8 @@ def check_dependencies(fix=False):
200
231
  except ImportError:
201
232
  missing_core.append(pkg)
202
233
  else:
203
- print(' [MISS] ' + result['hint'])
234
+ print(' [MISS] 依赖仍未装齐, 手动: pip install -r requirements.txt '
235
+ '-i https://pypi.tuna.tsinghua.edu.cn/simple')
204
236
  # 重新验证, 看哪些真的还缺
205
237
  missing_core = []
206
238
  for mod, pkg, usage, is_core in PIP_DEPS:
@@ -246,7 +278,7 @@ def check_developer(fix, name=None, role=None):
246
278
  return None
247
279
  if name and (not current or current != name):
248
280
  if fix:
249
- from common.developer import init_developer
281
+ from foundation.identity.developer import init_developer
250
282
  if init_developer(name, role):
251
283
  actions.append('注册/切换开发者: ' + name)
252
284
  return name
@@ -430,11 +462,11 @@ def print_degraded_status():
430
462
  print('=' * 56)
431
463
  print(' 以下功能需要源码, 当前不可用:')
432
464
  print(' /wl-search 搜代码 (无源码 = 搜不到)')
433
- print(' /wl-prd-full 完整 PRD 的字段/API 锚定 (会跳过, 原型可用)')
465
+ print(' /wl-prd 完整 PRD 的字段/API 锚定 (会跳过, 原型可用)')
434
466
  print(' 知识图谱 MCP search_code/api 等工具 (启动但返回空)')
435
467
  print()
436
468
  print(' 以下功能不依赖源码, 当前可用:')
437
- print(' /wl-prd-quick 零星需求 (纯文案/小改动)')
469
+ print(' /wl-prd 零星需求模式 (纯文案/小改动)')
438
470
  print(' /wl-task 任务管理')
439
471
  print(' /wl-report 日报周报')
440
472
  print(' /wl-commit 代码提交 (提交的是工作流本身的改动)')
@@ -730,7 +762,7 @@ def check_lanhu():
730
762
  mcp_file = os.path.join(home, '.qoderwork', 'mcp.json')
731
763
  if not os.path.isfile(mcp_file):
732
764
  say(WARN, '未配置蓝湖 MCP (团队不用蓝湖可忽略)')
733
- print(' 用的话跑: python .qoder/scripts/setup.py 或 setup_lanhu.py')
765
+ print(' 用的话跑: python .qoder/scripts/deployment/setup/setup_lanhu.py')
734
766
  return
735
767
 
736
768
  try:
@@ -742,7 +774,7 @@ def check_lanhu():
742
774
 
743
775
  if 'lanhu' not in servers:
744
776
  say(WARN, '未配置蓝湖 MCP (团队不用蓝湖可忽略)')
745
- print(' 用的话跑: python .qoder/scripts/setup.py 或 setup_lanhu.py')
777
+ print(' 用的话跑: python .qoder/scripts/deployment/setup/setup_lanhu.py')
746
778
  return
747
779
 
748
780
  entry = servers['lanhu']
@@ -818,7 +850,7 @@ def main():
818
850
  print('=' * 56)
819
851
  return 1
820
852
  if _has_source_code():
821
- print('环境健康, 可以开始工作: /wl-prd-full <需求描述>')
853
+ print('环境健康, 可以开始工作: /wl-prd <需求描述>')
822
854
  else:
823
855
  print('工作流核心已就绪 (见上方降级说明补源码)。')
824
856
  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,16 +647,21 @@ 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:
651
659
  warn(f'cron 注册失败: {(r.stderr or "").strip()[:100]}')
652
660
  else:
653
- print(' 跳过。以后可手动跑: python .qoder/scripts/setup_weekly_cron.bat')
661
+ if sys.platform == 'win32':
662
+ print(' 跳过。以后可手动跑 (双击或命令行): .qoder\\scripts\\setup_weekly_cron.bat')
663
+ else:
664
+ print(' 跳过。以后可手动跑: bash .qoder/scripts/setup_weekly_cron.sh')
654
665
 
655
666
 
656
667
  # ============================================================
@@ -764,13 +775,25 @@ def print_ready(name, role):
764
775
  if projects:
765
776
  ok(f'源码仓库: {len(projects)} 个项目 ({", ".join(projects[:3])})')
766
777
 
767
- # 索引
768
- ki = BASE / 'data' / 'index' / 'code-keyword.json'
769
- if ki.is_file():
778
+ # 知识图谱 (DuckDB 是唯一事实源; 旧 code-keyword.json 已废弃)
779
+ kg = BASE / 'data' / 'index' / 'kg.duckdb'
780
+ if kg.is_file():
770
781
  try:
771
- import json
772
- data = json.loads(ki.read_text(encoding='utf-8'))
773
- ok(f'知识图谱: {len(data)} keywords')
782
+ size_kb = kg.stat().st_size // 1024
783
+ # 尝试读关键词行数作为"有内容"的证据 (读不到只报大小)
784
+ kw_n = None
785
+ try:
786
+ import duckdb as _ddb
787
+ con = _ddb.connect(str(kg), read_only=True)
788
+ row = con.execute('SELECT COUNT(*) FROM keywords').fetchone()
789
+ con.close()
790
+ kw_n = row[0] if row else None
791
+ except Exception:
792
+ pass
793
+ if kw_n:
794
+ ok(f'知识图谱: {kw_n} keywords (kg.duckdb {size_kb} KB)')
795
+ else:
796
+ ok(f'知识图谱: kg.duckdb {size_kb} KB')
774
797
  except Exception:
775
798
  pass
776
799
 
@@ -793,7 +816,7 @@ def print_ready(name, role):
793
816
 
794
817
  print()
795
818
  print(' 现在可以开始了:')
796
- print(' /wl-prd-full 写需求 /wl-search 查代码 /wl-task 建任务')
819
+ print(' /wl-prd 写需求 /wl-search 查代码 /wl-task 建任务')
797
820
  print(' /wl-status 看进度 /wl-report 出日报 /wl-commit 提交')
798
821
  print()
799
822
  print(' 或直接用自然语言:')