@furongjun1999/dsh-memory 0.4.11 → 0.5.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 (504) hide show
  1. package/README.md +16 -16
  2. package/codebuddy/CODEBUDDY.md +11 -3
  3. package/codebuddy/README.md +92 -90
  4. package/codebuddy/mcp.json +27 -27
  5. package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -169
  6. package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -144
  7. package/docs/README.md +142 -111
  8. package/docs/discipline/harnesses.yaml +244 -226
  9. package/docs/discipline/templates/full.md.tmpl +61 -61
  10. package/docs/discipline/templates/rules.mdc.tmpl +68 -0
  11. package/docs/discipline/templates/skill.md.tmpl +23 -23
  12. package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md +299 -299
  13. package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md +239 -239
  14. package/docs/eval//345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md +174 -174
  15. package/docs/eval//346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md +223 -223
  16. package/docs/{mdcg → hive}//344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md +165 -160
  17. package/docs/hive//344/273/244/347/211/214/350/257/255/344/271/211/344/277/256/346/255/243_/344/273/262/350/243/201/344/275/215_v0.1.md +76 -0
  18. package/docs/{mdcg → hive}//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.5.md +236 -236
  19. package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -43
  20. package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +85 -0
  21. package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +102 -102
  22. package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +47 -0
  23. package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +503 -503
  24. package/docs/hive//350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +85 -85
  25. package/docs/hive//350/234/202/345/267/242/350/256/276/350/256/241_/347/220/206/350/256/272/345/257/271/351/275/220_v0.1.md +191 -0
  26. package/docs/hive//350/234/202/345/267/242/350/277/255/344/273/243_/345/256/217/350/247/202/344/270/216/347/276/244/344/275/223/350/260/203/345/272/246_v0.1.md +90 -0
  27. package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -216
  28. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
  29. package/docs/mdcg/lingshu_tutorial.html +14449 -14449
  30. package/docs/mdcg/release_v0.4.11.md +49 -0
  31. package/docs/mdcg/release_v0.4.5.md +55 -55
  32. package/docs/mdcg/tool_table_v0.3.0.md +117 -117
  33. package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -600
  34. package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
  35. package/docs/mdcg//345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +275 -275
  36. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
  37. package/docs/mdcg//346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +130 -130
  38. package/docs/mdcg//347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md +278 -278
  39. package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +172 -172
  40. package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
  41. package/docs/mdcg//350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +491 -491
  42. package/docs/mdcg//350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md +340 -340
  43. package/docs/mdcg//350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +588 -588
  44. package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -176
  45. package/docs/plans//345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +81 -81
  46. package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
  47. package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -242
  48. package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -129
  49. package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -134
  50. package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
  51. package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -145
  52. package/docs/theory//347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +144 -144
  53. package/docs/theory//347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +198 -198
  54. package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -221
  55. package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -237
  56. package/docs//345/217/221/345/270/203/344/273/266/345/233/236/346/272/257/350/257/264/346/230/216_v0.1.md +82 -82
  57. package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +28 -2
  58. package/dsh/README.md +82 -82
  59. package/dsh/cordis.yml.example +139 -139
  60. package/dsh/update-lingshu.bat +11 -11
  61. package/lib/hooks.js +36 -2
  62. package/lib/lib/roleplay_web.js +427 -427
  63. package/md_cg/__init__.py +7 -7
  64. package/md_cg/audit.py +368 -368
  65. package/md_cg/autonomy.py +287 -287
  66. package/md_cg/backfill.py +1327 -1327
  67. package/md_cg/backfill_bigdomain.py +34 -34
  68. package/md_cg/bench6_arms.py +410 -410
  69. package/md_cg/bench6_common.py +230 -230
  70. package/md_cg/bench6_competitors.py +212 -212
  71. package/md_cg/bench_axis_domain.py +257 -257
  72. package/md_cg/bench_blind_comp.py +308 -308
  73. package/md_cg/bench_en_atoms_public.py +230 -230
  74. package/md_cg/bench_governance.py +348 -348
  75. package/md_cg/bench_lme_zh.py +410 -410
  76. package/md_cg/bench_locomo.py +121 -121
  77. package/md_cg/bench_locomo_zh.py +450 -450
  78. package/md_cg/bench_locomo_zh_public.py +147 -147
  79. package/md_cg/bench_longmem.py +112 -112
  80. package/md_cg/bench_membench.py +632 -632
  81. package/md_cg/bench_p0.py +149 -149
  82. package/md_cg/bench_progressive.py +287 -287
  83. package/md_cg/bench_role_views.py +238 -238
  84. package/md_cg/bench_task_ab.py +243 -243
  85. package/md_cg/bench_task_ab_llm.py +408 -408
  86. package/md_cg/bench_unified_en.py +204 -204
  87. package/md_cg/bench_zh_mad.py +601 -601
  88. package/md_cg/blindspot_tickets.py +123 -123
  89. package/md_cg/branches.py +285 -285
  90. package/md_cg/build_postings.py +73 -73
  91. package/md_cg/ccgc.py +1005 -948
  92. package/md_cg/census.py +132 -132
  93. package/md_cg/chain.py +300 -300
  94. package/md_cg/codeindex.py +531 -531
  95. package/md_cg/coldverify.py +292 -292
  96. package/md_cg/comment_gate.py +337 -337
  97. package/md_cg/cond_compose.py +190 -190
  98. package/md_cg/cond_facts.py +154 -154
  99. package/md_cg/cond_template.json +106 -106
  100. package/md_cg/condition_anchor.py +142 -142
  101. package/md_cg/conformance.py +726 -726
  102. package/md_cg/consistency.py +717 -717
  103. package/md_cg/consolidate.py +1536 -1439
  104. package/md_cg/corpus.py +110 -110
  105. package/md_cg/crosscheck.py +1097 -1097
  106. package/md_cg/crypto.py +437 -437
  107. package/md_cg/d_meta.py +310 -310
  108. package/md_cg/datapath.py +334 -334
  109. package/md_cg/docindex.py +473 -473
  110. package/md_cg/eval_common.py +575 -575
  111. package/md_cg/evidence.py +580 -580
  112. package/md_cg/evolution.py +477 -477
  113. package/md_cg/export.py +220 -220
  114. package/md_cg/forgetting.py +581 -581
  115. package/md_cg/fsutil.py +329 -329
  116. package/md_cg/hotcache.py +238 -214
  117. package/md_cg/hyperedge.py +251 -251
  118. package/md_cg/identity.py +390 -390
  119. package/md_cg/insight.py +500 -500
  120. package/md_cg/interop.py +199 -0
  121. package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
  122. package/md_cg/lexicon/build_standard_en.py +171 -171
  123. package/md_cg/lexicon/expand_en_zh.py +211 -211
  124. package/md_cg/lifecycle.py +272 -272
  125. package/md_cg/linkref.py +280 -280
  126. package/md_cg/links.py +622 -622
  127. package/md_cg/mcp_server.py +129 -32
  128. package/md_cg/md_whitebox.py +345 -345
  129. package/md_cg/mdcg.py +176 -117
  130. package/md_cg/mdcos.py +79 -13
  131. package/md_cg/metacognition.py +591 -591
  132. package/md_cg/migrate.py +119 -119
  133. package/md_cg/migrate_aeis.py +221 -221
  134. package/md_cg/migrate_roleplay.py +293 -293
  135. package/md_cg/migrate_wisdom_graph.py +360 -360
  136. package/md_cg/mreview/__init__.py +25 -25
  137. package/md_cg/mreview/__main__.py +110 -110
  138. package/md_cg/mreview/bundle.py +178 -178
  139. package/md_cg/mreview/candidates.py +262 -262
  140. package/md_cg/mreview/govern.py +693 -693
  141. package/md_cg/mreview/locate.py +939 -939
  142. package/md_cg/mreview/pipeline.py +728 -728
  143. package/md_cg/mreview/rules/duplication.json +21 -21
  144. package/md_cg/mreview/rules/field_coverage.json +54 -54
  145. package/md_cg/mreview/rules/source_license.json +21 -21
  146. package/md_cg/mreview/rules/template_flow.json +21 -21
  147. package/md_cg/mreview/ruleset.py +252 -252
  148. package/md_cg/nodefile.py +575 -575
  149. package/md_cg/pooling.py +484 -472
  150. package/md_cg/postings.py +298 -298
  151. package/md_cg/predict.py +1100 -1100
  152. package/md_cg/progressive.py +123 -123
  153. package/md_cg/protect.py +272 -272
  154. package/md_cg/protocol/md_cg_gate.proto +33 -33
  155. package/md_cg/protocol.py +372 -372
  156. package/md_cg/provenance.py +582 -582
  157. package/md_cg/reach.py +453 -453
  158. package/md_cg/readcache.py +85 -0
  159. package/md_cg/refindex.py +833 -833
  160. package/md_cg/refine.py +604 -604
  161. package/md_cg/roleviews.py +89 -89
  162. package/md_cg/routing.py +365 -365
  163. package/md_cg/scrub.py +852 -852
  164. package/md_cg/security.py +274 -274
  165. package/md_cg/self_state.py +1029 -1029
  166. package/md_cg/selfreport.py +151 -151
  167. package/md_cg/semantic/__init__.py +10 -10
  168. package/md_cg/semantic/canonical.py +122 -122
  169. package/md_cg/semantic/en_normalizer.py +364 -364
  170. package/md_cg/semantic/en_zh_map.json +28694 -0
  171. package/md_cg/semantic/export_en_zh_map.py +64 -0
  172. package/md_cg/semantic/unify.py +45 -0
  173. package/md_cg/semantic/zh_en_atoms.py +139 -139
  174. package/md_cg/signer.py +562 -562
  175. package/md_cg/sources.py +815 -582
  176. package/md_cg/statushdr.py +179 -179
  177. package/md_cg/stg.py +48 -37
  178. package/md_cg/subgraph.py +729 -729
  179. package/md_cg/sustain.py +1138 -1138
  180. package/md_cg/tasks.py +470 -470
  181. package/md_cg/test_action_derive.py +203 -203
  182. package/md_cg/test_audit_rotate.py +270 -270
  183. package/md_cg/test_autonomy.py +143 -143
  184. package/md_cg/test_bench_governance.py +102 -102
  185. package/md_cg/test_blindspot_tickets.py +166 -166
  186. package/md_cg/test_branches.py +249 -249
  187. package/md_cg/test_ccg_perturb.py +184 -184
  188. package/md_cg/test_ccgc.py +433 -433
  189. package/md_cg/test_census_prune.py +81 -81
  190. package/md_cg/test_cond_compose_anchors.py +76 -76
  191. package/md_cg/test_cond_match.py +165 -165
  192. package/md_cg/test_condition_anchor.py +81 -81
  193. package/md_cg/test_d_meta.py +412 -412
  194. package/md_cg/test_datapath_root.py +199 -199
  195. package/md_cg/test_en_pipeline.py +166 -166
  196. package/md_cg/test_gain_gate.py +212 -212
  197. package/md_cg/test_health_scale.py +173 -173
  198. package/md_cg/test_hive_ingest.py +285 -0
  199. package/md_cg/test_hot_cold.py +215 -215
  200. package/md_cg/test_hyperedge.py +245 -245
  201. package/md_cg/test_i26_empty_first_write.py +116 -0
  202. package/md_cg/test_i27_e041_identity.py +128 -0
  203. package/md_cg/test_i28_hotcache_prodpath.py +122 -0
  204. package/md_cg/test_identity_attribution.py +147 -147
  205. package/md_cg/test_index_durability.py +224 -224
  206. package/md_cg/test_interop.py +93 -0
  207. package/md_cg/test_lifecycle.py +309 -309
  208. package/md_cg/test_linkref.py +306 -306
  209. package/md_cg/test_lock.py +43 -43
  210. package/md_cg/test_md_access_parity.py +255 -255
  211. package/md_cg/test_md_writepath.py +345 -345
  212. package/md_cg/test_mdstore_search_parity.py +160 -0
  213. package/md_cg/test_mr_m2.py +587 -587
  214. package/md_cg/test_mr_m3.py +710 -710
  215. package/md_cg/test_mr_m4.py +485 -485
  216. package/md_cg/test_p0.py +250 -250
  217. package/md_cg/test_p1.py +316 -316
  218. package/md_cg/test_p10_identity.py +173 -173
  219. package/md_cg/test_p11_consistency.py +233 -233
  220. package/md_cg/test_p12_metacognition.py +212 -212
  221. package/md_cg/test_p13_encryption.py +241 -241
  222. package/md_cg/test_p14_sustain.py +249 -249
  223. package/md_cg/test_p15_scrub.py +280 -280
  224. package/md_cg/test_p16_self_state.py +301 -301
  225. package/md_cg/test_p17_predict.py +354 -354
  226. package/md_cg/test_p18_whitebox.py +171 -171
  227. package/md_cg/test_p19_migrate_roleplay.py +149 -149
  228. package/md_cg/test_p20_evolution.py +315 -315
  229. package/md_cg/test_p21_tokens.py +293 -270
  230. package/md_cg/test_p22_theory.py +175 -175
  231. package/md_cg/test_p23_links.py +311 -311
  232. package/md_cg/test_p24_evidence.py +227 -227
  233. package/md_cg/test_p25_weights.py +156 -156
  234. package/md_cg/test_p26_refindex.py +416 -416
  235. package/md_cg/test_p27_docindex.py +765 -765
  236. package/md_cg/test_p28_refcheck.py +305 -305
  237. package/md_cg/test_p29_session_ingest_export.py +354 -333
  238. package/md_cg/test_p3.py +11 -2
  239. package/md_cg/test_p30_maintain.py +330 -330
  240. package/md_cg/test_p31_insight.py +534 -534
  241. package/md_cg/test_p32_backfill.py +298 -298
  242. package/md_cg/test_p33_ccg_wiring.py +293 -293
  243. package/md_cg/test_p34_crosscheck.py +331 -331
  244. package/md_cg/test_p35_conditioned_claim.py +252 -252
  245. package/md_cg/test_p36_kp_align.py +230 -230
  246. package/md_cg/test_p37_condition_space.py +248 -248
  247. package/md_cg/test_p38_concurrent_flush.py +102 -0
  248. package/md_cg/test_p38_contextualize.py +273 -273
  249. package/md_cg/test_p39_verify_flow.py +113 -0
  250. package/md_cg/test_p39_vision_evidence.py +369 -369
  251. package/md_cg/test_p40_refine_worklist.py +241 -241
  252. package/md_cg/test_p41_evolve_patrol.py +224 -224
  253. package/md_cg/test_p42_provenance.py +269 -269
  254. package/md_cg/test_p43_pooling.py +412 -398
  255. package/md_cg/test_p44_md_whitebox.py +231 -231
  256. package/md_cg/test_p45_session_identity.py +219 -219
  257. package/md_cg/test_p46_unit_scope.py +272 -272
  258. package/md_cg/test_p47_session_view.py +281 -0
  259. package/md_cg/test_p4_fuzzy.py +223 -223
  260. package/md_cg/test_p5_semantic.py +226 -226
  261. package/md_cg/test_p6_consolidate.py +440 -387
  262. package/md_cg/test_p7_goals_recent.py +202 -202
  263. package/md_cg/test_p8_subgraph_chain.py +200 -200
  264. package/md_cg/test_p9_forget_protect.py +231 -231
  265. package/md_cg/test_predict_beta.py +135 -135
  266. package/md_cg/test_preflight_failclosed.py +100 -100
  267. package/md_cg/test_progressive.py +146 -146
  268. package/md_cg/test_protocol.py +243 -243
  269. package/md_cg/test_reach.py +378 -378
  270. package/md_cg/test_reach_keys.py +201 -201
  271. package/md_cg/test_read_clip.py +141 -141
  272. package/md_cg/test_readcache_prodpath.py +155 -0
  273. package/md_cg/test_retr_gates_prodpath.py +140 -0
  274. package/md_cg/test_retr_s1.py +340 -340
  275. package/md_cg/test_retr_s1b.py +209 -209
  276. package/md_cg/test_retr_s3.py +194 -194
  277. package/md_cg/test_retr_s4.py +163 -163
  278. package/md_cg/test_retr_s5.py +200 -200
  279. package/md_cg/test_retr_s6.py +157 -157
  280. package/md_cg/test_retr_s7.py +384 -384
  281. package/md_cg/test_retr_s8_time.py +369 -316
  282. package/md_cg/test_retr_s9_edges.py +286 -286
  283. package/md_cg/test_retr_s9_entity_ctx.py +175 -175
  284. package/md_cg/test_review_conformance.py +367 -367
  285. package/md_cg/test_role_views.py +354 -354
  286. package/md_cg/test_sem_noise.py +242 -242
  287. package/md_cg/test_semantic_canonical.py +241 -241
  288. package/md_cg/test_subproc_encoding.py +192 -192
  289. package/md_cg/test_sustain_mutual.py +153 -153
  290. package/md_cg/test_tasks.py +409 -409
  291. package/md_cg/test_tool_face.py +189 -189
  292. package/md_cg/test_transfer.py +180 -180
  293. package/md_cg/test_trust.py +361 -361
  294. package/md_cg/test_twophase.py +286 -286
  295. package/md_cg/test_v14_fixes.py +397 -397
  296. package/md_cg/test_validity_filter.py +280 -280
  297. package/md_cg/test_verify_answer.py +138 -138
  298. package/md_cg/test_wisdom_md_store.py +292 -292
  299. package/md_cg/test_writelimit.py +197 -197
  300. package/md_cg/test_writepipe.py +214 -214
  301. package/md_cg/theory.py +273 -273
  302. package/md_cg/tokens.py +677 -663
  303. package/md_cg/tool_face.py +260 -260
  304. package/md_cg/trust.py +986 -950
  305. package/md_cg/twophase.py +231 -231
  306. package/md_cg/units.py +667 -667
  307. package/md_cg/vision_evidence.py +666 -666
  308. package/md_cg/weights.py +624 -624
  309. package/md_cg/whitebox.py +527 -527
  310. package/md_cg/whitebox_kb/__init__.py +37 -37
  311. package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
  312. package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
  313. package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
  314. package/md_cg/whitebox_kb/engine.py +310 -310
  315. package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
  316. package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
  317. package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
  318. package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
  319. package/md_cg/whitebox_kb/wisdom/code_solidified.json +6195 -6195
  320. package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
  321. package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
  322. package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
  323. package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
  324. package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
  325. package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
  326. package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
  327. package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
  328. package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
  329. package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
  330. package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
  331. package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
  332. package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
  333. package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
  334. package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
  335. package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
  336. package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
  337. package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
  338. package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
  339. package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
  340. package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
  341. package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
  342. package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
  343. package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
  344. package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
  345. package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
  346. package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
  347. package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
  348. package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
  349. package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
  350. package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
  351. package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
  352. package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
  353. package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
  354. package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
  355. package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
  356. package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
  357. package/md_cg/writelimit.py +356 -356
  358. package/md_cg/writepipe.py +550 -542
  359. package/package.json +97 -96
  360. package/skills/plugin.json +54 -54
  361. package/skills/skills/designer-perspective/SKILL.md +158 -158
  362. package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
  363. package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
  364. package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
  365. package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
  366. package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
  367. package/skills/skills/designer-perspective/scripts/designer.py +545 -545
  368. package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
  369. package/skills/skills/designer-perspective/tests/selftest.py +61 -61
  370. package/skills/skills/lingshu-browser/SKILL.md +60 -60
  371. package/skills/skills/lingshu-compiler/SKILL.md +56 -56
  372. package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
  373. package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
  374. package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
  375. package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
  376. package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
  377. package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
  378. package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
  379. package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
  380. package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
  381. package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
  382. package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
  383. package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
  384. package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
  385. package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
  386. package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
  387. package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
  388. package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
  389. package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
  390. package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
  391. package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
  392. package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
  393. package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
  394. package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
  395. package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
  396. package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
  397. package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
  398. package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
  399. package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
  400. package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
  401. package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
  402. package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
  403. package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
  404. package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
  405. package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
  406. package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
  407. package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
  408. package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
  409. package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
  410. package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
  411. package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
  412. package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
  413. package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
  414. package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
  415. package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
  416. package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
  417. package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
  418. package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
  419. package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
  420. package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
  421. package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
  422. package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
  423. package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
  424. package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
  425. package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
  426. package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
  427. package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
  428. package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
  429. package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
  430. package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
  431. package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
  432. package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
  433. package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
  434. package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
  435. package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
  436. package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
  437. package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
  438. package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
  439. package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
  440. package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
  441. package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
  442. package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
  443. package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
  444. package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
  445. package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
  446. package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
  447. package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
  448. package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
  449. package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
  450. package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
  451. package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
  452. package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
  453. package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
  454. package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
  455. package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
  456. package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
  457. package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
  458. package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
  459. package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
  460. package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
  461. package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
  462. package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
  463. package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
  464. package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
  465. package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
  466. package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
  467. package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
  468. package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
  469. package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
  470. package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
  471. package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
  472. package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
  473. package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
  474. package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
  475. package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
  476. package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
  477. package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
  478. package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
  479. package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
  480. package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
  481. package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
  482. package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
  483. package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
  484. package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
  485. package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
  486. package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
  487. package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
  488. package/skills/skills/lingshu-graph/SKILL.md +63 -63
  489. package/skills/skills/lingshu-net/SKILL.md +48 -48
  490. package/skills/skills/lingshu-os/SKILL.md +64 -64
  491. package/skills/skills/lingshu-pylang/SKILL.md +71 -71
  492. package/src/bridge.ts +401 -401
  493. package/src/hooks.ts +38 -2
  494. package/src/lib/datapath.ts +326 -326
  495. package/src/lib/mdcg_client.ts +413 -413
  496. package/src/lib/mutual.ts +428 -428
  497. package/src/lib/prompt_safety.ts +62 -62
  498. package/src/lib/python_path.ts +71 -71
  499. package/src/lib/roleplay_web.ts +932 -932
  500. package/src/lib/token_store.ts +192 -192
  501. package/src/tools.ts +212 -212
  502. package/zcode/AGENTS.md +11 -3
  503. package/zcode/README.md +41 -41
  504. /package/docs/{mdcg → hive}//344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md" +0 -0
package/md_cg/datapath.py CHANGED
@@ -1,335 +1,335 @@
1
- # -*- coding: utf-8 -*-
2
- """datapath.py · 灵枢数据根解析(记忆写入路径可配置)
3
-
4
- 与 node 侧 `src/lib/datapath.ts` **同口径**——两侧读同一份
5
- `<用户级状态根>/paths.json`(旧 `<插件仓>/data/paths.json` 兼容读)。
6
-
7
- 解析优先级(高 → 低):
8
- 1. 环境变量 `MDCG_DATA_ROOT`(数据根)/ `MDCG_ROOT`(认知图根)
9
- 2. 用户可编辑的路径文件 `paths.json` 的 "data_root" / "root"
10
- (位置:`<用户级状态根>/paths.json`;旧 `<插件仓>/data/paths.json` 兼容读)
11
- 3. 默认:`<用户级状态根>/data`(**插件包目录之外**,与进程 cwd 解耦)
12
-
13
- 为什么默认**不**锚定「插件仓自身 data/」(issue #18 相邻问题,数据丢失级):
14
- DSH 插件按 hoisted 布局装在 `<profile>/node_modules/<pkg>`,`pnpm` 更新该包会
15
- **整个替换包目录**——运行时数据落在包内时,每次更新成功即连目录一起删掉
16
- (实机实证:`data/` 54 文件 → 0,46 条记忆节点靠人工备份回填);`paths.json`
17
- 同址,用户配置一并丢失。故默认数据根与配置文件一律落**用户级状态根**
18
- (见 state_root()),与包目录彻底解耦。
19
-
20
- 为什么默认不锚定 `data/mdcg` 相对路径:
21
- 相对路径随进程 cwd 漂移——node 侧插件与 python 侧脚本 cwd 不同
22
- (历史事故:DSH 进程 cwd 在私有库目录时,记忆真源落到 `[私有库]/data/mdcg`,
23
- 与插件仓内的 `data/` 分裂成两处)。
24
-
25
- 设计边界:
26
- - 本模块只决定「**新写入去哪**」。唯一的搬运是 `migrate_legacy_data()`:
27
- 默认数据根生效且旧包内位置仍有内容时,一次性**复制**(不删除、不覆盖)
28
- 到用户级位置——见该函数注释。
29
- - 纯标准库、无包内相对导入——可被 `sys.path` 以顶层模块方式加载,
30
- 绕开 `md_cg/__init__.py` 的重依赖。
31
-
32
- 用法:
33
- from datapath import data_root, mdcg_root, state_dir # scripts/ 内
34
- python md_cg/datapath.py # 打印当前解析结果
35
- python md_cg/datapath.py --set-root D:/x/data # 写入 paths.json(用户可改)
36
- python md_cg/datapath.py --migrate-legacy # 把旧包内数据复制到用户级根
37
- """
38
- from __future__ import annotations
39
-
40
- import json
41
- import os
42
- import shutil
43
-
44
- ENV_DATA_ROOT = "MDCG_DATA_ROOT"
45
- ENV_MDCG_ROOT = "MDCG_ROOT"
46
- ENV_STATE_ROOT = "MDCG_STATE_ROOT"
47
-
48
-
49
- # 生效条件:无入参,恒返回本文件 __file__ 绝对路径上溯两级得到的插件仓根目录。
50
- def plugin_root() -> str:
51
- """插件仓根目录(本文件位于 <root>/md_cg/datapath.py)。"""
52
- return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
53
-
54
-
55
- # 生效条件:无入参;ENV_STATE_ROOT 环境变量为非空真值时返回其 abspath,为空串/未设时若 DSH_HOME 为非空真值则返回其 abspath 下 ".dsh-memory",两者皆无则返回 ~/.dsh/.dsh-memory 的 abspath。
56
- def state_root() -> str:
57
- """用户级状态根(**插件包目录之外**):路径配置与默认数据根的落点。
58
-
59
- `DSH_HOME` **未必**由宿主注入(本仓 `dsh/dsh-web-start.bat` 自行 set),
60
- 故家目录兜底;`~/.dsh` 是本插件既有约定(node 侧调试日志同址)。
61
- """
62
- env = os.environ.get(ENV_STATE_ROOT)
63
- if env:
64
- return os.path.abspath(env)
65
- dsh_home = os.environ.get("DSH_HOME")
66
- if dsh_home:
67
- return os.path.join(os.path.abspath(dsh_home), ".dsh-memory")
68
- return os.path.join(os.path.expanduser("~"), ".dsh", ".dsh-memory")
69
-
70
-
71
- # 生效条件:无入参,恒返回 plugin_root() 下 "data" 的拼接路径(旧版落点,更新时被整目录替换,只作兼容读与迁移源)。
72
- def legacy_data_root() -> str:
73
- """旧版落点(插件包内 `data/`)——更新时会被整个替换。"""
74
- return os.path.join(plugin_root(), "data")
75
-
76
-
77
- # 生效条件:无入参,恒返回 legacy_data_root() 下 "paths.json" 的拼接路径。
78
- def legacy_paths_file() -> str:
79
- """旧版路径配置文件位置(包内,兼容读)。"""
80
- return os.path.join(legacy_data_root(), "paths.json")
81
-
82
-
83
- # 生效条件:两个路径参数经 normpath+normcase 规范化后相等时返回 True,否则 False(Windows 大小写不敏感)。
84
- def _same_path(a: str, b: str) -> bool:
85
- return (os.path.normcase(os.path.normpath(a)) ==
86
- os.path.normcase(os.path.normpath(b)))
87
-
88
-
89
- # 生效条件:无入参;<state_root()>/paths.json 存在(isfile)时返回之,不存在而 legacy_paths_file() 存在时返回旧件,两者皆不存在时返回新位置路径(首次写入时创建),不受 data_root() 取值影响。
90
- def paths_file() -> str:
91
- """用户可编辑的路径配置文件——用户级优先,旧包内位置兼容读。
92
-
93
- 新位置:`<用户级状态根>/paths.json`(随包更新不丢)。
94
- 旧位置:`<插件仓>/data/paths.json`(旧版约定,仅当新位置不存在时读它,
95
- 已存在新件则新件说了算——不做自动复制,避免旧件后续编辑静默失效)。
96
- """
97
- current = os.path.join(state_root(), "paths.json")
98
- if os.path.isfile(current):
99
- return current
100
- legacy = legacy_paths_file()
101
- return legacy if os.path.isfile(legacy) else current
102
-
103
-
104
- # 生效条件:无入参;paths_file() 的所在目录与 state_root() 同路径时返回 "user",否则返回 "legacy"(兼容读旧包内位置)。
105
- def paths_file_source() -> str:
106
- """生效中的 paths.json 位置来源:`user` / `legacy`。"""
107
- return "user" if _same_path(os.path.dirname(paths_file()),
108
- state_root()) else "legacy"
109
-
110
-
111
- # 生效条件:无入参;paths_file() 的 JSON 顶层为 dict 时返回该 dict,JSON 解析或读取抛任何异常、或顶层非 dict 时返回 {}。
112
- def _user_paths() -> dict:
113
- try:
114
- with open(paths_file(), encoding="utf-8") as f:
115
- d = json.load(f)
116
- return d if isinstance(d, dict) else {}
117
- except Exception:
118
- return {}
119
-
120
-
121
- # 生效条件:无入参,恒返回 state_root() 下 "data" 的拼接路径(插件包目录之外,更新不触碰)。
122
- def default_data_root() -> str:
123
- """默认数据根 = 用户级状态根下 data/。"""
124
- return os.path.join(state_root(), "data")
125
-
126
-
127
- # 生效条件:p 为目录且其下无任何条目时返回 True,p 不存在/是文件/OSError 时返回 False。
128
- def _is_empty_dir(p: str) -> bool:
129
- try:
130
- return os.path.isdir(p) and not os.listdir(p)
131
- except OSError:
132
- return False
133
-
134
-
135
- # 生效条件:无入参;data_root() 与 default_data_root() 不同路径时返回 {ran:False, reason:"数据根为显式配置(env/paths.json),不迁移", from, to, copied:0, failed:[]};相同则继续——legacy_data_root() 非目录时返回 reason="旧位置不存在(多为更新时已随包目录被替换)",其下无条目(除 paths.json 外)时返回 reason="旧位置无数据",否则把其余顶层条目逐个复制到 default_data_root() 下(目标条目已存在且非空目录则跳过;只复制不删除、不覆盖;单个条目异常记入 failed 不抛),返回 ran=(copied>0)、copied、failed 与失败时的 reason("目标不可写" 或 "新位置已有数据,未覆盖")。
136
- def migrate_legacy_data() -> dict:
137
- """一次性迁移:把旧版包内 `data/` 的数据面复制到用户级默认数据根。
138
-
139
- 触发条件(三条同时满足,缺一不动):
140
- ① 数据根未被显式配置(env `MDCG_DATA_ROOT` / paths.json 的 "data_root"
141
- 都未设,即 data_root() 恰为默认值)——显式配置是用户的决定;
142
- ② 旧位置存在;③ 目标顶层条目不存在或为空目录(不覆盖、不合并)。
143
-
144
- `paths.json` 不复制(配置走 paths_file() 兼容读,复制会制造两说)。
145
- 任何异常逐项吞掉并记入 `failed`——迁移是增益,不该成为启动失败源。
146
-
147
- 边界(如实):pnpm 更新是**先替换包目录再启动新代码**,旧数据在升级瞬间即
148
- 已消失,本函数只能接手「旧位置那时仍在」的情形;已在升级中丢掉的数据无法
149
- 由此恢复——发布说明须提示 0.4.8 及更早用户升级前备份包内 `data/`。
150
- """
151
- frm = legacy_data_root()
152
- to = default_data_root()
153
- out = {"ran": False, "reason": "", "from": frm, "to": to,
154
- "copied": 0, "failed": []}
155
- if not _same_path(data_root(), to):
156
- out["reason"] = "数据根为显式配置(env/paths.json),不迁移"
157
- return out
158
- if not os.path.isdir(frm):
159
- out["reason"] = "旧位置不存在(多为更新时已随包目录被替换)"
160
- return out
161
- try:
162
- names = [n for n in os.listdir(frm) if n != "paths.json"]
163
- except OSError:
164
- out["reason"] = "旧位置不可读"
165
- return out
166
- if not names:
167
- out["reason"] = "旧位置无数据"
168
- return out
169
- for name in names:
170
- src = os.path.join(frm, name)
171
- dst = os.path.join(to, name)
172
- # 新位置已有实质内容 → 跳过(宁可少搬,不可覆盖)
173
- if os.path.exists(dst) and not _is_empty_dir(dst):
174
- continue
175
- try:
176
- os.makedirs(to, exist_ok=True)
177
- if os.path.isdir(src):
178
- shutil.copytree(src, dst, dirs_exist_ok=True)
179
- else:
180
- shutil.copy2(src, dst)
181
- out["copied"] += 1
182
- except Exception: # noqa: BLE001 —— 迁移不得成为启动失败源
183
- out["failed"].append(name)
184
- out["ran"] = out["copied"] > 0
185
- if not out["ran"]:
186
- out["reason"] = ("目标不可写" if out["failed"]
187
- else "新位置已有数据,未覆盖")
188
- return out
189
-
190
-
191
- # 生效条件:无入参;ENV_DATA_ROOT 环境变量为非空真值时返回其 abspath,为空串/未设时若 paths.json 的 "data_root" 为真值则按其是否为绝对路径决定直接 abspath 还是拼 plugin_root() 后 abspath,该键缺失或为假值时回落 default_data_root()。
192
- def data_root() -> str:
193
- """数据根(记忆/账本/运行态的父目录)。"""
194
- env = os.environ.get(ENV_DATA_ROOT)
195
- if env:
196
- return os.path.abspath(env)
197
- cfg = _user_paths().get("data_root")
198
- if cfg:
199
- return os.path.abspath(cfg) if os.path.isabs(cfg) else \
200
- os.path.abspath(os.path.join(plugin_root(), cfg))
201
- return default_data_root()
202
-
203
-
204
- # 生效条件:无入参;ENV_MDCG_ROOT 环境变量为非空真值时返回其 abspath,为空串/未设时若 paths.json 的 "root" 为真值则按其是否为绝对路径决定直接 abspath 还是拼 plugin_root() 后 abspath,该键缺失或为假值时返回 data_root() 下 "mdcg" 的拼接路径。
205
- def mdcg_root() -> str:
206
- """认知图(记忆唯一真源)根目录。"""
207
- env = os.environ.get(ENV_MDCG_ROOT)
208
- if env:
209
- return os.path.abspath(env)
210
- cfg = _user_paths().get("root")
211
- if cfg:
212
- return os.path.abspath(cfg) if os.path.isabs(cfg) else \
213
- os.path.abspath(os.path.join(plugin_root(), cfg))
214
- return os.path.join(data_root(), "mdcg")
215
-
216
-
217
- # 生效条件:parts 非空时路径为 data_root() 与各 part 的 join,parts 为空时路径即 data_root();create 为真值(默认 True)时对该路径 makedirs(exist_ok=True),create 为假值时只返回路径不建目录。
218
- def state_dir(*parts: str, create: bool = True) -> str:
219
- """运行态子目录(日志/队列/草稿…),默认挂在数据根下。"""
220
- p = os.path.join(data_root(), *parts) if parts else data_root()
221
- if create:
222
- os.makedirs(p, exist_ok=True)
223
- return p
224
-
225
-
226
- # 生效条件:name 依次拼成 data_root()/name、plugin_root()/name、dirname(plugin_root())/[私有归档根]/_archive/ctp-aeis-data/name 三个候选,仅保留其中 os.path.isfile 为真的项并按此顺序返回列表。
227
- def archive_root() -> str | None:
228
- """私有侧归档根(公开仓不含私有库名):本机配置提供,未配置则没有该候选。
229
-
230
- 取值顺序:环境变量 MDCG_ARCHIVE_ROOT -> 插件仓同级的 .mdcg_archive_root 文件内容。
231
- """
232
- value = os.environ.get("MDCG_ARCHIVE_ROOT", "").strip()
233
- if value:
234
- return value
235
- marker = os.path.join(os.path.dirname(plugin_root()), ".mdcg_archive_root")
236
- if os.path.isfile(marker):
237
- try:
238
- with open(marker, "r", encoding="utf-8") as fh:
239
- text = fh.read().strip()
240
- except OSError:
241
- return None
242
- return text or None
243
- return None
244
-
245
-
246
- # 生效条件:给定 name 时按 data_root()/name、plugin_root()/name 顺序拼接候选,仅当 archive_root() 不为 None 才追加其下 _archive/ctp-aeis-data/name,最终只返回其中 os.path.isfile 为真的路径(其余被过滤掉),故全都不满足时返回空列表。
247
- def legacy_candidates(name: str) -> list:
248
- """历史位置候选(只读兼容:三仓分离前的校验缓存等)。
249
-
250
- 仅用于「读旧件」,顺序:数据根 → 插件仓根 → 归档区。
251
- """
252
- out = [os.path.join(data_root(), name),
253
- os.path.join(plugin_root(), name)]
254
- archive = archive_root()
255
- if archive is not None:
256
- out.append(os.path.join(archive, "_archive", "ctp-aeis-data", name))
257
- return [p for p in out if os.path.isfile(p)]
258
-
259
-
260
- # 生效条件:name 对应的 legacy_candidates(name) 列表非空时返回其首个元素,为空列表时返回 None。
261
- def find_existing(name: str) -> str | None:
262
- """在数据根/插件仓/归档区中找已存在的同名文件,找不到返回 None。"""
263
- hits = legacy_candidates(name)
264
- return hits[0] if hits else None
265
-
266
-
267
- # 生效条件:无入参;恒返回含 plugin_root/state_root/data_root/mdcg_root/default_data_root/is_default/source/paths_file/paths_file_source/legacy_data_root/legacy_data_exists/data_root_exists/mdcg_root_exists 的字典,其中 source 按 ENV_DATA_ROOT 非空取 "env:MDCG_DATA_ROOT" → 否则 ENV_MDCG_ROOT 非空取 "env:MDCG_MDCG_ROOT" → 否则 _user_paths() 为非空 dict 取 "paths.json(用户级)" 或 "paths.json(兼容读旧包内位置)"(按 paths_file_source())→ 否则取 "default(用户级状态根 data/)"。
268
- def describe() -> dict:
269
- """当前解析结果的完整快照(供心跳/日志留痕)。"""
270
- dr = data_root()
271
- mr = mdcg_root()
272
- pf_src = paths_file_source()
273
- return {
274
- "plugin_root": plugin_root(),
275
- "state_root": state_root(),
276
- "data_root": dr,
277
- "mdcg_root": mr,
278
- "default_data_root": default_data_root(),
279
- "is_default": _same_path(dr, default_data_root()),
280
- "source": ("env:" + ENV_DATA_ROOT if os.environ.get(ENV_DATA_ROOT)
281
- else ("env:" + ENV_MDCG_ROOT if os.environ.get(ENV_MDCG_ROOT)
282
- else (("paths.json(用户级)" if pf_src == "user"
283
- else "paths.json(兼容读旧包内位置)")
284
- if _user_paths()
285
- else "default(用户级状态根 data/)"))),
286
- "paths_file": paths_file(),
287
- "paths_file_source": pf_src,
288
- "legacy_data_root": legacy_data_root(),
289
- "legacy_data_exists": os.path.isdir(legacy_data_root()),
290
- "data_root_exists": os.path.isdir(dr),
291
- "mdcg_root_exists": os.path.isdir(mr),
292
- }
293
-
294
-
295
- # 生效条件:path 为传入字符串(写入前反斜杠替换为 "/"),key 默认 "data_root"(传入时写入该键名);先确保 <state_root()> 存在,读取 _user_paths()(可能来自旧包内位置的兼容读,异常时为 {},故旧配置在首次改写时被带到新位置并从此由新件说了算)并补 "_comment",再以该内容覆写 <state_root()>/paths.json 并返回该路径。
296
- def set_user_root(path: str, key: str = "data_root") -> str:
297
- """把用户选择的路径写入**用户级** paths.json(不存在则创建)。返回文件路径。
298
-
299
- 永远写新位置(不写旧包内那件)——旧位置会随包更新被删除,写进去等于
300
- 用户设置迟早丢失;旧件的既有取值经 _user_paths() 带入新件,不丢配置。
301
- """
302
- pf = os.path.join(state_root(), "paths.json")
303
- os.makedirs(os.path.dirname(pf), exist_ok=True)
304
- d = _user_paths()
305
- d.setdefault("_comment",
306
- "灵枢记忆写入路径(用户可改)。删掉本文件即回落到用户级默认数据根"
307
- "(~/.dsh/.dsh-memory/data)。")
308
- d[key] = path.replace("\\", "/")
309
- with open(pf, "w", encoding="utf-8") as f:
310
- json.dump(d, f, ensure_ascii=False, indent=2)
311
- return pf
312
-
313
-
314
- if __name__ == "__main__":
315
- import argparse
316
- import sys
317
-
318
- sys.stdout.reconfigure(encoding="utf-8", errors="replace")
319
- ap = argparse.ArgumentParser(description="灵枢数据根解析与设置")
320
- ap.add_argument("--set-root", metavar="PATH",
321
- help="把数据根写入 <用户级状态根>/paths.json(用户可改)")
322
- ap.add_argument("--set-mdcg-root", metavar="PATH",
323
- help="把认知图根写入 <用户级状态根>/paths.json")
324
- ap.add_argument("--migrate-legacy", action="store_true",
325
- help="把旧版包内 data/ 的数据面复制到用户级默认数据根"
326
- "(只复制不删除;默认数据根被显式配置时不动作)")
327
- a = ap.parse_args()
328
- if a.set_root:
329
- print("written:", set_user_root(a.set_root, "data_root"))
330
- if a.set_mdcg_root:
331
- print("written:", set_user_root(a.set_mdcg_root, "root"))
332
- if a.migrate_legacy:
333
- print("migrate:", json.dumps(migrate_legacy_data(),
334
- ensure_ascii=False))
1
+ # -*- coding: utf-8 -*-
2
+ """datapath.py · 灵枢数据根解析(记忆写入路径可配置)
3
+
4
+ 与 node 侧 `src/lib/datapath.ts` **同口径**——两侧读同一份
5
+ `<用户级状态根>/paths.json`(旧 `<插件仓>/data/paths.json` 兼容读)。
6
+
7
+ 解析优先级(高 → 低):
8
+ 1. 环境变量 `MDCG_DATA_ROOT`(数据根)/ `MDCG_ROOT`(认知图根)
9
+ 2. 用户可编辑的路径文件 `paths.json` 的 "data_root" / "root"
10
+ (位置:`<用户级状态根>/paths.json`;旧 `<插件仓>/data/paths.json` 兼容读)
11
+ 3. 默认:`<用户级状态根>/data`(**插件包目录之外**,与进程 cwd 解耦)
12
+
13
+ 为什么默认**不**锚定「插件仓自身 data/」(issue #18 相邻问题,数据丢失级):
14
+ DSH 插件按 hoisted 布局装在 `<profile>/node_modules/<pkg>`,`pnpm` 更新该包会
15
+ **整个替换包目录**——运行时数据落在包内时,每次更新成功即连目录一起删掉
16
+ (实机实证:`data/` 54 文件 → 0,46 条记忆节点靠人工备份回填);`paths.json`
17
+ 同址,用户配置一并丢失。故默认数据根与配置文件一律落**用户级状态根**
18
+ (见 state_root()),与包目录彻底解耦。
19
+
20
+ 为什么默认不锚定 `data/mdcg` 相对路径:
21
+ 相对路径随进程 cwd 漂移——node 侧插件与 python 侧脚本 cwd 不同
22
+ (历史事故:DSH 进程 cwd 在私有库目录时,记忆真源落到 `[私有库]/data/mdcg`,
23
+ 与插件仓内的 `data/` 分裂成两处)。
24
+
25
+ 设计边界:
26
+ - 本模块只决定「**新写入去哪**」。唯一的搬运是 `migrate_legacy_data()`:
27
+ 默认数据根生效且旧包内位置仍有内容时,一次性**复制**(不删除、不覆盖)
28
+ 到用户级位置——见该函数注释。
29
+ - 纯标准库、无包内相对导入——可被 `sys.path` 以顶层模块方式加载,
30
+ 绕开 `md_cg/__init__.py` 的重依赖。
31
+
32
+ 用法:
33
+ from datapath import data_root, mdcg_root, state_dir # scripts/ 内
34
+ python md_cg/datapath.py # 打印当前解析结果
35
+ python md_cg/datapath.py --set-root D:/x/data # 写入 paths.json(用户可改)
36
+ python md_cg/datapath.py --migrate-legacy # 把旧包内数据复制到用户级根
37
+ """
38
+ from __future__ import annotations
39
+
40
+ import json
41
+ import os
42
+ import shutil
43
+
44
+ ENV_DATA_ROOT = "MDCG_DATA_ROOT"
45
+ ENV_MDCG_ROOT = "MDCG_ROOT"
46
+ ENV_STATE_ROOT = "MDCG_STATE_ROOT"
47
+
48
+
49
+ # 生效条件:无入参,恒返回本文件 __file__ 绝对路径上溯两级得到的插件仓根目录。
50
+ def plugin_root() -> str:
51
+ """插件仓根目录(本文件位于 <root>/md_cg/datapath.py)。"""
52
+ return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
53
+
54
+
55
+ # 生效条件:无入参;ENV_STATE_ROOT 环境变量为非空真值时返回其 abspath,为空串/未设时若 DSH_HOME 为非空真值则返回其 abspath 下 ".dsh-memory",两者皆无则返回 ~/.dsh/.dsh-memory 的 abspath。
56
+ def state_root() -> str:
57
+ """用户级状态根(**插件包目录之外**):路径配置与默认数据根的落点。
58
+
59
+ `DSH_HOME` **未必**由宿主注入(本仓 `dsh/dsh-web-start.bat` 自行 set),
60
+ 故家目录兜底;`~/.dsh` 是本插件既有约定(node 侧调试日志同址)。
61
+ """
62
+ env = os.environ.get(ENV_STATE_ROOT)
63
+ if env:
64
+ return os.path.abspath(env)
65
+ dsh_home = os.environ.get("DSH_HOME")
66
+ if dsh_home:
67
+ return os.path.join(os.path.abspath(dsh_home), ".dsh-memory")
68
+ return os.path.join(os.path.expanduser("~"), ".dsh", ".dsh-memory")
69
+
70
+
71
+ # 生效条件:无入参,恒返回 plugin_root() 下 "data" 的拼接路径(旧版落点,更新时被整目录替换,只作兼容读与迁移源)。
72
+ def legacy_data_root() -> str:
73
+ """旧版落点(插件包内 `data/`)——更新时会被整个替换。"""
74
+ return os.path.join(plugin_root(), "data")
75
+
76
+
77
+ # 生效条件:无入参,恒返回 legacy_data_root() 下 "paths.json" 的拼接路径。
78
+ def legacy_paths_file() -> str:
79
+ """旧版路径配置文件位置(包内,兼容读)。"""
80
+ return os.path.join(legacy_data_root(), "paths.json")
81
+
82
+
83
+ # 生效条件:两个路径参数经 normpath+normcase 规范化后相等时返回 True,否则 False(Windows 大小写不敏感)。
84
+ def _same_path(a: str, b: str) -> bool:
85
+ return (os.path.normcase(os.path.normpath(a)) ==
86
+ os.path.normcase(os.path.normpath(b)))
87
+
88
+
89
+ # 生效条件:无入参;<state_root()>/paths.json 存在(isfile)时返回之,不存在而 legacy_paths_file() 存在时返回旧件,两者皆不存在时返回新位置路径(首次写入时创建),不受 data_root() 取值影响。
90
+ def paths_file() -> str:
91
+ """用户可编辑的路径配置文件——用户级优先,旧包内位置兼容读。
92
+
93
+ 新位置:`<用户级状态根>/paths.json`(随包更新不丢)。
94
+ 旧位置:`<插件仓>/data/paths.json`(旧版约定,仅当新位置不存在时读它,
95
+ 已存在新件则新件说了算——不做自动复制,避免旧件后续编辑静默失效)。
96
+ """
97
+ current = os.path.join(state_root(), "paths.json")
98
+ if os.path.isfile(current):
99
+ return current
100
+ legacy = legacy_paths_file()
101
+ return legacy if os.path.isfile(legacy) else current
102
+
103
+
104
+ # 生效条件:无入参;paths_file() 的所在目录与 state_root() 同路径时返回 "user",否则返回 "legacy"(兼容读旧包内位置)。
105
+ def paths_file_source() -> str:
106
+ """生效中的 paths.json 位置来源:`user` / `legacy`。"""
107
+ return "user" if _same_path(os.path.dirname(paths_file()),
108
+ state_root()) else "legacy"
109
+
110
+
111
+ # 生效条件:无入参;paths_file() 的 JSON 顶层为 dict 时返回该 dict,JSON 解析或读取抛任何异常、或顶层非 dict 时返回 {}。
112
+ def _user_paths() -> dict:
113
+ try:
114
+ with open(paths_file(), encoding="utf-8") as f:
115
+ d = json.load(f)
116
+ return d if isinstance(d, dict) else {}
117
+ except Exception:
118
+ return {}
119
+
120
+
121
+ # 生效条件:无入参,恒返回 state_root() 下 "data" 的拼接路径(插件包目录之外,更新不触碰)。
122
+ def default_data_root() -> str:
123
+ """默认数据根 = 用户级状态根下 data/。"""
124
+ return os.path.join(state_root(), "data")
125
+
126
+
127
+ # 生效条件:p 为目录且其下无任何条目时返回 True,p 不存在/是文件/OSError 时返回 False。
128
+ def _is_empty_dir(p: str) -> bool:
129
+ try:
130
+ return os.path.isdir(p) and not os.listdir(p)
131
+ except OSError:
132
+ return False
133
+
134
+
135
+ # 生效条件:无入参;data_root() 与 default_data_root() 不同路径时返回 {ran:False, reason:"数据根为显式配置(env/paths.json),不迁移", from, to, copied:0, failed:[]};相同则继续——legacy_data_root() 非目录时返回 reason="旧位置不存在(多为更新时已随包目录被替换)",其下无条目(除 paths.json 外)时返回 reason="旧位置无数据",否则把其余顶层条目逐个复制到 default_data_root() 下(目标条目已存在且非空目录则跳过;只复制不删除、不覆盖;单个条目异常记入 failed 不抛),返回 ran=(copied>0)、copied、failed 与失败时的 reason("目标不可写" 或 "新位置已有数据,未覆盖")。
136
+ def migrate_legacy_data() -> dict:
137
+ """一次性迁移:把旧版包内 `data/` 的数据面复制到用户级默认数据根。
138
+
139
+ 触发条件(三条同时满足,缺一不动):
140
+ ① 数据根未被显式配置(env `MDCG_DATA_ROOT` / paths.json 的 "data_root"
141
+ 都未设,即 data_root() 恰为默认值)——显式配置是用户的决定;
142
+ ② 旧位置存在;③ 目标顶层条目不存在或为空目录(不覆盖、不合并)。
143
+
144
+ `paths.json` 不复制(配置走 paths_file() 兼容读,复制会制造两说)。
145
+ 任何异常逐项吞掉并记入 `failed`——迁移是增益,不该成为启动失败源。
146
+
147
+ 边界(如实):pnpm 更新是**先替换包目录再启动新代码**,旧数据在升级瞬间即
148
+ 已消失,本函数只能接手「旧位置那时仍在」的情形;已在升级中丢掉的数据无法
149
+ 由此恢复——发布说明须提示 0.4.8 及更早用户升级前备份包内 `data/`。
150
+ """
151
+ frm = legacy_data_root()
152
+ to = default_data_root()
153
+ out = {"ran": False, "reason": "", "from": frm, "to": to,
154
+ "copied": 0, "failed": []}
155
+ if not _same_path(data_root(), to):
156
+ out["reason"] = "数据根为显式配置(env/paths.json),不迁移"
157
+ return out
158
+ if not os.path.isdir(frm):
159
+ out["reason"] = "旧位置不存在(多为更新时已随包目录被替换)"
160
+ return out
161
+ try:
162
+ names = [n for n in os.listdir(frm) if n != "paths.json"]
163
+ except OSError:
164
+ out["reason"] = "旧位置不可读"
165
+ return out
166
+ if not names:
167
+ out["reason"] = "旧位置无数据"
168
+ return out
169
+ for name in names:
170
+ src = os.path.join(frm, name)
171
+ dst = os.path.join(to, name)
172
+ # 新位置已有实质内容 → 跳过(宁可少搬,不可覆盖)
173
+ if os.path.exists(dst) and not _is_empty_dir(dst):
174
+ continue
175
+ try:
176
+ os.makedirs(to, exist_ok=True)
177
+ if os.path.isdir(src):
178
+ shutil.copytree(src, dst, dirs_exist_ok=True)
179
+ else:
180
+ shutil.copy2(src, dst)
181
+ out["copied"] += 1
182
+ except Exception: # noqa: BLE001 —— 迁移不得成为启动失败源
183
+ out["failed"].append(name)
184
+ out["ran"] = out["copied"] > 0
185
+ if not out["ran"]:
186
+ out["reason"] = ("目标不可写" if out["failed"]
187
+ else "新位置已有数据,未覆盖")
188
+ return out
189
+
190
+
191
+ # 生效条件:无入参;ENV_DATA_ROOT 环境变量为非空真值时返回其 abspath,为空串/未设时若 paths.json 的 "data_root" 为真值则按其是否为绝对路径决定直接 abspath 还是拼 plugin_root() 后 abspath,该键缺失或为假值时回落 default_data_root()。
192
+ def data_root() -> str:
193
+ """数据根(记忆/账本/运行态的父目录)。"""
194
+ env = os.environ.get(ENV_DATA_ROOT)
195
+ if env:
196
+ return os.path.abspath(env)
197
+ cfg = _user_paths().get("data_root")
198
+ if cfg:
199
+ return os.path.abspath(cfg) if os.path.isabs(cfg) else \
200
+ os.path.abspath(os.path.join(plugin_root(), cfg))
201
+ return default_data_root()
202
+
203
+
204
+ # 生效条件:无入参;ENV_MDCG_ROOT 环境变量为非空真值时返回其 abspath,为空串/未设时若 paths.json 的 "root" 为真值则按其是否为绝对路径决定直接 abspath 还是拼 plugin_root() 后 abspath,该键缺失或为假值时返回 data_root() 下 "mdcg" 的拼接路径。
205
+ def mdcg_root() -> str:
206
+ """认知图(记忆唯一真源)根目录。"""
207
+ env = os.environ.get(ENV_MDCG_ROOT)
208
+ if env:
209
+ return os.path.abspath(env)
210
+ cfg = _user_paths().get("root")
211
+ if cfg:
212
+ return os.path.abspath(cfg) if os.path.isabs(cfg) else \
213
+ os.path.abspath(os.path.join(plugin_root(), cfg))
214
+ return os.path.join(data_root(), "mdcg")
215
+
216
+
217
+ # 生效条件:parts 非空时路径为 data_root() 与各 part 的 join,parts 为空时路径即 data_root();create 为真值(默认 True)时对该路径 makedirs(exist_ok=True),create 为假值时只返回路径不建目录。
218
+ def state_dir(*parts: str, create: bool = True) -> str:
219
+ """运行态子目录(日志/队列/草稿…),默认挂在数据根下。"""
220
+ p = os.path.join(data_root(), *parts) if parts else data_root()
221
+ if create:
222
+ os.makedirs(p, exist_ok=True)
223
+ return p
224
+
225
+
226
+ # 生效条件:name 依次拼成 data_root()/name、plugin_root()/name、dirname(plugin_root())/[私有归档根]/_archive/ctp-aeis-data/name 三个候选,仅保留其中 os.path.isfile 为真的项并按此顺序返回列表。
227
+ def archive_root() -> str | None:
228
+ """私有侧归档根(公开仓不含私有库名):本机配置提供,未配置则没有该候选。
229
+
230
+ 取值顺序:环境变量 MDCG_ARCHIVE_ROOT -> 插件仓同级的 .mdcg_archive_root 文件内容。
231
+ """
232
+ value = os.environ.get("MDCG_ARCHIVE_ROOT", "").strip()
233
+ if value:
234
+ return value
235
+ marker = os.path.join(os.path.dirname(plugin_root()), ".mdcg_archive_root")
236
+ if os.path.isfile(marker):
237
+ try:
238
+ with open(marker, "r", encoding="utf-8") as fh:
239
+ text = fh.read().strip()
240
+ except OSError:
241
+ return None
242
+ return text or None
243
+ return None
244
+
245
+
246
+ # 生效条件:给定 name 时按 data_root()/name、plugin_root()/name 顺序拼接候选,仅当 archive_root() 不为 None 才追加其下 _archive/ctp-aeis-data/name,最终只返回其中 os.path.isfile 为真的路径(其余被过滤掉),故全都不满足时返回空列表。
247
+ def legacy_candidates(name: str) -> list:
248
+ """历史位置候选(只读兼容:三仓分离前的校验缓存等)。
249
+
250
+ 仅用于「读旧件」,顺序:数据根 → 插件仓根 → 归档区。
251
+ """
252
+ out = [os.path.join(data_root(), name),
253
+ os.path.join(plugin_root(), name)]
254
+ archive = archive_root()
255
+ if archive is not None:
256
+ out.append(os.path.join(archive, "_archive", "ctp-aeis-data", name))
257
+ return [p for p in out if os.path.isfile(p)]
258
+
259
+
260
+ # 生效条件:name 对应的 legacy_candidates(name) 列表非空时返回其首个元素,为空列表时返回 None。
261
+ def find_existing(name: str) -> str | None:
262
+ """在数据根/插件仓/归档区中找已存在的同名文件,找不到返回 None。"""
263
+ hits = legacy_candidates(name)
264
+ return hits[0] if hits else None
265
+
266
+
267
+ # 生效条件:无入参;恒返回含 plugin_root/state_root/data_root/mdcg_root/default_data_root/is_default/source/paths_file/paths_file_source/legacy_data_root/legacy_data_exists/data_root_exists/mdcg_root_exists 的字典,其中 source 按 ENV_DATA_ROOT 非空取 "env:MDCG_DATA_ROOT" → 否则 ENV_MDCG_ROOT 非空取 "env:MDCG_MDCG_ROOT" → 否则 _user_paths() 为非空 dict 取 "paths.json(用户级)" 或 "paths.json(兼容读旧包内位置)"(按 paths_file_source())→ 否则取 "default(用户级状态根 data/)"。
268
+ def describe() -> dict:
269
+ """当前解析结果的完整快照(供心跳/日志留痕)。"""
270
+ dr = data_root()
271
+ mr = mdcg_root()
272
+ pf_src = paths_file_source()
273
+ return {
274
+ "plugin_root": plugin_root(),
275
+ "state_root": state_root(),
276
+ "data_root": dr,
277
+ "mdcg_root": mr,
278
+ "default_data_root": default_data_root(),
279
+ "is_default": _same_path(dr, default_data_root()),
280
+ "source": ("env:" + ENV_DATA_ROOT if os.environ.get(ENV_DATA_ROOT)
281
+ else ("env:" + ENV_MDCG_ROOT if os.environ.get(ENV_MDCG_ROOT)
282
+ else (("paths.json(用户级)" if pf_src == "user"
283
+ else "paths.json(兼容读旧包内位置)")
284
+ if _user_paths()
285
+ else "default(用户级状态根 data/)"))),
286
+ "paths_file": paths_file(),
287
+ "paths_file_source": pf_src,
288
+ "legacy_data_root": legacy_data_root(),
289
+ "legacy_data_exists": os.path.isdir(legacy_data_root()),
290
+ "data_root_exists": os.path.isdir(dr),
291
+ "mdcg_root_exists": os.path.isdir(mr),
292
+ }
293
+
294
+
295
+ # 生效条件:path 为传入字符串(写入前反斜杠替换为 "/"),key 默认 "data_root"(传入时写入该键名);先确保 <state_root()> 存在,读取 _user_paths()(可能来自旧包内位置的兼容读,异常时为 {},故旧配置在首次改写时被带到新位置并从此由新件说了算)并补 "_comment",再以该内容覆写 <state_root()>/paths.json 并返回该路径。
296
+ def set_user_root(path: str, key: str = "data_root") -> str:
297
+ """把用户选择的路径写入**用户级** paths.json(不存在则创建)。返回文件路径。
298
+
299
+ 永远写新位置(不写旧包内那件)——旧位置会随包更新被删除,写进去等于
300
+ 用户设置迟早丢失;旧件的既有取值经 _user_paths() 带入新件,不丢配置。
301
+ """
302
+ pf = os.path.join(state_root(), "paths.json")
303
+ os.makedirs(os.path.dirname(pf), exist_ok=True)
304
+ d = _user_paths()
305
+ d.setdefault("_comment",
306
+ "灵枢记忆写入路径(用户可改)。删掉本文件即回落到用户级默认数据根"
307
+ "(~/.dsh/.dsh-memory/data)。")
308
+ d[key] = path.replace("\\", "/")
309
+ with open(pf, "w", encoding="utf-8") as f:
310
+ json.dump(d, f, ensure_ascii=False, indent=2)
311
+ return pf
312
+
313
+
314
+ if __name__ == "__main__":
315
+ import argparse
316
+ import sys
317
+
318
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
319
+ ap = argparse.ArgumentParser(description="灵枢数据根解析与设置")
320
+ ap.add_argument("--set-root", metavar="PATH",
321
+ help="把数据根写入 <用户级状态根>/paths.json(用户可改)")
322
+ ap.add_argument("--set-mdcg-root", metavar="PATH",
323
+ help="把认知图根写入 <用户级状态根>/paths.json")
324
+ ap.add_argument("--migrate-legacy", action="store_true",
325
+ help="把旧版包内 data/ 的数据面复制到用户级默认数据根"
326
+ "(只复制不删除;默认数据根被显式配置时不动作)")
327
+ a = ap.parse_args()
328
+ if a.set_root:
329
+ print("written:", set_user_root(a.set_root, "data_root"))
330
+ if a.set_mdcg_root:
331
+ print("written:", set_user_root(a.set_mdcg_root, "root"))
332
+ if a.migrate_legacy:
333
+ print("migrate:", json.dumps(migrate_legacy_data(),
334
+ ensure_ascii=False))
335
335
  print(json.dumps(describe(), ensure_ascii=False, indent=2))