@hupan56/wlkj 3.0.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/bin/cli.js +1435 -1373
  2. package/package.json +1 -1
  3. package/templates/qoder/commands/optional/wl-insight.md +6 -4
  4. package/templates/qoder/commands/optional/wl-report.md +20 -39
  5. package/templates/qoder/commands/optional/wl-status.md +4 -4
  6. package/templates/qoder/commands/wl-code.md +2 -2
  7. package/templates/qoder/commands/wl-design.md +5 -5
  8. package/templates/qoder/commands/wl-init.md +3 -3
  9. package/templates/qoder/commands/wl-prd.md +26 -13
  10. package/templates/qoder/commands/wl-req.md +3 -3
  11. package/templates/qoder/commands/wl-search.md +78 -47
  12. package/templates/qoder/commands/wl-task.md +343 -40
  13. package/templates/qoder/commands/wl-test.md +10 -10
  14. package/templates/qoder/config.yaml +35 -13
  15. package/templates/qoder/hooks/post-tool-use.py +181 -0
  16. package/templates/qoder/hooks/session-start.py +82 -1
  17. package/templates/qoder/hooks/stop-eval.py +207 -0
  18. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  19. package/templates/qoder/rules/wl-pipeline.md +70 -8
  20. package/templates/qoder/scripts/README.md +78 -115
  21. package/templates/qoder/scripts/capability/__init__.py +26 -0
  22. package/templates/qoder/scripts/capability/__main__.py +72 -0
  23. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  24. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  25. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  26. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  27. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  28. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  29. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  30. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  31. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  32. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  33. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  34. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  35. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  36. package/templates/qoder/scripts/capability/chain.py +92 -0
  37. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  38. package/templates/qoder/scripts/capability/registry.py +246 -0
  39. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  40. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  41. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  42. package/templates/qoder/scripts/{report → deployment/setup}/__init__.py +11 -11
  43. package/templates/qoder/scripts/{setup → deployment/setup}/carriers.py +33 -26
  44. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  45. package/templates/qoder/scripts/{setup → deployment/setup}/init_doctor.py +40 -16
  46. package/templates/qoder/scripts/{setup → deployment/setup}/install_qoderwork.py +20 -12
  47. package/templates/qoder/scripts/{setup → deployment/setup}/platform_doctor.py +8 -2
  48. package/templates/qoder/scripts/{setup → deployment/setup}/repo_root.py +113 -112
  49. package/templates/qoder/scripts/{setup → deployment/setup}/setup.py +31 -11
  50. package/templates/qoder/scripts/{setup → deployment/setup}/setup_lanhu.py +13 -7
  51. package/templates/qoder/scripts/domain/__init__.py +0 -0
  52. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  53. package/templates/qoder/scripts/{report → domain/design}/fill_prototype.py +12 -6
  54. package/templates/qoder/scripts/{report → domain/design}/gen_design_doc.py +8 -2
  55. package/templates/qoder/scripts/{setup → domain/kg}/__init__.py +11 -11
  56. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  57. package/templates/qoder/scripts/{kg → domain/kg/build}/build_entity_registry.py +7 -2
  58. package/templates/qoder/scripts/{kg → domain/kg/build}/build_relations.py +7 -2
  59. package/templates/qoder/scripts/{kg → domain/kg/build}/build_style_index.py +13 -7
  60. package/templates/qoder/scripts/{kg → domain/kg/build}/build_workflows.py +7 -2
  61. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build.py +76 -9
  62. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build_db.py +7 -2
  63. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_incremental.py +11 -6
  64. package/templates/qoder/scripts/{report → domain/kg/build}/learn_aggregate.py +9 -4
  65. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  66. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/test_extract.py +115 -115
  68. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  69. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  70. package/templates/qoder/scripts/{kg → domain/kg/graph}/kg_link_db.py +7 -2
  71. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  72. package/templates/qoder/scripts/{kg → domain/kg}/kg.py +263 -30
  73. package/templates/qoder/scripts/{common → domain/kg}/kg_capabilities.py +182 -182
  74. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  75. package/templates/qoder/scripts/{kg → domain/kg/search}/context_pack.py +30 -9
  76. package/templates/qoder/scripts/{kg → domain/kg/search}/enrich_prompt.py +10 -4
  77. package/templates/qoder/scripts/{kg → domain/kg/search}/prefetch.py +33 -8
  78. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  79. package/templates/qoder/scripts/{kg → domain/kg/search}/search_index.py +143 -77
  80. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  81. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  82. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  83. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  84. package/templates/qoder/scripts/{kg → domain/kg/storage}/kg_duckdb.py +38 -14
  85. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  86. package/templates/qoder/scripts/{report → domain/learning}/learn.py +8 -3
  87. package/templates/qoder/scripts/{mcp → domain/report}/__init__.py +11 -11
  88. package/templates/qoder/scripts/{report → domain/report}/add_session.py +9 -3
  89. package/templates/qoder/scripts/{report → domain/report}/export.py +10 -5
  90. package/templates/qoder/scripts/{report → domain/report}/report.py +9 -4
  91. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  92. package/templates/qoder/scripts/{report → domain/report}/role.py +10 -4
  93. package/templates/qoder/scripts/{report → domain/report}/status.py +112 -9
  94. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  95. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  96. package/templates/qoder/scripts/{report → domain/requirement}/archive_prd.py +8 -2
  97. package/templates/qoder/scripts/{report → domain/requirement}/req.py +228 -222
  98. package/templates/qoder/scripts/{kg → domain/task}/__init__.py +11 -11
  99. package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
  100. package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
  101. package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
  102. package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
  103. package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
  104. package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
  105. package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
  106. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  107. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  108. package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
  109. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  110. package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
  111. package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
  112. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
  113. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  114. package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
  115. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  116. package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
  117. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
  118. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  119. package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
  120. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
  121. package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
  122. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
  123. package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
  124. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  125. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  126. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
  127. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  128. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  129. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  130. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  131. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  132. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  133. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  134. package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
  135. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  136. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  137. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  138. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  139. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  140. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  141. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  142. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  143. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  144. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  145. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  146. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  147. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  148. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  153. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  154. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  155. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  156. package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
  157. package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
  158. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  159. package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
  160. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  161. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  162. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  163. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  164. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  165. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  166. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  167. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  168. package/templates/qoder/scripts/validation/__init__.py +0 -0
  169. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  171. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  172. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  173. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  174. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  175. package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
  176. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  177. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  178. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  179. package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
  180. package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
  181. package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
  182. package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
  183. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  184. package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
  185. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  186. package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
  187. package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
  188. package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
  189. package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
  190. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  191. package/templates/qoder/settings.json +30 -0
  192. package/templates/qoder/skills/design-import/SKILL.md +22 -13
  193. package/templates/qoder/skills/design-review/SKILL.md +19 -10
  194. package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
  195. package/templates/qoder/skills/prd-review/SKILL.md +6 -4
  196. package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
  197. package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
  198. package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
  199. package/templates/qoder/skills/test-generator/SKILL.md +7 -5
  200. package/templates/qoder/skills/wl-code/SKILL.md +23 -11
  201. package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
  202. package/templates/qoder/skills/wl-design/SKILL.md +5 -3
  203. package/templates/qoder/skills/wl-init/SKILL.md +6 -6
  204. package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
  205. package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
  206. package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
  207. package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
  208. package/templates/qoder/skills/wl-report/SKILL.md +25 -23
  209. package/templates/qoder/skills/wl-search/SKILL.md +149 -78
  210. package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
  211. package/templates/qoder/skills/wl-status/SKILL.md +48 -16
  212. package/templates/qoder/skills/wl-task/SKILL.md +92 -10
  213. package/templates/qoder/skills/wl-test/SKILL.md +75 -29
  214. package/templates/qoder/templates/prd-full-template.md +7 -0
  215. package/templates/root/AGENTS.md +275 -236
  216. package/templates/root/requirements.txt +3 -0
  217. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  218. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  219. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
  220. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
  221. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
  222. package/templates/.qoder/learning/eval-history.jsonl +0 -28
  223. package/templates/data/index/wiki-index.json +0 -8
  224. package/templates/qoder/nul +0 -4
  225. package/templates/qoder/scripts/kg/extract.py +0 -398
  226. package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
  227. package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
  228. package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
  229. package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
  230. package/templates/qoder/scripts/task/__init__.py +0 -11
  231. package/templates/qoder/scripts/test/__init__.py +0 -11
  232. package/templates/qoder/scripts/wlkj.py +0 -116
  233. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  234. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  235. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  236. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  237. /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
@@ -1,28 +0,0 @@
1
- {"a1_reality": 0.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 0.0, "time": "2026-06-23T15:06:47.512881"}
2
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:06:48.151944"}
3
- {"a1_reality": 0.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 0.0, "time": "2026-06-23T15:07:06.380363"}
4
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:07:20.277445"}
5
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:08:26.677411"}
6
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:08:27.209288"}
7
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:08:55.802944"}
8
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:08:56.234057"}
9
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:11:32.306461"}
10
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:11:32.761987"}
11
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:19:28.644771"}
12
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:19:29.240469"}
13
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:26:51.416116"}
14
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:26:52.129295"}
15
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:32:16.110663"}
16
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:32:16.669572"}
17
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:35:31.618489"}
18
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:35:32.085857"}
19
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:44:50.176279"}
20
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:44:50.849511"}
21
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T15:49:54.375114"}
22
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T15:49:54.852542"}
23
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T16:09:00.572162"}
24
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T16:09:01.184157"}
25
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T16:28:54.661703"}
26
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T16:28:55.227433"}
27
- {"a1_reality": 0.5, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-good.md", "score_pct": 28.6, "time": "2026-06-23T16:46:57.600191"}
28
- {"a1_reality": 1.0, "a2_style": null, "a3_template": 0.0, "passed": false, "prd": "req-poor.md", "score_pct": 57.1, "time": "2026-06-23T16:46:58.135094"}
@@ -1,8 +0,0 @@
1
- {
2
- "index": {},
3
- "stats": {
4
- "projects": 0,
5
- "pages": 0,
6
- "keywords": 0
7
- }
8
- }
@@ -1,4 +0,0 @@
1
- dir: cannot access '/s': No such file or directory
2
- dir: cannot access '/b': No such file or directory
3
- dir: cannot access '*.py': No such file or directory
4
- dir: cannot access '*.md': No such file or directory
@@ -1,398 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """extract.py - 三种提取策略 (Strategy 模式, v3.0 合并3文件)
4
-
5
- v3.0 合并自: extract_routes(regex扫路由) + extract_routes_tree(API拉路由树) + extract_api_params(提取API参数)。
6
- 三种"提取"是同一抽象的不同策略, 合一用子命令分发。
7
-
8
- 用法:
9
- python extract.py routes regex扫前端路由→frontend-routes.json
10
- python extract.py routes-tree API拉菜单树→menu-routes-tree.json (需登录态)
11
- python extract.py api-params 提取API参数→api-params.json
12
- """
13
- # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
14
- import os as _o, sys as _s
15
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
16
- if _cp not in _s.path: _s.path.insert(0, _cp)
17
- from bootstrap import setup; setup()
18
-
19
- import sys, os, re, glob, json
20
- from common.paths import PROJECT_ROOT
21
-
22
- # ==================== routes-tree 的辅助函数 ====================
23
- def read_developer():
24
- f = os.path.join(PROJECT, '.qoder', '.developer')
25
- for ln in open(f, encoding='utf-8'):
26
- if ln.strip().startswith('name='):
27
- return ln.strip().split('=', 1)[1].strip()
28
- raise RuntimeError('无 .developer, 先 /wl-init')
29
-
30
-
31
-
32
- # ==================== Strategy 1: routes (regex扫) ====================
33
- def main_routes():
34
- """提取前端路由 (regex扫.ts文件). 原extract_routes.py"""
35
- router_dir = str(PROJECT_ROOT / 'data' / 'code' / 'fywl-ui' / 'apps' / 'ics' / 'src' / 'router')
36
- routes = []
37
-
38
- for rf in glob.glob(os.path.join(router_dir, '**', '*.ts'), recursive=True):
39
- try:
40
- txt = open(rf, encoding='utf-8', errors='ignore').read()
41
- except Exception:
42
- continue
43
- # 匹配 path: 'xxx' 和 component: () => import('xxx')
44
- # 或 path: 'xxx', name: 'yyy'
45
- for m in re.finditer(
46
- r"path:\s*['\"`]([^'\"`]+)['\"`]"
47
- r"[^}]*?(?:name:\s*['\"]([^'\"]+)['\"])?"
48
- r"[^}]*?(?:component:\s*\([^)]*\)\s*=>\s*import\(['\"]([^'\"]+)['\"]\))?",
49
- txt, re.S):
50
- path, name, component = m.group(1), m.group(2) or '', m.group(3) or ''
51
- if path and not path.startswith(':') and len(path) > 1:
52
- routes.append({'path': path, 'name': name, 'component': component})
53
-
54
- # 也扫后台菜单路由(通常在数据库 sys_menu 表, 但前端可能有硬编码)
55
- # 搜 views 目录下的 Vue 文件路径作为页面标识
56
- views_dir = str(PROJECT_ROOT / 'data' / 'code' / 'fywl-ui' / 'apps' / 'ics' / 'src' / 'views')
57
- vue_views = glob.glob(os.path.join(views_dir, '**', '*.vue'), recursive=True)
58
- view_paths = [v.replace('\\', '/').split('/views/')[-1].replace('.vue', '') for v in vue_views]
59
-
60
- print('路由定义: %d 条' % len(routes))
61
- print('Vue 页面: %d 个' % len(view_paths))
62
-
63
- # 保存路由索引
64
- output = {
65
- 'version': '1.0',
66
- 'total_routes': len(routes),
67
- 'total_views': len(view_paths),
68
- 'routes': routes,
69
- 'views': sorted(view_paths),
70
- }
71
- out_path = str(PROJECT_ROOT / 'data' / 'index' / 'frontend-routes.json')
72
- with open(out_path, 'w', encoding='utf-8') as f:
73
- json.dump(output, f, ensure_ascii=False, indent=2)
74
- print('已保存: %s' % out_path)
75
-
76
- # 样本
77
- print('\n样本路由:')
78
- for r in routes[:8]:
79
- print(' %s -> %s' % (r['path'], r['component'][:50] if r['component'] else r['name']))
80
-
81
- # 保险相关
82
- print('\n保险相关路由:')
83
- for r in routes:
84
- if 'insur' in r['path'].lower() or '保险' in r.get('name', ''):
85
- print(' %s' % r['path'])
86
-
87
-
88
- # ==================== Strategy 2: routes-tree (API拉) ====================
89
- def main_routes_tree():
90
- """从getRouters API拉菜单树(准确path). 原extract_routes_tree.py"""
91
- dev = read_developer()
92
- auth_file = os.path.join(PROJECT, 'workspace', 'members', dev, 'auth-state.json')
93
- if not os.path.exists(auth_file):
94
- print('无 auth-state, 先登录: python .qoder/scripts/kg_auto_login.py'); sys.exit(1)
95
- auth = json.load(open(auth_file, encoding='utf-8'))
96
- token = auth['access_token']
97
- base = auth['base_url']; prefix = auth.get('api_prefix', '/test-api')
98
-
99
- print('拉取 getRouters...')
100
- r = requests.get(base + prefix + '/system/menu/getRouters',
101
- headers={'Authorization': 'Bearer ' + token, 'clientid': 'e5cd7e4891bf95d1d19206ce24a7b32e'},
102
- timeout=20)
103
- d = r.json()
104
- if d.get('code') != 200:
105
- print('getRouters 失败:', d.get('msg')); sys.exit(1)
106
- tree = d.get('data') or []
107
-
108
-
109
- def walk(nodes, parent_path=''):
110
- """递归拼接准确 path, 返回 [{full_path, name, component}].
111
- name 优先用 meta.title(中文), 回退 name(i18n key)."""
112
- out = []
113
- for n in nodes:
114
- seg = n.get('path', '').lstrip('/')
115
- meta = n.get('meta') or {}
116
- name = meta.get('title', '') or n.get('name', '')
117
- comp = n.get('component', '')
118
- full = (parent_path.rstrip('/') + '/' + seg) if parent_path else '/' + seg
119
- while '//' in full:
120
- full = full.replace('//', '/')
121
- kids = n.get('children') or []
122
- if kids:
123
- out.extend(walk(kids, full))
124
- elif comp and comp != '#' and ':' not in full:
125
- out.append({'path': full, 'name': name, 'component': comp, 'i18n_key': n.get('name', '')})
126
- return out
127
-
128
-
129
- pages = walk(tree)
130
- # 去重
131
- seen = set(); uniq = []
132
- for p in pages:
133
- if p['path'] not in seen:
134
- seen.add(p['path']); uniq.append(p)
135
-
136
- out_file = os.path.join(PROJECT, 'data', 'index', 'menu-routes-tree.json')
137
- json.dump({
138
- 'source': 'getRouters API (父子树递归拼接, 准确 path)',
139
- 'total': len(uniq),
140
- 'routes': uniq,
141
- }, open(out_file, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
142
-
143
- print('已存 %d 条准确路由 -> %s' % (len(uniq), out_file))
144
- print()
145
- # 验证关键页面
146
- for kw in ['abnormalRecords', 'insurance', 'ticket']:
147
- hits = [p for p in uniq if kw.lower() in (p['path'] + p['name']).lower()]
148
- for h in hits[:2]:
149
- print(' %-12s -> %s' % (h['name'][:10], h['path']))
150
-
151
-
152
- # ==================== Strategy 3: api-params (来自extract_api_params) ====================
153
- BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
154
- KG_PATH = os.path.join(BASE, 'data', 'index', 'kg.duckdb')
155
- PARAMS_FILE = os.path.join(BASE, 'data', 'index', 'api-params.json')
156
-
157
-
158
- # ── TS 解析 ──────────────────────────────────────────────────
159
-
160
- def parse_ts_param_types():
161
- """扫所有 TS api 文件, 建 {fn_name: param_type} 映射。"""
162
- fn_map = {}
163
- ts_root = os.path.join(BASE, 'data', 'code', 'fywl-ui', 'apps', 'ics', 'src', 'api')
164
- for tf in glob.glob(os.path.join(ts_root, '**', '*.ts'), recursive=True):
165
- try:
166
- if os.path.getsize(tf) > 50000:
167
- continue
168
- txt = open(tf, encoding='utf-8', errors='ignore').read()
169
- except Exception:
170
- continue
171
- for m in re.finditer(r'export\s+(?:async\s+)?function\s+(\w+)\s*\(\s*(?:\w+)?\s*(?::\s*(\w+|Partial<[^>]+>))?', txt):
172
- fn_map[m.group(1)] = m.group(2) or 'none'
173
- for m in re.finditer(r'export\s+const\s+(\w+)\s*=\s*\(\s*(?:\w+)?\s*(?::\s*(\w+|Partial<[^>]+>|Record<[^>]+>))?', txt):
174
- fn_map[m.group(1)] = m.group(2) or 'none'
175
- return fn_map
176
-
177
-
178
- # ── Java Bo 解析 ─────────────────────────────────────────────
179
-
180
- def build_bo_index():
181
- """预扫所有 Bo/Dto/Query 类, 建 {类名: 路径} 索引。"""
182
- index = {}
183
- root = os.path.join(BASE, 'data', 'code', 'fywl-ics')
184
- for pattern in ['**/*Bo.java', '**/*Dto.java', '**/*QueryBo.java', '**/*Query.java']:
185
- for f in glob.glob(os.path.join(root, pattern), recursive=True):
186
- if 'target' in f or '/classes/' in f:
187
- continue
188
- base_name = os.path.basename(f).replace('.java', '')
189
- for suffix in ['QueryBo', 'Bo', 'Dto', 'Query']:
190
- if base_name.endswith(suffix):
191
- index[base_name] = f
192
- short = base_name[:-len(suffix)]
193
- if short not in index:
194
- index[short] = f
195
- break
196
- else:
197
- index[base_name] = f
198
- return index
199
-
200
-
201
- def gen_default(java_type, field_name):
202
- """按 Java 类型 + 字段名生成智能默认值。"""
203
- FIELD_DEFAULTS = {
204
- 'pageNum': 1, 'pageSize': 10, 'page': 1, 'size': 10, 'current': 1,
205
- 'id': 1, 'parentId': 0, 'pid': 0, 'deptId': 100,
206
- 'userId': 1, 'tenantId': '000000',
207
- 'status': 0, 'type': '', 'code': '', 'name': 'test',
208
- 'phone': '13800000000', 'mobile': '13800000000', 'email': 'test@test.com',
209
- 'isAsc': 'asc', 'orderByColumn': 'id',
210
- }
211
- if field_name in FIELD_DEFAULTS:
212
- return FIELD_DEFAULTS[field_name]
213
- fn = (field_name or '').lower()
214
- if 'phone' in fn or 'mobile' in fn:
215
- return '13800000000'
216
- if 'email' in fn:
217
- return 'test@test.com'
218
- if 'date' in fn or 'time' in fn:
219
- return '2026-01-01'
220
- if 'name' in fn:
221
- return 'test'
222
- if 'code' in fn:
223
- return 'TEST001'
224
- if fn == 'id' or fn.endswith('id'):
225
- return 1
226
- jt = (java_type or '').strip()
227
- if jt in ('Long', 'long', 'Integer', 'int', 'BigInteger', 'BigDecimal', 'Number'):
228
- return 1
229
- if jt in ('String', 'CharSequence', 'char'):
230
- return 'test'
231
- if jt in ('Boolean', 'boolean'):
232
- return False
233
- if jt in ('Date', 'LocalDate', 'LocalDateTime', 'Timestamp'):
234
- return '2026-01-01'
235
- if jt in ('Double', 'double', 'Float', 'float'):
236
- return 1.0
237
- if jt.startswith('List') or jt.startswith('Set') or jt.startswith('Collection'):
238
- return []
239
- if jt.startswith('Map'):
240
- return {}
241
- return None
242
-
243
-
244
- def parse_bo_fields(java_path):
245
- """解析 Java Bo 类的字段+类型+校验注解。"""
246
- try:
247
- if not os.path.isfile(java_path) or os.path.getsize(java_path) > 80000:
248
- return []
249
- txt = open(java_path, encoding='utf-8', errors='ignore').read()
250
- except Exception:
251
- return []
252
- fields = []
253
- try:
254
- for m in re.finditer(
255
- r'((?:@\w+(?:\([^)]*\))?\s*)*)'
256
- r'(?:private\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)\s*;', txt):
257
- anns, jtype, fname = m.group(1), m.group(2), m.group(3)
258
- if fname in ('serialVersionUID', 'logger', 'LOG') or fname.isupper():
259
- continue
260
- required = bool(re.search(r'@(?:NotNull|NotBlank|NotEmpty|Valid)\b', anns))
261
- fields.append({'name': fname, 'type': jtype, 'required': required})
262
- except Exception:
263
- pass
264
- return fields
265
-
266
-
267
- _BO_CACHE = {}
268
-
269
-
270
- def bo_to_params(bo_class, bo_index):
271
- """从 Bo 类名解析出参数 JSON (带缓存)。"""
272
- if not bo_class or bo_class in _BO_CACHE:
273
- return _BO_CACHE.get(bo_class)
274
- jf = bo_index.get(bo_class) or bo_index.get(bo_class + 'Bo') or bo_index.get(bo_class + 'Dto')
275
- if not jf:
276
- _BO_CACHE[bo_class] = None
277
- return None
278
- fields = parse_bo_fields(jf)
279
- if not fields:
280
- _BO_CACHE[bo_class] = None
281
- return None
282
- params = {}
283
- for f in fields:
284
- val = gen_default(f['type'], f['name'])
285
- if f['required'] and val is None:
286
- val = 1 if 'id' in f['name'].lower() else 'test'
287
- params[f['name']] = val
288
- _BO_CACHE[bo_class] = params
289
- return params
290
-
291
-
292
- # ── 参数生成 ─────────────────────────────────────────────────
293
-
294
- def gen_params(ptype, bo_index=None):
295
- """按 TS 参数类型生成默认参数 JSON。Bo 类型解析 Java 字段。"""
296
- if ptype == 'PageQuery':
297
- return {'pageNum': 1, 'pageSize': 10, 'isAsc': 'asc', 'orderByColumn': 'id'}, 'PageQuery'
298
- if ptype in ('ID', 'Id'):
299
- return {'id': 1}, 'ID'
300
- if ptype == 'IDS':
301
- return {'ids': [1]}, 'IDS'
302
- if ptype == 'string':
303
- return {'id': '1'}, 'string'
304
- if ptype == 'number':
305
- return {'id': 1}, 'number'
306
- if ptype and ptype not in ('any', 'none', 'Recordable', 'Partial', 'Record', 'boolean', 'Blob'):
307
- if bo_index:
308
- bp = bo_to_params(ptype, bo_index)
309
- if bp:
310
- return bp, 'Bo:' + ptype
311
- return {}, 'Bo:' + ptype
312
- if ptype == 'any':
313
- return {}, 'any'
314
- return {}, 'none'
315
-
316
-
317
- # ── 主流程 ───────────────────────────────────────────────────
318
-
319
- def main_api_params():
320
- t0 = time.time()
321
-
322
- # 1. 读主库(只读)拿接口列表
323
- kg = duckdb.connect(KG_PATH, read_only=True)
324
- rows = kg.execute("SELECT fn_name, url, verb FROM api_functions WHERE url IS NOT NULL").fetchall()
325
- kg.close()
326
- sys.stderr.write('[%.1fs] DuckDB: %d rows\n' % (time.time() - t0, len(rows)))
327
-
328
- # 2. TS 参数类型
329
- fn_map = parse_ts_param_types()
330
- sys.stderr.write('[%.1fs] TS: %d fns\n' % (time.time() - t0, len(fn_map)))
331
-
332
- # 2b. Bo 类索引
333
- bo_index = build_bo_index()
334
- sys.stderr.write('[%.1fs] Bo index: %d\n' % (time.time() - t0, len(bo_index)))
335
-
336
- # 3. 生成参数
337
- results = []
338
- source_dist = {}
339
- for fn, url, verb in rows:
340
- if not url or url.startswith('$'):
341
- continue
342
- ptype = fn_map.get(fn, 'none')
343
- params, source = gen_params(ptype, bo_index)
344
- req = [k for k, v in params.items() if v is not None]
345
- results.append({
346
- 'url': url, 'verb': verb or '', 'param_source': source,
347
- 'params': params, 'required': req,
348
- })
349
- skey = source.split(':')[0]
350
- source_dist[skey] = source_dist.get(skey, 0) + 1
351
-
352
- sys.stderr.write('[%.1fs] Generated: %d\n' % (time.time() - t0, len(results)))
353
-
354
- # 4. 写 JSON
355
- output = {
356
- 'version': '1.0',
357
- 'extracted_at': datetime.now().isoformat()[:19],
358
- 'total': len(results),
359
- 'apis': results,
360
- }
361
- with open(PARAMS_FILE, 'w', encoding='utf-8') as f:
362
- json.dump(output, f, ensure_ascii=False, indent=2)
363
- sys.stderr.write('[%.1fs] Written: %s\n' % (time.time() - t0, PARAMS_FILE))
364
-
365
- # 5. 报告
366
- sys.stderr.write('\n=== API 参数提取 ===\n')
367
- sys.stderr.write('总接口: %d, 已提取: %d\n' % (len(rows), len(results)))
368
- for s, c in sorted(source_dist.items(), key=lambda x: -x[1]):
369
- sys.stderr.write(' %-15s %d\n' % (s, c))
370
-
371
- # 样本
372
- for r in results:
373
- if r['param_source'] not in ('none', 'any') and r['params']:
374
- sys.stderr.write('\n样本: %s [%s] %s\n' % (
375
- r['url'][:50], r['param_source'],
376
- json.dumps(r['params'], ensure_ascii=False)[:60]))
377
- break
378
-
379
-
380
-
381
-
382
- # ============================================================
383
- # Facade: 统一入口分发
384
- # ============================================================
385
- def main():
386
- cmd = sys.argv[1] if len(sys.argv) > 1 else 'routes'
387
- sys.argv = [sys.argv[0]] + sys.argv[2:]
388
- if cmd == 'routes':
389
- main_routes()
390
- elif cmd == 'routes-tree':
391
- main_routes_tree()
392
- elif cmd == 'api-params':
393
- main_api_params()
394
- else:
395
- print('用法: extract.py [routes|routes-tree|api-params]')
396
-
397
- if __name__ == '__main__':
398
- main()
@@ -1,156 +0,0 @@
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
- LLM semantic labeling layer for the knowledge graph.
10
-
11
- After kg_build.py extracts structural data (AST-level), this module:
12
- 1. Finds entities that lack semantic labels (cn == dir, no business_domain)
13
- 2. Outputs a labeling prompt for the AI (QoderWork) to fill in
14
- 3. Provides a write-back function to store labels in DuckDB
15
-
16
- The AI (QoderWork's LLM) sees the prompt during session-start or when
17
- kg_build reports new modules, and labels them — zero human trigger.
18
-
19
- Usage (called by AI automatically):
20
- python kg_semantic.py --check # check what needs labeling
21
- python kg_semantic.py --label '{"assets": {"cn": "资产管理", "domain": "固定资产"}}'
22
- """
23
- import json
24
- import os
25
- import sys
26
-
27
- SCRIPTS = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 子包→scripts/根
28
- sys.path.insert(0, SCRIPTS)
29
- from common.paths import DATA_INDEX_DIR
30
- from kg_duckdb import get_db
31
-
32
- DB_PATH = str(DATA_INDEX_DIR / 'kg.duckdb')
33
-
34
-
35
- def check_unlabeled():
36
- """Find modules that need semantic labeling (cn == dir or cn is empty)."""
37
- con = get_db()
38
- # Find FEATURE entities where cn == dir (unlabeled) or cn is empty
39
- rows = con.execute("""
40
- SELECT id, canonical, cn FROM entities
41
- WHERE type = 'FEATURE'
42
- AND (cn = canonical OR cn = '' OR cn IS NULL)
43
- ORDER BY canonical
44
- """).fetchall()
45
-
46
- if not rows:
47
- return None
48
-
49
- # Build labeling prompt
50
- modules = []
51
- for eid, dirname, cn in rows:
52
- # Gather context: what endpoints/pages does this module have?
53
- ep_count = con.execute(
54
- "SELECT COUNT(*) FROM edges WHERE from_id = ? AND edge_type = 'has_endpoint'",
55
- [eid]
56
- ).fetchone()[0]
57
- btn_count = con.execute(
58
- "SELECT COUNT(*) FROM edges WHERE from_id = ? AND edge_type = 'has_button'",
59
- [eid]
60
- ).fetchone()[0]
61
- # Sample endpoints for context
62
- sample_eps = con.execute("""
63
- SELECT e.to_id FROM edges e
64
- WHERE e.from_id = ? AND e.edge_type = 'has_endpoint' LIMIT 5
65
- """, [eid]).fetchall()
66
-
67
- modules.append({
68
- 'dir': dirname,
69
- 'endpoints': ep_count,
70
- 'buttons': btn_count,
71
- 'sample_apis': [r[0].replace('E:', '') for r in sample_eps],
72
- })
73
-
74
- con.close()
75
-
76
- prompt = {
77
- 'action': 'semantic_labeling_needed',
78
- 'description': '以下模块需要语义标注(中文名+业务领域)。请根据目录名和API端点推断。',
79
- 'modules': modules,
80
- 'instructions': (
81
- '对每个模块返回: {"目录名": {"cn": "中文名", "domain": "业务领域"}}\n'
82
- '示例: {"assets": {"cn": "资产管理", "domain": "固定资产管理"}}\n'
83
- '然后用 kg_semantic.py --label 写回'
84
- ),
85
- }
86
- return prompt
87
-
88
-
89
- def apply_labels(labels_json):
90
- """Write semantic labels back to DuckDB.
91
-
92
- labels_json: {"assets": {"cn": "资产管理", "domain": "固定资产"}, ...}
93
- """
94
- labels = json.loads(labels_json) if isinstance(labels_json, str) else labels_json
95
- con = get_db()
96
- updated = 0
97
-
98
- for dirname, info in labels.items():
99
- cn = info.get('cn', dirname)
100
- domain = info.get('domain', '')
101
-
102
- # Find the FEATURE entity by canonical name (dir)
103
- rows = con.execute(
104
- "SELECT id FROM entities WHERE type='FEATURE' AND canonical = ?",
105
- [dirname]
106
- ).fetchall()
107
-
108
- for row in rows:
109
- eid = row[0]
110
- # Update cn
111
- con.execute(
112
- "UPDATE entities SET cn = ? WHERE id = ?",
113
- [cn, eid]
114
- )
115
- # Update props with domain
116
- props_row = con.execute(
117
- "SELECT props FROM entities WHERE id = ?", [eid]
118
- ).fetchone()
119
- if props_row:
120
- try:
121
- props = json.loads(props_row[0]) if props_row[0] else {}
122
- except Exception:
123
- props = {}
124
- props['business_domain'] = domain
125
- props['labeled'] = True
126
- con.execute(
127
- "UPDATE entities SET props = ? WHERE id = ?",
128
- [json.dumps(props, ensure_ascii=False), eid]
129
- )
130
- # Update alias
131
- con.execute(
132
- "INSERT OR REPLACE INTO aliases VALUES (?, ?)",
133
- [cn.lower(), eid]
134
- )
135
- updated += 1
136
-
137
- con.close()
138
- return updated
139
-
140
-
141
- if __name__ == '__main__':
142
- if len(sys.argv) > 1 and sys.argv[1] == '--check':
143
- result = check_unlabeled()
144
- if result:
145
- print(json.dumps(result, ensure_ascii=False, indent=2))
146
- else:
147
- print('{"status": "all_labeled", "message": "所有模块已有语义标注"}')
148
-
149
- elif len(sys.argv) > 2 and sys.argv[1] == '--label':
150
- count = apply_labels(sys.argv[2])
151
- print('Updated %d entities with semantic labels' % count)
152
-
153
- else:
154
- print('Usage:')
155
- print(' python kg_semantic.py --check # 查看待标注模块')
156
- print(' python kg_semantic.py --label \'{"assets":{"cn":"资产管理","domain":"固定资产"}}\'')