@hupan56/wlkj 2.7.11 → 3.0.0

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 (152) hide show
  1. package/bin/cli.js +375 -78
  2. package/package.json +29 -29
  3. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +23 -0
  4. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +23 -0
  5. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +1 -0
  6. package/templates/.qoder/learning/eval-history.jsonl +28 -0
  7. package/templates/data/index/wiki-index.json +8 -0
  8. package/templates/qoder/agents/insight-planning.md +1 -1
  9. package/templates/qoder/agents/insight-research.md +28 -15
  10. package/templates/qoder/commands/optional/wl-insight.md +159 -161
  11. package/templates/qoder/commands/optional/wl-report.md +4 -4
  12. package/templates/qoder/commands/optional/wl-status.md +2 -2
  13. package/templates/qoder/commands/wl-code.md +2 -2
  14. package/templates/qoder/commands/wl-design.md +2 -2
  15. package/templates/qoder/commands/wl-init.md +3 -3
  16. package/templates/qoder/commands/wl-prd.md +2 -2
  17. package/templates/qoder/commands/wl-req.md +43 -0
  18. package/templates/qoder/commands/wl-search.md +8 -8
  19. package/templates/qoder/commands/wl-task.md +17 -17
  20. package/templates/qoder/commands/wl-test.md +41 -15
  21. package/templates/qoder/config.yaml +17 -1
  22. package/templates/qoder/hooks/session-start.py +12 -22
  23. package/templates/qoder/nul +4 -0
  24. package/templates/qoder/rules/wl-pipeline.md +22 -48
  25. package/templates/qoder/scripts/README.md +139 -0
  26. package/templates/qoder/scripts/common/autotest_auth.py +109 -0
  27. package/templates/qoder/scripts/common/bootstrap.py +145 -0
  28. package/templates/qoder/scripts/common/check_publish.py +98 -0
  29. package/templates/qoder/scripts/common/cmd_registry.py +112 -0
  30. package/templates/qoder/scripts/common/config.py +187 -0
  31. package/templates/qoder/scripts/common/contract.py +317 -0
  32. package/templates/qoder/scripts/common/developer.py +2 -1
  33. package/templates/qoder/scripts/common/feishu.py +10 -9
  34. package/templates/qoder/scripts/common/guard.py +159 -0
  35. package/templates/qoder/scripts/common/identity.py +121 -2
  36. package/templates/qoder/scripts/common/kg_capabilities.py +182 -0
  37. package/templates/qoder/scripts/common/mcp_base.py +268 -0
  38. package/templates/qoder/scripts/common/paths.py +187 -1
  39. package/templates/qoder/scripts/common/result.py +223 -0
  40. package/templates/qoder/scripts/common/roles.py +60 -0
  41. package/templates/qoder/scripts/common/task_utils.py +21 -9
  42. package/templates/qoder/scripts/common/test_extract.py +115 -0
  43. package/templates/qoder/scripts/kg/__init__.py +11 -0
  44. package/templates/qoder/scripts/kg/build_entity_registry.py +196 -0
  45. package/templates/qoder/scripts/kg/build_relations.py +127 -0
  46. package/templates/qoder/scripts/{build_style_index.py → kg/build_style_index.py} +39 -10
  47. package/templates/qoder/scripts/kg/build_workflows.py +144 -0
  48. package/templates/qoder/scripts/{context_pack.py → kg/context_pack.py} +18 -11
  49. package/templates/qoder/scripts/{enrich_prompt.py → kg/enrich_prompt.py} +232 -226
  50. package/templates/qoder/scripts/{extract_api_params.py → kg/extract.py} +398 -246
  51. package/templates/qoder/scripts/{kg.py → kg/kg.py} +638 -708
  52. package/templates/qoder/scripts/{kg_build.py → kg/kg_build.py} +618 -612
  53. package/templates/qoder/scripts/{kg_build_db.py → kg/kg_build_db.py} +333 -327
  54. package/templates/qoder/scripts/{kg_duckdb.py → kg/kg_duckdb.py} +38 -37
  55. package/templates/qoder/scripts/{kg_incremental.py → kg/kg_incremental.py} +420 -393
  56. package/templates/qoder/scripts/{kg_link_db.py → kg/kg_link_db.py} +230 -224
  57. package/templates/qoder/scripts/{kg_semantic.py → kg/kg_semantic.py} +156 -150
  58. package/templates/qoder/scripts/kg/prefetch.py +359 -0
  59. package/templates/qoder/scripts/{search_index.py → kg/search_index.py} +70 -14
  60. package/templates/qoder/scripts/mcp/__init__.py +11 -0
  61. package/templates/qoder/scripts/{kg_mcp_server.py → mcp/kg_mcp_server.py} +77 -272
  62. package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → mcp/lanhu_stdio_wrapper.py} +125 -119
  63. package/templates/qoder/scripts/{check_mcp.py → mcp/mcp_doctor.py} +515 -298
  64. package/templates/qoder/scripts/{mcp_launcher.py → mcp/mcp_launcher.py} +442 -414
  65. package/templates/qoder/scripts/{mysql_mcp_server.py → mcp/mysql_mcp_server.py} +347 -396
  66. package/templates/qoder/scripts/{zentao_mcp_server.py → mcp/zentao_mcp_server.py} +384 -424
  67. package/templates/qoder/scripts/report/__init__.py +11 -0
  68. package/templates/qoder/scripts/{add_session.py → report/add_session.py} +250 -244
  69. package/templates/qoder/scripts/{archive_prd.py → report/archive_prd.py} +383 -377
  70. package/templates/qoder/scripts/{eval_prd.py → report/eval_prd.py} +73 -11
  71. package/templates/qoder/scripts/{export.py → report/export.py} +63 -0
  72. package/templates/qoder/scripts/{fill_prototype.py → report/fill_prototype.py} +6 -0
  73. package/templates/qoder/scripts/{gen_design_doc.py → report/gen_design_doc.py} +400 -394
  74. package/templates/qoder/scripts/{learn.py → report/learn.py} +152 -146
  75. package/templates/qoder/scripts/{learn_aggregate.py → report/learn_aggregate.py} +207 -201
  76. package/templates/qoder/scripts/{report.py → report/report.py} +287 -281
  77. package/templates/qoder/scripts/report/req.py +222 -0
  78. package/templates/qoder/scripts/report/role.py +33 -0
  79. package/templates/qoder/scripts/{status.py → report/status.py} +634 -628
  80. package/templates/qoder/scripts/setup/__init__.py +11 -0
  81. package/templates/qoder/scripts/setup/carriers.py +662 -0
  82. package/templates/qoder/scripts/{init_doctor.py → setup/init_doctor.py} +63 -26
  83. package/templates/qoder/scripts/{install_qoderwork.py → setup/install_qoderwork.py} +36 -26
  84. package/templates/qoder/scripts/{platform_doctor.py → setup/platform_doctor.py} +265 -259
  85. package/templates/qoder/scripts/{repo_root.py → setup/repo_root.py} +112 -106
  86. package/templates/qoder/scripts/{setup.py → setup/setup.py} +147 -0
  87. package/templates/qoder/scripts/{setup_lanhu.py → setup/setup_lanhu.py} +973 -963
  88. package/templates/qoder/scripts/task/__init__.py +11 -0
  89. package/templates/qoder/scripts/{git_sync.py → task/git_sync.py} +52 -31
  90. package/templates/qoder/scripts/{syncgate.py → task/syncgate.py} +6 -0
  91. package/templates/qoder/scripts/task/task.py +221 -0
  92. package/templates/qoder/scripts/task/task_lifecycle.py +596 -0
  93. package/templates/qoder/scripts/task/task_query.py +161 -0
  94. package/templates/qoder/scripts/task/task_relations.py +424 -0
  95. package/templates/qoder/scripts/{team_sync.py → task/team_sync.py} +93 -20
  96. package/templates/qoder/scripts/test/__init__.py +11 -0
  97. package/templates/qoder/scripts/{autotest.py → test/autotest.py} +1174 -1751
  98. package/templates/qoder/scripts/{autotest_batch.py → test/autotest_batch.py} +242 -224
  99. package/templates/qoder/scripts/test/autotest_data.py +675 -0
  100. package/templates/qoder/scripts/{autotest_run.py → test/autotest_run.py} +309 -297
  101. package/templates/qoder/scripts/{benchmark.py → test/benchmark.py} +6 -0
  102. package/templates/qoder/scripts/{kg_auto_login.py → test/kg_auto_login.py} +202 -196
  103. package/templates/qoder/scripts/{kg_test_runner.py → test/kg_test_runner.py} +7 -1
  104. package/templates/qoder/scripts/{page_probe.py → test/page_probe.py} +465 -459
  105. package/templates/qoder/scripts/wlkj.py +116 -0
  106. package/templates/qoder/settings.json +1 -10
  107. package/templates/qoder/skills/design-import/SKILL.md +226 -226
  108. package/templates/qoder/skills/design-review/SKILL.md +82 -82
  109. package/templates/qoder/skills/prd-generator/SKILL.md +26 -16
  110. package/templates/qoder/skills/prd-review/SKILL.md +5 -5
  111. package/templates/qoder/skills/prototype-generator/SKILL.md +256 -256
  112. package/templates/qoder/skills/spec-coder/SKILL.md +4 -4
  113. package/templates/qoder/skills/spec-generator/SKILL.md +4 -4
  114. package/templates/qoder/skills/test-generator/SKILL.md +5 -5
  115. package/templates/qoder/skills/wl-code/SKILL.md +4 -4
  116. package/templates/qoder/skills/wl-commit/SKILL.md +4 -4
  117. package/templates/qoder/skills/wl-design/SKILL.md +3 -3
  118. package/templates/qoder/skills/wl-init/SKILL.md +8 -8
  119. package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
  120. package/templates/qoder/skills/wl-prd-full/SKILL.md +6 -6
  121. package/templates/qoder/skills/wl-prd-quick/SKILL.md +6 -6
  122. package/templates/qoder/skills/wl-prd-review/SKILL.md +4 -4
  123. package/templates/qoder/skills/wl-report/SKILL.md +7 -7
  124. package/templates/qoder/skills/wl-search/SKILL.md +13 -13
  125. package/templates/qoder/skills/wl-spec/SKILL.md +5 -5
  126. package/templates/qoder/skills/wl-status/SKILL.md +5 -5
  127. package/templates/qoder/skills/wl-task/SKILL.md +6 -6
  128. package/templates/qoder/skills/wl-test/SKILL.md +102 -39
  129. package/templates/root/AGENTS.md +39 -40
  130. package/templates/qoder/hooks/inject-workflow-state.py +0 -169
  131. package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
  132. package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
  133. package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
  134. package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
  135. package/templates/qoder/scripts/check_carriers.py +0 -238
  136. package/templates/qoder/scripts/check_mcp_launch.py +0 -183
  137. package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
  138. package/templates/qoder/scripts/collect_prds.py +0 -31
  139. package/templates/qoder/scripts/common/mentions.py +0 -134
  140. package/templates/qoder/scripts/common/utf8.py +0 -38
  141. package/templates/qoder/scripts/extract_routes.py +0 -54
  142. package/templates/qoder/scripts/extract_routes_tree.py +0 -78
  143. package/templates/qoder/scripts/handoff.py +0 -22
  144. package/templates/qoder/scripts/init_developer.py +0 -76
  145. package/templates/qoder/scripts/parse_prds.py +0 -33
  146. package/templates/qoder/scripts/role.py +0 -51
  147. package/templates/qoder/scripts/sync_carriers.py +0 -259
  148. package/templates/qoder/scripts/task.py +0 -1261
  149. package/templates/qoder/scripts/workspace_init.py +0 -102
  150. package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
  151. package/templates/qoder/skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp +0 -0
  152. /package/templates/qoder/scripts/{secure-ls.js → test/secure-ls.js} +0 -0
@@ -1,146 +1,152 @@
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
+ _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
22
+ if _cp not in _s.path: _s.path.insert(0, _cp)
23
+ from bootstrap import setup; setup()
24
+
25
+ import os
26
+ import sys
27
+ import json
28
+ from datetime import datetime
29
+
30
+ SCRIPTS = os.path.dirname(os.path.abspath(__file__))
31
+ sys.path.insert(0, SCRIPTS)
32
+
33
+ from common.paths import get_developer, get_developer_journal_dir
34
+
35
+
36
+ def _feedback_path():
37
+ """当前开发者的 feedback 文件 (workspace/members/{dev}/journal/feedback.jsonl)。"""
38
+ dev = get_developer()
39
+ if not dev:
40
+ raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
41
+ return get_developer_journal_dir(dev) / 'feedback.jsonl'
42
+
43
+
44
+ def _prefs_path():
45
+ """当前开发者的统计文件 (workspace/members/{dev}/journal/learning.yaml)。"""
46
+ dev = get_developer()
47
+ if not dev:
48
+ raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
49
+ return get_developer_journal_dir(dev) / 'learning.yaml'
50
+
51
+
52
+ def record_feedback(event, data=None):
53
+ """记录一条事件到当前开发者的 feedback.jsonl。
54
+ 每条带 dev 字段 (聚合时区分来源)。
55
+ """
56
+ dev = get_developer()
57
+ if not dev:
58
+ raise RuntimeError('未初始化开发者身份, 请先运行 /wl-init')
59
+ if data is None:
60
+ data = {}
61
+ entry = {
62
+ 'ts': datetime.now().isoformat(timespec='seconds'),
63
+ 'dev': dev,
64
+ 'event': event,
65
+ 'data': data,
66
+ }
67
+ fb_path = _feedback_path()
68
+ fb_path.parent.mkdir(parents=True, exist_ok=True)
69
+ with open(fb_path, 'a', encoding='utf-8') as f:
70
+ f.write(json.dumps(entry, ensure_ascii=False) + '\n')
71
+ _update_stats(event)
72
+ print('Recorded: %s → %s' % (event, fb_path.name))
73
+
74
+
75
+ def _update_stats(event):
76
+ """更新当前开发者的统计计数 (learning.yaml)。
77
+ 事件→列名映射来自 common/events.py (SSOT), 不再硬编码。
78
+ """
79
+ try:
80
+ import yaml
81
+ except ImportError:
82
+ return # yaml 库则跳过统计, 不阻塞埋点
83
+ from common.events import stats_event_map
84
+ key = stats_event_map().get(event)
85
+ if not key:
86
+ return
87
+ prefs = _load_prefs()
88
+ prefs[key] = prefs.get(key, 0) + 1
89
+ _save_prefs(prefs)
90
+
91
+
92
+ def _load_prefs():
93
+ try:
94
+ import yaml
95
+ except ImportError:
96
+ return {}
97
+ p = _prefs_path()
98
+ if not p.is_file():
99
+ return {}
100
+ try:
101
+ return yaml.safe_load(p.read_text(encoding='utf-8')) or {}
102
+ except Exception:
103
+ return {}
104
+
105
+
106
+ def _save_prefs(prefs):
107
+ try:
108
+ import yaml
109
+ except ImportError:
110
+ return
111
+ p = _prefs_path()
112
+ p.parent.mkdir(parents=True, exist_ok=True)
113
+ with open(p, 'w', encoding='utf-8') as f:
114
+ yaml.dump(prefs, f, allow_unicode=True, default_flow_style=False)
115
+
116
+
117
+ def get_prefs():
118
+ return _load_prefs()
119
+
120
+
121
+ def should_evolve():
122
+ """是否到了该提炼模式的阈值 (每完成 10 个任务)。"""
123
+ return _load_prefs().get('tasks_completed', 0) % 10 == 0
124
+
125
+
126
+ def aggregate_all():
127
+ """管理员聚合: 扫所有人的 feedback.jsonl → 写入 kg.duckdb。
128
+ 委托给 learn_aggregate.py (同构 kg_build.py)。
129
+ """
130
+ import learn_aggregate
131
+ return learn_aggregate.aggregate()
132
+
133
+
134
+ if __name__ == '__main__':
135
+ if len(sys.argv) < 2:
136
+ print(__doc__)
137
+ print('用法: learn.py record <event> [json] | learn.py status | learn.py aggregate')
138
+ elif sys.argv[1] == 'status':
139
+ prefs = get_prefs()
140
+ print('Learning Stats (%s):' % (get_developer() or 'unknown'))
141
+ for k, v in prefs.items():
142
+ if isinstance(v, int):
143
+ print(' %s: %d' % (k, v))
144
+ print(' Evolve ready: %s' % should_evolve())
145
+ elif sys.argv[1] == 'aggregate':
146
+ n = aggregate_all()
147
+ print('聚合完成: %d 条事件 → kg.duckdb' % n)
148
+ elif sys.argv[1] == 'record' and len(sys.argv) >= 3:
149
+ data = json.loads(sys.argv[3]) if len(sys.argv) > 3 else {}
150
+ record_feedback(sys.argv[2], data)
151
+ else:
152
+ print('未知子命令: %s' % sys.argv[1])