@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/src/bridge.ts CHANGED
@@ -1,401 +1,401 @@
1
- /**
2
- * 灵枢 MCP stdio 桥:管理大脑(md_cg)Python 子进程的生命周期,
3
- * 通过逐行 JSON-RPC 完成握手、工具发现与调用。
4
- *
5
- * 与官方 @deepseek-ai/dsh-mcp-client 不同,本桥零运行时依赖(不引入
6
- * @modelcontextprotocol/sdk),直接实现灵枢 server 使用的 2024-11-05 协议
7
- * 子集——与灵枢库 D-005「核心零外部依赖」的工程哲学一致。
8
- */
9
-
10
- import { spawn, type ChildProcess } from 'node:child_process'
11
- import { createInterface } from 'node:readline'
12
- import { mkdirSync, appendFileSync } from 'node:fs'
13
- import { dirname, join } from 'node:path'
14
- import { homedir } from 'node:os'
15
- // issue #19:自检命令文案按平台给出(Windows python / 其它 python3)、
16
- // 并在 ENOENT 时把「解释器名不匹配」这一第一因直接写进日志。
17
- import { explainMissingPython, selfCheckCommand } from './lib/python_path.js'
18
-
19
- /**
20
- * 调试探针:记录桥生命周期到独立文件(绕过 DSH 日志系统,便于定位启动问题)。
21
- * 路径从用户家目录动态解析(issue #5)——此前硬编码作者本机绝对路径,
22
- * 其他用户机器上目录不存在且无权限,探针静默失效,恰在排查启动问题时失明。
23
- */
24
- const DEBUG_LOG = join(homedir(), '.dsh', 'logs', 'lingshu-bridge-debug.log')
25
- let debugLogDirReady = false
26
- function probe(msg: string): void {
27
- try {
28
- if (!debugLogDirReady) {
29
- mkdirSync(dirname(DEBUG_LOG), { recursive: true })
30
- debugLogDirReady = true
31
- }
32
- appendFileSync(DEBUG_LOG, `[${new Date().toISOString()}] ${msg}\n`)
33
- } catch { /* 探针失败忽略 */ }
34
- }
35
-
36
- /** 灵枢 MCP server 暴露的原始工具(tools/list 结果项)。 */
37
- export interface McpTool {
38
- name: string
39
- description: string
40
- inputSchema?: Record<string, unknown>
41
- }
42
-
43
- /** 一次 tools/call 的标准化结果。 */
44
- export interface McpCallResult {
45
- content: Array<{ type: string; text?: string; [key: string]: unknown }>
46
- isError: boolean
47
- }
48
-
49
- /** 启动灵枢子进程的配置。 */
50
- export interface BridgeOptions {
51
- /** Python 可执行文件(或 md_cg-mcp console script),默认 python。 */
52
- python: string
53
- /** 传给 python 的参数,默认 ['-m', 'md_cg.mcp_server']。 */
54
- args: string[]
55
- /** 追加到子进程的环境变量(MDCG_* / MDCG_MCP_SURFACE / 密钥等)。 */
56
- env: Record<string, string>
57
- /** 子进程工作目录。 */
58
- cwd?: string
59
- /** 单次工具调用超时(毫秒),默认 60s。 */
60
- timeoutMs: number
61
- /** 断线重连的最大间隔(毫秒),默认 30s。 */
62
- maxRetryDelayMs: number
63
- }
64
-
65
- interface PendingCall {
66
- resolve: (value: unknown) => void
67
- reject: (reason: Error) => void
68
- timer: NodeJS.Timeout
69
- }
70
-
71
- /**
72
- * 连续启动失败的最大重试次数(issue #6):指数退避到 maxRetryDelayMs 后
73
- * 若无上限,python 环境损坏时会以 30s 间隔永久空转(假激活 + 资源浪费)。
74
- * 达到上限即进入 failed 终态并停止调度;后续所有请求快速失败并给出
75
- * 明确的修复指引。握手成功后计数归零——运行期偶发崩溃重启不受影响。
76
- */
77
- const MAX_RETRIES = 8
78
-
79
- export class LingshuBridge {
80
- private readonly options: BridgeOptions
81
- private proc: ChildProcess | null = null
82
- private rl: ReturnType<typeof createInterface> | null = null
83
- private nextId = 1
84
- private pending = new Map<number, PendingCall>()
85
- private started = false
86
- private disposed = false
87
- private retryDelayMs = 1000
88
- private retries = 0
89
- private retryTimer: NodeJS.Timeout | null = null
90
- private bootQueue: Array<(ok: boolean) => void> = []
91
- private readyState: 'pending' | 'ok' | 'failed' = 'pending'
92
- /** issue #7:当前子进程启动时间(计算 uptime,区分秒退与长存后外部关闭) */
93
- private procStartedAt = 0
94
- /** issue #7:运行期反复退出的滑动窗口(时间戳列表)——防无限重启刷屏 */
95
- private unexpectedExits: number[] = []
96
-
97
- constructor(options: BridgeOptions) {
98
- this.options = options
99
- }
100
-
101
- /**
102
- * 启动灵枢进程并完成握手(initialize → notifications/initialized)。
103
- * 进程崩溃后自动指数退避重启,并重新握手。
104
- */
105
- start(): void {
106
- if (this.started || this.disposed) return
107
- this.started = true
108
- this.spawnAndHandshake()
109
- }
110
-
111
- /** 拉取灵枢的全部工具清单(每次实时请求,不缓存)。 */
112
- async listTools(): Promise<McpTool[]> {
113
- const result = await this.request('tools/list', {})
114
- const tools = result as { tools?: McpTool[] }
115
- return tools.tools ?? []
116
- }
117
-
118
- /** 调用灵枢的一个工具,返回标准化 MCP 结果。 */
119
- async callTool(name: string, args: Record<string, unknown>,
120
- signal?: AbortSignal): Promise<McpCallResult> {
121
- const result = await this.request('tools/call', { name, arguments: args }, signal)
122
- return result as McpCallResult
123
- }
124
-
125
- /** 关闭进程并释放资源(写 stdin EOF 优雅退出,超时兜底 kill)。 */
126
- dispose(): void {
127
- this.disposed = true
128
- if (this.retryTimer) clearTimeout(this.retryTimer)
129
- const proc = this.proc
130
- if (!proc || proc.exitCode !== null) return
131
- try {
132
- proc.stdin?.end()
133
- } catch {
134
- /* 已关闭则忽略 */
135
- }
136
- const killer = setTimeout(() => proc.kill(), 2000)
137
- killer.unref()
138
- }
139
-
140
- /** 进程是否存活。 */
141
- get alive(): boolean {
142
- return this.proc !== null && this.proc.exitCode === null
143
- }
144
-
145
- /** 桥是否已握手就绪(工具注册用;防止轮询访问 private readyState)。 */
146
- isReady(): boolean {
147
- return this.readyState === 'ok'
148
- }
149
-
150
- /** 是否已达放弃终态(连续启动失败超上限,不再自动重启)。 */
151
- get gaveUp(): boolean {
152
- return this.retries >= MAX_RETRIES
153
- }
154
-
155
- /** 等待握手完成(用于 apply 阶段同步就绪)。 */
156
- waitReady(): Promise<boolean> {
157
- if (this.readyState === 'ok') return Promise.resolve(true)
158
- if (this.readyState === 'failed') return Promise.resolve(false)
159
- return new Promise((resolve) => this.bootQueue.push(resolve))
160
- }
161
-
162
- private spawnAndHandshake(): void {
163
- if (this.disposed) return
164
- this.procStartedAt = Date.now()
165
- const { python, args, env, cwd } = this.options
166
- const childEnv = { ...process.env, ...env }
167
- // 确保 DB 目录存在(灵枢 server 也会防御性创建,这里提前为可读错误)
168
- const dbPath = env['AEIS_DB']
169
- if (dbPath && dbPath !== ':memory:') {
170
- try {
171
- mkdirSync(dirname(dbPath), { recursive: true })
172
- } catch {
173
- /* 目录创建失败由灵枢侧兜底 */
174
- }
175
- }
176
- const proc = spawn(python, args, {
177
- env: childEnv,
178
- cwd,
179
- stdio: ['pipe', 'pipe', 'pipe'],
180
- windowsHide: true,
181
- })
182
- this.proc = proc
183
- this.rl = createInterface({ input: proc.stdout!, crlfDelay: Infinity })
184
-
185
- proc.stderr?.on('data', (chunk: Buffer) => {
186
- // stderr 透传日志(灵枢把日志写在 stderr,避免污染协议流)
187
- const text = chunk.toString('utf8').trim()
188
- if (text) console.error(`[lingshu-bridge] ${text}`)
189
- })
190
-
191
- this.rl.on('line', (line: string) => {
192
- if (!line.trim()) return
193
- let msg: Record<string, unknown>
194
- try {
195
- msg = JSON.parse(line)
196
- } catch {
197
- console.error(`[lingshu-bridge] 非 JSON 输出: ${line.slice(0, 200)}`)
198
- return
199
- }
200
- if (typeof msg['id'] === 'number') {
201
- this.settle(msg['id'] as number, msg)
202
- }
203
- })
204
-
205
- proc.on('error', (err) => {
206
- // 进程无法启动(python 不存在等)——响亮失败
207
- if (!this.disposed) {
208
- console.error(`[lingshu-bridge] 灵枢进程启动失败: ${err.message}`)
209
- // issue #19:ENOENT 的第一因通常不是「环境损坏」,而是解释器名与平台不匹配
210
- // (Linux/macOS 按 PEP 394 只有 python3)。把成因与修法写进同一条日志——
211
- // 原始日志把该缺陷伪装成「调用超时」,用户按超时方向排查只会白耗一轮。
212
- if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
213
- console.error(`[lingshu-bridge] ${explainMissingPython(python)}`)
214
- }
215
- probe(`spawn error: ${String(err)}`)
216
- this.readyState = 'failed'
217
- this.flushBootQueue(false)
218
- this.scheduleRetry()
219
- }
220
- })
221
-
222
- proc.on('exit', (code, signal) => {
223
- // 探针:写独立文件记录退出(绕过 DSH 日志系统,便于定位)
224
- const uptimeS = this.procStartedAt
225
- ? Math.round((Date.now() - this.procStartedAt) / 1000)
226
- : -1
227
- probe(`exit code=${code} signal=${signal} disposed=${this.disposed} ready=${this.readyState} started=${this.started} uptime=${uptimeS}s`)
228
- console.error(`[lingshu-bridge] 灵枢进程退出 code=${code} signal=${signal}(存活 ${uptimeS}s)`)
229
- this.rl?.close()
230
- this.rl = null
231
- this.rejectAll(new Error(`灵枢进程已退出(code=${code} signal=${signal ?? 'none'})`))
232
- if (!this.disposed) {
233
- // issue #7:长存后 code=0 退出 = stdin 被外部关闭(非崩溃)。
234
- // 记录滑动窗口(10 分钟内 ≥3 次)→ 进入冷却,防「外部反复关闭 +
235
- // 无限重启」刷屏;冷却结束自动恢复,不进入放弃终态。
236
- this.unexpectedExits = this.unexpectedExits.filter(
237
- (t) => Date.now() - t < 600_000,
238
- )
239
- this.unexpectedExits.push(Date.now())
240
- if (uptimeS >= 0 && uptimeS < 5) {
241
- console.error(
242
- `[lingshu-bridge] 进程启动后 5 秒内即退出——请检查 ${python} 可执行文件与 md_cg 依赖。` +
243
- `自检 \`${selfCheckCommand(python)}\` 须在插件包根目录运行` +
244
- '(插件已自动锚定 cwd 与 PYTHONPATH,issue #12)。')
245
- } else if (this.unexpectedExits.length >= 3) {
246
- console.error(
247
- `[lingshu-bridge] 10 分钟内已意外退出 ${this.unexpectedExits.length} 次,` +
248
- '冷却 5 分钟后自动恢复。若持续出现,请检查是否有多个插件/脚本'
249
- + '同时管理灵枢进程(重复 spawn 会互相关闭对方子进程的 stdin)。')
250
- probe(`cooldown: ${this.unexpectedExits.length} unexpected exits in 10min`)
251
- this.retryTimer = setTimeout(() => {
252
- this.retryTimer = null
253
- this.unexpectedExits = []
254
- if (!this.disposed) this.spawnAndHandshake()
255
- }, 300_000)
256
- this.retryTimer.unref()
257
- return
258
- }
259
- // 有挂起请求的失败是异常的;仅启动失败的等待者得到 false
260
- this.readyState = 'failed'
261
- this.flushBootQueue(false)
262
- this.scheduleRetry()
263
- }
264
- })
265
-
266
- void this.handshake()
267
- }
268
-
269
- private async handshake(): Promise<void> {
270
- try {
271
- await this.request('initialize', {
272
- protocolVersion: '2024-11-05',
273
- capabilities: {},
274
- clientInfo: { name: 'dsh-memory', version: '0.1.0' },
275
- })
276
- // 初始化通知:无 id、无响应
277
- this.writeRaw({ jsonrpc: '2.0', method: 'notifications/initialized' })
278
- // 握手成功:重置退避与失败计数(issue #6)——运行期偶发崩溃重启
279
- // 不累积启动失败;只有「从未握手成功的连续失败」才走向放弃终态
280
- this.retryDelayMs = 1000
281
- this.retries = 0
282
- this.readyState = 'ok'
283
- this.flushBootQueue(true)
284
- } catch (err) {
285
- if (!this.disposed) {
286
- console.error(`[lingshu-bridge] 握手失败: ${(err as Error).message}`)
287
- probe(`handshake failed: ${String(err)}`)
288
- this.readyState = 'failed'
289
- this.flushBootQueue(false)
290
- this.scheduleRetry()
291
- }
292
- }
293
- }
294
-
295
- private scheduleRetry(): void {
296
- if (this.disposed || this.retryTimer || this.gaveUp) return
297
- this.retries += 1
298
- if (this.gaveUp) {
299
- // issue #6:放弃机制——明确终态,停止后台空转;请求方收到清晰错误而非超时
300
- this.readyState = 'failed'
301
- this.flushBootQueue(false)
302
- console.error(
303
- `[lingshu-bridge] 连续启动失败 ${this.retries} 次,已停止自动重启(不再后台空转)。` +
304
- `请检查 ${this.options.python} 可执行文件与 md_cg 依赖;` +
305
- `自检 \`${selfCheckCommand(this.options.python)}\` 须在插件包根目录运行` +
306
- '(插件已自动锚定 cwd 与 PYTHONPATH,issue #12),修复后在 DSH 中重新启用 dsh-memory 插件。')
307
- probe(`give up: ${this.retries} consecutive failures, entering failed terminal state`)
308
- return
309
- }
310
- const delay = this.retryDelayMs
311
- this.retryDelayMs = Math.min(this.retryDelayMs * 2, this.options.maxRetryDelayMs)
312
- console.error(`[lingshu-bridge] 将进行第 ${this.retries}/${MAX_RETRIES} 次重试(${delay}ms 后)`)
313
- probe(`schedule retry ${this.retries}/${MAX_RETRIES} in ${delay}ms`)
314
- this.retryTimer = setTimeout(() => {
315
- this.retryTimer = null
316
- if (!this.disposed) this.spawnAndHandshake()
317
- }, delay)
318
- this.retryTimer.unref()
319
- }
320
-
321
- private writeRaw(msg: Record<string, unknown>): void {
322
- const proc = this.proc
323
- if (!proc || !proc.stdin?.writable) {
324
- throw new Error('灵枢进程不可写')
325
- }
326
- proc.stdin.write(JSON.stringify(msg) + '\n')
327
- }
328
-
329
- private request(method: string, params: Record<string, unknown>,
330
- signal?: AbortSignal): Promise<unknown> {
331
- // issue #6:放弃终态下快速失败——之前进程不在且不再重启,请求只能白等超时
332
- if (this.gaveUp) {
333
- return Promise.reject(new Error(
334
- '灵枢进程不可用:连续启动失败已达上限,已停止重试。' +
335
- `请检查 ${this.options.python} 可执行文件与 md_cg 依赖` +
336
- `(自检 \`${selfCheckCommand(this.options.python)}\` 须在插件包根目录运行),` +
337
- '修复后重新启用 dsh-memory 插件。'))
338
- }
339
- const id = this.nextId++
340
- const timeout = this.options.timeoutMs
341
- // P0 修复(GPT 审查):定时器直接调 settle——settle 内部会 delete + clearTimeout
342
- // 并 reject。此前先 pending.delete(id) 再 settle(),settle 找不到 entry 直接
343
- // return,Promise 永不 resolve/reject(超时逻辑完全失效,子进程挂死时插件永久挂住)。
344
- const timer = setTimeout(() => {
345
- this.settle(id, {
346
- error: { code: -32000, message: `灵枢调用超时(${timeout}ms):${method}` },
347
- })
348
- }, timeout)
349
- if (signal?.aborted) {
350
- clearTimeout(timer)
351
- return Promise.reject(new Error(`已取消:${method}`))
352
- }
353
- const onAbort = (): void => {
354
- this.settle(id, { error: { code: -32800, message: `已取消:${method}` } })
355
- }
356
- signal?.addEventListener('abort', onAbort, { once: true })
357
- const promise = new Promise<unknown>((resolve, reject) => {
358
- this.pending.set(id, { resolve, reject, timer })
359
- })
360
- // settle 后移除 abort 监听,避免内存积累
361
- promise.finally(() => {
362
- signal?.removeEventListener('abort', onAbort)
363
- }).catch(() => { /* finally 链的 catch 防未处理拒绝 */ })
364
- try {
365
- this.writeRaw({ jsonrpc: '2.0', id, method, params })
366
- } catch (err) {
367
- clearTimeout(timer)
368
- this.pending.delete(id)
369
- signal?.removeEventListener('abort', onAbort)
370
- return Promise.reject(err)
371
- }
372
- return promise
373
- }
374
-
375
- private settle(id: number, msg: Record<string, unknown>): void {
376
- const entry = this.pending.get(id)
377
- if (!entry) return
378
- this.pending.delete(id)
379
- clearTimeout(entry.timer)
380
- if (msg['error']) {
381
- const err = msg['error'] as { message?: string; code?: number }
382
- entry.reject(new Error(`灵枢错误 ${err.code ?? ''}: ${err.message ?? 'unknown'}`))
383
- } else {
384
- entry.resolve(msg['result'])
385
- }
386
- }
387
-
388
- private rejectAll(reason: Error): void {
389
- for (const [, entry] of this.pending) {
390
- clearTimeout(entry.timer)
391
- entry.reject(reason)
392
- }
393
- this.pending.clear()
394
- }
395
-
396
- private flushBootQueue(ok: boolean): void {
397
- const queue = this.bootQueue
398
- this.bootQueue = []
399
- for (const cb of queue) cb(ok)
400
- }
401
- }
1
+ /**
2
+ * 灵枢 MCP stdio 桥:管理大脑(md_cg)Python 子进程的生命周期,
3
+ * 通过逐行 JSON-RPC 完成握手、工具发现与调用。
4
+ *
5
+ * 与官方 @deepseek-ai/dsh-mcp-client 不同,本桥零运行时依赖(不引入
6
+ * @modelcontextprotocol/sdk),直接实现灵枢 server 使用的 2024-11-05 协议
7
+ * 子集——与灵枢库 D-005「核心零外部依赖」的工程哲学一致。
8
+ */
9
+
10
+ import { spawn, type ChildProcess } from 'node:child_process'
11
+ import { createInterface } from 'node:readline'
12
+ import { mkdirSync, appendFileSync } from 'node:fs'
13
+ import { dirname, join } from 'node:path'
14
+ import { homedir } from 'node:os'
15
+ // issue #19:自检命令文案按平台给出(Windows python / 其它 python3)、
16
+ // 并在 ENOENT 时把「解释器名不匹配」这一第一因直接写进日志。
17
+ import { explainMissingPython, selfCheckCommand } from './lib/python_path.js'
18
+
19
+ /**
20
+ * 调试探针:记录桥生命周期到独立文件(绕过 DSH 日志系统,便于定位启动问题)。
21
+ * 路径从用户家目录动态解析(issue #5)——此前硬编码作者本机绝对路径,
22
+ * 其他用户机器上目录不存在且无权限,探针静默失效,恰在排查启动问题时失明。
23
+ */
24
+ const DEBUG_LOG = join(homedir(), '.dsh', 'logs', 'lingshu-bridge-debug.log')
25
+ let debugLogDirReady = false
26
+ function probe(msg: string): void {
27
+ try {
28
+ if (!debugLogDirReady) {
29
+ mkdirSync(dirname(DEBUG_LOG), { recursive: true })
30
+ debugLogDirReady = true
31
+ }
32
+ appendFileSync(DEBUG_LOG, `[${new Date().toISOString()}] ${msg}\n`)
33
+ } catch { /* 探针失败忽略 */ }
34
+ }
35
+
36
+ /** 灵枢 MCP server 暴露的原始工具(tools/list 结果项)。 */
37
+ export interface McpTool {
38
+ name: string
39
+ description: string
40
+ inputSchema?: Record<string, unknown>
41
+ }
42
+
43
+ /** 一次 tools/call 的标准化结果。 */
44
+ export interface McpCallResult {
45
+ content: Array<{ type: string; text?: string; [key: string]: unknown }>
46
+ isError: boolean
47
+ }
48
+
49
+ /** 启动灵枢子进程的配置。 */
50
+ export interface BridgeOptions {
51
+ /** Python 可执行文件(或 md_cg-mcp console script),默认 python。 */
52
+ python: string
53
+ /** 传给 python 的参数,默认 ['-m', 'md_cg.mcp_server']。 */
54
+ args: string[]
55
+ /** 追加到子进程的环境变量(MDCG_* / MDCG_MCP_SURFACE / 密钥等)。 */
56
+ env: Record<string, string>
57
+ /** 子进程工作目录。 */
58
+ cwd?: string
59
+ /** 单次工具调用超时(毫秒),默认 60s。 */
60
+ timeoutMs: number
61
+ /** 断线重连的最大间隔(毫秒),默认 30s。 */
62
+ maxRetryDelayMs: number
63
+ }
64
+
65
+ interface PendingCall {
66
+ resolve: (value: unknown) => void
67
+ reject: (reason: Error) => void
68
+ timer: NodeJS.Timeout
69
+ }
70
+
71
+ /**
72
+ * 连续启动失败的最大重试次数(issue #6):指数退避到 maxRetryDelayMs 后
73
+ * 若无上限,python 环境损坏时会以 30s 间隔永久空转(假激活 + 资源浪费)。
74
+ * 达到上限即进入 failed 终态并停止调度;后续所有请求快速失败并给出
75
+ * 明确的修复指引。握手成功后计数归零——运行期偶发崩溃重启不受影响。
76
+ */
77
+ const MAX_RETRIES = 8
78
+
79
+ export class LingshuBridge {
80
+ private readonly options: BridgeOptions
81
+ private proc: ChildProcess | null = null
82
+ private rl: ReturnType<typeof createInterface> | null = null
83
+ private nextId = 1
84
+ private pending = new Map<number, PendingCall>()
85
+ private started = false
86
+ private disposed = false
87
+ private retryDelayMs = 1000
88
+ private retries = 0
89
+ private retryTimer: NodeJS.Timeout | null = null
90
+ private bootQueue: Array<(ok: boolean) => void> = []
91
+ private readyState: 'pending' | 'ok' | 'failed' = 'pending'
92
+ /** issue #7:当前子进程启动时间(计算 uptime,区分秒退与长存后外部关闭) */
93
+ private procStartedAt = 0
94
+ /** issue #7:运行期反复退出的滑动窗口(时间戳列表)——防无限重启刷屏 */
95
+ private unexpectedExits: number[] = []
96
+
97
+ constructor(options: BridgeOptions) {
98
+ this.options = options
99
+ }
100
+
101
+ /**
102
+ * 启动灵枢进程并完成握手(initialize → notifications/initialized)。
103
+ * 进程崩溃后自动指数退避重启,并重新握手。
104
+ */
105
+ start(): void {
106
+ if (this.started || this.disposed) return
107
+ this.started = true
108
+ this.spawnAndHandshake()
109
+ }
110
+
111
+ /** 拉取灵枢的全部工具清单(每次实时请求,不缓存)。 */
112
+ async listTools(): Promise<McpTool[]> {
113
+ const result = await this.request('tools/list', {})
114
+ const tools = result as { tools?: McpTool[] }
115
+ return tools.tools ?? []
116
+ }
117
+
118
+ /** 调用灵枢的一个工具,返回标准化 MCP 结果。 */
119
+ async callTool(name: string, args: Record<string, unknown>,
120
+ signal?: AbortSignal): Promise<McpCallResult> {
121
+ const result = await this.request('tools/call', { name, arguments: args }, signal)
122
+ return result as McpCallResult
123
+ }
124
+
125
+ /** 关闭进程并释放资源(写 stdin EOF 优雅退出,超时兜底 kill)。 */
126
+ dispose(): void {
127
+ this.disposed = true
128
+ if (this.retryTimer) clearTimeout(this.retryTimer)
129
+ const proc = this.proc
130
+ if (!proc || proc.exitCode !== null) return
131
+ try {
132
+ proc.stdin?.end()
133
+ } catch {
134
+ /* 已关闭则忽略 */
135
+ }
136
+ const killer = setTimeout(() => proc.kill(), 2000)
137
+ killer.unref()
138
+ }
139
+
140
+ /** 进程是否存活。 */
141
+ get alive(): boolean {
142
+ return this.proc !== null && this.proc.exitCode === null
143
+ }
144
+
145
+ /** 桥是否已握手就绪(工具注册用;防止轮询访问 private readyState)。 */
146
+ isReady(): boolean {
147
+ return this.readyState === 'ok'
148
+ }
149
+
150
+ /** 是否已达放弃终态(连续启动失败超上限,不再自动重启)。 */
151
+ get gaveUp(): boolean {
152
+ return this.retries >= MAX_RETRIES
153
+ }
154
+
155
+ /** 等待握手完成(用于 apply 阶段同步就绪)。 */
156
+ waitReady(): Promise<boolean> {
157
+ if (this.readyState === 'ok') return Promise.resolve(true)
158
+ if (this.readyState === 'failed') return Promise.resolve(false)
159
+ return new Promise((resolve) => this.bootQueue.push(resolve))
160
+ }
161
+
162
+ private spawnAndHandshake(): void {
163
+ if (this.disposed) return
164
+ this.procStartedAt = Date.now()
165
+ const { python, args, env, cwd } = this.options
166
+ const childEnv = { ...process.env, ...env }
167
+ // 确保 DB 目录存在(灵枢 server 也会防御性创建,这里提前为可读错误)
168
+ const dbPath = env['AEIS_DB']
169
+ if (dbPath && dbPath !== ':memory:') {
170
+ try {
171
+ mkdirSync(dirname(dbPath), { recursive: true })
172
+ } catch {
173
+ /* 目录创建失败由灵枢侧兜底 */
174
+ }
175
+ }
176
+ const proc = spawn(python, args, {
177
+ env: childEnv,
178
+ cwd,
179
+ stdio: ['pipe', 'pipe', 'pipe'],
180
+ windowsHide: true,
181
+ })
182
+ this.proc = proc
183
+ this.rl = createInterface({ input: proc.stdout!, crlfDelay: Infinity })
184
+
185
+ proc.stderr?.on('data', (chunk: Buffer) => {
186
+ // stderr 透传日志(灵枢把日志写在 stderr,避免污染协议流)
187
+ const text = chunk.toString('utf8').trim()
188
+ if (text) console.error(`[lingshu-bridge] ${text}`)
189
+ })
190
+
191
+ this.rl.on('line', (line: string) => {
192
+ if (!line.trim()) return
193
+ let msg: Record<string, unknown>
194
+ try {
195
+ msg = JSON.parse(line)
196
+ } catch {
197
+ console.error(`[lingshu-bridge] 非 JSON 输出: ${line.slice(0, 200)}`)
198
+ return
199
+ }
200
+ if (typeof msg['id'] === 'number') {
201
+ this.settle(msg['id'] as number, msg)
202
+ }
203
+ })
204
+
205
+ proc.on('error', (err) => {
206
+ // 进程无法启动(python 不存在等)——响亮失败
207
+ if (!this.disposed) {
208
+ console.error(`[lingshu-bridge] 灵枢进程启动失败: ${err.message}`)
209
+ // issue #19:ENOENT 的第一因通常不是「环境损坏」,而是解释器名与平台不匹配
210
+ // (Linux/macOS 按 PEP 394 只有 python3)。把成因与修法写进同一条日志——
211
+ // 原始日志把该缺陷伪装成「调用超时」,用户按超时方向排查只会白耗一轮。
212
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
213
+ console.error(`[lingshu-bridge] ${explainMissingPython(python)}`)
214
+ }
215
+ probe(`spawn error: ${String(err)}`)
216
+ this.readyState = 'failed'
217
+ this.flushBootQueue(false)
218
+ this.scheduleRetry()
219
+ }
220
+ })
221
+
222
+ proc.on('exit', (code, signal) => {
223
+ // 探针:写独立文件记录退出(绕过 DSH 日志系统,便于定位)
224
+ const uptimeS = this.procStartedAt
225
+ ? Math.round((Date.now() - this.procStartedAt) / 1000)
226
+ : -1
227
+ probe(`exit code=${code} signal=${signal} disposed=${this.disposed} ready=${this.readyState} started=${this.started} uptime=${uptimeS}s`)
228
+ console.error(`[lingshu-bridge] 灵枢进程退出 code=${code} signal=${signal}(存活 ${uptimeS}s)`)
229
+ this.rl?.close()
230
+ this.rl = null
231
+ this.rejectAll(new Error(`灵枢进程已退出(code=${code} signal=${signal ?? 'none'})`))
232
+ if (!this.disposed) {
233
+ // issue #7:长存后 code=0 退出 = stdin 被外部关闭(非崩溃)。
234
+ // 记录滑动窗口(10 分钟内 ≥3 次)→ 进入冷却,防「外部反复关闭 +
235
+ // 无限重启」刷屏;冷却结束自动恢复,不进入放弃终态。
236
+ this.unexpectedExits = this.unexpectedExits.filter(
237
+ (t) => Date.now() - t < 600_000,
238
+ )
239
+ this.unexpectedExits.push(Date.now())
240
+ if (uptimeS >= 0 && uptimeS < 5) {
241
+ console.error(
242
+ `[lingshu-bridge] 进程启动后 5 秒内即退出——请检查 ${python} 可执行文件与 md_cg 依赖。` +
243
+ `自检 \`${selfCheckCommand(python)}\` 须在插件包根目录运行` +
244
+ '(插件已自动锚定 cwd 与 PYTHONPATH,issue #12)。')
245
+ } else if (this.unexpectedExits.length >= 3) {
246
+ console.error(
247
+ `[lingshu-bridge] 10 分钟内已意外退出 ${this.unexpectedExits.length} 次,` +
248
+ '冷却 5 分钟后自动恢复。若持续出现,请检查是否有多个插件/脚本'
249
+ + '同时管理灵枢进程(重复 spawn 会互相关闭对方子进程的 stdin)。')
250
+ probe(`cooldown: ${this.unexpectedExits.length} unexpected exits in 10min`)
251
+ this.retryTimer = setTimeout(() => {
252
+ this.retryTimer = null
253
+ this.unexpectedExits = []
254
+ if (!this.disposed) this.spawnAndHandshake()
255
+ }, 300_000)
256
+ this.retryTimer.unref()
257
+ return
258
+ }
259
+ // 有挂起请求的失败是异常的;仅启动失败的等待者得到 false
260
+ this.readyState = 'failed'
261
+ this.flushBootQueue(false)
262
+ this.scheduleRetry()
263
+ }
264
+ })
265
+
266
+ void this.handshake()
267
+ }
268
+
269
+ private async handshake(): Promise<void> {
270
+ try {
271
+ await this.request('initialize', {
272
+ protocolVersion: '2024-11-05',
273
+ capabilities: {},
274
+ clientInfo: { name: 'dsh-memory', version: '0.1.0' },
275
+ })
276
+ // 初始化通知:无 id、无响应
277
+ this.writeRaw({ jsonrpc: '2.0', method: 'notifications/initialized' })
278
+ // 握手成功:重置退避与失败计数(issue #6)——运行期偶发崩溃重启
279
+ // 不累积启动失败;只有「从未握手成功的连续失败」才走向放弃终态
280
+ this.retryDelayMs = 1000
281
+ this.retries = 0
282
+ this.readyState = 'ok'
283
+ this.flushBootQueue(true)
284
+ } catch (err) {
285
+ if (!this.disposed) {
286
+ console.error(`[lingshu-bridge] 握手失败: ${(err as Error).message}`)
287
+ probe(`handshake failed: ${String(err)}`)
288
+ this.readyState = 'failed'
289
+ this.flushBootQueue(false)
290
+ this.scheduleRetry()
291
+ }
292
+ }
293
+ }
294
+
295
+ private scheduleRetry(): void {
296
+ if (this.disposed || this.retryTimer || this.gaveUp) return
297
+ this.retries += 1
298
+ if (this.gaveUp) {
299
+ // issue #6:放弃机制——明确终态,停止后台空转;请求方收到清晰错误而非超时
300
+ this.readyState = 'failed'
301
+ this.flushBootQueue(false)
302
+ console.error(
303
+ `[lingshu-bridge] 连续启动失败 ${this.retries} 次,已停止自动重启(不再后台空转)。` +
304
+ `请检查 ${this.options.python} 可执行文件与 md_cg 依赖;` +
305
+ `自检 \`${selfCheckCommand(this.options.python)}\` 须在插件包根目录运行` +
306
+ '(插件已自动锚定 cwd 与 PYTHONPATH,issue #12),修复后在 DSH 中重新启用 dsh-memory 插件。')
307
+ probe(`give up: ${this.retries} consecutive failures, entering failed terminal state`)
308
+ return
309
+ }
310
+ const delay = this.retryDelayMs
311
+ this.retryDelayMs = Math.min(this.retryDelayMs * 2, this.options.maxRetryDelayMs)
312
+ console.error(`[lingshu-bridge] 将进行第 ${this.retries}/${MAX_RETRIES} 次重试(${delay}ms 后)`)
313
+ probe(`schedule retry ${this.retries}/${MAX_RETRIES} in ${delay}ms`)
314
+ this.retryTimer = setTimeout(() => {
315
+ this.retryTimer = null
316
+ if (!this.disposed) this.spawnAndHandshake()
317
+ }, delay)
318
+ this.retryTimer.unref()
319
+ }
320
+
321
+ private writeRaw(msg: Record<string, unknown>): void {
322
+ const proc = this.proc
323
+ if (!proc || !proc.stdin?.writable) {
324
+ throw new Error('灵枢进程不可写')
325
+ }
326
+ proc.stdin.write(JSON.stringify(msg) + '\n')
327
+ }
328
+
329
+ private request(method: string, params: Record<string, unknown>,
330
+ signal?: AbortSignal): Promise<unknown> {
331
+ // issue #6:放弃终态下快速失败——之前进程不在且不再重启,请求只能白等超时
332
+ if (this.gaveUp) {
333
+ return Promise.reject(new Error(
334
+ '灵枢进程不可用:连续启动失败已达上限,已停止重试。' +
335
+ `请检查 ${this.options.python} 可执行文件与 md_cg 依赖` +
336
+ `(自检 \`${selfCheckCommand(this.options.python)}\` 须在插件包根目录运行),` +
337
+ '修复后重新启用 dsh-memory 插件。'))
338
+ }
339
+ const id = this.nextId++
340
+ const timeout = this.options.timeoutMs
341
+ // P0 修复(GPT 审查):定时器直接调 settle——settle 内部会 delete + clearTimeout
342
+ // 并 reject。此前先 pending.delete(id) 再 settle(),settle 找不到 entry 直接
343
+ // return,Promise 永不 resolve/reject(超时逻辑完全失效,子进程挂死时插件永久挂住)。
344
+ const timer = setTimeout(() => {
345
+ this.settle(id, {
346
+ error: { code: -32000, message: `灵枢调用超时(${timeout}ms):${method}` },
347
+ })
348
+ }, timeout)
349
+ if (signal?.aborted) {
350
+ clearTimeout(timer)
351
+ return Promise.reject(new Error(`已取消:${method}`))
352
+ }
353
+ const onAbort = (): void => {
354
+ this.settle(id, { error: { code: -32800, message: `已取消:${method}` } })
355
+ }
356
+ signal?.addEventListener('abort', onAbort, { once: true })
357
+ const promise = new Promise<unknown>((resolve, reject) => {
358
+ this.pending.set(id, { resolve, reject, timer })
359
+ })
360
+ // settle 后移除 abort 监听,避免内存积累
361
+ promise.finally(() => {
362
+ signal?.removeEventListener('abort', onAbort)
363
+ }).catch(() => { /* finally 链的 catch 防未处理拒绝 */ })
364
+ try {
365
+ this.writeRaw({ jsonrpc: '2.0', id, method, params })
366
+ } catch (err) {
367
+ clearTimeout(timer)
368
+ this.pending.delete(id)
369
+ signal?.removeEventListener('abort', onAbort)
370
+ return Promise.reject(err)
371
+ }
372
+ return promise
373
+ }
374
+
375
+ private settle(id: number, msg: Record<string, unknown>): void {
376
+ const entry = this.pending.get(id)
377
+ if (!entry) return
378
+ this.pending.delete(id)
379
+ clearTimeout(entry.timer)
380
+ if (msg['error']) {
381
+ const err = msg['error'] as { message?: string; code?: number }
382
+ entry.reject(new Error(`灵枢错误 ${err.code ?? ''}: ${err.message ?? 'unknown'}`))
383
+ } else {
384
+ entry.resolve(msg['result'])
385
+ }
386
+ }
387
+
388
+ private rejectAll(reason: Error): void {
389
+ for (const [, entry] of this.pending) {
390
+ clearTimeout(entry.timer)
391
+ entry.reject(reason)
392
+ }
393
+ this.pending.clear()
394
+ }
395
+
396
+ private flushBootQueue(ok: boolean): void {
397
+ const queue = this.bootQueue
398
+ this.bootQueue = []
399
+ for (const cb of queue) cb(ok)
400
+ }
401
+ }