@hupan56/wlkj 2.7.12 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/bin/cli.js +1435 -1107
  2. package/package.json +29 -29
  3. package/templates/qoder/agents/insight-planning.md +1 -1
  4. package/templates/qoder/agents/insight-research.md +28 -15
  5. package/templates/qoder/commands/optional/wl-insight.md +161 -161
  6. package/templates/qoder/commands/optional/wl-report.md +20 -39
  7. package/templates/qoder/commands/optional/wl-status.md +4 -4
  8. package/templates/qoder/commands/wl-code.md +2 -2
  9. package/templates/qoder/commands/wl-design.md +6 -6
  10. package/templates/qoder/commands/wl-init.md +3 -3
  11. package/templates/qoder/commands/wl-prd.md +26 -13
  12. package/templates/qoder/commands/wl-req.md +43 -0
  13. package/templates/qoder/commands/wl-search.md +78 -47
  14. package/templates/qoder/commands/wl-task.md +343 -40
  15. package/templates/qoder/commands/wl-test.md +43 -17
  16. package/templates/qoder/config.yaml +52 -14
  17. package/templates/qoder/hooks/post-tool-use.py +181 -0
  18. package/templates/qoder/hooks/session-start.py +94 -23
  19. package/templates/qoder/hooks/stop-eval.py +207 -0
  20. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  21. package/templates/qoder/rules/wl-pipeline.md +85 -49
  22. package/templates/qoder/scripts/README.md +102 -0
  23. package/templates/qoder/scripts/capability/__init__.py +26 -0
  24. package/templates/qoder/scripts/capability/__main__.py +72 -0
  25. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  26. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  27. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  28. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  29. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  30. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  31. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  32. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  33. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  34. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  35. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  36. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  37. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  38. package/templates/qoder/scripts/capability/chain.py +92 -0
  39. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  40. package/templates/qoder/scripts/capability/registry.py +246 -0
  41. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  42. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  43. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  44. package/templates/qoder/scripts/deployment/setup/__init__.py +11 -0
  45. package/templates/qoder/scripts/deployment/setup/carriers.py +669 -0
  46. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  47. package/templates/qoder/scripts/{init_doctor.py → deployment/setup/init_doctor.py} +100 -39
  48. package/templates/qoder/scripts/{install_qoderwork.py → deployment/setup/install_qoderwork.py} +48 -30
  49. package/templates/qoder/scripts/{platform_doctor.py → deployment/setup/platform_doctor.py} +271 -259
  50. package/templates/qoder/scripts/{repo_root.py → deployment/setup/repo_root.py} +9 -2
  51. package/templates/qoder/scripts/{setup.py → deployment/setup/setup.py} +143 -14
  52. package/templates/qoder/scripts/{setup_lanhu.py → deployment/setup/setup_lanhu.py} +979 -963
  53. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  54. package/templates/qoder/scripts/{fill_prototype.py → domain/design/fill_prototype.py} +17 -5
  55. package/templates/qoder/scripts/{gen_design_doc.py → domain/design/gen_design_doc.py} +406 -394
  56. package/templates/qoder/scripts/domain/kg/__init__.py +11 -0
  57. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  58. package/templates/qoder/scripts/domain/kg/build/build_entity_registry.py +201 -0
  59. package/templates/qoder/scripts/domain/kg/build/build_relations.py +132 -0
  60. package/templates/qoder/scripts/{build_style_index.py → domain/kg/build/build_style_index.py} +50 -15
  61. package/templates/qoder/scripts/domain/kg/build/build_workflows.py +149 -0
  62. package/templates/qoder/scripts/{kg_build.py → domain/kg/build/kg_build.py} +685 -612
  63. package/templates/qoder/scripts/{kg_build_db.py → domain/kg/build/kg_build_db.py} +338 -327
  64. package/templates/qoder/scripts/{kg_incremental.py → domain/kg/build/kg_incremental.py} +425 -393
  65. package/templates/qoder/scripts/{learn_aggregate.py → domain/kg/build/learn_aggregate.py} +212 -201
  66. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  68. package/templates/qoder/scripts/domain/kg/extract/test_extract.py +115 -0
  69. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  70. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  71. package/templates/qoder/scripts/{kg_link_db.py → domain/kg/graph/kg_link_db.py} +235 -224
  72. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  73. package/templates/qoder/scripts/{kg.py → domain/kg/kg.py} +871 -708
  74. package/templates/qoder/scripts/domain/kg/kg_capabilities.py +182 -0
  75. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  76. package/templates/qoder/scripts/{context_pack.py → domain/kg/search/context_pack.py} +45 -17
  77. package/templates/qoder/scripts/{enrich_prompt.py → domain/kg/search/enrich_prompt.py} +238 -226
  78. package/templates/qoder/scripts/domain/kg/search/prefetch.py +384 -0
  79. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  80. package/templates/qoder/scripts/{search_index.py → domain/kg/search/search_index.py} +210 -88
  81. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  82. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  83. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  84. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  85. package/templates/qoder/scripts/{kg_duckdb.py → domain/kg/storage/kg_duckdb.py} +70 -45
  86. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  87. package/templates/qoder/scripts/{learn.py → domain/learning/learn.py} +157 -146
  88. package/templates/qoder/scripts/domain/report/__init__.py +11 -0
  89. package/templates/qoder/scripts/{add_session.py → domain/report/add_session.py} +256 -244
  90. package/templates/qoder/scripts/{export.py → domain/report/export.py} +72 -4
  91. package/templates/qoder/scripts/{report.py → domain/report/report.py} +292 -281
  92. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  93. package/templates/qoder/scripts/domain/report/role.py +39 -0
  94. package/templates/qoder/scripts/{status.py → domain/report/status.py} +737 -628
  95. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  96. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  97. package/templates/qoder/scripts/{archive_prd.py → domain/requirement/archive_prd.py} +389 -377
  98. package/templates/qoder/scripts/domain/requirement/req.py +228 -0
  99. package/templates/qoder/scripts/domain/task/__init__.py +11 -0
  100. package/templates/qoder/scripts/{git_sync.py → domain/task/git_sync.py} +90 -50
  101. package/templates/qoder/scripts/{syncgate.py → domain/task/syncgate.py} +18 -7
  102. package/templates/qoder/scripts/domain/task/task.py +229 -0
  103. package/templates/qoder/scripts/domain/task/task_lifecycle.py +606 -0
  104. package/templates/qoder/scripts/domain/task/task_query.py +162 -0
  105. package/templates/qoder/scripts/domain/task/task_relations.py +425 -0
  106. package/templates/qoder/scripts/{team_sync.py → domain/task/team_sync.py} +101 -23
  107. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  108. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  109. package/templates/qoder/scripts/foundation/bootstrap.py +145 -0
  110. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  111. package/templates/qoder/scripts/foundation/core/cmd_registry.py +112 -0
  112. package/templates/qoder/scripts/foundation/core/config.py +187 -0
  113. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -400
  114. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  115. package/templates/qoder/scripts/foundation/data/contract.py +317 -0
  116. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  117. package/templates/qoder/scripts/foundation/data/result.py +223 -0
  118. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -392
  119. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  120. package/templates/qoder/scripts/foundation/identity/check_publish.py +103 -0
  121. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -238
  122. package/templates/qoder/scripts/foundation/identity/guard.py +159 -0
  123. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +132 -9
  124. package/templates/qoder/scripts/foundation/identity/roles.py +60 -0
  125. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  126. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  127. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +11 -10
  128. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  129. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  130. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  131. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  132. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  133. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  134. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  135. package/templates/qoder/scripts/foundation/protocol/mcp_base.py +268 -0
  136. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  137. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  138. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  139. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  140. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  141. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  142. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  143. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  144. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  145. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  146. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  147. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  148. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  153. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  154. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  155. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  156. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  157. package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → protocol/mcp/lanhu_stdio_wrapper.py} +131 -119
  158. package/templates/qoder/scripts/protocol/mcp/mcp_doctor.py +548 -0
  159. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  160. package/templates/qoder/scripts/protocol/mcp/mysql_mcp_server.py +461 -0
  161. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  162. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  163. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  164. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  165. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  166. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  167. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  168. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  169. package/templates/qoder/scripts/validation/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  171. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  172. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  173. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  174. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  175. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  176. package/templates/qoder/scripts/{eval_prd.py → validation/metrics/eval_prd.py} +84 -15
  177. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  178. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  179. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  180. package/templates/qoder/scripts/{autotest.py → validation/test/autotest.py} +1234 -1751
  181. package/templates/qoder/scripts/validation/test/autotest_auth.py +109 -0
  182. package/templates/qoder/scripts/{autotest_batch.py → validation/test/autotest_batch.py} +255 -224
  183. package/templates/qoder/scripts/validation/test/autotest_data.py +680 -0
  184. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  185. package/templates/qoder/scripts/{autotest_run.py → validation/test/autotest_run.py} +323 -297
  186. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  187. package/templates/qoder/scripts/{benchmark.py → validation/test/benchmark.py} +17 -5
  188. package/templates/qoder/scripts/{kg_auto_login.py → validation/test/kg_auto_login.py} +208 -196
  189. package/templates/qoder/scripts/{kg_test_runner.py → validation/test/kg_test_runner.py} +13 -2
  190. package/templates/qoder/scripts/{page_probe.py → validation/test/page_probe.py} +470 -459
  191. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  192. package/templates/qoder/settings.json +23 -2
  193. package/templates/qoder/skills/design-import/SKILL.md +235 -226
  194. package/templates/qoder/skills/design-review/SKILL.md +91 -82
  195. package/templates/qoder/skills/prd-generator/SKILL.md +38 -24
  196. package/templates/qoder/skills/prd-review/SKILL.md +8 -6
  197. package/templates/qoder/skills/prototype-generator/SKILL.md +296 -247
  198. package/templates/qoder/skills/spec-coder/SKILL.md +24 -15
  199. package/templates/qoder/skills/spec-generator/SKILL.md +24 -12
  200. package/templates/qoder/skills/test-generator/SKILL.md +9 -7
  201. package/templates/qoder/skills/wl-code/SKILL.md +25 -13
  202. package/templates/qoder/skills/wl-commit/SKILL.md +10 -9
  203. package/templates/qoder/skills/wl-design/SKILL.md +7 -5
  204. package/templates/qoder/skills/wl-init/SKILL.md +8 -8
  205. package/templates/qoder/skills/wl-insight/SKILL.md +25 -12
  206. package/templates/qoder/skills/wl-prd-full/SKILL.md +59 -8
  207. package/templates/qoder/skills/wl-prd-quick/SKILL.md +7 -7
  208. package/templates/qoder/skills/wl-prd-review/SKILL.md +18 -6
  209. package/templates/qoder/skills/wl-report/SKILL.md +27 -25
  210. package/templates/qoder/skills/wl-search/SKILL.md +151 -80
  211. package/templates/qoder/skills/wl-spec/SKILL.md +9 -7
  212. package/templates/qoder/skills/wl-status/SKILL.md +50 -18
  213. package/templates/qoder/skills/wl-task/SKILL.md +94 -12
  214. package/templates/qoder/skills/wl-test/SKILL.md +154 -45
  215. package/templates/qoder/templates/prd-full-template.md +7 -0
  216. package/templates/root/AGENTS.md +275 -237
  217. package/templates/root/requirements.txt +3 -0
  218. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  219. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  220. package/templates/qoder/hooks/inject-workflow-state.py +0 -169
  221. package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
  222. package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
  223. package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
  224. package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
  225. package/templates/qoder/scripts/check_carriers.py +0 -238
  226. package/templates/qoder/scripts/check_mcp.py +0 -298
  227. package/templates/qoder/scripts/check_mcp_launch.py +0 -183
  228. package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
  229. package/templates/qoder/scripts/collect_prds.py +0 -31
  230. package/templates/qoder/scripts/common/mentions.py +0 -134
  231. package/templates/qoder/scripts/common/utf8.py +0 -38
  232. package/templates/qoder/scripts/extract_api_params.py +0 -246
  233. package/templates/qoder/scripts/extract_routes.py +0 -54
  234. package/templates/qoder/scripts/extract_routes_tree.py +0 -78
  235. package/templates/qoder/scripts/handoff.py +0 -22
  236. package/templates/qoder/scripts/init_developer.py +0 -76
  237. package/templates/qoder/scripts/kg_mcp_server.py +0 -801
  238. package/templates/qoder/scripts/kg_semantic.py +0 -150
  239. package/templates/qoder/scripts/mcp_launcher.py +0 -414
  240. package/templates/qoder/scripts/mysql_mcp_server.py +0 -396
  241. package/templates/qoder/scripts/parse_prds.py +0 -33
  242. package/templates/qoder/scripts/role.py +0 -51
  243. package/templates/qoder/scripts/sync_carriers.py +0 -259
  244. package/templates/qoder/scripts/task.py +0 -1261
  245. package/templates/qoder/scripts/workspace_init.py +0 -102
  246. package/templates/qoder/scripts/zentao_mcp_server.py +0 -424
  247. package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
  248. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  249. /package/templates/qoder/{skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp → scripts/domain/__init__.py} +0 -0
  250. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  251. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  252. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  253. /package/templates/qoder/scripts/{secure-ls.js → validation/test/secure-ls.js} +0 -0
@@ -1,146 +1,157 @@
1
- # -*- coding: utf-8 -*-
2
- """learn.py - Learning engine: 个人埋点 (workspace/members/{dev}/journal/)
3
-
4
- 数据归属 (和 kg.duckdb 对称的设计):
5
- - 原始事件流 → workspace/members/{dev}/journal/feedback.jsonl (个人, 进git, 按人分不冲突)
6
- - 统计计数 → workspace/members/{dev}/journal/learning.yaml (个人, 进git)
7
- - 团队聚合 → data/index/kg.duckdb 的 learning_events 表 (管理员跑 learn_aggregate.py 聚合)
8
-
9
- 为什么按人分文件:
10
- team_sync 用单分支 rebase 协作, 所有人 append 同一个 feedback.jsonl 会冲突。
11
- 每人写自己的文件 → rebase 时改的是不同文件 → git 自动合并, 零冲突。
12
- (旧版把 feedback 放 .qoder/learning/ 并 gitignore, 导致数据不随团队同步 = 丢失)
13
-
14
- 用法:
15
- python learn.py record prd_accepted '{"req_id":"REQ-2026-009","score":87}'
16
- python learn.py status
17
- python learn.py aggregate # 管理员: 扫所有人 → kg.duckdb
18
- """
19
- import os
20
- import sys
21
- import json
22
- from datetime import datetime
23
-
24
- SCRIPTS = os.path.dirname(os.path.abspath(__file__))
25
- sys.path.insert(0, SCRIPTS)
26
-
27
- from common.paths import get_developer, get_developer_journal_dir
28
-
29
-
30
- def _feedback_path():
31
- """当前开发者的 feedback 文件 (workspace/members/{dev}/journal/feedback.jsonl)。"""
32
- dev = get_developer()
33
- if not dev:
34
- raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
35
- return get_developer_journal_dir(dev) / 'feedback.jsonl'
36
-
37
-
38
- def _prefs_path():
39
- """当前开发者的统计文件 (workspace/members/{dev}/journal/learning.yaml)。"""
40
- dev = get_developer()
41
- if not dev:
42
- raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
43
- return get_developer_journal_dir(dev) / 'learning.yaml'
44
-
45
-
46
- def record_feedback(event, data=None):
47
- """记录一条事件到当前开发者的 feedback.jsonl。
48
- 每条带 dev 字段 (聚合时区分来源)。
49
- """
50
- dev = get_developer()
51
- if not dev:
52
- raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
53
- if data is None:
54
- data = {}
55
- entry = {
56
- 'ts': datetime.now().isoformat(timespec='seconds'),
57
- 'dev': dev,
58
- 'event': event,
59
- 'data': data,
60
- }
61
- fb_path = _feedback_path()
62
- fb_path.parent.mkdir(parents=True, exist_ok=True)
63
- with open(fb_path, 'a', encoding='utf-8') as f:
64
- f.write(json.dumps(entry, ensure_ascii=False) + '\n')
65
- _update_stats(event)
66
- print('Recorded: %s → %s' % (event, fb_path.name))
67
-
68
-
69
- def _update_stats(event):
70
- """更新当前开发者的统计计数 (learning.yaml)。
71
- 事件→列名映射来自 common/events.py (SSOT), 不再硬编码。
72
- """
73
- try:
74
- import yaml
75
- except ImportError:
76
- return # 无 yaml 库则跳过统计, 不阻塞埋点
77
- from common.events import stats_event_map
78
- key = stats_event_map().get(event)
79
- if not key:
80
- return
81
- prefs = _load_prefs()
82
- prefs[key] = prefs.get(key, 0) + 1
83
- _save_prefs(prefs)
84
-
85
-
86
- def _load_prefs():
87
- try:
88
- import yaml
89
- except ImportError:
90
- return {}
91
- p = _prefs_path()
92
- if not p.is_file():
93
- return {}
94
- try:
95
- return yaml.safe_load(p.read_text(encoding='utf-8')) or {}
96
- except Exception:
97
- return {}
98
-
99
-
100
- def _save_prefs(prefs):
101
- try:
102
- import yaml
103
- except ImportError:
104
- return
105
- p = _prefs_path()
106
- p.parent.mkdir(parents=True, exist_ok=True)
107
- with open(p, 'w', encoding='utf-8') as f:
108
- yaml.dump(prefs, f, allow_unicode=True, default_flow_style=False)
109
-
110
-
111
- def get_prefs():
112
- return _load_prefs()
113
-
114
-
115
- def should_evolve():
116
- """是否到了该提炼模式的阈值 (每完成 10 个任务)。"""
117
- return _load_prefs().get('tasks_completed', 0) % 10 == 0
118
-
119
-
120
- def aggregate_all():
121
- """管理员聚合: 扫所有人的 feedback.jsonl → 写入 kg.duckdb。
122
- 委托给 learn_aggregate.py (同构 kg_build.py)
123
- """
124
- import learn_aggregate
125
- return learn_aggregate.aggregate()
126
-
127
-
128
- if __name__ == '__main__':
129
- if len(sys.argv) < 2:
130
- print(__doc__)
131
- print('用法: learn.py record <event> [json] | learn.py status | learn.py aggregate')
132
- elif sys.argv[1] == 'status':
133
- prefs = get_prefs()
134
- print('Learning Stats (%s):' % (get_developer() or 'unknown'))
135
- for k, v in prefs.items():
136
- if isinstance(v, int):
137
- print(' %s: %d' % (k, v))
138
- print(' Evolve ready: %s' % should_evolve())
139
- elif sys.argv[1] == 'aggregate':
140
- n = aggregate_all()
141
- print('聚合完成: %d 条事件 → kg.duckdb' % n)
142
- elif sys.argv[1] == 'record' and len(sys.argv) >= 3:
143
- data = json.loads(sys.argv[3]) if len(sys.argv) > 3 else {}
144
- record_feedback(sys.argv[2], data)
145
- else:
146
- print('未知子命令: %s' % sys.argv[1])
1
+ # -*- coding: utf-8 -*-
2
+ """learn.py - Learning engine: 个人埋点 (workspace/members/{dev}/journal/)
3
+
4
+ 数据归属 (和 kg.duckdb 对称的设计):
5
+ - 原始事件流 → workspace/members/{dev}/journal/feedback.jsonl (个人, 进git, 按人分不冲突)
6
+ - 统计计数 → workspace/members/{dev}/journal/learning.yaml (个人, 进git)
7
+ - 团队聚合 → data/index/kg.duckdb 的 learning_events 表 (管理员跑 learn_aggregate.py 聚合)
8
+
9
+ 为什么按人分文件:
10
+ team_sync 用单分支 rebase 协作, 所有人 append 同一个 feedback.jsonl 会冲突。
11
+ 每人写自己的文件 → rebase 时改的是不同文件 → git 自动合并, 零冲突。
12
+ (旧版把 feedback 放 .qoder/learning/ 并 gitignore, 导致数据不随团队同步 = 丢失)
13
+
14
+ 用法:
15
+ python learn.py record prd_accepted '{"req_id":"REQ-2026-009","score":87}'
16
+ python learn.py status
17
+ python learn.py aggregate # 管理员: 扫所有人 → kg.duckdb
18
+ """
19
+ # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
20
+ import os as _o, sys as _s
21
+ _f = _o.path.abspath(__file__)
22
+ for _ in range(10):
23
+ _f = _o.path.dirname(_f)
24
+ _cp = _o.path.join(_f, 'foundation')
25
+ if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
26
+ break
27
+ if _cp not in _s.path: _s.path.insert(0, _cp)
28
+ from bootstrap import setup; setup()
29
+
30
+ import os
31
+ import sys
32
+ import json
33
+ from datetime import datetime
34
+
35
+ SCRIPTS = os.path.dirname(os.path.abspath(__file__))
36
+ sys.path.insert(0, SCRIPTS)
37
+
38
+ from foundation.core.paths import get_developer, get_developer_journal_dir
39
+
40
+
41
+ def _feedback_path():
42
+ """当前开发者的 feedback 文件 (workspace/members/{dev}/journal/feedback.jsonl)。"""
43
+ dev = get_developer()
44
+ if not dev:
45
+ raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
46
+ return get_developer_journal_dir(dev) / 'feedback.jsonl'
47
+
48
+
49
+ def _prefs_path():
50
+ """当前开发者的统计文件 (workspace/members/{dev}/journal/learning.yaml)。"""
51
+ dev = get_developer()
52
+ if not dev:
53
+ raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
54
+ return get_developer_journal_dir(dev) / 'learning.yaml'
55
+
56
+
57
+ def record_feedback(event, data=None):
58
+ """记录一条事件到当前开发者的 feedback.jsonl。
59
+ 每条带 dev 字段 (聚合时区分来源)。
60
+ """
61
+ dev = get_developer()
62
+ if not dev:
63
+ raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
64
+ if data is None:
65
+ data = {}
66
+ entry = {
67
+ 'ts': datetime.now().isoformat(timespec='seconds'),
68
+ 'dev': dev,
69
+ 'event': event,
70
+ 'data': data,
71
+ }
72
+ fb_path = _feedback_path()
73
+ fb_path.parent.mkdir(parents=True, exist_ok=True)
74
+ with open(fb_path, 'a', encoding='utf-8') as f:
75
+ f.write(json.dumps(entry, ensure_ascii=False) + '\n')
76
+ _update_stats(event)
77
+ print('Recorded: %s %s' % (event, fb_path.name))
78
+
79
+
80
+ def _update_stats(event):
81
+ """更新当前开发者的统计计数 (learning.yaml)
82
+ 事件→列名映射来自 common/events.py (SSOT), 不再硬编码。
83
+ """
84
+ try:
85
+ import yaml
86
+ except ImportError:
87
+ return # 无 yaml 库则跳过统计, 不阻塞埋点
88
+ from foundation.data.events import stats_event_map
89
+ key = stats_event_map().get(event)
90
+ if not key:
91
+ return
92
+ prefs = _load_prefs()
93
+ prefs[key] = prefs.get(key, 0) + 1
94
+ _save_prefs(prefs)
95
+
96
+
97
+ def _load_prefs():
98
+ try:
99
+ import yaml
100
+ except ImportError:
101
+ return {}
102
+ p = _prefs_path()
103
+ if not p.is_file():
104
+ return {}
105
+ try:
106
+ return yaml.safe_load(p.read_text(encoding='utf-8')) or {}
107
+ except Exception:
108
+ return {}
109
+
110
+
111
+ def _save_prefs(prefs):
112
+ try:
113
+ import yaml
114
+ except ImportError:
115
+ return
116
+ p = _prefs_path()
117
+ p.parent.mkdir(parents=True, exist_ok=True)
118
+ with open(p, 'w', encoding='utf-8') as f:
119
+ yaml.dump(prefs, f, allow_unicode=True, default_flow_style=False)
120
+
121
+
122
+ def get_prefs():
123
+ return _load_prefs()
124
+
125
+
126
+ def should_evolve():
127
+ """是否到了该提炼模式的阈值 (每完成 10 个任务)。"""
128
+ return _load_prefs().get('tasks_completed', 0) % 10 == 0
129
+
130
+
131
+ def aggregate_all():
132
+ """管理员聚合: 扫所有人的 feedback.jsonl 写入 kg.duckdb。
133
+ 委托给 learn_aggregate.py (同构 kg_build.py)
134
+ """
135
+ import learn_aggregate
136
+ return learn_aggregate.aggregate()
137
+
138
+
139
+ if __name__ == '__main__':
140
+ if len(sys.argv) < 2:
141
+ print(__doc__)
142
+ print('用法: learn.py record <event> [json] | learn.py status | learn.py aggregate')
143
+ elif sys.argv[1] == 'status':
144
+ prefs = get_prefs()
145
+ print('Learning Stats (%s):' % (get_developer() or 'unknown'))
146
+ for k, v in prefs.items():
147
+ if isinstance(v, int):
148
+ print(' %s: %d' % (k, v))
149
+ print(' Evolve ready: %s' % should_evolve())
150
+ elif sys.argv[1] == 'aggregate':
151
+ n = aggregate_all()
152
+ print('聚合完成: %d 条事件 → kg.duckdb' % n)
153
+ elif sys.argv[1] == 'record' and len(sys.argv) >= 3:
154
+ data = json.loads(sys.argv[3]) if len(sys.argv) > 3 else {}
155
+ record_feedback(sys.argv[2], data)
156
+ else:
157
+ print('未知子命令: %s' % sys.argv[1])
@@ -0,0 +1,11 @@
1
+ # 子包初始化: 注入 scripts/根 + 所有子包到 sys.path
2
+ # 让跨包 import (旧式不带前缀) 仍可用, 兼容现有代码
3
+ import os as _os, sys as _sys
4
+ _root = _os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))
5
+ if _root not in _sys.path:
6
+ _sys.path.insert(0, _root)
7
+ # 注入所有子包目录 (兼容旧式 import xxx)
8
+ for _sub in ('kg', 'build', 'test', 'setup', 'io'):
9
+ _subdir = _os.path.join(_root, _sub)
10
+ if _os.path.isdir(_subdir) and _subdir not in _sys.path:
11
+ _sys.path.insert(0, _subdir)