chatlab-cli 0.36.1 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/dist/{chat-command-XPJ43KSW.mjs → chat-command-WBAJBKIE.mjs} +15 -16
  2. package/dist/{chat-command-XPJ43KSW.mjs.map → chat-command-WBAJBKIE.mjs.map} +1 -1
  3. package/dist/chunk-2TV7M4CC.mjs +101 -0
  4. package/dist/chunk-2TV7M4CC.mjs.map +1 -0
  5. package/dist/{chunk-Q3NEL2KK.mjs → chunk-4J4MA3RC.mjs} +2606 -671
  6. package/dist/chunk-4J4MA3RC.mjs.map +1 -0
  7. package/dist/{chunk-NFTCEJBJ.mjs → chunk-5YOHLJFB.mjs} +98 -284
  8. package/dist/chunk-5YOHLJFB.mjs.map +1 -0
  9. package/dist/{chunk-L7TIIVAY.mjs → chunk-CR2MU7LN.mjs} +49 -55
  10. package/dist/chunk-CR2MU7LN.mjs.map +1 -0
  11. package/dist/{chunk-2JPFBIAG.mjs → chunk-DKIYHA3O.mjs} +284 -31
  12. package/dist/chunk-DKIYHA3O.mjs.map +1 -0
  13. package/dist/{chunk-FJOGBUXU.mjs → chunk-DQR2YS3I.mjs} +1930 -33
  14. package/dist/chunk-DQR2YS3I.mjs.map +1 -0
  15. package/dist/{chunk-JOVL7OTW.mjs → chunk-EJBBVLUN.mjs} +3 -3
  16. package/dist/chunk-EJBBVLUN.mjs.map +1 -0
  17. package/dist/{chunk-X2QBH24F.mjs → chunk-FM3GXNEO.mjs} +1643 -3
  18. package/dist/chunk-FM3GXNEO.mjs.map +1 -0
  19. package/dist/{chunk-R73XMAB2.mjs → chunk-MSMDLDPB.mjs} +96 -5
  20. package/dist/chunk-MSMDLDPB.mjs.map +1 -0
  21. package/dist/{chunk-NQHZPSW2.mjs → chunk-N2WGG3MS.mjs} +2 -2
  22. package/dist/{chunk-67HNPYZJ.mjs → chunk-RXMSZIYD.mjs} +3 -3
  23. package/dist/{chunk-5MJO4AJB.mjs → chunk-SQWN4GTQ.mjs} +2 -2
  24. package/dist/cli.mjs +9 -9
  25. package/dist/contacts-worker.mjs +2 -2
  26. package/dist/global-insight-worker.mjs +1 -1
  27. package/dist/{http-5RVY5J5U.mjs → http-X6OEOOSH.mjs} +12 -12
  28. package/dist/{import-ILTWVHKU.mjs → import-WBJ6YIQ7.mjs} +7 -7
  29. package/dist/index.mjs +12 -12
  30. package/dist/{mcp-Y2YXOFB4.mjs → mcp-FR6OKWKL.mjs} +8 -8
  31. package/dist/people-relationships-worker.mjs +2 -2
  32. package/dist/semantic-index-worker.mjs +1 -1
  33. package/dist/{src-OV5ZNE3Z.mjs → src-WE5HNN2O.mjs} +44 -14
  34. package/dist/{stream-import-XOUM3Z5W.mjs → stream-import-YYQVZDGQ.mjs} +7 -7
  35. package/dist/{worker-runtime-JNGURHDM.mjs → worker-runtime-YGB5ZDE4.mjs} +5 -5
  36. package/dist-cli-web/assets/AISettingsTab-Co2sM1iY.js +1 -0
  37. package/dist-cli-web/assets/{AboutTab-CxI8zJNz.js → AboutTab-DQ8r6mYE.js} +1 -1
  38. package/dist-cli-web/assets/ActionToolsPanel-CmYpw8Mt.css +1 -0
  39. package/dist-cli-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang--RPlmfIu.js +75 -0
  40. package/dist-cli-web/assets/{Alert-_MYcI_E2.js → Alert-DU1tLAAg.js} +1 -1
  41. package/dist-cli-web/assets/ApiSettingsTab-D5g5b79L.js +2 -0
  42. package/dist-cli-web/assets/BatchManageTab-BFUyVaGU.js +1 -0
  43. package/dist-cli-web/assets/{BufferResource-i64DlwQT.js → BufferResource-C-RfYwQW.js} +1 -1
  44. package/dist-cli-web/assets/{CanvasRenderer-B76mEt9A.js → CanvasRenderer-Dz7JAMrR.js} +1 -1
  45. package/dist-cli-web/assets/CardDecoration-D28DI1G9.js +1 -0
  46. package/dist-cli-web/assets/ChatRecordDrawer-Cph819yY.js +1 -0
  47. package/dist-cli-web/assets/{ChatRecordWorkspace-CyfPIlIy.js → ChatRecordWorkspace-BAfERdPc.js} +1 -1
  48. package/dist-cli-web/assets/Checkbox-B8uqt13j.js +1 -0
  49. package/dist-cli-web/assets/DataDirCleanupNotice-3sGBE5vU.js +1 -0
  50. package/dist-cli-web/assets/{DatePicker.vue_vue_type_script_setup_true_lang-DqNBNa1D.js → DatePicker.vue_vue_type_script_setup_true_lang-CQuub8-f.js} +1 -1
  51. package/dist-cli-web/assets/{DebugToolsPanel-CbNsD9co.js → DebugToolsPanel-Cwkr0BOY.js} +1 -1
  52. package/dist-cli-web/assets/EChart.vue_vue_type_script_setup_true_lang-BuLujQCF.js +1 -0
  53. package/dist-cli-web/assets/EChartBar.vue_vue_type_script_setup_true_lang-DuA5xbcC.js +1 -0
  54. package/dist-cli-web/assets/EChartLine.vue_vue_type_script_setup_true_lang-CvmMEfYq.js +1 -0
  55. package/dist-cli-web/assets/EChartWordcloud-CHVtyPR7.js +1 -0
  56. package/dist-cli-web/assets/FileDropZone.vue_vue_type_script_setup_true_lang-BKPy9Qv-.js +1 -0
  57. package/dist-cli-web/assets/{Filter-yxkeHO78.js → Filter-CMfRHIoK.js} +1 -1
  58. package/dist-cli-web/assets/GlobalTaskBar-Jz6MASCu.js +1 -0
  59. package/dist-cli-web/assets/GlobalTaskBar-haLzezqY.css +1 -0
  60. package/dist-cli-web/assets/GroupRelationshipGalaxyView-Ch4obfEq.js +1 -0
  61. package/dist-cli-web/assets/Label-CuryuymO.js +1 -0
  62. package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-CoeQsaiL.js +1 -0
  63. package/dist-cli-web/assets/MessageExportModal-JqGZ-iLr.js +1 -0
  64. package/dist-cli-web/assets/PageHeader-CPLgiKT8.css +1 -0
  65. package/dist-cli-web/assets/PageHeader-D4up77TB.js +1 -0
  66. package/dist-cli-web/assets/{PageTabs.vue_vue_type_script_setup_true_lang-_j82asQU.js → PageTabs.vue_vue_type_script_setup_true_lang-DYQRFk9s.js} +1 -1
  67. package/dist-cli-web/assets/{RelationshipGalaxyCanvas-BODk18aA.js → RelationshipGalaxyCanvas-Cn7Eta5U.js} +3 -3
  68. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-BJyuRiC-.js → RelationshipGalaxyThreeCanvas-LlaX57z6.js} +1 -1
  69. package/dist-cli-web/assets/{RenderTargetSystem-CVMvAUSv.js → RenderTargetSystem-JhA2PUFi.js} +1 -1
  70. package/dist-cli-web/assets/{RovingFocusItem-DC_06OmN.js → RovingFocusItem-DHaiTb4j.js} +1 -1
  71. package/dist-cli-web/assets/{ScreenCaptureModal-DrBFDOtC.js → ScreenCaptureModal-Bxhyt5g1.js} +1 -1
  72. package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-BlAje3Tf.js +1 -0
  73. package/dist-cli-web/assets/Select-Beeqv0wU.js +1 -0
  74. package/dist-cli-web/assets/SettingsModal-DV8yDBJs.js +2 -0
  75. package/dist-cli-web/assets/{StorageTab-B0ebN0f8.js → StorageTab-B7GHadia.js} +1 -1
  76. package/dist-cli-web/assets/Switch-u4zlvUMa.js +1 -0
  77. package/dist-cli-web/assets/{Tabs-N3Q-Mpqi.js → Tabs-B7-Koq3x.js} +1 -1
  78. package/dist-cli-web/assets/Tabs-RWKHwtfM.js +1 -0
  79. package/dist-cli-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-ndsa3-aT.js +1 -0
  80. package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-Ccunouyf.js → TimeSelect.vue_vue_type_script_setup_true_lang-DKa1flT-.js} +1 -1
  81. package/dist-cli-web/assets/{VisuallyHiddenInput-OAJEt_Y5.js → VisuallyHiddenInput-DGDqcvUy.js} +1 -1
  82. package/dist-cli-web/assets/{WebGLRenderer-DuUeftYD.js → WebGLRenderer-ifvgA1fe.js} +1 -1
  83. package/dist-cli-web/assets/{WebGPURenderer-DoWQxiWZ.js → WebGPURenderer-DwzmuWF0.js} +1 -1
  84. package/dist-cli-web/assets/aiChat-BY4C3UQe.js +8 -0
  85. package/dist-cli-web/assets/base-BWDX-164.js +1 -0
  86. package/dist-cli-web/assets/{browserAll-Cb-mtR2y.js → browserAll-CSIIETeE.js} +1 -1
  87. package/dist-cli-web/assets/chatMessages--r0obAVw.css +1 -0
  88. package/dist-cli-web/assets/chatMessages-Zywjea1n.js +147 -0
  89. package/dist-cli-web/assets/cli-web-BRY49NWe.js +1 -0
  90. package/dist-cli-web/assets/{fetch-BbcFaCRB.js → fetch-Bf4cqeM3.js} +1 -1
  91. package/dist-cli-web/assets/{fetch-B-6tyYWu.js → fetch-BiXab0IF.js} +1 -1
  92. package/dist-cli-web/assets/{fetch-DEub4tOo.js → fetch-C8CcoTWY.js} +1 -1
  93. package/dist-cli-web/assets/{fetch-Qs38Hx1V.js → fetch-Co2vLmiE.js} +1 -1
  94. package/dist-cli-web/assets/{fetch-DLTlYnDB.js → fetch-D3nLtFBi.js} +1 -1
  95. package/dist-cli-web/assets/{fetch-BkA_so1e.js → fetch-DNSDHSqQ.js} +1 -1
  96. package/dist-cli-web/assets/{fetch-sYDJ-Zs8.js → fetch-DeHqF6yL.js} +1 -1
  97. package/dist-cli-web/assets/{fetch-B4PYy5JS.js → fetch-jx1VdM9j.js} +3 -3
  98. package/dist-cli-web/assets/{fetch-CW2fKvGp.js → fetch-mYSeL4Ki.js} +1 -1
  99. package/dist-cli-web/assets/fetch-qBaUXqFt.js +1 -0
  100. package/dist-cli-web/assets/{fetch-BzXuAaT3.js → fetch-r6mhEGrP.js} +1 -1
  101. package/dist-cli-web/assets/{fetch-AvsnJLWJ.js → fetch-wzv71PYy.js} +1 -1
  102. package/dist-cli-web/assets/{host-DYIkQqvY.js → host-1emQf9_4.js} +1 -1
  103. package/dist-cli-web/assets/{host-B6SQ6OGo.js → host-jXJHyyOX.js} +1 -1
  104. package/dist-cli-web/assets/index-2dJCozDq.js +64 -0
  105. package/dist-cli-web/assets/index-6ejRbH3h.js +2 -0
  106. package/dist-cli-web/assets/index-B4mJkX_d.js +1 -0
  107. package/dist-cli-web/assets/index-B7biznha.js +1 -0
  108. package/dist-cli-web/assets/index-BOcFyPCa.js +1 -0
  109. package/dist-cli-web/assets/index-BQ463TS7.js +1 -0
  110. package/dist-cli-web/assets/index-BZpR015e.css +1 -0
  111. package/dist-cli-web/assets/index-BgelKQTW.css +1 -0
  112. package/dist-cli-web/assets/index-C1A1FwpO.css +1 -0
  113. package/dist-cli-web/assets/index-CIIyg_o9.css +1 -0
  114. package/dist-cli-web/assets/{index-CShh95fU.js → index-CYc_VLgK.js} +1 -1
  115. package/dist-cli-web/assets/index-ClHMs0-a.js +2 -0
  116. package/dist-cli-web/assets/{index-D64XYYts.js → index-Cw0IhKZ6.js} +10 -10
  117. package/dist-cli-web/assets/{index-C_OS8Y8W.js → index-DOqbUvhA.js} +1 -1
  118. package/dist-cli-web/assets/index-DnpnIyle.js +135 -0
  119. package/dist-cli-web/assets/index-LV9LfFNu.js +1 -0
  120. package/dist-cli-web/assets/index-kePiJ3ca.js +137 -0
  121. package/dist-cli-web/assets/index-slDUxib2.js +1 -0
  122. package/dist-cli-web/assets/{people-page-header-0jvXFFnh.js → people-page-header-Cx5r9Bk2.js} +1 -1
  123. package/dist-cli-web/assets/{prompt-BPYj29Vq.js → prompt-BggEDxxi.js} +1 -1
  124. package/dist-cli-web/assets/{semantic-index-config-builder-vO37z355.js → semantic-index-config-builder-1sO0aEc1.js} +1 -1
  125. package/dist-cli-web/assets/{service-D29Vftq9.js → service-Bvq1fRkC.js} +1 -1
  126. package/dist-cli-web/assets/service-DkPheDt8.js +1 -0
  127. package/dist-cli-web/assets/service-DvI8O_7K.js +1 -0
  128. package/dist-cli-web/assets/useFormControl-B0aShtLp.js +1 -0
  129. package/dist-cli-web/assets/useTable-DC7oxmBl.js +1 -0
  130. package/dist-cli-web/assets/{useToast-BA0EwImD.js → useToast-CCPBE-Sy.js} +1 -1
  131. package/dist-cli-web/assets/{vendor-echarts-hTLhTs52.js → vendor-echarts-C9ugTmum.js} +1 -1
  132. package/dist-cli-web/assets/{vendor-echarts-wordcloud-B8CF_NgP.js → vendor-echarts-wordcloud-DNiU8Psq.js} +1 -1
  133. package/dist-cli-web/assets/{webworkerAll-ZPE_yGnC.js → webworkerAll-FCJk6reG.js} +1 -1
  134. package/dist-cli-web/index.html +2 -2
  135. package/package.json +1 -1
  136. package/dist/chunk-2JPFBIAG.mjs.map +0 -1
  137. package/dist/chunk-6QP47LID.mjs +0 -41
  138. package/dist/chunk-6QP47LID.mjs.map +0 -1
  139. package/dist/chunk-FJOGBUXU.mjs.map +0 -1
  140. package/dist/chunk-JOVL7OTW.mjs.map +0 -1
  141. package/dist/chunk-L7TIIVAY.mjs.map +0 -1
  142. package/dist/chunk-NFTCEJBJ.mjs.map +0 -1
  143. package/dist/chunk-Q3NEL2KK.mjs.map +0 -1
  144. package/dist/chunk-R73XMAB2.mjs.map +0 -1
  145. package/dist/chunk-X2QBH24F.mjs.map +0 -1
  146. package/dist-cli-web/assets/AISettingsTab-vvjijrc5.js +0 -1
  147. package/dist-cli-web/assets/ActionToolsPanel-Dp-ojXjO.css +0 -1
  148. package/dist-cli-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-w0hHEodr.js +0 -110
  149. package/dist-cli-web/assets/ApiSettingsTab-CK7U6dVA.js +0 -2
  150. package/dist-cli-web/assets/BatchManageTab-1WnEqqpB.js +0 -1
  151. package/dist-cli-web/assets/ChatRecordDrawer-Bp6OSCrz.js +0 -1
  152. package/dist-cli-web/assets/Checkbox-Ci7IeRw1.js +0 -1
  153. package/dist-cli-web/assets/DataDirCleanupNotice-Dh63pOLt.js +0 -1
  154. package/dist-cli-web/assets/EChart.vue_vue_type_script_setup_true_lang-YeqmodwE.js +0 -1
  155. package/dist-cli-web/assets/EChartBar.vue_vue_type_script_setup_true_lang-C3pZmq0v.js +0 -1
  156. package/dist-cli-web/assets/EChartLine.vue_vue_type_script_setup_true_lang-Co6olfwv.js +0 -1
  157. package/dist-cli-web/assets/EChartWordcloud-rDusZwSq.js +0 -1
  158. package/dist-cli-web/assets/GlobalTaskBar-BlZ-fFiq.js +0 -1
  159. package/dist-cli-web/assets/GlobalTaskBar-COW_uBX6.css +0 -1
  160. package/dist-cli-web/assets/GroupRelationshipGalaxyView-BXQBX0zJ.js +0 -1
  161. package/dist-cli-web/assets/Label-CFAZFBQX.js +0 -1
  162. package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-CwgpqtMZ.js +0 -1
  163. package/dist-cli-web/assets/MessageExportModal-DU71grc7.js +0 -1
  164. package/dist-cli-web/assets/PageHeader-BDPf4NuI.js +0 -1
  165. package/dist-cli-web/assets/PageHeader-XIXMTomn.css +0 -1
  166. package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-C-Zj2biH.js +0 -1
  167. package/dist-cli-web/assets/Select-DLK2LYhO.js +0 -1
  168. package/dist-cli-web/assets/SettingsModal-DqaR4Dx5.js +0 -2
  169. package/dist-cli-web/assets/Switch-CokhQWxm.js +0 -1
  170. package/dist-cli-web/assets/Tabs-D1UiZNaZ.js +0 -1
  171. package/dist-cli-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-OT-I0mbU.js +0 -1
  172. package/dist-cli-web/assets/aiChat-CdADfRnU.js +0 -8
  173. package/dist-cli-web/assets/cli-web-BHQCZLLg.js +0 -1
  174. package/dist-cli-web/assets/fetch-ul8-uQIb.js +0 -1
  175. package/dist-cli-web/assets/index--IEkRjKe.js +0 -64
  176. package/dist-cli-web/assets/index-9iaY_EWG.js +0 -1
  177. package/dist-cli-web/assets/index-B4J99zv3.css +0 -1
  178. package/dist-cli-web/assets/index-BBeqtL8d.css +0 -1
  179. package/dist-cli-web/assets/index-BnaLj2dx.css +0 -1
  180. package/dist-cli-web/assets/index-C7omDgiJ.js +0 -2
  181. package/dist-cli-web/assets/index-CHsM84U1.js +0 -2
  182. package/dist-cli-web/assets/index-CL8u01Pf.js +0 -137
  183. package/dist-cli-web/assets/index-DrCc8p_I.css +0 -1
  184. package/dist-cli-web/assets/index-UpTe1KzQ.js +0 -1
  185. package/dist-cli-web/assets/index-a8Hw6eD8.js +0 -1
  186. package/dist-cli-web/assets/index-jwjzZNKm.js +0 -1
  187. package/dist-cli-web/assets/index-pkxlF8Ee.js +0 -1
  188. package/dist-cli-web/assets/index-sWxuTsa7.js +0 -36
  189. package/dist-cli-web/assets/service-CVoA9yNf.js +0 -1
  190. package/dist-cli-web/assets/service-DMysyLCa.js +0 -1
  191. package/dist-cli-web/assets/useFormControl-DVawP2DO.js +0 -1
  192. package/dist-cli-web/assets/useTable-Bv3R_Hux.js +0 -1
  193. /package/dist/{chunk-NQHZPSW2.mjs.map → chunk-N2WGG3MS.mjs.map} +0 -0
  194. /package/dist/{chunk-67HNPYZJ.mjs.map → chunk-RXMSZIYD.mjs.map} +0 -0
  195. /package/dist/{chunk-5MJO4AJB.mjs.map → chunk-SQWN4GTQ.mjs.map} +0 -0
  196. /package/dist/{http-5RVY5J5U.mjs.map → http-X6OEOOSH.mjs.map} +0 -0
  197. /package/dist/{import-ILTWVHKU.mjs.map → import-WBJ6YIQ7.mjs.map} +0 -0
  198. /package/dist/{mcp-Y2YXOFB4.mjs.map → mcp-FR6OKWKL.mjs.map} +0 -0
  199. /package/dist/{src-OV5ZNE3Z.mjs.map → src-WE5HNN2O.mjs.map} +0 -0
  200. /package/dist/{stream-import-XOUM3Z5W.mjs.map → stream-import-YYQVZDGQ.mjs.map} +0 -0
  201. /package/dist/{worker-runtime-JNGURHDM.mjs.map → worker-runtime-YGB5ZDE4.mjs.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../packages/node-runtime/src/services/contacts/facts-cache.ts","../../../packages/node-runtime/src/services/contacts/time-range.ts","../../../packages/node-runtime/src/services/contacts/compute.ts"],"sourcesContent":["import { ChatType, type ChatPlatform, type ContactsTimeRangeState } from '@openchatlab/shared-types'\nimport type { ContactMemberRef } from '@openchatlab/core'\nimport { getCache, setCache, deleteSessionCache } from '../../cache/session-cache'\n\nexport const CONTACTS_FACTS_FORMAT_VERSION = 1\n\nexport interface ContactsFactsCacheStats {\n latestHits: number\n latestMisses: number\n factsHits: number\n factsMisses: number\n writes: number\n}\n\nexport interface ContactsSessionMetaFacts {\n name: string\n platform: ChatPlatform\n type: ChatType.PRIVATE | ChatType.GROUP\n ownerId: string | null\n}\n\nexport interface ContactsCachedPrivateFacts {\n contact: ContactMemberRef\n privateMessageCount: number\n activeMonths: string[]\n lastMessageTs: number | null\n}\n\nexport interface ContactsCachedGroupFacts {\n contact: ContactMemberRef\n messageCount: number\n coOccurrenceCount: number\n coOccurrenceRawScore: number\n replyInteractionCount: number\n repliesFromOwnerToContact: number\n repliesFromContactToOwner: number\n lastInteractionTs: number | null\n}\n\nexport type ContactsSessionFacts =\n | { kind: 'not_chat_db'; latestMessageTs: null }\n | { kind: 'missing_meta'; latestMessageTs: number | null }\n | { kind: 'unsupported_type'; latestMessageTs: number | null }\n | { kind: 'missing_owner'; meta: ContactsSessionMetaFacts; latestMessageTs: number | null }\n | { kind: 'unresolved_owner'; meta: ContactsSessionMetaFacts; latestMessageTs: number | null }\n | { kind: 'private_missing'; meta: ContactsSessionMetaFacts; latestMessageTs: number | null }\n | { kind: 'private_ambiguous'; meta: ContactsSessionMetaFacts; latestMessageTs: number | null }\n | {\n kind: 'private'\n meta: ContactsSessionMetaFacts\n latestMessageTs: number | null\n facts: ContactsCachedPrivateFacts\n }\n | {\n kind: 'group'\n meta: ContactsSessionMetaFacts\n latestMessageTs: number | null\n facts: ContactsCachedGroupFacts[]\n }\n\nexport interface ContactsSessionLatestFacts {\n latestMessageTs: number | null\n}\n\nexport type ContactsCacheReadResult<T> = { hit: true; data: T } | { hit: false }\n\ninterface VersionedContactsCacheEntry<T> {\n v: string\n data: T\n}\n\nexport function createEmptyContactsFactsCacheStats(): ContactsFactsCacheStats {\n return {\n latestHits: 0,\n latestMisses: 0,\n factsHits: 0,\n factsMisses: 0,\n writes: 0,\n }\n}\n\nexport function buildContactsSessionLatestCacheKey(algorithmVersion: string): string {\n return `contacts:latest:v${CONTACTS_FACTS_FORMAT_VERSION}:${algorithmVersion}`\n}\n\nexport function buildContactsSessionFactsCacheKey(algorithmVersion: string, timeRange: ContactsTimeRangeState): string {\n return [\n 'contacts:facts',\n `v${CONTACTS_FACTS_FORMAT_VERSION}`,\n algorithmVersion,\n `preset:${timeRange.preset}`,\n `start:${timeRange.startTs ?? 'all'}`,\n ].join(':')\n}\n\nexport function readCachedContactsSessionLatest(\n sessionId: string,\n cacheDir: string,\n key: string,\n dbVersion: string\n): ContactsCacheReadResult<ContactsSessionLatestFacts> {\n const cached = getCache<VersionedContactsCacheEntry<ContactsSessionLatestFacts>>(sessionId, key, cacheDir)\n if (!cached || cached.v !== dbVersion || !isContactsSessionLatestFacts(cached.data)) return { hit: false }\n return { hit: true, data: cached.data }\n}\n\nexport function writeCachedContactsSessionLatest(\n sessionId: string,\n cacheDir: string,\n key: string,\n dbVersion: string,\n data: ContactsSessionLatestFacts\n): void {\n setCache<VersionedContactsCacheEntry<ContactsSessionLatestFacts>>(sessionId, key, { v: dbVersion, data }, cacheDir)\n}\n\nexport function readCachedContactsSessionFacts(\n sessionId: string,\n cacheDir: string,\n key: string,\n dbVersion: string\n): ContactsCacheReadResult<ContactsSessionFacts> {\n const cached = getCache<VersionedContactsCacheEntry<ContactsSessionFacts>>(sessionId, key, cacheDir)\n if (!cached || cached.v !== dbVersion || !isContactsSessionFacts(cached.data)) return { hit: false }\n return { hit: true, data: cached.data }\n}\n\nexport function writeCachedContactsSessionFacts(\n sessionId: string,\n cacheDir: string,\n key: string,\n dbVersion: string,\n data: ContactsSessionFacts\n): void {\n setCache<VersionedContactsCacheEntry<ContactsSessionFacts>>(sessionId, key, { v: dbVersion, data }, cacheDir)\n}\n\nexport function deleteContactsSessionFactsCache(sessionId: string, cacheDir: string): void {\n deleteSessionCache(sessionId, cacheDir)\n}\n\nfunction isContactsSessionLatestFacts(value: unknown): value is ContactsSessionLatestFacts {\n return isObject(value) && isNullableNumber(value.latestMessageTs)\n}\n\nfunction isContactsSessionFacts(value: unknown): value is ContactsSessionFacts {\n if (!isObject(value) || typeof value.kind !== 'string' || !isNullableNumber(value.latestMessageTs)) return false\n switch (value.kind) {\n case 'not_chat_db':\n case 'missing_meta':\n case 'unsupported_type':\n return true\n case 'missing_owner':\n case 'unresolved_owner':\n case 'private_missing':\n case 'private_ambiguous':\n return isContactsSessionMetaFacts(value.meta)\n case 'private':\n return isContactsSessionMetaFacts(value.meta) && isContactsCachedPrivateFacts(value.facts)\n case 'group':\n return (\n isContactsSessionMetaFacts(value.meta) &&\n Array.isArray(value.facts) &&\n value.facts.every(isContactsCachedGroupFacts)\n )\n default:\n return false\n }\n}\n\nfunction isContactsSessionMetaFacts(value: unknown): value is ContactsSessionMetaFacts {\n return (\n isObject(value) &&\n typeof value.name === 'string' &&\n typeof value.platform === 'string' &&\n (value.type === ChatType.PRIVATE || value.type === ChatType.GROUP) &&\n (typeof value.ownerId === 'string' || value.ownerId === null)\n )\n}\n\nfunction isContactsCachedPrivateFacts(value: unknown): value is ContactsCachedPrivateFacts {\n return (\n isObject(value) &&\n isContactMemberRef(value.contact) &&\n isFiniteNumber(value.privateMessageCount) &&\n Array.isArray(value.activeMonths) &&\n value.activeMonths.every((month) => typeof month === 'string') &&\n isNullableNumber(value.lastMessageTs)\n )\n}\n\nfunction isContactsCachedGroupFacts(value: unknown): value is ContactsCachedGroupFacts {\n return (\n isObject(value) &&\n isContactMemberRef(value.contact) &&\n isFiniteNumber(value.messageCount) &&\n isFiniteNumber(value.coOccurrenceCount) &&\n isFiniteNumber(value.coOccurrenceRawScore) &&\n isFiniteNumber(value.replyInteractionCount) &&\n isFiniteNumber(value.repliesFromOwnerToContact) &&\n isFiniteNumber(value.repliesFromContactToOwner) &&\n isNullableNumber(value.lastInteractionTs)\n )\n}\n\nfunction isContactMemberRef(value: unknown): value is ContactMemberRef {\n return (\n isObject(value) &&\n isFiniteNumber(value.id) &&\n typeof value.platformId === 'string' &&\n typeof value.name === 'string' &&\n Array.isArray(value.aliases) &&\n value.aliases.every((alias) => typeof alias === 'string') &&\n (typeof value.avatar === 'string' || value.avatar === null)\n )\n}\n\nfunction isNullableNumber(value: unknown): value is number | null {\n return value === null || isFiniteNumber(value)\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value)\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n","import {\n CONTACTS_TIME_RANGE_PRESETS,\n type ContactsTimeRangePreset,\n type ContactsTimeRangeState,\n} from '@openchatlab/shared-types'\n\nconst SECONDS_PER_YEAR = 365 * 24 * 60 * 60\nconst DEFAULT_CONTACTS_TIME_RANGE_PRESET: ContactsTimeRangePreset = '1y'\n\nconst YEARS_BY_PRESET: Partial<Record<ContactsTimeRangePreset, number>> = {\n '1y': 1,\n '2y': 2,\n '3y': 3,\n '5y': 5,\n}\n\nexport function normalizeContactsTimeRangePreset(value: unknown): ContactsTimeRangePreset {\n return CONTACTS_TIME_RANGE_PRESETS.includes(value as ContactsTimeRangePreset)\n ? (value as ContactsTimeRangePreset)\n : DEFAULT_CONTACTS_TIME_RANGE_PRESET\n}\n\nexport function resolveContactsTimeRange(\n presetInput: unknown,\n anchorTs: number | null | undefined\n): ContactsTimeRangeState {\n const preset = normalizeContactsTimeRangePreset(presetInput)\n const normalizedAnchor = typeof anchorTs === 'number' ? anchorTs : null\n const years = YEARS_BY_PRESET[preset]\n\n return {\n preset,\n anchorTs: normalizedAnchor,\n startTs: normalizedAnchor !== null && years ? normalizedAnchor - years * SECONDS_PER_YEAR : null,\n }\n}\n","import { ChatType } from '@openchatlab/shared-types'\nimport type {\n ChatPlatform,\n ContactItem,\n ContactsDiagnostics,\n ContactsTimeRangePreset,\n ContactsTimeRangeState,\n ContactSourceSession,\n} from '@openchatlab/shared-types'\nimport {\n buildContactKey,\n computeFriendScores,\n computeNonFriendScores,\n getGroupContactFacts,\n getLatestContactMessageTs,\n getPrivateContactFacts,\n getSessionMeta,\n isChatSessionDb,\n resolveOwnerMember,\n shouldScopeContactToSession,\n shouldEnableContactsEntry,\n} from '@openchatlab/core'\nimport type { ContactMemberRef, SessionMeta } from '@openchatlab/core'\nimport { getDbFileVersion } from '../../cache/analytics-cache'\nimport { appLogger } from '../../logging/app-logger'\nimport type { SessionRuntimeAdapter } from '../adapters'\nimport {\n buildContactsSessionFactsCacheKey,\n buildContactsSessionLatestCacheKey,\n createEmptyContactsFactsCacheStats,\n readCachedContactsSessionFacts,\n readCachedContactsSessionLatest,\n writeCachedContactsSessionFacts,\n writeCachedContactsSessionLatest,\n type ContactsCachedGroupFacts,\n type ContactsCachedPrivateFacts,\n type ContactsFactsCacheStats,\n type ContactsSessionFacts,\n type ContactsSessionLatestFacts,\n type ContactsSessionMetaFacts,\n} from './facts-cache'\nimport { resolveContactsTimeRange } from './time-range'\n\nexport const CONTACTS_ALGORITHM_VERSION = 'contacts-v2'\n\nexport interface ContactsWorkerStats {\n durationMs: number\n totalSessions: number\n processedSessions: number\n skippedFailedSessions: number\n}\n\nexport interface ContactsSnapshot {\n contacts: ContactItem[]\n diagnostics: ContactsDiagnostics\n algorithmVersion: string\n signature: string\n timeRange: ContactsTimeRangeState\n computedAt: number\n workerStats: ContactsWorkerStats\n}\n\nexport interface ContactsComputeProgress {\n processedSessions: number\n totalSessions: number\n currentSessionId?: string\n}\n\nexport interface ComputeContactsSnapshotOptions {\n adapter: SessionRuntimeAdapter\n signature: string\n timeRangePreset?: ContactsTimeRangePreset\n factsCacheDir?: string\n now?: () => number\n onProgress?: (progress: ContactsComputeProgress) => void\n}\n\ninterface ContactAccumulator {\n key: string\n platform: ChatPlatform\n platformId: string\n sessionScoped: boolean\n sessionId?: string\n displayName: string\n aliases: Set<string>\n avatar: string | null\n isFriend: boolean\n privateMessageCount: number\n activePrivateMonths: Set<string>\n commonGroupSessionIds: Set<string>\n coOccurrenceCount: number\n coOccurrenceRawScore: number\n replyInteractionCount: number\n repliesFromOwnerToContact: number\n repliesFromContactToOwner: number\n sourceSessions: ContactSourceSession[]\n lastInteractionTs: number | null\n}\n\ninterface BuildContactsResult {\n contacts: ContactItem[]\n diagnostics: ContactsDiagnostics\n}\n\ninterface ContactsFactsCacheContext {\n dir: string\n latestKey: string\n stats: ContactsFactsCacheStats\n}\n\nexport function computeContactsSnapshot(options: ComputeContactsSnapshotOptions): ContactsSnapshot {\n const startedAt = options.now?.() ?? Date.now()\n const sessionIds = options.adapter.listSessionIds()\n const factsCache = options.factsCacheDir ? createFactsCacheContext(options.factsCacheDir) : null\n const timeRange = resolveContactsTimeRange(\n options.timeRangePreset,\n findGlobalLatestMessageTs(options.adapter, sessionIds, factsCache)\n )\n const result = computeContacts({\n adapter: options.adapter,\n sessionIds,\n timeRange,\n factsCache,\n onProgress: options.onProgress,\n })\n const finishedAt = options.now?.() ?? Date.now()\n if (factsCache) {\n appLogger.info('contacts', 'contacts session facts cache summary', factsCache.stats)\n }\n return {\n ...result,\n algorithmVersion: CONTACTS_ALGORITHM_VERSION,\n signature: options.signature,\n timeRange,\n computedAt: finishedAt,\n workerStats: {\n durationMs: Math.max(0, finishedAt - startedAt),\n totalSessions: sessionIds.length,\n processedSessions: sessionIds.length,\n skippedFailedSessions: result.diagnostics.skippedFailedSessions,\n },\n }\n}\n\nfunction computeContacts(options: {\n adapter: SessionRuntimeAdapter\n sessionIds: string[]\n timeRange: ContactsTimeRangeState\n factsCache: ContactsFactsCacheContext | null\n onProgress?: (progress: ContactsComputeProgress) => void\n}): BuildContactsResult {\n const diagnostics = createEmptyDiagnostics()\n const accumulators = new Map<string, ContactAccumulator>()\n let processedSessions = 0\n let activeGroupSessionCount = 0\n\n for (const sessionId of options.sessionIds) {\n options.onProgress?.({ processedSessions, totalSessions: options.sessionIds.length, currentSessionId: sessionId })\n try {\n const facts = getSessionFacts(options.adapter, sessionId, options.timeRange, options.factsCache)\n if (applySessionFacts(accumulators, diagnostics, sessionId, facts)) activeGroupSessionCount++\n } catch (error) {\n diagnostics.skippedFailedSessions++\n appLogger.error('contacts', `failed to process contact session: ${sessionId}`, error)\n } finally {\n processedSessions++\n options.onProgress?.({ processedSessions, totalSessions: options.sessionIds.length, currentSessionId: sessionId })\n }\n }\n\n diagnostics.contactsEnabled = shouldEnableContactsEntry({\n privateSessionCount: diagnostics.activePrivateSessionCount,\n groupSessionCount: activeGroupSessionCount,\n })\n const contacts = buildContactItems([...accumulators.values()])\n return { contacts, diagnostics }\n}\n\nfunction findGlobalLatestMessageTs(\n adapter: SessionRuntimeAdapter,\n sessionIds: string[],\n factsCache: ContactsFactsCacheContext | null\n): number | null {\n let latest: number | null = null\n for (const sessionId of sessionIds) {\n const dbVersion = getSessionDbVersion(adapter, sessionId)\n const cached = readLatestFacts(sessionId, factsCache, dbVersion)\n if (cached) {\n if (cached.latestMessageTs !== null) latest = Math.max(latest ?? 0, cached.latestMessageTs)\n continue\n }\n try {\n const db = adapter.openReadonly(sessionId)\n const ts = db && isChatSessionDb(db) ? getLatestContactMessageTs(db) : null\n writeLatestFacts(adapter, sessionId, factsCache, { latestMessageTs: ts }, dbVersion)\n if (ts !== null) latest = Math.max(latest ?? 0, ts)\n } catch (error) {\n appLogger.error('contacts', `failed to inspect contact session range: ${sessionId}`, error)\n }\n }\n return latest\n}\n\nfunction getSessionFacts(\n adapter: SessionRuntimeAdapter,\n sessionId: string,\n timeRange: ContactsTimeRangeState,\n factsCache: ContactsFactsCacheContext | null\n): ContactsSessionFacts {\n const dbVersion = getSessionDbVersion(adapter, sessionId)\n const cached = readSessionFacts(sessionId, timeRange, factsCache, dbVersion)\n if (cached) return cached\n\n const facts = computeSessionFacts(adapter, sessionId, timeRange)\n writeSessionFacts(adapter, sessionId, timeRange, factsCache, facts, dbVersion)\n return facts\n}\n\nfunction computeSessionFacts(\n adapter: SessionRuntimeAdapter,\n sessionId: string,\n timeRange: ContactsTimeRangeState\n): ContactsSessionFacts {\n const db = adapter.openReadonly(sessionId)\n if (!db || !isChatSessionDb(db)) return { kind: 'not_chat_db', latestMessageTs: null }\n\n const latestMessageTs = getLatestContactMessageTs(db)\n const meta = getSessionMeta(db)\n if (!meta) return { kind: 'missing_meta', latestMessageTs }\n if (meta.type !== ChatType.PRIVATE && meta.type !== ChatType.GROUP)\n return { kind: 'unsupported_type', latestMessageTs }\n\n const cachedMeta = toContactsSessionMetaFacts(meta)\n if (!meta.ownerId?.trim()) return { kind: 'missing_owner', meta: cachedMeta, latestMessageTs }\n\n const owner = resolveOwnerMember(db)\n if (!owner) return { kind: 'unresolved_owner', meta: cachedMeta, latestMessageTs }\n\n if (meta.type === ChatType.PRIVATE) {\n const facts = getPrivateContactFacts(db, owner.id, { startTs: timeRange.startTs })\n if (facts.type === 'missing') return { kind: 'private_missing', meta: cachedMeta, latestMessageTs }\n if (facts.type === 'ambiguous') return { kind: 'private_ambiguous', meta: cachedMeta, latestMessageTs }\n return { kind: 'private', meta: cachedMeta, latestMessageTs, facts }\n }\n\n return {\n kind: 'group',\n meta: cachedMeta,\n latestMessageTs,\n facts: getGroupContactFacts(db, owner.id, { startTs: timeRange.startTs }),\n }\n}\n\nfunction applySessionFacts(\n accumulators: Map<string, ContactAccumulator>,\n diagnostics: ContactsDiagnostics,\n sessionId: string,\n sessionFacts: ContactsSessionFacts\n): boolean {\n if ('meta' in sessionFacts && sessionFacts.meta.type === ChatType.PRIVATE) diagnostics.privateSessionCount++\n\n switch (sessionFacts.kind) {\n case 'missing_owner':\n diagnostics.skippedMissingOwnerSessions++\n return false\n case 'unresolved_owner':\n diagnostics.skippedUnresolvedOwnerSessions++\n return false\n case 'private_ambiguous':\n diagnostics.skippedAmbiguousPrivateSessions++\n return false\n case 'private':\n applyPrivateFacts(accumulators, diagnostics, sessionId, sessionFacts.meta, sessionFacts.facts)\n return false\n case 'group':\n applyGroupFacts(accumulators, sessionId, sessionFacts.meta, sessionFacts.facts)\n return true\n default:\n return false\n }\n}\n\nfunction applyPrivateFacts(\n accumulators: Map<string, ContactAccumulator>,\n diagnostics: ContactsDiagnostics,\n sessionId: string,\n meta: ContactsSessionMetaFacts,\n facts: ContactsCachedPrivateFacts\n): void {\n if (facts.privateMessageCount <= 0) return\n diagnostics.activePrivateSessionCount++\n\n const acc = getOrCreateAccumulator(accumulators, sessionId, meta, facts.contact)\n acc.isFriend = true\n acc.privateMessageCount += facts.privateMessageCount\n for (const month of facts.activeMonths) acc.activePrivateMonths.add(month)\n updateLastInteraction(acc, facts.lastMessageTs)\n acc.sourceSessions.push({\n id: sessionId,\n name: meta.name,\n platform: meta.platform,\n type: ChatType.PRIVATE,\n messageCount: facts.privateMessageCount,\n privateMessageCount: facts.privateMessageCount,\n lastMessageTs: facts.lastMessageTs,\n })\n}\n\nfunction applyGroupFacts(\n accumulators: Map<string, ContactAccumulator>,\n sessionId: string,\n meta: ContactsSessionMetaFacts,\n sessionFacts: ContactsCachedGroupFacts[]\n): void {\n for (const facts of sessionFacts) {\n if (!hasGroupContactSignal(facts)) continue\n const acc = getOrCreateAccumulator(accumulators, sessionId, meta, facts.contact)\n acc.commonGroupSessionIds.add(sessionId)\n acc.coOccurrenceCount += facts.coOccurrenceCount\n acc.coOccurrenceRawScore += facts.coOccurrenceRawScore\n acc.replyInteractionCount += facts.replyInteractionCount\n acc.repliesFromOwnerToContact += facts.repliesFromOwnerToContact\n acc.repliesFromContactToOwner += facts.repliesFromContactToOwner\n updateLastInteraction(acc, facts.lastInteractionTs)\n acc.sourceSessions.push({\n id: sessionId,\n name: meta.name,\n platform: meta.platform,\n type: ChatType.GROUP,\n messageCount: facts.messageCount,\n coOccurrenceCount: facts.coOccurrenceCount,\n coOccurrenceRawScore: facts.coOccurrenceRawScore,\n replyInteractionCount: facts.replyInteractionCount,\n repliesFromOwnerToContact: facts.repliesFromOwnerToContact,\n repliesFromContactToOwner: facts.repliesFromContactToOwner,\n lastInteractionTs: facts.lastInteractionTs,\n })\n }\n}\n\nfunction hasGroupContactSignal(facts: ContactsCachedGroupFacts): boolean {\n return facts.messageCount > 0 || facts.coOccurrenceCount > 0 || facts.replyInteractionCount > 0\n}\n\nfunction createFactsCacheContext(dir: string): ContactsFactsCacheContext {\n return {\n dir,\n latestKey: buildContactsSessionLatestCacheKey(CONTACTS_ALGORITHM_VERSION),\n stats: createEmptyContactsFactsCacheStats(),\n }\n}\n\nfunction readLatestFacts(\n sessionId: string,\n factsCache: ContactsFactsCacheContext | null,\n dbVersion: string\n): ContactsSessionLatestFacts | null {\n if (!factsCache) return null\n const cached = readCachedContactsSessionLatest(sessionId, factsCache.dir, factsCache.latestKey, dbVersion)\n if (!cached.hit) {\n factsCache.stats.latestMisses++\n return null\n }\n factsCache.stats.latestHits++\n return cached.data\n}\n\nfunction writeLatestFacts(\n adapter: SessionRuntimeAdapter,\n sessionId: string,\n factsCache: ContactsFactsCacheContext | null,\n data: ContactsSessionLatestFacts,\n expectedDbVersion: string\n): void {\n if (!factsCache) return\n const dbVersion = getSessionDbVersion(adapter, sessionId)\n if (dbVersion !== expectedDbVersion) {\n appLogger.debug('contacts', 'skipped contacts latest facts cache write because db version changed', {\n sessionId,\n })\n return\n }\n writeCachedContactsSessionLatest(sessionId, factsCache.dir, factsCache.latestKey, dbVersion, data)\n factsCache.stats.writes++\n}\n\nfunction readSessionFacts(\n sessionId: string,\n timeRange: ContactsTimeRangeState,\n factsCache: ContactsFactsCacheContext | null,\n dbVersion: string\n): ContactsSessionFacts | null {\n if (!factsCache) return null\n const cached = readCachedContactsSessionFacts(\n sessionId,\n factsCache.dir,\n buildContactsSessionFactsCacheKey(CONTACTS_ALGORITHM_VERSION, timeRange),\n dbVersion\n )\n if (!cached.hit) {\n factsCache.stats.factsMisses++\n return null\n }\n factsCache.stats.factsHits++\n return cached.data\n}\n\nfunction writeSessionFacts(\n adapter: SessionRuntimeAdapter,\n sessionId: string,\n timeRange: ContactsTimeRangeState,\n factsCache: ContactsFactsCacheContext | null,\n facts: ContactsSessionFacts,\n expectedDbVersion: string\n): void {\n if (!factsCache) return\n const dbVersion = getSessionDbVersion(adapter, sessionId)\n if (dbVersion !== expectedDbVersion) {\n appLogger.debug('contacts', 'skipped contacts session facts cache write because db version changed', {\n sessionId,\n })\n return\n }\n writeCachedContactsSessionFacts(\n sessionId,\n factsCache.dir,\n buildContactsSessionFactsCacheKey(CONTACTS_ALGORITHM_VERSION, timeRange),\n dbVersion,\n facts\n )\n writeCachedContactsSessionLatest(sessionId, factsCache.dir, factsCache.latestKey, dbVersion, {\n latestMessageTs: facts.latestMessageTs,\n })\n factsCache.stats.writes += 2\n}\n\nfunction getSessionDbVersion(adapter: SessionRuntimeAdapter, sessionId: string): string {\n return getDbFileVersion(adapter.getDbPath(sessionId))\n}\n\nfunction toContactsSessionMetaFacts(meta: SessionMeta): ContactsSessionMetaFacts {\n return {\n name: meta.name,\n platform: meta.platform,\n type: meta.type as ChatType.PRIVATE | ChatType.GROUP,\n ownerId: meta.ownerId,\n }\n}\n\nfunction buildContactItems(accumulators: ContactAccumulator[]): ContactItem[] {\n const friendInputs = accumulators\n .filter((acc) => acc.isFriend)\n .map((acc) => ({\n acc,\n privateMessageCount: acc.privateMessageCount,\n activeMonths: [...acc.activePrivateMonths],\n commonGroupCount: acc.commonGroupSessionIds.size,\n }))\n const nonFriendInputs = accumulators\n .filter((acc) => !acc.isFriend)\n .map((acc) => ({\n acc,\n coOccurrenceRawScore: acc.coOccurrenceRawScore,\n commonGroupCount: acc.commonGroupSessionIds.size,\n replyInteractionCount: acc.replyInteractionCount,\n coOccurrenceCount: acc.coOccurrenceCount,\n }))\n\n const friendScores = computeFriendScores(friendInputs)\n const nonFriendScores = computeNonFriendScores(nonFriendInputs)\n const contacts: ContactItem[] = []\n\n for (const input of friendInputs) {\n const score = friendScores.get(input) ?? { score: 0, scoreBreakdown: {} }\n contacts.push(toContactItem(input.acc, 'friend', score))\n }\n\n for (const input of nonFriendInputs) {\n const score = nonFriendScores.get(input) ?? { score: 0, scoreBreakdown: {} }\n contacts.push(toContactItem(input.acc, 'non_friend', score))\n }\n\n return contacts.sort((a, b) => b.score - a.score || a.displayName.localeCompare(b.displayName))\n}\n\nfunction toContactItem(\n acc: ContactAccumulator,\n pool: 'friend' | 'non_friend',\n scoring: { score: number; scoreBreakdown: ContactItem['scoreBreakdown'] }\n): ContactItem {\n const aliases = [...acc.aliases].filter((alias) => alias !== acc.displayName)\n const searchText = [acc.displayName, acc.platformId, ...aliases].join(' ').toLowerCase()\n\n const item: ContactItem = {\n key: acc.key,\n platform: acc.platform,\n platformId: acc.platformId,\n sessionScoped: acc.sessionScoped,\n sessionId: acc.sessionId,\n displayName: acc.displayName,\n aliases,\n avatar: acc.avatar,\n isFriend: acc.isFriend,\n pool,\n score: scoring.score,\n scoreBreakdown: {\n ...scoring.scoreBreakdown,\n privateMessageCount: acc.privateMessageCount || scoring.scoreBreakdown.privateMessageCount,\n activePrivateMonths: acc.activePrivateMonths.size || scoring.scoreBreakdown.activePrivateMonths,\n commonGroupCount: acc.commonGroupSessionIds.size,\n coOccurrenceCount: acc.coOccurrenceCount,\n coOccurrenceRawScore: acc.coOccurrenceRawScore,\n replyInteractionCount: acc.replyInteractionCount,\n repliesFromOwnerToContact: acc.repliesFromOwnerToContact,\n repliesFromContactToOwner: acc.repliesFromContactToOwner,\n },\n sourceSessions: acc.sourceSessions,\n searchText,\n lastInteractionTs: acc.lastInteractionTs,\n }\n if (pool === 'friend') item.friendSource = 'private'\n return item\n}\n\nexport function createEmptyContactsDiagnostics(): ContactsDiagnostics {\n return createEmptyDiagnostics()\n}\n\nfunction createEmptyDiagnostics(): ContactsDiagnostics {\n return {\n privateSessionCount: 0,\n activePrivateSessionCount: 0,\n contactsEnabled: false,\n skippedMissingOwnerSessions: 0,\n skippedUnresolvedOwnerSessions: 0,\n skippedAmbiguousPrivateSessions: 0,\n skippedInvalidPlatformIdMembers: 0,\n skippedFailedSessions: 0,\n warnings: [],\n }\n}\n\nfunction getOrCreateAccumulator(\n accumulators: Map<string, ContactAccumulator>,\n sessionId: string,\n meta: ContactsSessionMetaFacts,\n contact: ContactMemberRef\n): ContactAccumulator {\n const sessionScoped = shouldScopeContactToSession(meta.platform, contact)\n const key = buildContactKey(meta.platform, contact.platformId, sessionScoped ? sessionId : undefined)\n const existing = accumulators.get(key)\n if (existing) {\n mergeContactIdentity(existing, contact)\n return existing\n }\n\n const created: ContactAccumulator = {\n key,\n platform: meta.platform,\n platformId: contact.platformId,\n sessionScoped,\n sessionId: sessionScoped ? sessionId : undefined,\n displayName: contact.name || contact.platformId,\n aliases: new Set([contact.platformId, contact.name, ...contact.aliases].filter(Boolean)),\n avatar: contact.avatar,\n isFriend: false,\n privateMessageCount: 0,\n activePrivateMonths: new Set(),\n commonGroupSessionIds: new Set(),\n coOccurrenceCount: 0,\n coOccurrenceRawScore: 0,\n replyInteractionCount: 0,\n repliesFromOwnerToContact: 0,\n repliesFromContactToOwner: 0,\n sourceSessions: [],\n lastInteractionTs: null,\n }\n accumulators.set(key, created)\n return created\n}\n\nfunction mergeContactIdentity(acc: ContactAccumulator, contact: ContactMemberRef): void {\n if (contact.name) acc.aliases.add(contact.name)\n acc.aliases.add(contact.platformId)\n for (const alias of contact.aliases) acc.aliases.add(alias)\n if ((!acc.displayName || acc.displayName === acc.platformId) && contact.name) {\n acc.displayName = contact.name\n }\n if (!acc.avatar && contact.avatar) acc.avatar = contact.avatar\n}\n\nfunction updateLastInteraction(acc: ContactAccumulator, ts: number | null): void {\n if (ts === null) return\n acc.lastInteractionTs = Math.max(acc.lastInteractionTs ?? 0, ts)\n}\n"],"mappings":"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","names":[]}