chatlab-cli 0.36.2 → 0.37.1

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 (203) hide show
  1. package/dist/{chat-command-SEV6N3AR.mjs → chat-command-YAFRLHMQ.mjs} +15 -16
  2. package/dist/{chat-command-SEV6N3AR.mjs.map → chat-command-YAFRLHMQ.mjs.map} +1 -1
  3. package/dist/{chunk-6EZPD3XJ.mjs → chunk-2PY4XCH3.mjs} +6 -3
  4. package/dist/chunk-2PY4XCH3.mjs.map +1 -0
  5. package/dist/{chunk-HWIXK7SU.mjs → chunk-73TJ2S7W.mjs} +1643 -3
  6. package/dist/chunk-73TJ2S7W.mjs.map +1 -0
  7. package/dist/{chunk-YUH3H3QW.mjs → chunk-ARIBCH47.mjs} +96 -5
  8. package/dist/chunk-ARIBCH47.mjs.map +1 -0
  9. package/dist/{chunk-WRBFV2GX.mjs → chunk-FPVRSXQ4.mjs} +49 -55
  10. package/dist/chunk-FPVRSXQ4.mjs.map +1 -0
  11. package/dist/{chunk-VREVDZ4Q.mjs → chunk-GKCIRKOH.mjs} +1934 -35
  12. package/dist/chunk-GKCIRKOH.mjs.map +1 -0
  13. package/dist/{chunk-TJ3NOBVI.mjs → chunk-JWJREWVN.mjs} +119 -288
  14. package/dist/chunk-JWJREWVN.mjs.map +1 -0
  15. package/dist/{chunk-TWH422HC.mjs → chunk-MMTEGUQA.mjs} +3 -3
  16. package/dist/{chunk-VUYWUHWW.mjs → chunk-N4SB6QZV.mjs} +3 -3
  17. package/dist/chunk-N4SB6QZV.mjs.map +1 -0
  18. package/dist/{chunk-TRGR3KKJ.mjs → chunk-OTYNMDDL.mjs} +2643 -682
  19. package/dist/chunk-OTYNMDDL.mjs.map +1 -0
  20. package/dist/{chunk-CH5YAZ4Q.mjs → chunk-PDQV4RUA.mjs} +2 -2
  21. package/dist/{chunk-WJQOXOMR.mjs → chunk-UP6JIV3S.mjs} +285 -41
  22. package/dist/chunk-UP6JIV3S.mjs.map +1 -0
  23. package/dist/chunk-WDLO7OLX.mjs +101 -0
  24. package/dist/chunk-WDLO7OLX.mjs.map +1 -0
  25. package/dist/cli.mjs +9 -9
  26. package/dist/contacts-worker.mjs +2 -2
  27. package/dist/global-insight-worker.mjs +1 -1
  28. package/dist/{http-237XYNRT.mjs → http-LPFPVTBC.mjs} +12 -12
  29. package/dist/{import-R2E2TFAK.mjs → import-T4WX2ZJL.mjs} +7 -7
  30. package/dist/index.mjs +12 -12
  31. package/dist/{mcp-BED4AARV.mjs → mcp-SMF3NWIN.mjs} +8 -8
  32. package/dist/people-relationships-worker.mjs +2 -2
  33. package/dist/semantic-index-worker.mjs +1 -1
  34. package/dist/{src-AYMALWU5.mjs → src-EGLLMTAU.mjs} +44 -14
  35. package/dist/{stream-import-RXNSOOYH.mjs → stream-import-2BXJTTCE.mjs} +7 -7
  36. package/dist/{worker-runtime-JGAZU7MC.mjs → worker-runtime-RDLSPXFT.mjs} +5 -5
  37. package/dist-cli-web/assets/AISettingsTab-CEhrXlYR.js +1 -0
  38. package/dist-cli-web/assets/{AboutTab-DCM1-glA.js → AboutTab-Bbu0SsMM.js} +1 -1
  39. package/dist-cli-web/assets/ActionToolsPanel-DDNXXH8v.css +1 -0
  40. package/dist-cli-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-IB1yZxCE.js +75 -0
  41. package/dist-cli-web/assets/{Alert-D-egBWcb.js → Alert-510jTN3l.js} +1 -1
  42. package/dist-cli-web/assets/ApiSettingsTab-Bi1GRMN4.js +2 -0
  43. package/dist-cli-web/assets/BatchManageTab-DhnqMCSM.js +1 -0
  44. package/dist-cli-web/assets/{BufferResource-BE2_2bZK.js → BufferResource-CKZxnACp.js} +1 -1
  45. package/dist-cli-web/assets/{CanvasRenderer-DDKdvEYQ.js → CanvasRenderer-BeK5POBy.js} +1 -1
  46. package/dist-cli-web/assets/CardDecoration-RuBA3N2j.js +1 -0
  47. package/dist-cli-web/assets/ChatRecordDrawer-BY_-lIEj.js +1 -0
  48. package/dist-cli-web/assets/{ChatRecordWorkspace-DqUI4QiU.js → ChatRecordWorkspace-7prKd-Tq.js} +1 -1
  49. package/dist-cli-web/assets/Checkbox-_eH64bb0.js +1 -0
  50. package/dist-cli-web/assets/DataDirCleanupNotice-BHaXwlfr.js +1 -0
  51. package/dist-cli-web/assets/{DatePicker.vue_vue_type_script_setup_true_lang-sPDoPzZ9.js → DatePicker.vue_vue_type_script_setup_true_lang-D9Ul_GYz.js} +1 -1
  52. package/dist-cli-web/assets/{DebugToolsPanel-BIHA6jw4.js → DebugToolsPanel-ByKItGrS.js} +1 -1
  53. package/dist-cli-web/assets/EChart.vue_vue_type_script_setup_true_lang-DubnuUXI.js +1 -0
  54. package/dist-cli-web/assets/EChartBar.vue_vue_type_script_setup_true_lang-DKNCZuFm.js +1 -0
  55. package/dist-cli-web/assets/EChartLine.vue_vue_type_script_setup_true_lang-Fl7xAOSR.js +1 -0
  56. package/dist-cli-web/assets/EChartWordcloud-C6XM4KOX.js +1 -0
  57. package/dist-cli-web/assets/FileDropZone.vue_vue_type_script_setup_true_lang-DYDdRSNE.js +1 -0
  58. package/dist-cli-web/assets/{Filter-kO4dIDJ2.js → Filter-CByj_rCR.js} +1 -1
  59. package/dist-cli-web/assets/GlobalTaskBar-BdELjzrs.js +1 -0
  60. package/dist-cli-web/assets/GlobalTaskBar-haLzezqY.css +1 -0
  61. package/dist-cli-web/assets/GroupRelationshipGalaxyView-CnzPEgUS.js +1 -0
  62. package/dist-cli-web/assets/Label-DCIcxkhU.js +1 -0
  63. package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-BBcCt_Qm.js +1 -0
  64. package/dist-cli-web/assets/MessageExportModal-DNU16Bs8.js +1 -0
  65. package/dist-cli-web/assets/PageHeader-CKeZjNNR.js +1 -0
  66. package/dist-cli-web/assets/PageHeader-CPLgiKT8.css +1 -0
  67. package/dist-cli-web/assets/{PageTabs.vue_vue_type_script_setup_true_lang-Cgungbjl.js → PageTabs.vue_vue_type_script_setup_true_lang-C8M3wNNH.js} +1 -1
  68. package/dist-cli-web/assets/{RelationshipGalaxyCanvas-Cod1JX9m.js → RelationshipGalaxyCanvas-CDhljGyJ.js} +3 -3
  69. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-CkefzeFJ.js → RelationshipGalaxyThreeCanvas-BP8fsvvf.js} +1 -1
  70. package/dist-cli-web/assets/{RenderTargetSystem-SuQ7cbze.js → RenderTargetSystem-D76QrDT_.js} +1 -1
  71. package/dist-cli-web/assets/{RovingFocusItem-psoFYxrC.js → RovingFocusItem-BJMUQ5DJ.js} +1 -1
  72. package/dist-cli-web/assets/{ScreenCaptureModal-D4r9ixKh.js → ScreenCaptureModal-DkX4z-M1.js} +1 -1
  73. package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-qFhJO5B0.js +1 -0
  74. package/dist-cli-web/assets/Select-B5oJc5y1.js +1 -0
  75. package/dist-cli-web/assets/SettingsModal-BO-QKQ2h.js +2 -0
  76. package/dist-cli-web/assets/{StorageTab-DhSJ-0Ir.js → StorageTab-CPPXXaRm.js} +1 -1
  77. package/dist-cli-web/assets/Switch-CDk3LZ4_.js +1 -0
  78. package/dist-cli-web/assets/Tabs-BMq9wODW.js +1 -0
  79. package/dist-cli-web/assets/{Tabs-Bnm_Q7yW.js → Tabs-DqWTBV8x.js} +1 -1
  80. package/dist-cli-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-D2outEOV.js +1 -0
  81. package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-Cjz8Wpg-.js → TimeSelect.vue_vue_type_script_setup_true_lang-BcflxP_U.js} +1 -1
  82. package/dist-cli-web/assets/{VisuallyHiddenInput-Bo_XwaLu.js → VisuallyHiddenInput-BAFpkxMI.js} +1 -1
  83. package/dist-cli-web/assets/{WebGLRenderer-D1x9WZRj.js → WebGLRenderer-DjCPvR_O.js} +1 -1
  84. package/dist-cli-web/assets/{WebGPURenderer-37Nw-tLm.js → WebGPURenderer-C2B_u03z.js} +1 -1
  85. package/dist-cli-web/assets/aiChat--CR4g2M7.js +8 -0
  86. package/dist-cli-web/assets/base-F6s0vTrr.js +1 -0
  87. package/dist-cli-web/assets/{browserAll-CWrz_-4U.js → browserAll-DiUAZg4L.js} +1 -1
  88. package/dist-cli-web/assets/chatMessages-BGRbSlvD.css +1 -0
  89. package/dist-cli-web/assets/chatMessages-Bd33SSXI.js +147 -0
  90. package/dist-cli-web/assets/cli-web-DoibEdj2.js +1 -0
  91. package/dist-cli-web/assets/{fetch-CkXgOxcu.js → fetch-4nh1LaVF.js} +3 -3
  92. package/dist-cli-web/assets/fetch-7lUvXbhU.js +1 -0
  93. package/dist-cli-web/assets/{fetch-CFpLXWTe.js → fetch-BEaW1j5H.js} +1 -1
  94. package/dist-cli-web/assets/{fetch-CgA1peJD.js → fetch-B_YFABxI.js} +1 -1
  95. package/dist-cli-web/assets/{fetch-BGmCCyzz.js → fetch-BeX69kpS.js} +1 -1
  96. package/dist-cli-web/assets/{fetch-Du-wU0OO.js → fetch-CRocA-4C.js} +1 -1
  97. package/dist-cli-web/assets/{fetch-DPSWt6yX.js → fetch-CXM-cjDS.js} +1 -1
  98. package/dist-cli-web/assets/{fetch-qd2FgBWQ.js → fetch-CXqeAbnY.js} +1 -1
  99. package/dist-cli-web/assets/{fetch-6pcVxB9h.js → fetch-CxVcHNid.js} +1 -1
  100. package/dist-cli-web/assets/fetch-DBpDMy29.js +1 -0
  101. package/dist-cli-web/assets/{fetch-Gu4qQjUB.js → fetch-DKBBS9Op.js} +1 -1
  102. package/dist-cli-web/assets/{fetch-DZ6OF-xW.js → fetch-epFXmPIQ.js} +1 -1
  103. package/dist-cli-web/assets/{host-D8zlA62K.js → host-C4rU8pKA.js} +1 -1
  104. package/dist-cli-web/assets/{host-CWsAWKgy.js → host-CtSqR_Zm.js} +1 -1
  105. package/dist-cli-web/assets/{index-Dy0fRMDf.js → index-4DVZ2g0M.js} +10 -10
  106. package/dist-cli-web/assets/index-B1oj9KDv.js +135 -0
  107. package/dist-cli-web/assets/index-BFH1j_R9.js +1 -0
  108. package/dist-cli-web/assets/index-BZpR015e.css +1 -0
  109. package/dist-cli-web/assets/index-BgelKQTW.css +1 -0
  110. package/dist-cli-web/assets/{index-v6DlL4ue.js → index-BvMAw3Zd.js} +1 -1
  111. package/dist-cli-web/assets/index-C1A1FwpO.css +1 -0
  112. package/dist-cli-web/assets/index-CIIyg_o9.css +1 -0
  113. package/dist-cli-web/assets/index-CaYtkONV.js +64 -0
  114. package/dist-cli-web/assets/index-CuCQ1d9f.js +1 -0
  115. package/dist-cli-web/assets/index-D3Hyjv4e.js +137 -0
  116. package/dist-cli-web/assets/index-D8cHMqV-.js +2 -0
  117. package/dist-cli-web/assets/index-DlHuILT_.js +1 -0
  118. package/dist-cli-web/assets/index-R4LqAnx9.js +2 -0
  119. package/dist-cli-web/assets/index-_m1mf1jm.js +1 -0
  120. package/dist-cli-web/assets/{index-a7CT8DQm.js → index-ekvsNmfe.js} +1 -1
  121. package/dist-cli-web/assets/index-mXe1LssU.js +1 -0
  122. package/dist-cli-web/assets/index-mbLXPIyC.js +1 -0
  123. package/dist-cli-web/assets/{people-page-header-Czt9e1jv.js → people-page-header-BbYSSpsO.js} +1 -1
  124. package/dist-cli-web/assets/{prompt-DGazz143.js → prompt-C-ofJ7t_.js} +1 -1
  125. package/dist-cli-web/assets/{semantic-index-config-builder-BkFHzIUy.js → semantic-index-config-builder-D3TYVYC-.js} +1 -1
  126. package/dist-cli-web/assets/service-BYOUkk7V.js +1 -0
  127. package/dist-cli-web/assets/{service-CAp0YJoS.js → service-CppETV4a.js} +1 -1
  128. package/dist-cli-web/assets/service-tEx-5LUL.js +1 -0
  129. package/dist-cli-web/assets/useFormControl-CrWi_6Hn.js +1 -0
  130. package/dist-cli-web/assets/useTable-Clk7ecq-.js +1 -0
  131. package/dist-cli-web/assets/{useToast-YAHDkKDN.js → useToast-B5LaA6c-.js} +1 -1
  132. package/dist-cli-web/assets/{vendor-echarts-hTLhTs52.js → vendor-echarts-C9ugTmum.js} +1 -1
  133. package/dist-cli-web/assets/{vendor-echarts-wordcloud-B8CF_NgP.js → vendor-echarts-wordcloud-DNiU8Psq.js} +1 -1
  134. package/dist-cli-web/assets/{webworkerAll-CvSp2Y8j.js → webworkerAll-CyA4b4LT.js} +1 -1
  135. package/dist-cli-web/index.html +2 -2
  136. package/package.json +3 -3
  137. package/dist/chunk-6E46U4H2.mjs +0 -41
  138. package/dist/chunk-6E46U4H2.mjs.map +0 -1
  139. package/dist/chunk-6EZPD3XJ.mjs.map +0 -1
  140. package/dist/chunk-HWIXK7SU.mjs.map +0 -1
  141. package/dist/chunk-TJ3NOBVI.mjs.map +0 -1
  142. package/dist/chunk-TRGR3KKJ.mjs.map +0 -1
  143. package/dist/chunk-VREVDZ4Q.mjs.map +0 -1
  144. package/dist/chunk-VUYWUHWW.mjs.map +0 -1
  145. package/dist/chunk-WJQOXOMR.mjs.map +0 -1
  146. package/dist/chunk-WRBFV2GX.mjs.map +0 -1
  147. package/dist/chunk-YUH3H3QW.mjs.map +0 -1
  148. package/dist-cli-web/assets/AISettingsTab-VgI7PiJd.js +0 -1
  149. package/dist-cli-web/assets/ActionToolsPanel-BTGgwXVD.css +0 -1
  150. package/dist-cli-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-a7RMjjve.js +0 -112
  151. package/dist-cli-web/assets/ApiSettingsTab-Co3LWf1f.js +0 -2
  152. package/dist-cli-web/assets/BatchManageTab-2LrckmQm.js +0 -1
  153. package/dist-cli-web/assets/ChatRecordDrawer-DRhztqLG.js +0 -1
  154. package/dist-cli-web/assets/Checkbox-EfpQmv4A.js +0 -1
  155. package/dist-cli-web/assets/DataDirCleanupNotice-BYIiR58J.js +0 -1
  156. package/dist-cli-web/assets/EChart.vue_vue_type_script_setup_true_lang-DryMSoCz.js +0 -1
  157. package/dist-cli-web/assets/EChartBar.vue_vue_type_script_setup_true_lang-BdFW-hvt.js +0 -1
  158. package/dist-cli-web/assets/EChartLine.vue_vue_type_script_setup_true_lang-C69Kdw9X.js +0 -1
  159. package/dist-cli-web/assets/EChartWordcloud-DM7UEHdK.js +0 -1
  160. package/dist-cli-web/assets/GlobalTaskBar-BZS_h0zC.js +0 -1
  161. package/dist-cli-web/assets/GlobalTaskBar-COW_uBX6.css +0 -1
  162. package/dist-cli-web/assets/GroupRelationshipGalaxyView--WIaHx_F.js +0 -1
  163. package/dist-cli-web/assets/Label-CIuDXyeM.js +0 -1
  164. package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-B_7VHxTx.js +0 -1
  165. package/dist-cli-web/assets/MessageExportModal-BQsIpyxv.js +0 -1
  166. package/dist-cli-web/assets/PageHeader-DxhQHF_0.js +0 -1
  167. package/dist-cli-web/assets/PageHeader-XIXMTomn.css +0 -1
  168. package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-v_7aRBgM.js +0 -1
  169. package/dist-cli-web/assets/Select-CxurgslB.js +0 -1
  170. package/dist-cli-web/assets/SettingsModal-DBZucuf6.js +0 -2
  171. package/dist-cli-web/assets/Switch-3D81G6uV.js +0 -1
  172. package/dist-cli-web/assets/Tabs-DB603EEu.js +0 -1
  173. package/dist-cli-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BDTdkH5i.js +0 -1
  174. package/dist-cli-web/assets/aiChat-BCzYQeZq.js +0 -8
  175. package/dist-cli-web/assets/cli-web-C-8N0CJh.js +0 -1
  176. package/dist-cli-web/assets/fetch-B69OkB6B.js +0 -1
  177. package/dist-cli-web/assets/fetch-z9M9FcIC.js +0 -1
  178. package/dist-cli-web/assets/index-BGd4ZfhO.js +0 -2
  179. package/dist-cli-web/assets/index-BYZF1ngN.js +0 -1
  180. package/dist-cli-web/assets/index-BcuwlCin.css +0 -1
  181. package/dist-cli-web/assets/index-BnaLj2dx.css +0 -1
  182. package/dist-cli-web/assets/index-Bq5q3kSU.js +0 -36
  183. package/dist-cli-web/assets/index-CPR3jdC2.js +0 -137
  184. package/dist-cli-web/assets/index-D3AjvaOX.js +0 -1
  185. package/dist-cli-web/assets/index-DAitScUA.js +0 -1
  186. package/dist-cli-web/assets/index-DBSMWAJ0.js +0 -1
  187. package/dist-cli-web/assets/index-DTn9htw-.js +0 -64
  188. package/dist-cli-web/assets/index-DV_rWxcH.js +0 -1
  189. package/dist-cli-web/assets/index-DxhAGqYM.css +0 -1
  190. package/dist-cli-web/assets/index-I0mIcDpE.css +0 -1
  191. package/dist-cli-web/assets/index-onwNShRw.js +0 -2
  192. package/dist-cli-web/assets/service-BMqwB74f.js +0 -1
  193. package/dist-cli-web/assets/service-CUQ8iHdS.js +0 -1
  194. package/dist-cli-web/assets/useFormControl-DcSMUc2d.js +0 -1
  195. package/dist-cli-web/assets/useTable-Clmq3sge.js +0 -1
  196. /package/dist/{chunk-TWH422HC.mjs.map → chunk-MMTEGUQA.mjs.map} +0 -0
  197. /package/dist/{chunk-CH5YAZ4Q.mjs.map → chunk-PDQV4RUA.mjs.map} +0 -0
  198. /package/dist/{http-237XYNRT.mjs.map → http-LPFPVTBC.mjs.map} +0 -0
  199. /package/dist/{import-R2E2TFAK.mjs.map → import-T4WX2ZJL.mjs.map} +0 -0
  200. /package/dist/{mcp-BED4AARV.mjs.map → mcp-SMF3NWIN.mjs.map} +0 -0
  201. /package/dist/{src-AYMALWU5.mjs.map → src-EGLLMTAU.mjs.map} +0 -0
  202. /package/dist/{stream-import-RXNSOOYH.mjs.map → stream-import-2BXJTTCE.mjs.map} +0 -0
  203. /package/dist/{worker-runtime-JGAZU7MC.mjs.map → worker-runtime-RDLSPXFT.mjs.map} +0 -0
@@ -54,6 +54,7 @@ import {
54
54
  getChatLabTempScopeDir,
55
55
  getLocalProfileByModelId,
56
56
  getLocalProfilesForLocale,
57
+ hasUnmatchedFallbackOnlyMessage,
57
58
  isKeylessSemanticIndexApiBaseUrl,
58
59
  isSemanticIndexConfigured,
59
60
  isSemanticVoid,
@@ -68,32 +69,36 @@ import {
68
69
  semanticSearch,
69
70
  vecTableName,
70
71
  vecTableSchema
71
- } from "./chunk-VREVDZ4Q.mjs";
72
+ } from "./chunk-GKCIRKOH.mjs";
72
73
  import {
73
74
  CHATLAB_FORMAT_VERSION,
74
75
  DESENSITIZE_RULES_SCHEMA_VERSION,
75
76
  MEANINGFUL_POS_TAGS,
76
- POS_TAG_DEFINITIONS,
77
77
  StaticPathProvider,
78
78
  appLogger,
79
+ batchSegmentChineseWithStats,
80
+ batchSegmentWithFrequency,
79
81
  buildExcludeKeywordsConditions,
80
- cleanText,
82
+ clearJiebaInstance,
83
+ collectPosTagStats,
81
84
  detectConflictsInMessages,
82
85
  getCollidingPlatformIds,
83
86
  getCollidingPlatformIdsFromMessages,
87
+ getJieba,
84
88
  isStopword,
85
- isValidWord,
89
+ isSystemMessageContent,
86
90
  loadConfig,
87
91
  mergeMembers2 as mergeMembers,
88
92
  migrateFromElectronIfNeeded,
89
93
  normalizePlatformId,
90
94
  readJsonFile,
91
95
  resolveApiKey,
96
+ segment,
92
97
  snapshotPathProvider,
93
98
  withFileLock,
94
99
  writeConfigField,
95
100
  writeJsonFileAtomically
96
- } from "./chunk-TRGR3KKJ.mjs";
101
+ } from "./chunk-OTYNMDDL.mjs";
97
102
  import {
98
103
  __export
99
104
  } from "./chunk-VSOWNKPA.mjs";
@@ -559,220 +564,6 @@ function expandHome(filePath) {
559
564
  return filePath;
560
565
  }
561
566
 
562
- // ../../packages/node-runtime/src/nlp/segmenter.ts
563
- import * as fs3 from "fs";
564
- import * as path3 from "path";
565
- import { createRequire } from "module";
566
- var _nlpDir = null;
567
- var jiebaInstances = /* @__PURE__ */ new Map();
568
- var require2 = createRequire(import.meta.url);
569
- function initNlpDir(nlpDir) {
570
- _nlpDir = nlpDir;
571
- }
572
- function getNlpDir() {
573
- return _nlpDir;
574
- }
575
- function existsDictOnDisk(dictId) {
576
- if (!_nlpDir) return false;
577
- return fs3.existsSync(path3.join(_nlpDir, `${dictId}.dict`));
578
- }
579
- function tryLoadDictFromDisk(dictId) {
580
- if (!_nlpDir) return null;
581
- const dictPath = path3.join(_nlpDir, `${dictId}.dict`);
582
- if (!fs3.existsSync(dictPath)) return null;
583
- try {
584
- return fs3.readFileSync(dictPath);
585
- } catch {
586
- return null;
587
- }
588
- }
589
- function getJieba(dictType = "default") {
590
- const effectiveType = dictType === "default" ? "zh-CN" : dictType;
591
- const cached = jiebaInstances.get(effectiveType);
592
- if (cached) {
593
- if (cached.fromDiskDict === existsDictOnDisk(effectiveType)) return cached.instance;
594
- jiebaInstances.delete(effectiveType);
595
- console.error(`[NLP] jieba cache invalidated (dict ${cached.fromDiskDict ? "removed" : "added"}): ${effectiveType}`);
596
- }
597
- try {
598
- const { Jieba } = require2("@node-rs/jieba");
599
- let instance;
600
- const diskDict = tryLoadDictFromDisk(effectiveType);
601
- if (diskDict) {
602
- instance = Jieba.withDict(diskDict);
603
- console.error(`[NLP] jieba dict loaded: ${effectiveType} (${diskDict.length} bytes)`);
604
- } else {
605
- instance = new Jieba();
606
- console.warn(`[NLP] jieba dict missing: ${effectiveType}, fallback to built-in tokenizer`);
607
- }
608
- jiebaInstances.set(effectiveType, { instance, fromDiskDict: !!diskDict });
609
- return instance;
610
- } catch (error) {
611
- console.error(`[NLP] Failed to load jieba module (dict=${effectiveType}):`, error);
612
- throw new Error(`jieba \u6A21\u5757\u52A0\u8F7D\u5931\u8D25 (${effectiveType})`);
613
- }
614
- }
615
- function clearJiebaInstance(dictType) {
616
- jiebaInstances.delete(dictType);
617
- console.error(`[NLP] jieba instance cleared: ${dictType}`);
618
- }
619
- function segmentChinese(text, options = {}) {
620
- const { posFilterMode = "meaningful", customPosTags, dictType = "default" } = options;
621
- const cleaned = cleanText(text);
622
- if (!cleaned) return [];
623
- try {
624
- const jieba = getJieba(dictType);
625
- if (posFilterMode === "all") return jieba.cut(cleaned, false);
626
- const tagged = jieba.tag(cleaned);
627
- const allowedTags = posFilterMode === "custom" && customPosTags ? new Set(customPosTags) : MEANINGFUL_POS_TAGS;
628
- return tagged.filter((item) => allowedTags.has(item.tag)).map((item) => item.word);
629
- } catch (error) {
630
- console.error("[NLP] Chinese segmentation failed:", error);
631
- try {
632
- return getJieba("default").cut(cleanText(text), false);
633
- } catch {
634
- return cleaned.split("");
635
- }
636
- }
637
- }
638
- function segmentEnglish(text) {
639
- const cleaned = cleanText(text);
640
- if (!cleaned) return [];
641
- try {
642
- const segmenter = new Intl.Segmenter("en", { granularity: "word" });
643
- return [...segmenter.segment(cleaned)].filter((s) => s.isWordLike).map((s) => s.segment.toLowerCase());
644
- } catch {
645
- return cleaned.toLowerCase().split(/\s+/).filter((w) => w.length > 0);
646
- }
647
- }
648
- function segmentJapanese(text) {
649
- const cleaned = cleanText(text);
650
- if (!cleaned) return [];
651
- try {
652
- const segmenter = new Intl.Segmenter("ja", { granularity: "word" });
653
- return [...segmenter.segment(cleaned)].filter((s) => s.isWordLike).map((s) => s.segment);
654
- } catch {
655
- return cleaned.split("").filter((ch) => ch.trim().length > 0);
656
- }
657
- }
658
- function segment(text, locale, options = {}) {
659
- const {
660
- minLength,
661
- posFilterMode = "meaningful",
662
- customPosTags,
663
- enableStopwords = true,
664
- dictType = "default"
665
- } = options;
666
- const isChinese = locale.startsWith("zh");
667
- const isJapanese = locale === "ja-JP";
668
- const defaultMinLength = isChinese || isJapanese ? 2 : 3;
669
- const effectiveMinLength = minLength ?? defaultMinLength;
670
- let words;
671
- if (isChinese) {
672
- words = segmentChinese(text, { posFilterMode, customPosTags, dictType });
673
- } else if (isJapanese) {
674
- words = segmentJapanese(text);
675
- } else {
676
- words = segmentEnglish(text);
677
- }
678
- return words.filter((word) => isValidWord(word, locale, effectiveMinLength, enableStopwords, isStopword));
679
- }
680
- function batchSegmentWithFrequency(texts, locale, options = {}) {
681
- const {
682
- minLength,
683
- minCount = 2,
684
- topN = 100,
685
- posFilterMode,
686
- customPosTags,
687
- enableStopwords,
688
- dictType,
689
- excludeWords
690
- } = options;
691
- const wordFrequency = /* @__PURE__ */ new Map();
692
- const excludeSet = excludeWords?.length ? new Set(excludeWords.map((w) => w.toLowerCase())) : null;
693
- for (const text of texts) {
694
- const words = segment(text, locale, { minLength, posFilterMode, customPosTags, enableStopwords, dictType });
695
- for (const word of words) {
696
- if (excludeSet && excludeSet.has(word.toLowerCase())) continue;
697
- wordFrequency.set(word, (wordFrequency.get(word) || 0) + 1);
698
- }
699
- }
700
- const filtered = /* @__PURE__ */ new Map();
701
- let totalWords = 0;
702
- for (const [word, count] of wordFrequency) {
703
- if (count >= minCount) {
704
- filtered.set(word, count);
705
- totalWords += count;
706
- }
707
- }
708
- const sorted = [...filtered.entries()].sort((a, b) => b[1] - a[1]).slice(0, topN);
709
- return { words: new Map(sorted), uniqueWords: filtered.size, totalWords };
710
- }
711
- function batchSegmentChineseWithStats(texts, locale, options = {}) {
712
- const {
713
- minLength,
714
- minCount = 2,
715
- topN = 100,
716
- posFilterMode = "meaningful",
717
- customPosTags,
718
- enableStopwords = true,
719
- dictType = "default",
720
- excludeWords
721
- } = options;
722
- const effectiveMinLength = minLength ?? 2;
723
- const allowedTags = posFilterMode === "custom" && customPosTags ? new Set(customPosTags) : MEANINGFUL_POS_TAGS;
724
- const excludeSet = excludeWords?.length ? new Set(excludeWords.map((w) => w.toLowerCase())) : null;
725
- const wordFrequency = /* @__PURE__ */ new Map();
726
- const posTagStats = /* @__PURE__ */ new Map();
727
- try {
728
- const jieba = getJieba(dictType);
729
- for (const text of texts) {
730
- const cleaned = cleanText(text);
731
- if (!cleaned) continue;
732
- for (const { tag, word } of jieba.tag(cleaned)) {
733
- if (!isValidWord(word, locale, effectiveMinLength, enableStopwords, isStopword)) continue;
734
- posTagStats.set(tag, (posTagStats.get(tag) || 0) + 1);
735
- if (!allowedTags.has(tag)) continue;
736
- if (excludeSet && excludeSet.has(word.toLowerCase())) continue;
737
- wordFrequency.set(word, (wordFrequency.get(word) || 0) + 1);
738
- }
739
- }
740
- } catch (error) {
741
- console.error("[NLP] Chinese single-pass segmentation failed:", error);
742
- }
743
- const filtered = /* @__PURE__ */ new Map();
744
- let totalWords = 0;
745
- for (const [word, count] of wordFrequency) {
746
- if (count >= minCount) {
747
- filtered.set(word, count);
748
- totalWords += count;
749
- }
750
- }
751
- const sorted = [...filtered.entries()].sort((a, b) => b[1] - a[1]).slice(0, topN);
752
- return { words: new Map(sorted), uniqueWords: filtered.size, totalWords, posTagStats };
753
- }
754
- function collectPosTagStats(texts, minWordLength = 2, enableStopwords = true, dictType = "default") {
755
- const posStats = /* @__PURE__ */ new Map();
756
- try {
757
- const jieba = getJieba(dictType);
758
- for (const text of texts) {
759
- const cleaned = cleanText(text);
760
- if (!cleaned) continue;
761
- const tagged = jieba.tag(cleaned);
762
- for (const item of tagged) {
763
- if (!isValidWord(item.word, "zh-CN", minWordLength, enableStopwords, isStopword)) continue;
764
- posStats.set(item.tag, (posStats.get(item.tag) || 0) + 1);
765
- }
766
- }
767
- } catch (error) {
768
- console.error("[NLP] Failed to collect POS stats:", error);
769
- }
770
- return posStats;
771
- }
772
- function getPosTagDefinitions() {
773
- return POS_TAG_DEFINITIONS;
774
- }
775
-
776
567
  // ../../packages/node-runtime/src/jieba-nlp-provider.ts
777
568
  function createJiebaNlpProvider(dictType = "default") {
778
569
  return {
@@ -806,7 +597,7 @@ function buildMessageQuery(timeFilter, memberId, excludeKeywords) {
806
597
  params.push(...exclude.params);
807
598
  }
808
599
  conditions.push("COALESCE(m.account_name, '') != '\u7CFB\u7EDF\u6D88\u606F'");
809
- conditions.push("msg.type = 0");
600
+ conditions.push(`msg.type IN (${0 /* TEXT */}, ${5 /* EMOJI */})`);
810
601
  conditions.push("msg.content IS NOT NULL");
811
602
  conditions.push("TRIM(msg.content) != ''");
812
603
  return {
@@ -834,7 +625,11 @@ function computeWordFrequency(db, params) {
834
625
  if (messages.length === 0) {
835
626
  return { words: [], totalWords: 0, totalMessages: 0, uniqueWords: 0 };
836
627
  }
837
- const texts = messages.map((m) => m.content);
628
+ const analyzableMessages = messages.filter((message) => !isSystemMessageContent(message.content));
629
+ if (analyzableMessages.length === 0) {
630
+ return { words: [], totalWords: 0, totalMessages: 0, uniqueWords: 0 };
631
+ }
632
+ const texts = analyzableMessages.map((m) => m.content);
838
633
  const segmentOptions = {
839
634
  minLength: minWordLength,
840
635
  minCount,
@@ -868,7 +663,7 @@ function computeWordFrequency(db, params) {
868
663
  return {
869
664
  words,
870
665
  totalWords: result.totalWords,
871
- totalMessages: messages.length,
666
+ totalMessages: analyzableMessages.length,
872
667
  uniqueWords: result.uniqueWords,
873
668
  posTagStats
874
669
  };
@@ -878,8 +673,8 @@ function segmentText(text, locale, minLength) {
878
673
  }
879
674
 
880
675
  // ../../packages/node-runtime/src/nlp/dict-manager.ts
881
- import * as fs4 from "fs";
882
- import * as path4 from "path";
676
+ import * as fs3 from "fs";
677
+ import * as path3 from "path";
883
678
  import { createHash } from "crypto";
884
679
  var DICT_DOWNLOAD_URL_BASE = "https://chatlab.fun/assets/nlp";
885
680
  var DICT_SHA256 = {
@@ -891,19 +686,19 @@ var AVAILABLE_DICTS = [
891
686
  { id: "zh-TW", label: "\u7E41\u9AD4\u4E2D\u6587", locale: "zh-TW" }
892
687
  ];
893
688
  function getDictFilePath(nlpDir, dictId) {
894
- return path4.join(nlpDir, `${dictId}.dict`);
689
+ return path3.join(nlpDir, `${dictId}.dict`);
895
690
  }
896
691
  function isDictDownloaded(nlpDir, dictId) {
897
- return fs4.existsSync(getDictFilePath(nlpDir, dictId));
692
+ return fs3.existsSync(getDictFilePath(nlpDir, dictId));
898
693
  }
899
694
  function getDictList(nlpDir) {
900
695
  return AVAILABLE_DICTS.map((d) => {
901
696
  const filePath = getDictFilePath(nlpDir, d.id);
902
- const downloaded = fs4.existsSync(filePath);
697
+ const downloaded = fs3.existsSync(filePath);
903
698
  let fileSize;
904
699
  if (downloaded) {
905
700
  try {
906
- fileSize = fs4.statSync(filePath).size;
701
+ fileSize = fs3.statSync(filePath).size;
907
702
  } catch {
908
703
  }
909
704
  }
@@ -912,9 +707,9 @@ function getDictList(nlpDir) {
912
707
  }
913
708
  function loadDictBuffer(nlpDir, dictId) {
914
709
  const filePath = getDictFilePath(nlpDir, dictId);
915
- if (!fs4.existsSync(filePath)) return null;
710
+ if (!fs3.existsSync(filePath)) return null;
916
711
  try {
917
- return fs4.readFileSync(filePath);
712
+ return fs3.readFileSync(filePath);
918
713
  } catch (error) {
919
714
  console.error(`[NLP DictManager] Failed to read dict file: ${filePath}`, error);
920
715
  return null;
@@ -924,7 +719,7 @@ async function downloadDict(nlpDir, dictId, onProgress) {
924
719
  if (!AVAILABLE_DICTS.find((d) => d.id === dictId)) {
925
720
  return { success: false, error: `Unknown dict: ${dictId}` };
926
721
  }
927
- fs4.mkdirSync(nlpDir, { recursive: true });
722
+ fs3.mkdirSync(nlpDir, { recursive: true });
928
723
  const url = `${DICT_DOWNLOAD_URL_BASE}/${dictId}.dict`;
929
724
  const filePath = getDictFilePath(nlpDir, dictId);
930
725
  const tmpPath = filePath + ".tmp";
@@ -965,16 +760,16 @@ async function downloadDict(nlpDir, dictId, onProgress) {
965
760
  if (actualSha256 !== expectedSha256) {
966
761
  return { success: false, error: "Dictionary integrity check failed (SHA256 mismatch)" };
967
762
  }
968
- fs4.writeFileSync(tmpPath, buffer);
969
- if (fs4.existsSync(filePath)) fs4.unlinkSync(filePath);
970
- fs4.renameSync(tmpPath, filePath);
763
+ fs3.writeFileSync(tmpPath, buffer);
764
+ if (fs3.existsSync(filePath)) fs3.unlinkSync(filePath);
765
+ fs3.renameSync(tmpPath, filePath);
971
766
  clearJiebaInstance(dictId);
972
- console.log(`[NLP DictManager] Dict downloaded: ${dictId} (${fs4.statSync(filePath).size} bytes)`);
767
+ console.log(`[NLP DictManager] Dict downloaded: ${dictId} (${fs3.statSync(filePath).size} bytes)`);
973
768
  return { success: true };
974
769
  } catch (error) {
975
- if (fs4.existsSync(tmpPath)) {
770
+ if (fs3.existsSync(tmpPath)) {
976
771
  try {
977
- fs4.unlinkSync(tmpPath);
772
+ fs3.unlinkSync(tmpPath);
978
773
  } catch {
979
774
  }
980
775
  }
@@ -985,9 +780,9 @@ async function downloadDict(nlpDir, dictId, onProgress) {
985
780
  }
986
781
  function deleteDict(nlpDir, dictId) {
987
782
  const filePath = getDictFilePath(nlpDir, dictId);
988
- if (!fs4.existsSync(filePath)) return { success: true };
783
+ if (!fs3.existsSync(filePath)) return { success: true };
989
784
  try {
990
- fs4.unlinkSync(filePath);
785
+ fs3.unlinkSync(filePath);
991
786
  clearJiebaInstance(dictId);
992
787
  console.log(`[NLP DictManager] Dict deleted: ${dictId}`);
993
788
  return { success: true };
@@ -997,8 +792,20 @@ function deleteDict(nlpDir, dictId) {
997
792
  return { success: false, error: msg };
998
793
  }
999
794
  }
1000
- async function ensureDefaultDict(nlpDir) {
795
+ async function ensureDefaultDict(nlpDir, bundledDictDir) {
1001
796
  if (isDictDownloaded(nlpDir, "zh-CN")) return;
797
+ if (bundledDictDir) {
798
+ const bundledPath = getDictFilePath(bundledDictDir, "zh-CN");
799
+ if (fs3.existsSync(bundledPath)) {
800
+ fs3.mkdirSync(nlpDir, { recursive: true });
801
+ const filePath = getDictFilePath(nlpDir, "zh-CN");
802
+ const tmpPath = filePath + ".tmp";
803
+ fs3.copyFileSync(bundledPath, tmpPath);
804
+ fs3.renameSync(tmpPath, filePath);
805
+ console.log("[NLP DictManager] Installed bundled zh-CN dictionary");
806
+ return;
807
+ }
808
+ }
1002
809
  console.log("[NLP DictManager] zh-CN dict not found, starting background download...");
1003
810
  const result = await downloadDict(nlpDir, "zh-CN");
1004
811
  if (result.success) {
@@ -1009,8 +816,8 @@ async function ensureDefaultDict(nlpDir) {
1009
816
  }
1010
817
 
1011
818
  // ../../packages/node-runtime/src/preferences.ts
1012
- import * as fs5 from "fs";
1013
- import * as path5 from "path";
819
+ import * as fs4 from "fs";
820
+ import * as path4 from "path";
1014
821
  var DEFAULTS = {
1015
822
  pinnedSessionIds: [],
1016
823
  assistantUpgradeSkippedVersions: {},
@@ -1051,13 +858,13 @@ var PreferencesManager = class {
1051
858
  filePath;
1052
859
  cache = null;
1053
860
  constructor(systemDir) {
1054
- this.filePath = path5.join(systemDir, "preferences.json");
861
+ this.filePath = path4.join(systemDir, "preferences.json");
1055
862
  }
1056
863
  load() {
1057
864
  if (this.cache) return this.cache;
1058
865
  try {
1059
- if (fs5.existsSync(this.filePath)) {
1060
- const raw = fs5.readFileSync(this.filePath, "utf-8");
866
+ if (fs4.existsSync(this.filePath)) {
867
+ const raw = fs4.readFileSync(this.filePath, "utf-8");
1061
868
  const parsed = JSON.parse(raw);
1062
869
  const desensitizeMigration = this.migrateLegacyDesensitizeRules(parsed, raw);
1063
870
  const ownerMigration = this.migrateLegacyOwnerExclusions(desensitizeMigration.preferences);
@@ -1117,6 +924,7 @@ var PreferencesManager = class {
1117
924
  normalizeAiGlobalSettings(partial) {
1118
925
  const normalized = { ...partial ?? {} };
1119
926
  delete normalized.contextCompression;
927
+ delete normalized.allowProactiveMemory;
1120
928
  return { ...DEFAULTS.aiGlobalSettings, ...normalized };
1121
929
  }
1122
930
  normalizeAiPreprocessConfig(partial) {
@@ -1199,21 +1007,21 @@ var PreferencesManager = class {
1199
1007
  };
1200
1008
  }
1201
1009
  backupLegacyPreferences(rawContent) {
1202
- const backupDir = path5.join(path5.dirname(this.filePath), "backups");
1203
- if (!fs5.existsSync(backupDir)) {
1204
- fs5.mkdirSync(backupDir, { recursive: true });
1010
+ const backupDir = path4.join(path4.dirname(this.filePath), "backups");
1011
+ if (!fs4.existsSync(backupDir)) {
1012
+ fs4.mkdirSync(backupDir, { recursive: true });
1205
1013
  }
1206
1014
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1207
- const backupPath = path5.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`);
1208
- fs5.writeFileSync(backupPath, rawContent, "utf-8");
1015
+ const backupPath = path4.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`);
1016
+ fs4.writeFileSync(backupPath, rawContent, "utf-8");
1209
1017
  console.info(`[Preferences] Backed up legacy desensitize rules to ${backupPath}`);
1210
1018
  }
1211
1019
  writePreferences(preferences) {
1212
- const dir = path5.dirname(this.filePath);
1213
- if (!fs5.existsSync(dir)) {
1214
- fs5.mkdirSync(dir, { recursive: true });
1020
+ const dir = path4.dirname(this.filePath);
1021
+ if (!fs4.existsSync(dir)) {
1022
+ fs4.mkdirSync(dir, { recursive: true });
1215
1023
  }
1216
- fs5.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), "utf-8");
1024
+ fs4.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), "utf-8");
1217
1025
  }
1218
1026
  /**
1219
1027
  * Deep merge: arrays are replaced (not concatenated), objects are merged.
@@ -1261,6 +1069,31 @@ function createMessageIdNormalizer(scopes) {
1261
1069
  return `__chatlab_message_scope__${scopeIndexes.get(scope) ?? 0}__${encodeURIComponent(id)}`;
1262
1070
  };
1263
1071
  }
1072
+ function createFallbackOccurrenceTracker() {
1073
+ const maximumOccurrences = /* @__PURE__ */ new Map();
1074
+ const sourceOccurrences = /* @__PURE__ */ new Map();
1075
+ return (message, sourceIndex) => {
1076
+ if (message.platformMessageId) return false;
1077
+ const fallbackKey = generateFallbackMessageKey({
1078
+ timestamp: message.timestamp,
1079
+ senderPlatformId: message.senderPlatformId,
1080
+ type: message.type,
1081
+ content: message.content ?? null,
1082
+ replyToMessageId: message.replyToMessageId
1083
+ });
1084
+ let occurrences = sourceOccurrences.get(sourceIndex);
1085
+ if (!occurrences) {
1086
+ occurrences = /* @__PURE__ */ new Map();
1087
+ sourceOccurrences.set(sourceIndex, occurrences);
1088
+ }
1089
+ const occurrence = (occurrences.get(fallbackKey) ?? 0) + 1;
1090
+ occurrences.set(fallbackKey, occurrence);
1091
+ const previousMaximum = maximumOccurrences.get(fallbackKey) ?? 0;
1092
+ if (occurrence <= previousMaximum) return true;
1093
+ maximumOccurrences.set(fallbackKey, occurrence);
1094
+ return false;
1095
+ };
1096
+ }
1264
1097
  function createMessageScopeResolver(contexts) {
1265
1098
  const contextBySource = /* @__PURE__ */ new Map();
1266
1099
  const parents = /* @__PURE__ */ new Map();
@@ -1339,22 +1172,21 @@ function checkConflictsFromSources(dataSources) {
1339
1172
  const normalizeMessageId = createMessageIdNormalizer(
1340
1173
  preparedSources.map(({ sourceIndex }) => scopeResolver.resolve(sourceIndex))
1341
1174
  );
1342
- const dedupState = createMessageDedupState();
1175
+ const dedupState = createMessageDedupState([], [], [], { preserveFallbackMultiplicity: true });
1176
+ const isCoveredFallbackOccurrence = createFallbackOccurrenceTracker();
1343
1177
  let totalMessages = 0;
1344
1178
  for (const { msg, sourceIndex, platform } of allMessages) {
1345
1179
  const messageScope = scopeResolver.resolve(sourceIndex);
1346
1180
  const senderPlatformId = normalizePlatformId(msg.senderPlatformId, platform, collidingIds);
1347
- const duplicate = registerMessageAndCheckDuplicate(
1348
- {
1349
- platformMessageId: normalizeMessageId(msg.platformMessageId, messageScope),
1350
- timestamp: msg.timestamp,
1351
- senderPlatformId,
1352
- type: msg.type,
1353
- content: msg.content ?? null,
1354
- replyToMessageId: normalizeMessageId(msg.replyToMessageId, messageScope)
1355
- },
1356
- dedupState
1357
- );
1181
+ const dedupMessage = {
1182
+ platformMessageId: normalizeMessageId(msg.platformMessageId, messageScope),
1183
+ timestamp: msg.timestamp,
1184
+ senderPlatformId,
1185
+ type: msg.type,
1186
+ content: msg.content ?? null,
1187
+ replyToMessageId: normalizeMessageId(msg.replyToMessageId, messageScope)
1188
+ };
1189
+ const duplicate = isCoveredFallbackOccurrence(dedupMessage, sourceIndex) || registerMessageAndCheckDuplicate(dedupMessage, dedupState);
1358
1190
  if (!duplicate) totalMessages++;
1359
1191
  }
1360
1192
  return { ...result, totalMessages };
@@ -1398,7 +1230,8 @@ function buildMergedOutput(dataSources, outputName) {
1398
1230
  const normalizeMessageId = createMessageIdNormalizer(
1399
1231
  metas.map(({ sourceIndex }) => scopeResolver.resolve(sourceIndex))
1400
1232
  );
1401
- const dedupState = createMessageDedupState();
1233
+ const dedupState = createMessageDedupState([], [], [], { preserveFallbackMultiplicity: true });
1234
+ const isCoveredFallbackOccurrence = createFallbackOccurrenceTracker();
1402
1235
  const fallbackOnlyMessageIndexes = /* @__PURE__ */ new Map();
1403
1236
  const mergedMessages = [];
1404
1237
  for (const { source, meta, sourceIndex } of metas) {
@@ -1418,15 +1251,17 @@ function buildMergedOutput(dataSources, outputName) {
1418
1251
  replyToMessageId
1419
1252
  };
1420
1253
  const fallbackKey = generateFallbackMessageKey(dedupMessage);
1254
+ if (isCoveredFallbackOccurrence(dedupMessage, sourceIndex)) continue;
1421
1255
  const shouldBackfillId = Boolean(
1422
- platformMessageId && !dedupState.platformMessageIds.has(platformMessageId) && dedupState.fallbackOnlyKeys.has(fallbackKey)
1256
+ platformMessageId && !dedupState.platformMessageIds.has(platformMessageId) && hasUnmatchedFallbackOnlyMessage(dedupState, fallbackKey)
1423
1257
  );
1424
1258
  if (registerMessageAndCheckDuplicate(dedupMessage, dedupState)) {
1425
1259
  if (shouldBackfillId) {
1426
- const retainedIndex2 = fallbackOnlyMessageIndexes.get(fallbackKey);
1260
+ const retainedIndexes = fallbackOnlyMessageIndexes.get(fallbackKey);
1261
+ const retainedIndex2 = retainedIndexes?.shift();
1427
1262
  if (retainedIndex2 !== void 0) {
1428
1263
  mergedMessages[retainedIndex2].platformMessageId = platformMessageId;
1429
- fallbackOnlyMessageIndexes.delete(fallbackKey);
1264
+ if (retainedIndexes?.length === 0) fallbackOnlyMessageIndexes.delete(fallbackKey);
1430
1265
  }
1431
1266
  }
1432
1267
  continue;
@@ -1442,7 +1277,11 @@ function buildMergedOutput(dataSources, outputName) {
1442
1277
  content: msg.content,
1443
1278
  replyToMessageId
1444
1279
  });
1445
- if (!platformMessageId) fallbackOnlyMessageIndexes.set(fallbackKey, retainedIndex);
1280
+ if (!platformMessageId) {
1281
+ const retainedIndexes = fallbackOnlyMessageIndexes.get(fallbackKey) ?? [];
1282
+ retainedIndexes.push(retainedIndex);
1283
+ fallbackOnlyMessageIndexes.set(fallbackKey, retainedIndexes);
1284
+ }
1446
1285
  }
1447
1286
  });
1448
1287
  }
@@ -1495,7 +1334,7 @@ function* serializeChatLabToJsonl(data) {
1495
1334
  }
1496
1335
 
1497
1336
  // ../../packages/node-runtime/src/services/analytics.ts
1498
- import * as path6 from "path";
1337
+ import * as path5 from "path";
1499
1338
  import { randomUUID as randomUUID2 } from "crypto";
1500
1339
  var DEFAULT_DATA = {
1501
1340
  lastReportDate: null,
@@ -1607,7 +1446,7 @@ var AnalyticsService = class {
1607
1446
  // Daily-active deduplication is intentionally process-local unless concurrent runtimes become supported.
1608
1447
  dailyActivePromise = null;
1609
1448
  constructor(systemDir, options) {
1610
- this.dataPath = path6.join(systemDir, "analytics.json");
1449
+ this.dataPath = path5.join(systemDir, "analytics.json");
1611
1450
  this.options = {
1612
1451
  ...options,
1613
1452
  umami: options.umami ?? getUmamiConfigFromEnv()
@@ -1769,8 +1608,8 @@ var AnalyticsService = class {
1769
1608
  };
1770
1609
 
1771
1610
  // ../../packages/node-runtime/src/services/demo-import.ts
1772
- import * as fs6 from "fs";
1773
- import * as path7 from "path";
1611
+ import * as fs5 from "fs";
1612
+ import * as path6 from "path";
1774
1613
  var DEMO_BASE_URL = "https://chatlab.fun/assets/demo";
1775
1614
  var DEMO_FILES = ["demo-group.json", "demo-private-B-wukong.json"];
1776
1615
  async function importDemoSessions(options) {
@@ -1802,8 +1641,8 @@ async function importDemoSessions(options) {
1802
1641
  }
1803
1642
  const rebased = rebaseChatLabDemoDocuments(downloaded, options.now?.() ?? /* @__PURE__ */ new Date(), options.targetTimeZone);
1804
1643
  const localPaths = rebased.documents.map((document, index) => {
1805
- const localPath = path7.join(createdTempDir, DEMO_FILES[index]);
1806
- fs6.writeFileSync(localPath, document, "utf8");
1644
+ const localPath = path6.join(createdTempDir, DEMO_FILES[index]);
1645
+ fs5.writeFileSync(localPath, document, "utf8");
1807
1646
  return localPath;
1808
1647
  });
1809
1648
  appLogger.info("demo-import", "Demo timeline prepared", {
@@ -1914,7 +1753,7 @@ __export(semantic_index_exports, {
1914
1753
  });
1915
1754
 
1916
1755
  // ../../packages/node-runtime/src/semantic-index/worker-client.ts
1917
- import path8 from "path";
1756
+ import path7 from "path";
1918
1757
 
1919
1758
  // ../../packages/node-runtime/src/semantic-index/worker-thread-transport.ts
1920
1759
  import { Worker } from "worker_threads";
@@ -2296,7 +2135,7 @@ function createSemanticIndexWorkerClient(options) {
2296
2135
  }
2297
2136
  function createSemanticIndexWorkerRuntimeClient(options) {
2298
2137
  const configStore = new SemanticIndexConfigStore(
2299
- path8.join(options.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)
2138
+ path7.join(options.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)
2300
2139
  );
2301
2140
  return createSemanticIndexWorkerClient({
2302
2141
  configStore,
@@ -2351,14 +2190,6 @@ export {
2351
2190
  NodePathProvider,
2352
2191
  getDefaultNodeUserDataDir,
2353
2192
  getSystemLogsDir,
2354
- initNlpDir,
2355
- getNlpDir,
2356
- getJieba,
2357
- clearJiebaInstance,
2358
- segment,
2359
- batchSegmentWithFrequency,
2360
- collectPosTagStats,
2361
- getPosTagDefinitions,
2362
2193
  createJiebaNlpProvider,
2363
2194
  computeWordFrequency,
2364
2195
  segmentText,
@@ -2377,4 +2208,4 @@ export {
2377
2208
  createSemanticIndexWorkerRuntimeClient,
2378
2209
  semantic_index_exports
2379
2210
  };
2380
- //# sourceMappingURL=chunk-TJ3NOBVI.mjs.map
2211
+ //# sourceMappingURL=chunk-JWJREWVN.mjs.map