@furongjun1999/dsh-memory 0.4.7 → 0.4.9
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.
- package/README.md +130 -47
- package/codebuddy/CODEBUDDY.md +21 -10
- package/codebuddy/README.md +13 -1
- package/codebuddy/mcp.json +9 -0
- 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 -0
- 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 -0
- package/docs/README.md +111 -0
- package/docs/discipline/harnesses.yaml +226 -152
- package/docs/discipline/templates/full.md.tmpl +61 -58
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.md +127 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.png +0 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_/347/201/265/346/236/242_vs_dejavu_/347/273/237/344/270/200/350/257/204/345/210/206_v7.md +202 -0
- package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
- package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
- package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
- package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
- package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
- package/docs/experiments/m4-role-probe/census.py +86 -0
- package/docs/experiments/m4-role-probe/probe.py +89 -0
- package/docs/experiments/mapped_confidence/bench_mapped_conf.py +216 -0
- package/docs/experiments/mapped_confidence/post_check.py +75 -0
- package/docs/experiments/mapped_confidence/repro_thirdparty_tol.py +83 -0
- package/docs/experiments/mapped_confidence/result_mapped_conf.json +215 -0
- package/docs/hive//345/244/232/347/253/257harness/351/200/232/344/277/241/345/245/221/347/272/246_v0.1.md +42 -0
- 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 -0
- 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 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S1b/344/270/216/345/217/254/345/233/236/346/235/203/350/241/241_v0.1.md +57 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S7/345/200/222/346/216/222/345/200/231/351/200/211/345/261/202_v0.1.md +126 -0
- 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 -0
- 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 +14 -2
- package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -0
- package/docs/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
- package/docs/{ → mdcg/}/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 +1 -1
- package/docs/mdcg//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_/345/245/221/347/272/246_v0.1.md +82 -0
- 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 -0
- 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 +263 -0
- 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 +1 -1
- package/docs/mdcg//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 -0
- 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 +2 -2
- package/docs/{ → mdcg/}/347/201/265/346/236/242/344/270/211/345/261/202/346/213/206/345/210/206/350/247/204/345/210/222_v0.1.md +181 -181
- 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 -0
- package/docs/mdcg//347/216/257/344/272/214_/347/231/275/347/256/261/345/241/253/345/205/205/346/265/201/346/260/264/347/272/277_v0.1.md +31 -0
- package/docs/{ → mdcg/}/347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +2 -2
- 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 +1 -1
- 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 +4 -4
- package/docs/{ → mdcg/}/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_MdCGOS/344/270/216MCP/346/216/245/345/205/245_v0.1.md +2 -2
- package/docs/mdcg//350/267/250/347/253/257/351/252/214/350/257/201/344/270/216/345/220/214/346/255/245/345/215/217/350/256/256_v0.1.md +93 -0
- 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 -0
- package/docs/{ → swarm/}/350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +3 -3
- 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 -0
- 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 -0
- 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 -0
- 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 -0
- 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 +6 -6
- 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 +1 -1
- 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 -0
- 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 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/346/236/266/346/236/204/345/255/246/344/271/240_/345/244/226/351/203/250/347/220/206/350/256/272/345/257/271/347/205/247/344/270/216/350/267/257/347/272/277/344/272/244/346/216/245_20260916.md +98 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/347/245/236/347/273/217/347/275/221/347/273/234/346/236/266/346/236/204_/346/200/273/347/272/262/344/270/216/344/272/244/346/216/245_20260916.md +109 -0
- 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 +434 -405
- package/docs//347/201/265/346/236/242/350/207/252/346/210/221/346/224/271/350/277/233/345/267/245/344/275/234/350/256/241/345/210/222_/345/244/226/351/203/250/347/240/224/347/251/266/347/263/273/345/210/227/345/220/270/346/224/266_v1_20260919.md +286 -0
- package/docs//347/231/275/347/256/261/345/214/226/347/272/262/351/242/206_/344/270/211/351/241/271/347/233/256/345/255/246/344/271/240/346/200/273/346/236/266/346/236/204/344/270/216Ghidra/344/272/244/346/216/245_20260916.md +104 -0
- package/docs//350/256/260/345/277/206/350/257/204/345/256/241/347/263/273/347/273/237_/347/253/213/351/241/271/350/256/276/350/256/241/344/270/216/346/226/275/345/267/245/344/272/244/346/216/245_20260915.md +183 -0
- package/dsh/README.md +34 -1
- package/dsh/cordis.yml.example +13 -7
- package/dsh/hive-mcp-probe.mjs +94 -0
- package/dsh/hive-mcp.example.yml +62 -0
- package/dsh/update-lingshu.bat +11 -0
- package/dsh/update-lingshu.ps1 +337 -0
- package/lib/hooks.d.ts +8 -0
- package/lib/hooks.js +27 -24
- package/lib/index.d.ts +4 -2
- package/lib/index.js +29 -6
- package/lib/lib/datapath.d.ts +76 -1
- package/lib/lib/datapath.js +199 -13
- package/lib/lib/mdcg_client.d.ts +6 -3
- package/lib/lib/mdcg_client.js +6 -5
- package/lib/lib/mutual.js +4 -4
- package/lib/lib/prompt_safety.d.ts +48 -0
- package/lib/lib/prompt_safety.js +62 -0
- package/lib/lib/token_store.js +4 -5
- package/md_cg/audit.py +91 -2
- package/md_cg/autonomy.py +86 -15
- package/md_cg/backfill.py +36 -1
- package/md_cg/backfill_bigdomain.py +34 -0
- package/md_cg/bench6_arms.py +28 -1
- package/md_cg/bench6_common.py +10 -1
- package/md_cg/bench6_competitors.py +6 -1
- package/md_cg/bench_axis_domain.py +9 -1
- package/md_cg/bench_blind_comp.py +7 -1
- package/md_cg/bench_en_atoms_public.py +9 -0
- package/md_cg/bench_governance.py +348 -0
- package/md_cg/bench_lme_zh.py +16 -1
- package/md_cg/bench_locomo.py +2 -1
- package/md_cg/bench_locomo_zh.py +16 -1
- package/md_cg/bench_locomo_zh_public.py +4 -1
- package/md_cg/bench_longmem.py +2 -1
- package/md_cg/bench_membench.py +37 -6
- package/md_cg/bench_p0.py +4 -1
- package/md_cg/bench_progressive.py +61 -10
- package/md_cg/bench_role_views.py +238 -0
- package/md_cg/bench_task_ab.py +8 -1
- package/md_cg/bench_task_ab_llm.py +13 -1
- package/md_cg/bench_unified_en.py +6 -1
- package/md_cg/bench_zh_mad.py +20 -1
- package/md_cg/blindspot_tickets.py +123 -0
- package/md_cg/branches.py +286 -0
- package/md_cg/build_postings.py +73 -0
- package/md_cg/ccgc.py +949 -0
- package/md_cg/census.py +5 -1
- package/md_cg/chain.py +24 -3
- package/md_cg/codeindex.py +134 -17
- package/md_cg/coldverify.py +265 -0
- package/md_cg/comment_gate.py +338 -0
- package/md_cg/cond_compose.py +190 -0
- package/md_cg/cond_facts.py +155 -0
- package/md_cg/cond_template.json +107 -0
- package/md_cg/condition_anchor.py +143 -0
- package/md_cg/conformance.py +727 -0
- package/md_cg/consistency.py +25 -2
- package/md_cg/consolidate.py +53 -2
- package/md_cg/corpus.py +5 -1
- package/md_cg/crosscheck.py +42 -2
- package/md_cg/crypto.py +35 -1
- package/md_cg/d_meta.py +310 -0
- package/md_cg/datapath.py +201 -26
- package/md_cg/docindex.py +122 -1
- package/md_cg/eval_common.py +35 -6
- package/md_cg/evidence.py +27 -1
- package/md_cg/evolution.py +21 -1
- package/md_cg/export.py +11 -1
- package/md_cg/forgetting.py +34 -4
- package/md_cg/fsutil.py +81 -2
- package/md_cg/hotcache.py +214 -0
- package/md_cg/hyperedge.py +251 -0
- package/md_cg/identity.py +20 -3
- package/md_cg/insight.py +19 -3
- package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
- package/md_cg/lexicon/build_standard_en.py +171 -168
- package/md_cg/lexicon/expand_en_zh.py +6 -0
- package/md_cg/lifecycle.py +273 -0
- package/md_cg/linkref.py +281 -0
- package/md_cg/links.py +29 -1
- package/md_cg/mcp_server.py +894 -168
- package/md_cg/md_whitebox.py +53 -1
- package/md_cg/mdcg.py +1205 -41
- package/md_cg/mdcos.py +1060 -76
- package/md_cg/metacognition.py +39 -4
- package/md_cg/migrate.py +4 -0
- package/md_cg/migrate_aeis.py +221 -213
- package/md_cg/migrate_roleplay.py +8 -0
- package/md_cg/migrate_wisdom_graph.py +14 -1
- package/md_cg/mreview/__init__.py +25 -0
- package/md_cg/mreview/__main__.py +110 -0
- package/md_cg/mreview/bundle.py +178 -0
- package/md_cg/mreview/candidates.py +262 -0
- package/md_cg/mreview/govern.py +694 -0
- package/md_cg/mreview/locate.py +939 -0
- package/md_cg/mreview/pipeline.py +729 -0
- package/md_cg/mreview/rules/duplication.json +21 -0
- package/md_cg/mreview/rules/field_coverage.json +54 -0
- package/md_cg/mreview/rules/source_license.json +21 -0
- package/md_cg/mreview/rules/template_flow.json +21 -0
- package/md_cg/mreview/ruleset.py +253 -0
- package/md_cg/nodefile.py +269 -1
- package/md_cg/pooling.py +23 -1
- package/md_cg/postings.py +298 -0
- package/md_cg/predict.py +113 -15
- package/md_cg/progressive.py +3 -0
- package/md_cg/protect.py +18 -5
- package/md_cg/protocol.py +372 -0
- package/md_cg/provenance.py +262 -0
- package/md_cg/reach.py +453 -0
- package/md_cg/refindex.py +88 -4
- package/md_cg/refine.py +20 -1
- package/md_cg/roleviews.py +89 -0
- package/md_cg/routing.py +76 -0
- package/md_cg/scrub.py +68 -3
- package/md_cg/security.py +26 -1
- package/md_cg/self_state.py +65 -2
- package/md_cg/selfreport.py +151 -0
- package/md_cg/semantic/canonical.py +5 -0
- package/md_cg/semantic/en_normalizer.py +364 -295
- package/md_cg/semantic/zh_en_atoms.py +139 -136
- package/md_cg/signer.py +41 -1
- package/md_cg/sources.py +583 -547
- package/md_cg/statushdr.py +179 -0
- package/md_cg/stg.py +59 -18
- package/md_cg/subgraph.py +23 -0
- package/md_cg/sustain.py +74 -1
- package/md_cg/tasks.py +471 -0
- package/md_cg/test_action_derive.py +203 -0
- package/md_cg/test_audit_rotate.py +270 -0
- package/md_cg/test_autonomy.py +26 -0
- package/md_cg/test_bench_governance.py +102 -0
- package/md_cg/test_blindspot_tickets.py +166 -0
- package/md_cg/test_branches.py +249 -0
- package/md_cg/test_ccg_perturb.py +1 -1
- package/md_cg/test_ccgc.py +433 -0
- package/md_cg/test_codeindex.py +338 -0
- package/md_cg/test_comment_gate.py +187 -0
- package/md_cg/test_cond_compose_anchors.py +76 -0
- package/md_cg/test_condition_anchor.py +82 -0
- package/md_cg/test_conformance.py +343 -0
- package/md_cg/test_d_meta.py +412 -0
- package/md_cg/test_datapath_root.py +188 -0
- package/md_cg/test_en_pipeline.py +24 -0
- package/md_cg/test_gain_gate.py +47 -1
- package/md_cg/test_health_scale.py +173 -0
- package/md_cg/test_hot_cold.py +187 -0
- package/md_cg/test_hyperedge.py +245 -0
- package/md_cg/test_identity_attribution.py +6 -0
- package/md_cg/test_index_durability.py +224 -0
- package/md_cg/test_lifecycle.py +309 -0
- package/md_cg/test_linkref.py +306 -0
- package/md_cg/test_md_access_parity.py +15 -3
- package/md_cg/test_mr_m1.py +769 -0
- package/md_cg/test_mr_m2.py +587 -0
- package/md_cg/test_mr_m3.py +710 -0
- package/md_cg/test_mr_m4.py +485 -0
- package/md_cg/test_p1.py +1 -1
- package/md_cg/test_p11_consistency.py +1 -1
- package/md_cg/test_p12_metacognition.py +2 -2
- package/md_cg/test_p16_self_state.py +1 -1
- package/md_cg/test_p26_refindex.py +50 -21
- package/md_cg/test_p27_docindex.py +258 -4
- package/md_cg/test_p28_refcheck.py +1 -1
- package/md_cg/test_p29_session_ingest_export.py +1 -1
- package/md_cg/test_p2_mcp.py +7 -1
- package/md_cg/test_p31_insight.py +24 -0
- package/md_cg/test_p38_contextualize.py +1 -1
- package/md_cg/test_p39_vision_evidence.py +1 -1
- package/md_cg/test_p40_refine_worklist.py +1 -1
- package/md_cg/test_p41_evolve_patrol.py +1 -1
- package/md_cg/test_p42_provenance.py +1 -1
- package/md_cg/test_p43_pooling.py +41 -13
- package/md_cg/test_p44_md_whitebox.py +14 -1
- package/md_cg/test_protocol.py +243 -0
- package/md_cg/test_reach.py +378 -0
- package/md_cg/test_reach_keys.py +201 -0
- package/md_cg/test_reach_meta_exits.py +145 -0
- package/md_cg/test_read_clip.py +141 -0
- package/md_cg/test_retr_s1.py +340 -0
- package/md_cg/test_retr_s1b.py +209 -0
- package/md_cg/test_retr_s3.py +194 -0
- package/md_cg/test_retr_s4.py +163 -0
- package/md_cg/test_retr_s5.py +200 -0
- package/md_cg/test_retr_s6.py +157 -0
- package/md_cg/test_retr_s7.py +385 -0
- package/md_cg/test_retr_s8_time.py +316 -0
- package/md_cg/test_retr_s9_edges.py +286 -0
- package/md_cg/test_retr_s9_entity_ctx.py +175 -0
- package/md_cg/test_review_conformance.py +367 -0
- package/md_cg/test_role_views.py +354 -0
- package/md_cg/test_tasks.py +409 -0
- package/md_cg/test_tool_face.py +189 -0
- package/md_cg/test_trust.py +361 -0
- package/md_cg/test_twophase.py +286 -0
- package/md_cg/test_units_poll.py +71 -0
- package/md_cg/test_v14_fixes.py +397 -0
- package/md_cg/test_validity_filter.py +280 -0
- package/md_cg/test_wisdom_md_store.py +7 -3
- package/md_cg/test_writepipe.py +214 -0
- package/md_cg/theory.py +17 -2
- package/md_cg/tokens.py +134 -12
- package/md_cg/tool_face.py +261 -0
- package/md_cg/trust.py +943 -0
- package/md_cg/twophase.py +232 -0
- package/md_cg/units.py +665 -0
- package/md_cg/vision_evidence.py +25 -2
- package/md_cg/weights.py +25 -2
- package/md_cg/whitebox.py +33 -2
- package/md_cg/whitebox_kb/data/verify_cache.json +21233 -360
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +5124 -0
- package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
- package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
- package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
- package/md_cg/writelimit.py +37 -7
- package/md_cg/writepipe.py +543 -0
- package/package.json +2 -2
- package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
- package/skills/skills/designer-perspective/scripts/designer.py +17 -1
- package/skills/skills/designer-perspective/tests/selftest.py +3 -1
- package/src/hooks.ts +27 -22
- package/src/index.ts +33 -6
- package/src/lib/datapath.ts +211 -13
- package/src/lib/mdcg_client.ts +12 -8
- package/src/lib/mutual.ts +411 -411
- package/src/lib/prompt_safety.ts +62 -0
- package/src/lib/token_store.ts +4 -5
- package/zcode/AGENTS.md +21 -10
- package/zcode/README.md +4 -0
- package/docs//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +0 -221
- /package/docs/{AGI → 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" +0 -0
- /package/docs/{AGI → 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" +0 -0
- /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" +0 -0
- /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" +0 -0
- /package/docs/{guardrail-charter.md → mdcg/guardrail-charter.md} +0 -0
- /package/docs/{lingshu_tutorial.html → mdcg/lingshu_tutorial.html} +0 -0
- /package/docs/{memory-assessment.html → mdcg/memory-assessment.html} +0 -0
- /package/docs/{memory_score.html → mdcg/memory_score.html} +0 -0
- /package/docs/{memory_score.png → mdcg/memory_score.png} +0 -0
- /package/docs/{release_v0.3.0.md → mdcg/release_v0.3.0.md} +0 -0
- /package/docs/{release_v0.4.5.md → mdcg/release_v0.4.5.md} +0 -0
- /package/docs/{tool_table_v0.3.0.md → mdcg/tool_table_v0.3.0.md} +0 -0
- /package/docs/{ → mdcg/}/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" +0 -0
- /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" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242MCP/345/267/245/345/205/267/346/200/273/350/241/250_v3.4.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242_/350/207/252/346/210/221/345/261/202/345/256/232/344/271/211.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_MD/347/233/256/345/275/225/346/226/271/346/241/210_v0.1.md" +0 -0
- /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" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276/344/275/234/344/270/272/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_/350/257/204/344/274/260/344/270/216/350/267/257/347/272/277_v0.1.md" +0 -0
- /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" +0 -0
- /package/docs/{ → plans/}/347/237/245/350/257/206/345/233/276/350/260/261/351/241/271/347/233/256_/344/272/244/346/216/245/346/226/207/346/241/243_20260914.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/344/275/277/347/224/250/346/212/245/345/221/212_20260913.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/345/212/237/350/203/275/350/257/264/346/230/216_v0.6.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/347/233/262/345/214/272/346/240/207/350/256/260_v1.0.md" +0 -0
- /package/docs/{ → theory/}/344/277/241/346/201/257/345/267/256/344/270/272/344/273/200/344/271/210/345/277/205/347/204/266/345/255/230/345/234/250/344/270/224/350/207/252/347/204/266/346/211/251/345/244/247.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/345/205/254/347/220/206/345/214/226/345/237/272/347/237/263.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/350/256/244/347/237/245/350/277/207/347/250/213.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/350/256/2723.4.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/346/230/257/344/273/200/344/271/210/357/274/237.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/347/263/273/345/210/227/302/267/347/254/254/344/272/224/347/257/207/357/274/232/350/256/251AI/347/234/237/346/255/243/350/243/205/344/270/212/350/256/260/345/277/206.md" +0 -0
|
@@ -50,6 +50,7 @@ DIM_KEYWORDS = (
|
|
|
50
50
|
)
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
# 生效条件:对 sys.stdout 与 sys.stderr 依次尝试 reconfigure(encoding="utf-8"),任何异常都被 try/except 吞掉后继续;
|
|
53
54
|
def _stdout_utf8():
|
|
54
55
|
for stream in (sys.stdout, sys.stderr):
|
|
55
56
|
try:
|
|
@@ -58,6 +59,7 @@ def _stdout_utf8():
|
|
|
58
59
|
pass
|
|
59
60
|
|
|
60
61
|
|
|
62
|
+
# 生效条件:text 为 None 或空串时返回 default,text 已是 dict/list 时原样返回,否则返回 json.loads(text) 的结果;
|
|
61
63
|
def _load_json_arg(text, default):
|
|
62
64
|
if text is None or text == "":
|
|
63
65
|
return default
|
|
@@ -66,12 +68,14 @@ def _load_json_arg(text, default):
|
|
|
66
68
|
return json.loads(text)
|
|
67
69
|
|
|
68
70
|
|
|
71
|
+
# 生效条件:value 为假值(None/""/[]/{}/0)时返回 [],value 是 str 时返回 [value],其余返回 list(value);
|
|
69
72
|
def _as_list(value):
|
|
70
73
|
if not value:
|
|
71
74
|
return []
|
|
72
75
|
return [value] if isinstance(value, str) else list(value)
|
|
73
76
|
|
|
74
77
|
|
|
78
|
+
# 生效条件:text 为假值时先置为 "",按 DIM_KEYWORDS 顺序返回首个含命中关键词的维度,全部未命中返回 "条件边界";
|
|
75
79
|
def classify_dimension(text):
|
|
76
80
|
"""把失配描述归入五失配维度之一;未命中归入「条件边界」。"""
|
|
77
81
|
text = text or ""
|
|
@@ -81,10 +85,12 @@ def classify_dimension(text):
|
|
|
81
85
|
return "条件边界"
|
|
82
86
|
|
|
83
87
|
|
|
88
|
+
# 生效条件:key 在 FOUR_DIMS 中时原样返回 key,否则返回 classify_dimension(key) 的归类结果;
|
|
84
89
|
def _dim_of_key(key):
|
|
85
90
|
return key if key in FOUR_DIMS else classify_dimension(key)
|
|
86
91
|
|
|
87
92
|
|
|
93
|
+
# 生效条件:conditions 为假值(None/""/{})时返回 {},conditions 是 str 时先 json.loads 再 dict(...),其余直接 dict(conditions);
|
|
88
94
|
def normalize_conditions(conditions):
|
|
89
95
|
if not conditions:
|
|
90
96
|
return {}
|
|
@@ -95,6 +101,7 @@ def normalize_conditions(conditions):
|
|
|
95
101
|
|
|
96
102
|
# ---------------------------------------------------------------- 步骤 1:声明
|
|
97
103
|
|
|
104
|
+
# 生效条件:position 为假值时回落 "designer",不在 POSITION_MAP 中时 raise SystemExit,space 假值时用空 OrderedDict 并 setdefault 观测位置,返回含 space_id、layer、missing_dims 的 OrderedDict;
|
|
98
105
|
def declare_core(position="designer", space=None):
|
|
99
106
|
"""条件空间声明:四维 + 有效范围 + 切换规则(3.1/3.2)。"""
|
|
100
107
|
position = position or "designer"
|
|
@@ -115,6 +122,7 @@ def declare_core(position="designer", space=None):
|
|
|
115
122
|
|
|
116
123
|
# ---------------------------------------------------------------- 步骤 2-3:白箱三问 + 四态
|
|
117
124
|
|
|
125
|
+
# 生效条件:evidence 取 candidate["evidence"] or conditions["anchors"] 再 _as_list,vpath 取 verification_path or candidate["verification_path"] 再 _as_list;evidence 为空返回 (False,"观测工具",detail),否则 conditions 缺任一 FOUR_DIMS 时返回 (False, 首个缺失维度, detail),否则 vpath 为空返回 (False,"条件边界",detail),全齐返回 (True,None,detail);
|
|
118
126
|
def whitebox_check(candidate, conditions, verification_path=None):
|
|
119
127
|
"""白箱三问(第〇章)。返回 (ok, missing_dim, detail)。"""
|
|
120
128
|
evidence = _as_list(candidate.get("evidence") or conditions.get("anchors"))
|
|
@@ -134,6 +142,7 @@ def whitebox_check(candidate, conditions, verification_path=None):
|
|
|
134
142
|
return True, None, detail
|
|
135
143
|
|
|
136
144
|
|
|
145
|
+
# 生效条件:candidates 为假值(None/[])判 BLINDSPOT,否则逐候选按 not_applicable 与 query 的冲突记 REJECT、when 与 conditions 不符记 DEFER,全为 REJECT 判 REJECT、无合格候选取首个 DEFER、多个合格候选仅唯一 distinguishing 时选之否则 DEFER,verdict 仍空时由 whitebox_check(cand, conditions, verification_path) 定 ACCEPT 或 DEFER;
|
|
137
146
|
def judge_core(query, conditions=None, candidates=None, verification_path=None):
|
|
138
147
|
"""四态资格裁决(6章.2):先拒绝,后接受。"""
|
|
139
148
|
conditions = normalize_conditions(conditions)
|
|
@@ -248,6 +257,7 @@ def emit_mcp_calls(result):
|
|
|
248
257
|
return calls
|
|
249
258
|
|
|
250
259
|
|
|
260
|
+
# 生效条件:从 result["conditions"] 取四维(.get 缺键显示 <未声明>)、从 result["traces"] 中首个含 "whitebox" 的项渲染白箱行,emit_mcp 为真值时追加 emit_mcp_calls(result) 的 JSON,返回 '\n'.join(lines);
|
|
251
261
|
def render_verdict(result, emit_mcp=False):
|
|
252
262
|
c = result["conditions"]
|
|
253
263
|
lines = ["[判定单]",
|
|
@@ -275,6 +285,7 @@ def render_verdict(result, emit_mcp=False):
|
|
|
275
285
|
|
|
276
286
|
# ---------------------------------------------------------------- 步骤 5:归因 / 蒸馏
|
|
277
287
|
|
|
288
|
+
# 生效条件:error 为假值时先 dict({}),missing 取 error.get("missing",""),dim 取 error.get("dimension") or classify_dimension(missing) 且不在 FIVE_MISMATCH 时回落 "条件边界",返回含 triple/mismatch_dim/discipline 的 OrderedDict;
|
|
278
289
|
def attribute_core(error):
|
|
279
290
|
"""条件层归因:三方条件空间失配 + 五失配维度定位(附录22.3)。"""
|
|
280
291
|
error = dict(error or {})
|
|
@@ -297,6 +308,7 @@ def attribute_core(error):
|
|
|
297
308
|
])
|
|
298
309
|
|
|
299
310
|
|
|
311
|
+
# 生效条件:对 rows 每行按 dimension 或 classify_dimension(row.get("missing","")) 分组(不在 FIVE_MISMATCH 归入 "条件边界"),每组以首行 symptom/missing 生成一条带 when/rule/change 的纪律项,rows 为空返回空 items 列表;
|
|
300
312
|
def distill_core(rows):
|
|
301
313
|
"""失败集合 → 带适用条件的可复用纪律(1.1.1)。"""
|
|
302
314
|
groups = defaultdict(list)
|
|
@@ -318,6 +330,7 @@ def distill_core(rows):
|
|
|
318
330
|
return items
|
|
319
331
|
|
|
320
332
|
|
|
333
|
+
# 生效条件:对 items 逐项(依赖 it["missing"]/["rule"]/["when"]/["change"]/["evidence"])编号渲染 markdown 段落,items 为空时返回仅含标题与说明的文本;
|
|
321
334
|
def render_distill(items):
|
|
322
335
|
lines = ["# 蒸馏纪律(失败资产化)", "",
|
|
323
336
|
"> 失败 → 根因(条件层)→ 可复用纪律(带适用条件)→ 注入 → 不再犯(1.1.1)", ""]
|
|
@@ -334,6 +347,7 @@ def render_distill(items):
|
|
|
334
347
|
|
|
335
348
|
# ---------------------------------------------------------------- probe / selftest
|
|
336
349
|
|
|
350
|
+
# 生效条件:按 os.environ.get("DMCG_HOME") 再 DEFAULT_DMCG_HOME 顺序,跳过假值或不含 md_cg 子目录的 base,命中的 base 插入 sys.path 后 import md_cg.mdcos,成功返回 available=True/mode=read-only,import 抛异常返回 available=False/degraded 附 error,全部未命中返回 available=False、base=None;
|
|
337
351
|
def probe_mdcg():
|
|
338
352
|
"""探测 md_cg 认知图可用性(只读 import,不实例化、不写库)。"""
|
|
339
353
|
bases = [os.environ.get("DMCG_HOME"), DEFAULT_DMCG_HOME]
|
|
@@ -358,6 +372,7 @@ def probe_mdcg():
|
|
|
358
372
|
("error", "未找到 md_cg(可设 DMCG_HOME 指向 dsh-memory 根目录)")])
|
|
359
373
|
|
|
360
374
|
|
|
375
|
+
# 生效条件:按 case.get("kind") 分派 —— declare 比对 declare_core 的 missing_dims 与 expect 的 dims_complete/observation_position_contains,judge 与 verify 比对 judge_core 的 verdict/missing_dim 与 expect 的 state/missing_dim/require_verification_path/require_missing_dim,missing 比对 attribute_core 的 mismatch_dim,其余 kind 记 ok=False;
|
|
361
376
|
def run_cases(cases):
|
|
362
377
|
results = []
|
|
363
378
|
for case in cases:
|
|
@@ -397,6 +412,7 @@ def run_cases(cases):
|
|
|
397
412
|
|
|
398
413
|
# ---------------------------------------------------------------- CLI
|
|
399
414
|
|
|
415
|
+
# 生效条件:items 为假值(None/空列表)时返回空 OrderedDict,否则每项不含 "=" 时 raise SystemExit,含 "=" 的按首个 "=" 拆分并 strip 后写入 space;
|
|
400
416
|
def _parse_space(items):
|
|
401
417
|
space = OrderedDict()
|
|
402
418
|
for it in items or []:
|
|
@@ -527,4 +543,4 @@ def main(argv=None):
|
|
|
527
543
|
|
|
528
544
|
|
|
529
545
|
if __name__ == "__main__":
|
|
530
|
-
sys.exit(main())
|
|
546
|
+
sys.exit(main())
|
|
@@ -21,6 +21,7 @@ sys.path.insert(0, os.path.join(ROOT, "scripts"))
|
|
|
21
21
|
import designer # noqa: E402 (路径注入后导入)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
# 生效条件:读取 cases_path 的 JSONL(strip 后为空的行跳过)交给 designer.run_cases,返回 (results, passed, total) 三元组;
|
|
24
25
|
def run(cases_path):
|
|
25
26
|
with open(cases_path, encoding="utf-8") as fh:
|
|
26
27
|
cases = [json.loads(line) for line in fh if line.strip()]
|
|
@@ -30,6 +31,7 @@ def run(cases_path):
|
|
|
30
31
|
return results, passed, total
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
# 生效条件:argv(None 时取 sys.argv)解析后 --cases 缺省为 HERE/cases.jsonl,调用 run 后 passed==total 返回 0 否则返回 1,--json 为真值时打印 JSON 汇总、否则打印逐项明细;
|
|
33
35
|
def main(argv=None):
|
|
34
36
|
ap = argparse.ArgumentParser(prog="selftest.py",
|
|
35
37
|
description="设计者视角 · 认知能力验收")
|
|
@@ -57,4 +59,4 @@ def main(argv=None):
|
|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
if __name__ == "__main__":
|
|
60
|
-
sys.exit(main())
|
|
62
|
+
sys.exit(main())
|
package/src/hooks.ts
CHANGED
|
@@ -21,6 +21,14 @@
|
|
|
21
21
|
* 模型请求组装 system prompt 时自动注入灵枢最近记忆
|
|
22
22
|
* (`stg(op=timeline)`,最近记忆节点时间线),让记忆"自动可用"而不只依赖
|
|
23
23
|
* Agent 主动调用 recall/think 工具。失败静默(不影响请求)。
|
|
24
|
+
* ⚠️ 该注入块的**稳定性**决定宿主是否新追加快照:内容没变时也必须照旧 push
|
|
25
|
+
* (宿主按渲染后的整段文本去重);跳过 push 反而会各追加一份「有块/无块」的快照
|
|
26
|
+
* —— 详见 installMemoryHooks 里的长注释。
|
|
27
|
+
*
|
|
28
|
+
* ⚠️ 注入文本**必经** escapePromptBraces(src/lib/prompt_safety.ts,issue #16):
|
|
29
|
+
* 宿主对 context 文本做严格 `{{variable}}` 插值,裸 `{{` 会让每轮 assemble 抛错
|
|
30
|
+
* → 会话永久不可用(记忆永久在库,非偶发)。记忆真源不动,只在**注入副本**上
|
|
31
|
+
* 打断 `{{`——新增任何 push context/section 的代码,同样必须过这道转义。
|
|
24
32
|
*/
|
|
25
33
|
|
|
26
34
|
import '@deepseek-ai/dsh-session'
|
|
@@ -29,6 +37,7 @@ import type { Context } from '@deepseek-ai/cordis'
|
|
|
29
37
|
import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
|
30
38
|
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
|
31
39
|
import type { MdcgClient } from './lib/mdcg_client.js'
|
|
40
|
+
import { escapePromptBraces } from './lib/prompt_safety.js'
|
|
32
41
|
|
|
33
42
|
/** 自动记忆开关。 */
|
|
34
43
|
export interface MemoryHooksOptions {
|
|
@@ -120,8 +129,6 @@ const RECALL_MIN_CHARS = 24
|
|
|
120
129
|
const RECALL_MAX_CHARS = 1400
|
|
121
130
|
/** 永久层不自动注入(按需用 mdcg_recall / lingshu_stg 取)。 */
|
|
122
131
|
const RECALL_SKIP_LAYERS = new Set(['anchor', 'self'])
|
|
123
|
-
/** 连续跳过多少步后强制补一次(内容未变也刷新,防止压缩归档后块消失)。 */
|
|
124
|
-
const RECALL_REPUSH_EVERY = 8
|
|
125
132
|
|
|
126
133
|
/** 分级递减渲染:按距当前的次序逐档收窄,早期条目信息量更大。
|
|
127
134
|
*
|
|
@@ -153,17 +160,6 @@ function formatTimelineDecayed(payload: unknown): string {
|
|
|
153
160
|
return out.join('\n').slice(0, RECALL_MAX_CHARS)
|
|
154
161
|
}
|
|
155
162
|
|
|
156
|
-
/** 去重:内容与上次相同就不再 push 新副本。
|
|
157
|
-
*
|
|
158
|
-
* 背景:本钩子挂在 `system-prompt/assemble` 上,每个 step 都会 push 一份,而每份
|
|
159
|
-
* 都会留成独立的 surface 节点 → 同一块累积 N 份(实测 11 份 ≈2700 tok/请求),
|
|
160
|
-
* 随步数线性增长。去重后同一块只占 1 份,外加每 RECALL_REPUSH_EVERY 步一次自愈刷新。 */
|
|
161
|
-
function shouldPushRecall(text: string, lastText: string, skippedSincePush: number): boolean {
|
|
162
|
-
if (!text) return false
|
|
163
|
-
if (text !== lastText) return true
|
|
164
|
-
return skippedSincePush >= RECALL_REPUSH_EVERY
|
|
165
|
-
}
|
|
166
|
-
|
|
167
163
|
/** 安装自动记忆钩子(effect 作用域内,随插件卸载自动移除)。
|
|
168
164
|
*
|
|
169
165
|
* mdcg 为 null(config.mdcg.enabled=false)时自动记忆整体停用:记忆真源是
|
|
@@ -194,25 +190,34 @@ export function installMemoryHooks(ctx: Context, mdcg: MdcgClient | null, opts:
|
|
|
194
190
|
|
|
195
191
|
// P1 完善(自动 recall 注入):每次模型请求组装 system prompt 时,注入灵枢最近记忆。
|
|
196
192
|
// 用 system-prompt/assemble 事件(waterfall)而非 llm/stream——后者请求 deep-frozen 不可改写。
|
|
193
|
+
//
|
|
194
|
+
// ⚠️ 必须**每步都 push**,哪怕内容与上一步逐字节相同。原因在宿主侧(dsh-agent-loop 的
|
|
195
|
+
// RuntimeContextProjection):assembly.contexts 会被渲染成一段「运行时上下文快照」,
|
|
196
|
+
// 每个 step 拿渲染后的**整段文本**与上一份已提交的快照比对,**只有不同才**在会话里
|
|
197
|
+
// append 一条新的 user/message(append 语义,旧的不会被替换或移除)。于是:
|
|
198
|
+
// · 内容不变 + 照旧 push → 渲染文本不变 → 宿主不追加任何东西(零开销、零增长);
|
|
199
|
+
// · 内容不变 + 跳过 push → 渲染文本**变了**(少了本块)→ 宿主追加一份「没有本块」的
|
|
200
|
+
// 快照;下一步再 push 又把本块加回来 → **再**追加一份。跳过一次反而多花两份快照
|
|
201
|
+
// (实测每份 ~250 tok),这正是 v0.4.8「每 8 步强制补一次」的自愈刷新会把长会话的
|
|
202
|
+
// inject 推到 30k+ tok 的原因。
|
|
203
|
+
// 因此本实现把「要不要补」交还给宿主:压缩归档后宿主会把 retained 置空并重新投影快照
|
|
204
|
+
// (RuntimeContextProjection 的 retained === null 分支),本块自然跟着回来——
|
|
205
|
+
// 不需要插件自己数步数做自愈。
|
|
197
206
|
if (opts.autoRecall) {
|
|
198
207
|
const recallLimit = Math.max(1, Math.min(10, opts.autoRecallLimit || 4))
|
|
199
|
-
// 去重状态:同一块内容只保留一份 surface 节点,避免随步数线性增长。
|
|
200
|
-
let lastRecallText = ''
|
|
201
|
-
let skippedSincePush = 0
|
|
202
208
|
ctx.on('system-prompt/assemble', async (assembly, _ctx, next) => {
|
|
203
209
|
try {
|
|
204
210
|
// 异步取最近记忆节点(失败静默——不阻塞模型请求)
|
|
205
211
|
if (graph.isReady()) {
|
|
206
212
|
const text = formatTimelineDecayed(await graph.timeline(recallLimit))
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
if (text) {
|
|
214
|
+
// 注入边界转义(issue #16):宿主 system-prompt 对 context 文本做严格
|
|
215
|
+
// `{{variable}}` 插值,裸 `{{` 会 throw → 该轮请求整体失败。记忆原文
|
|
216
|
+
// (含用户命令里的 `{{.X}}`)必须保真落库,故只在注入副本上打断 `{{`。
|
|
210
217
|
assembly.contexts.push({
|
|
211
218
|
name: 'lingshu:auto-recall',
|
|
212
|
-
text: `【灵枢最近记忆】\n${text.slice(0, RECALL_MAX_CHARS)}
|
|
219
|
+
text: escapePromptBraces(`【灵枢最近记忆】\n${text.slice(0, RECALL_MAX_CHARS)}`),
|
|
213
220
|
})
|
|
214
|
-
} else {
|
|
215
|
-
skippedSincePush += 1
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
223
|
}
|
package/src/index.ts
CHANGED
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
* name: '@furongjun1999/dsh-memory'
|
|
18
18
|
* config:
|
|
19
19
|
* mdcg: # 记忆真源:认知图(md 文档)
|
|
20
|
-
* # root = 记忆写入路径(用户可改)。缺省 =
|
|
21
|
-
* #
|
|
20
|
+
* # root = 记忆写入路径(用户可改)。缺省 = 用户级状态根 data/mdcg
|
|
21
|
+
* # (~/.dsh/.dsh-memory/data/mdcg;**不在插件包内**——包内数据会被
|
|
22
|
+
* # pnpm 更新连目录一起删掉,见 src/lib/datapath.ts 头注)
|
|
23
|
+
* # 覆盖优先级:env MDCG_ROOT > <用户级状态根>/paths.json > 本项 > 默认
|
|
22
24
|
* # root: 'D:/somewhere/mdcg' # 例:把记忆库放到别处
|
|
23
25
|
* actor: 'dsh-memory'
|
|
24
26
|
* env: # 写入凭据:默认【关闭】,由你决定是否打开
|
|
@@ -52,7 +54,7 @@ import { installMemoryHooks, type MemoryHooksOptions } from './hooks.js'
|
|
|
52
54
|
// LIB 本地库:角色扮演网页 / 互维维护 / 白箱 LLM 适配器统一收在 src/lib/。
|
|
53
55
|
import { installRoleplayWeb } from './lib/roleplay_web.js'
|
|
54
56
|
import { MdcgClient } from './lib/mdcg_client.js'
|
|
55
|
-
import { describeDataPaths, mdcgRoot } from './lib/datapath.js'
|
|
57
|
+
import { describeDataPaths, migrateLegacyData, mdcgRoot, repoRoot } from './lib/datapath.js'
|
|
56
58
|
// 写入凭据密钥环(首启引导):显式配置 → ~/.mdcg/token → 首启自动签发。
|
|
57
59
|
import { resolveToken, type TokenResolution } from './lib/token_store.js'
|
|
58
60
|
|
|
@@ -178,8 +180,9 @@ export const Config: z<Config> = z.object({
|
|
|
178
180
|
.default({ enabled: false, heartbeatMs: 10 * 60 * 1000 }),
|
|
179
181
|
/** 认知图(md_cg):记忆唯一真源。
|
|
180
182
|
* root 为**记忆写入路径**(用户可改)。缺省空串 = 未指定,按优先级解析:
|
|
181
|
-
* ① env MDCG_ROOT ②
|
|
182
|
-
*
|
|
183
|
+
* ① env MDCG_ROOT ② `<用户级状态根>/paths.json` 的 root
|
|
184
|
+
* (旧 `<插件仓>/data/paths.json` 兼容读)
|
|
185
|
+
* ③ 本项 ④ 默认 `<用户级状态根>/data/mdcg`
|
|
183
186
|
* 相对路径一律相对**插件仓根**解析——历史教训:相对 cwd 的相对路径随
|
|
184
187
|
* 宿主 cwd 漂移,cwd 落在别仓时记忆真源分裂成互不可见的两处。
|
|
185
188
|
* tenant/actor 决定私有内容加解密的身份:与 migrate_roleplay 的
|
|
@@ -255,15 +258,39 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
|
|
|
255
258
|
timeoutMs: config.toolCallTimeoutMs,
|
|
256
259
|
maxRetryDelayMs: config.maxRetryDelayMs,
|
|
257
260
|
})
|
|
261
|
+
// 数据面迁出插件包(issue #18 相邻问题):旧版把运行时数据与路径配置写在包内
|
|
262
|
+
// `<pkg>/data`,pnpm 更新会连目录一起替换(实机实证:data/ 54 文件 → 0,
|
|
263
|
+
// 46 条记忆节点靠人工备份回填)。首启把「旧位置仍有货」的数据**复制**到用户级
|
|
264
|
+
// 数据根;必须在 mdcg.start() 之前——store 要在 Python 子进程接管前就位。
|
|
265
|
+
const migrated = migrateLegacyData()
|
|
266
|
+
if (migrated.ran) {
|
|
267
|
+
ctx.logger.info(
|
|
268
|
+
`dsh-memory: 数据面已迁出插件包(旧位置只复制未删除):`
|
|
269
|
+
+ `${migrated.from} → ${migrated.to}(${migrated.copied} 项`
|
|
270
|
+
+ `${migrated.failed.length ? `,失败 ${migrated.failed.join(',')}` : ''})`,
|
|
271
|
+
)
|
|
272
|
+
}
|
|
258
273
|
mdcg.start()
|
|
259
274
|
// 启动留痕:把「记忆真源在哪、由谁决定、路径是否存在」写进可审计日志,
|
|
260
275
|
// 避免再次出现「以为在记忆、其实写到了别仓」的静默分裂(历史事故)。
|
|
261
276
|
const dp = describeDataPaths(config.mdcg.root)
|
|
262
277
|
ctx.logger.info(
|
|
263
278
|
`dsh-memory: 记忆真源路径 = ${dp.mdcgRoot}(来源 ${dp.source},`
|
|
264
|
-
+
|
|
279
|
+
+ `状态根=${dp.stateRoot},dataRoot=${dp.dataRoot},`
|
|
280
|
+
+ `存在=${dp.mdcgRootExists ? '是' : '否(首次写入将创建)'},`
|
|
265
281
|
+ `用户可改:${dp.pathsFile})`,
|
|
266
282
|
)
|
|
283
|
+
// 包管理器装的插件 + 路径配置还在旧包内位置:pnpm 下次更新会把该文件连目录一起
|
|
284
|
+
// 删除,用户配置随之丢失(回落默认根 → 表现为「记忆不见了」)。只在真的会被删的
|
|
285
|
+
// 布局下提醒(开发用的 git clone 不含 node_modules 段 → 不打扰)。
|
|
286
|
+
const pnpmManaged = repoRoot().split(/[\\/]/).includes('node_modules')
|
|
287
|
+
if (pnpmManaged && String(dp.pathsFileSource) === 'legacy') {
|
|
288
|
+
ctx.logger.warn(
|
|
289
|
+
`dsh-memory: 路径配置仍在插件包内(${dp.pathsFile})——pnpm 更新该包会连目录`
|
|
290
|
+
+ `一起删除。请复制到 ${String(dp.stateRoot)}/paths.json 后重启`
|
|
291
|
+
+ `(数据面已自动复制到 ${String(dp.dataRoot)})。`,
|
|
292
|
+
)
|
|
293
|
+
}
|
|
267
294
|
brainReady = await mdcg.waitReady()
|
|
268
295
|
if (brainReady) {
|
|
269
296
|
ctx.logger.info(`dsh-memory: 认知图已就绪(MDCG_ROOT=${resolvedRoot})`)
|
package/src/lib/datapath.ts
CHANGED
|
@@ -2,21 +2,33 @@
|
|
|
2
2
|
* datapath.ts · 灵枢数据根解析(记忆写入路径可配置)
|
|
3
3
|
*
|
|
4
4
|
* 与 Python 侧 `md_cg/datapath.py` **同口径**——两侧读同一份
|
|
5
|
-
* `<插件仓>/data/paths.json
|
|
5
|
+
* `<用户级状态根>/paths.json`(新位置;旧版 `<插件仓>/data/paths.json`
|
|
6
|
+
* 仍兼容读),避免大脑与脚本对「记忆真源在哪」各持一说。
|
|
7
|
+
*
|
|
8
|
+
* 为什么默认不再取「插件仓自身 data/」(issue #18 相邻问题,数据丢失级):
|
|
9
|
+
* DSH 插件按 hoisted 布局装在 `<profile>/node_modules/<pkg>`,`pnpm` 更新该包
|
|
10
|
+
* 会**整个替换包目录**——运行时数据落在包内(`<pkg>/data`)时,每次更新成功
|
|
11
|
+
* 即连目录一起删掉(贡献者实机实证:`data/` 54 文件 → 0,46 条记忆节点只能
|
|
12
|
+
* 靠人工备份回填);`paths.json` 同址,用户配置一并丢失。故默认数据根与配置
|
|
13
|
+
* 文件一律落**用户级状态根**(见 `stateRoot()`),与包目录彻底解耦。
|
|
6
14
|
*
|
|
7
15
|
* 优先级(高 → 低):
|
|
8
16
|
* 1. 环境变量 `MDCG_DATA_ROOT`(数据根)/ `MDCG_ROOT`(认知图根)
|
|
9
|
-
* 2. 用户可编辑配置
|
|
17
|
+
* 2. 用户可编辑配置 `paths.json` 的 `data_root` / `root`
|
|
18
|
+
* (位置:`<用户级状态根>/paths.json`;旧 `<插件仓>/data/paths.json` 兼容读)
|
|
10
19
|
* 3. 插件配置项 `mdcg.root`(可为空=未指定)
|
|
11
|
-
* 4. 默认
|
|
20
|
+
* 4. 默认 `<用户级状态根>/data/mdcg`
|
|
12
21
|
*
|
|
13
|
-
*
|
|
22
|
+
* 为什么默认不取「相对 cwd 的 data/mdcg」:
|
|
14
23
|
* node 侧插件与 python 侧脚本的 cwd 不同,相对路径会漂移成
|
|
15
24
|
* `<cwd>/data/mdcg`。历史事故:宿主 cwd 落在 AEIS 时,记忆真源
|
|
16
25
|
* 分裂到 `AEIS/data/mdcg`,与插件仓 `data/` 变成互不可见的两处。
|
|
17
|
-
*
|
|
26
|
+
*
|
|
27
|
+
* 旧数据接手:`migrateLegacyData()` 在默认数据根生效且旧包内位置仍有内容时
|
|
28
|
+
* 一次性**复制**(不删除、不覆盖)到用户级位置——见该函数注释。
|
|
18
29
|
*/
|
|
19
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
30
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs'
|
|
31
|
+
import { homedir, tmpdir } from 'node:os'
|
|
20
32
|
import { delimiter, dirname, isAbsolute, join, resolve } from 'node:path'
|
|
21
33
|
import { fileURLToPath } from 'node:url'
|
|
22
34
|
|
|
@@ -43,9 +55,56 @@ export function repoRoot(): string {
|
|
|
43
55
|
return cachedRepoRoot
|
|
44
56
|
}
|
|
45
57
|
|
|
46
|
-
|
|
58
|
+
export const ENV_STATE_ROOT = 'MDCG_STATE_ROOT'
|
|
59
|
+
|
|
60
|
+
let cachedStateRoot: string | null = null
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 用户级状态根(**插件包目录之外**):路径配置与默认数据根的落点。
|
|
64
|
+
* 优先级:`MDCG_STATE_ROOT` → `$DSH_HOME/.dsh-memory` → `~/.dsh/.dsh-memory`。
|
|
65
|
+
* `DSH_HOME` **未必**由宿主注入(本仓 `dsh/dsh-web-start.bat` 自行 set),
|
|
66
|
+
* 故家目录兜底;`~/.dsh` 是本插件既有约定(`bridge.ts` 调试日志同址)。
|
|
67
|
+
*/
|
|
68
|
+
export function stateRoot(): string {
|
|
69
|
+
if (cachedStateRoot) return cachedStateRoot
|
|
70
|
+
const env = process.env[ENV_STATE_ROOT]
|
|
71
|
+
if (env) {
|
|
72
|
+
cachedStateRoot = resolve(env)
|
|
73
|
+
return cachedStateRoot
|
|
74
|
+
}
|
|
75
|
+
const dshHome = process.env['DSH_HOME']
|
|
76
|
+
cachedStateRoot = dshHome
|
|
77
|
+
? join(resolve(dshHome), '.dsh-memory')
|
|
78
|
+
: join(homedir(), '.dsh', '.dsh-memory')
|
|
79
|
+
return cachedStateRoot
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** 旧版落点(插件包内 `data/`)——更新时会被整个替换,只作兼容读与迁移源。 */
|
|
83
|
+
export function legacyDataRoot(): string {
|
|
84
|
+
return join(repoRoot(), 'data')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function samePath(a: string, b: string): boolean {
|
|
88
|
+
return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 用户可编辑的路径配置文件:
|
|
93
|
+
* `<用户级状态根>/paths.json` → 不存在则回落**旧** `<插件仓>/data/paths.json`
|
|
94
|
+
* (兼容读)→ 都不存在返回新位置(首次写入时创建)。
|
|
95
|
+
* 不做自动复制:配置文件是「谁说了算」的唯一真源,悄悄复制会让旧件的后续编辑
|
|
96
|
+
* 静默失效——迁移只搬数据面,配置显式交给用户搬(或用 `set_user_root`)。
|
|
97
|
+
*/
|
|
47
98
|
export function pathsFile(): string {
|
|
48
|
-
|
|
99
|
+
const current = join(stateRoot(), 'paths.json')
|
|
100
|
+
if (existsSync(current)) return current
|
|
101
|
+
const legacy = join(legacyDataRoot(), 'paths.json')
|
|
102
|
+
return existsSync(legacy) ? legacy : current
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** 生效中的 paths.json 位置来源:`user`=用户级 / `legacy`=旧包内(兼容读)。 */
|
|
106
|
+
export function pathsFileSource(): 'user' | 'legacy' {
|
|
107
|
+
return samePath(dirname(pathsFile()), stateRoot()) ? 'user' : 'legacy'
|
|
49
108
|
}
|
|
50
109
|
|
|
51
110
|
function readUserPaths(): Record<string, unknown> {
|
|
@@ -63,8 +122,141 @@ function anchor(p: string): string {
|
|
|
63
122
|
return isAbsolute(p) ? p : resolve(repoRoot(), p)
|
|
64
123
|
}
|
|
65
124
|
|
|
125
|
+
/** 默认数据根 = 用户级状态根下 `data/`(**插件包目录之外**,更新不触碰)。 */
|
|
66
126
|
export function defaultDataRoot(): string {
|
|
67
|
-
return join(
|
|
127
|
+
return join(stateRoot(), 'data')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface LegacyMigration {
|
|
131
|
+
/** 是否真的搬了(false 时 `reason` 说明为何没搬)。 */
|
|
132
|
+
ran: boolean
|
|
133
|
+
reason: string
|
|
134
|
+
from: string
|
|
135
|
+
to: string
|
|
136
|
+
/** 复制成功的顶层条目数。 */
|
|
137
|
+
copied: number
|
|
138
|
+
/** 复制失败的顶层条目(权限/占用等,逐项吞掉不抛)。 */
|
|
139
|
+
failed: string[]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** dst 为「空目录」时 true(不存在/非目录/有内容均为 false)。 */
|
|
143
|
+
function isEmptyDir(p: string): boolean {
|
|
144
|
+
try {
|
|
145
|
+
return readdirSync(p).length === 0
|
|
146
|
+
} catch {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 一次性迁移:把旧版留在**插件包内** `data/` 的数据面复制到用户级默认数据根。
|
|
153
|
+
*
|
|
154
|
+
* 触发条件(三条同时满足,缺一不动):
|
|
155
|
+
* ① 数据根未被显式配置(env `MDCG_DATA_ROOT` / paths.json 的 `data_root` 都未设,
|
|
156
|
+
* 即 `dataRoot()` 恰为默认值)——显式配置是用户的决定,越权搬运等于改他的真源;
|
|
157
|
+
* ② 旧位置存在;
|
|
158
|
+
* ③ 目标顶层条目不存在或为空目录(**不覆盖、不合并**已有数据)。
|
|
159
|
+
*
|
|
160
|
+
* 只复制不删除(旧目录随后由 pnpm 更新自然移除);`paths.json` 不复制
|
|
161
|
+
* (配置走 `pathsFile()` 兼容读,复制会制造「哪个文件说了算」的两说)。
|
|
162
|
+
* 任何异常逐项吞掉并记入 `failed`——迁移是增益,不该成为启动失败源。
|
|
163
|
+
*
|
|
164
|
+
* 边界(如实):pnpm 更新是**先替换包目录再启动新代码**,故旧数据在升级瞬间
|
|
165
|
+
* 即已消失,本函数只能接手「旧位置那时仍在」的情形(手工安装、就地覆盖、
|
|
166
|
+
* 或包目录未被清理);已在升级中丢掉的数据无法由此恢复——发布说明须提示
|
|
167
|
+
* 0.4.8 及更早用户升级前备份 `<profile>/node_modules/<pkg>/data/`。
|
|
168
|
+
*/
|
|
169
|
+
export function migrateLegacyData(): LegacyMigration {
|
|
170
|
+
const from = legacyDataRoot()
|
|
171
|
+
const to = defaultDataRoot()
|
|
172
|
+
const out: LegacyMigration = { ran: false, reason: '', from, to, copied: 0, failed: [] }
|
|
173
|
+
if (!samePath(dataRoot(), to)) {
|
|
174
|
+
out.reason = '数据根为显式配置(env/paths.json),不迁移'
|
|
175
|
+
return out
|
|
176
|
+
}
|
|
177
|
+
if (!existsSync(from)) {
|
|
178
|
+
out.reason = '旧位置不存在(多为更新时已随包目录被替换)'
|
|
179
|
+
return out
|
|
180
|
+
}
|
|
181
|
+
let entries: string[]
|
|
182
|
+
try {
|
|
183
|
+
entries = readdirSync(from)
|
|
184
|
+
} catch {
|
|
185
|
+
out.reason = '旧位置不可读'
|
|
186
|
+
return out
|
|
187
|
+
}
|
|
188
|
+
const names = entries.filter((n) => n !== 'paths.json')
|
|
189
|
+
if (!names.length) {
|
|
190
|
+
out.reason = '旧位置无数据'
|
|
191
|
+
return out
|
|
192
|
+
}
|
|
193
|
+
for (const name of names) {
|
|
194
|
+
const src = join(from, name)
|
|
195
|
+
const dst = join(to, name)
|
|
196
|
+
// 新位置已有实质内容 → 跳过(宁可少搬,不可覆盖)
|
|
197
|
+
if (existsSync(dst) && !isEmptyDir(dst)) continue
|
|
198
|
+
try {
|
|
199
|
+
mkdirSync(to, { recursive: true })
|
|
200
|
+
cpSync(src, dst, { recursive: true, force: false, errorOnExist: false })
|
|
201
|
+
out.copied += 1
|
|
202
|
+
} catch {
|
|
203
|
+
out.failed.push(name)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
out.ran = out.copied > 0
|
|
207
|
+
if (!out.ran) out.reason = out.failed.length ? '目标不可写' : '新位置已有数据,未覆盖'
|
|
208
|
+
return out
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export const ENV_CHILD_CWD = 'MDCG_CHILD_CWD'
|
|
212
|
+
|
|
213
|
+
let cachedRunRoot: string | null = null
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* 子进程的工作目录(**必须落在插件包目录之外**)。
|
|
217
|
+
*
|
|
218
|
+
* 为什么不能沿用 `repoRoot()`:Windows 不允许删除/改名「正被某进程当作 CWD」
|
|
219
|
+
* 的目录。DSH 的插件按 hoisted 布局安装在 `<profile>/node_modules/<pkg>`,
|
|
220
|
+
* 而 `pnpm` 每次更新该包都要先 `rmdir` 包目录 → 子进程一旦把包目录当 CWD,
|
|
221
|
+
* 更新必然 `ERR_PNPM_EBUSY: resource busy or locked`(含升级回滚一起失败,
|
|
222
|
+
* 应用内永远升不动这个插件)。注意落点也**不能**是 `<包>/data`——它仍在包内,
|
|
223
|
+
* 实测同样 `err=32`。
|
|
224
|
+
*
|
|
225
|
+
* 落点要求「稳定存在」:进程 cwd 指向已消失的目录会引出新的怪问题,故按稳定度
|
|
226
|
+
* 排候选目录,取**第一个能建成**的:
|
|
227
|
+
* 1. `MDCG_CHILD_CWD`(显式覆盖)
|
|
228
|
+
* 2. `$DSH_HOME/.dsh-memory/run`
|
|
229
|
+
* 3. `~/.dsh/.dsh-memory/run` —— 家目录兜底:`DSH_HOME` **未必**由宿主注入
|
|
230
|
+
* (本仓 `dsh/dsh-web-start.bat` 是自行 `set DSH_HOME=%USERPROFILE%\.dsh`),
|
|
231
|
+
* 而 `~/.dsh` 是本插件既有约定(`bridge.ts` 调试日志、`token_store` 密钥环同址)
|
|
232
|
+
* 4. 系统临时目录(可能被清理,故排最后)
|
|
233
|
+
* 全部建不成时不抛错,交给 spawn 报错——cwd 落点只是防呆,不该成为启动失败源。
|
|
234
|
+
*
|
|
235
|
+
* 安全性:`python -m` 的模块解析由 `pythonPathValue()` 的 PYTHONPATH 独立保证,
|
|
236
|
+
* 不依赖 cwd;已实测 cwd=包目录 与 cwd=包外 时,MCP initialize 握手与
|
|
237
|
+
* tools/list 工具面(33 个工具)完全一致。
|
|
238
|
+
*/
|
|
239
|
+
export function runRoot(): string {
|
|
240
|
+
if (cachedRunRoot) return cachedRunRoot
|
|
241
|
+
const candidates: string[] = []
|
|
242
|
+
const override = process.env[ENV_CHILD_CWD]
|
|
243
|
+
if (override) candidates.push(resolve(override))
|
|
244
|
+
const dshHome = process.env['DSH_HOME']
|
|
245
|
+
if (dshHome) candidates.push(join(resolve(dshHome), '.dsh-memory', 'run'))
|
|
246
|
+
candidates.push(join(homedir(), '.dsh', '.dsh-memory', 'run'))
|
|
247
|
+
candidates.push(join(tmpdir(), 'dsh-memory-run'))
|
|
248
|
+
for (const dir of candidates) {
|
|
249
|
+
try {
|
|
250
|
+
mkdirSync(dir, { recursive: true })
|
|
251
|
+
cachedRunRoot = dir
|
|
252
|
+
return dir
|
|
253
|
+
} catch {
|
|
254
|
+
/* 该候选不可用(父目录只读等)→ 试下一个 */
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const last = candidates[candidates.length - 1] ?? tmpdir()
|
|
258
|
+
cachedRunRoot = last
|
|
259
|
+
return last
|
|
68
260
|
}
|
|
69
261
|
|
|
70
262
|
/** 数据根(记忆/账本/运行态的父目录)。 */
|
|
@@ -110,18 +302,24 @@ export function describeDataPaths(configured?: string): Record<string, string |
|
|
|
110
302
|
const dr = dataRoot()
|
|
111
303
|
const mr = mdcgRoot(configured)
|
|
112
304
|
const paths = readUserPaths()
|
|
113
|
-
|
|
305
|
+
const pfSource = pathsFileSource()
|
|
306
|
+
let source = 'default(用户级状态根 data/)'
|
|
114
307
|
if (process.env[ENV_DATA_ROOT]) source = `env:${ENV_DATA_ROOT}`
|
|
115
308
|
else if (process.env[ENV_MDCG_ROOT]) source = `env:${ENV_MDCG_ROOT}`
|
|
116
|
-
else if (typeof paths['data_root'] === 'string' || typeof paths['root'] === 'string')
|
|
117
|
-
|
|
309
|
+
else if (typeof paths['data_root'] === 'string' || typeof paths['root'] === 'string') {
|
|
310
|
+
source = pfSource === 'user' ? 'paths.json(用户级)' : 'paths.json(兼容读旧包内位置)'
|
|
311
|
+
} else if (configured && configured.trim()) source = 'config.mdcg.root'
|
|
118
312
|
return {
|
|
119
313
|
repoRoot: repoRoot(),
|
|
314
|
+
stateRoot: stateRoot(),
|
|
120
315
|
dataRoot: dr,
|
|
121
316
|
mdcgRoot: mr,
|
|
122
317
|
source,
|
|
123
318
|
pathsFile: pathsFile(),
|
|
124
|
-
|
|
319
|
+
pathsFileSource: pfSource,
|
|
320
|
+
isDefault: samePath(dr, defaultDataRoot()),
|
|
321
|
+
legacyDataRoot: legacyDataRoot(),
|
|
322
|
+
legacyDataExists: existsSync(legacyDataRoot()),
|
|
125
323
|
dataRootExists: existsSync(dr),
|
|
126
324
|
mdcgRootExists: existsSync(mr),
|
|
127
325
|
}
|
package/src/lib/mdcg_client.ts
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
import { delimiter } from 'node:path'
|
|
39
39
|
import { LingshuBridge, type McpCallResult } from '../bridge.js'
|
|
40
|
-
import { pythonPathValue,
|
|
40
|
+
import { pythonPathValue, runRoot } from './datapath.js'
|
|
41
41
|
|
|
42
42
|
/** md_cg 子进程与根目录配置。 */
|
|
43
43
|
export interface MdcgOptions {
|
|
@@ -47,9 +47,12 @@ export interface MdcgOptions {
|
|
|
47
47
|
args?: string[]
|
|
48
48
|
/** 认知图根目录(MDCG_ROOT)。 */
|
|
49
49
|
root: string
|
|
50
|
-
/** Python
|
|
51
|
-
*
|
|
52
|
-
*
|
|
50
|
+
/** Python 子进程工作目录,默认 `runRoot()`——**插件包目录之外**的稳定目录
|
|
51
|
+
* (issue #18:Windows 不允许删除/改名「正被某进程当作 cwd」的目录,
|
|
52
|
+
* cwd 落在包内会让 pnpm 更新本包必然 `ERR_PNPM_EBUSY` 且永不自愈)。
|
|
53
|
+
* 模块解析**不依赖 cwd**:`python -m` 靠 `PYTHONPATH`
|
|
54
|
+
* (见 `pythonPathValue()`)解析随包 md_cg,issue #12 口径不变。
|
|
55
|
+
* 显式传入本项时完全尊重原值。 */
|
|
53
56
|
cwd?: string
|
|
54
57
|
/** 调用主体标识(MDCG_ACTOR)。私有内容按 (tenant, actor) 派生 DEK,
|
|
55
58
|
* 故与迁移脚本 --actor 必须一致,否则读不到已迁移节点。 */
|
|
@@ -122,10 +125,11 @@ export class MdcgClient {
|
|
|
122
125
|
readonly bridge: LingshuBridge
|
|
123
126
|
|
|
124
127
|
constructor(opts: MdcgOptions) {
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
|
|
128
|
+
// 子进程 cwd 必须落在插件包目录之外,否则 pnpm 更新本插件时
|
|
129
|
+
// rmdir 包目录会撞上 Windows 的「目录被当作 CWD」共享冲突 → ERR_PNPM_EBUSY。
|
|
130
|
+
// 模块解析不依赖 cwd:PYTHONPATH(pythonPathValue())已锚定随包 md_cg;
|
|
131
|
+
// opts.env 显式提供 PYTHONPATH 时完全接管(其展开在最后)。详见 datapath.runRoot()。
|
|
132
|
+
const cwd = opts.cwd ?? runRoot()
|
|
129
133
|
const env: Record<string, string> = {
|
|
130
134
|
// ⚠️ 必须显式 utf-8:Windows 下 piped 子进程默认 gbk + surrogateescape,
|
|
131
135
|
// Node 写出的 UTF-8 中文会被解成孤立代理字符(\udcXX),md_cg 在落盘 /
|