chatlab-cli 0.30.2 → 0.31.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 (141) hide show
  1. package/dist/{chat-command-VBDMWOKL.mjs → chat-command-MOETAGU5.mjs} +9 -8
  2. package/dist/{chat-command-VBDMWOKL.mjs.map → chat-command-MOETAGU5.mjs.map} +1 -1
  3. package/dist/{chunk-M2PXDX4G.mjs → chunk-2IXPWPLR.mjs} +168 -77
  4. package/dist/chunk-2IXPWPLR.mjs.map +1 -0
  5. package/dist/{chunk-TCZHG3G7.mjs → chunk-3VMKS7PU.mjs} +44 -5
  6. package/dist/chunk-3VMKS7PU.mjs.map +1 -0
  7. package/dist/{chunk-TEX44HNL.mjs → chunk-7HBVGVOB.mjs} +5 -15
  8. package/dist/chunk-7HBVGVOB.mjs.map +1 -0
  9. package/dist/{chunk-LVEJHB3X.mjs → chunk-DQ45LDKZ.mjs} +512 -98
  10. package/dist/chunk-DQ45LDKZ.mjs.map +1 -0
  11. package/dist/{chunk-ULNRUS55.mjs → chunk-E6W2RURS.mjs} +3 -3
  12. package/dist/{chunk-36JGKW6K.mjs → chunk-KCPGEILH.mjs} +1503 -530
  13. package/dist/chunk-KCPGEILH.mjs.map +1 -0
  14. package/dist/{chunk-WV5GSRQM.mjs → chunk-LJXSUN25.mjs} +5 -15
  15. package/dist/chunk-LJXSUN25.mjs.map +1 -0
  16. package/dist/chunk-N5AGDT7I.mjs +268 -0
  17. package/dist/chunk-N5AGDT7I.mjs.map +1 -0
  18. package/dist/{chunk-D3DPCDII.mjs → chunk-SZEBCNBB.mjs} +193 -79
  19. package/dist/chunk-SZEBCNBB.mjs.map +1 -0
  20. package/dist/{chunk-5EE2EFPE.mjs → chunk-VOVLPSG6.mjs} +29 -52
  21. package/dist/chunk-VOVLPSG6.mjs.map +1 -0
  22. package/dist/chunk-YAQLYL52.mjs +14 -0
  23. package/dist/chunk-YAQLYL52.mjs.map +1 -0
  24. package/dist/{chunk-326OCJOT.mjs → chunk-ZVWUR7ET.mjs} +2 -2
  25. package/dist/cli.mjs +10 -7
  26. package/dist/contacts-worker.mjs +2 -2
  27. package/dist/global-insight-worker.mjs +179 -0
  28. package/dist/global-insight-worker.mjs.map +1 -0
  29. package/dist/{http-L4AMELPZ.mjs → http-M6NHWJZD.mjs} +12 -11
  30. package/dist/{import-WWCSXGVS.mjs → import-SEYHFXS5.mjs} +12 -7
  31. package/dist/index.mjs +13 -12
  32. package/dist/{mcp-A4M3LT5O.mjs → mcp-MIPFYRLV.mjs} +12 -11
  33. package/dist/{mcp-A4M3LT5O.mjs.map → mcp-MIPFYRLV.mjs.map} +1 -1
  34. package/dist/people-relationships-worker.mjs +2 -2
  35. package/dist/semantic-index-worker.mjs +1 -1
  36. package/dist/{src-MPNBTFOE.mjs → src-7OD6RD5V.mjs} +38 -6
  37. package/dist/{stream-import-HIE7PNL4.mjs → stream-import-AWEHGQJY.mjs} +12 -7
  38. package/dist/{worker-runtime-BJXO24XX.mjs → worker-runtime-TGYMASIE.mjs} +6 -5
  39. package/dist/{worker-runtime-BJXO24XX.mjs.map → worker-runtime-TGYMASIE.mjs.map} +1 -1
  40. package/dist-web/assets/ActionToolsPanel-fAio70bI.css +1 -0
  41. package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-CkDGVRXe.js +110 -0
  42. package/dist-web/assets/{BufferResource-q3rzaWWd.js → BufferResource-CHI62pIA.js} +1 -1
  43. package/dist-web/assets/{CanvasRenderer-BRk1y8tp.js → CanvasRenderer-OZRoiF0j.js} +1 -1
  44. package/dist-web/assets/{EChartWordcloud-Clg60FMo.js → EChartWordcloud-DU3ZYdgz.js} +1 -1
  45. package/dist-web/assets/{Filter-BJwode73.js → Filter-DNb5VErW.js} +1 -1
  46. package/dist-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-D_dJuLWJ.js → LoadingState.vue_vue_type_script_setup_true_lang-DACMroOe.js} +1 -1
  47. package/dist-web/assets/MessageExportModal-CqP-w7HP.js +1 -0
  48. package/dist-web/assets/PageHeader-Ck8ULyZH.js +1 -0
  49. package/dist-web/assets/PageHeader-XIXMTomn.css +1 -0
  50. package/dist-web/assets/{RelationshipGalaxyCanvas-CORMD7vL.js → RelationshipGalaxyCanvas-ioRNObb5.js} +3 -3
  51. package/dist-web/assets/{RelationshipGalaxyThreeCanvas-B_w_P4ob.js → RelationshipGalaxyThreeCanvas-L1Y43p1A.js} +1 -1
  52. package/dist-web/assets/{RenderTargetSystem-CGhV9R9E.js → RenderTargetSystem-fJ7D7Chv.js} +1 -1
  53. package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BoZyssJF.js +1 -0
  54. package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-7SEaCxDL.js +1 -0
  55. package/dist-web/assets/{WebGLRenderer-CAokTE5X.js → WebGLRenderer-BD3ZUtxH.js} +1 -1
  56. package/dist-web/assets/{WebGPURenderer-DzP4ggSy.js → WebGPURenderer-DZXYsT6D.js} +1 -1
  57. package/dist-web/assets/annual-summary-time-range-DVLXK1r4.js +1 -0
  58. package/dist-web/assets/base-DTElkJcC.js +1 -0
  59. package/dist-web/assets/{browserAll-CAZCK6dd.js → browserAll-ChT6N6a9.js} +1 -1
  60. package/dist-web/assets/dateFormat-D9WibwOu.js +1 -0
  61. package/dist-web/assets/{electron-CkPDbAaS.js → electron-CIzyGxH_.js} +1 -1
  62. package/dist-web/assets/electron-hcWiB7Gg.js +1 -0
  63. package/dist-web/assets/fetch-Avtnh8cJ.js +3 -0
  64. package/dist-web/assets/{fetch-DQ9UNNAy.js → fetch-BFnrBahy.js} +1 -1
  65. package/dist-web/assets/fetch-C9rx2isC.js +31 -0
  66. package/dist-web/assets/fetch-Ccq_0ecb.js +1 -0
  67. package/dist-web/assets/{fetch-BIEXkvDq.js → fetch-CuiQUcO_.js} +1 -1
  68. package/dist-web/assets/{fetch-LX9jrJCC.js → fetch-CyKILLnB.js} +1 -1
  69. package/dist-web/assets/fetch-Dd6t3p1r.js +6 -0
  70. package/dist-web/assets/{fetch--UbRoBT7.js → fetch-DnGx-1_t.js} +1 -1
  71. package/dist-web/assets/{fetch-wqMSiaK3.js → fetch-qC7om4QG.js} +1 -1
  72. package/dist-web/assets/fetch-wSSfDBdV.js +1 -0
  73. package/dist-web/assets/index-BH9jI5kV.js +173 -0
  74. package/dist-web/assets/index-BWtNqcYK.js +22 -0
  75. package/dist-web/assets/index-BfO_LpDv.css +1 -0
  76. package/dist-web/assets/index-Bkq7-GBp.js +1 -0
  77. package/dist-web/assets/index-Bqr-LkS1.css +1 -0
  78. package/dist-web/assets/index-ByUaiVQK.css +1 -0
  79. package/dist-web/assets/index-C6qtsaP7.js +1 -0
  80. package/dist-web/assets/index-C_0GHEcb.css +1 -0
  81. package/dist-web/assets/index-ChFGuu70.js +1 -0
  82. package/dist-web/assets/{index-S-YQRH1E.js → index-CiS20iAR.js} +1 -1
  83. package/dist-web/assets/index-CqD6u57u.js +1 -0
  84. package/dist-web/assets/index-CzDG8LVr.js +2 -0
  85. package/dist-web/assets/index-D0Euk-vQ.js +1 -0
  86. package/dist-web/assets/index-D26BWhHz.js +1 -0
  87. package/dist-web/assets/index-DXHYzIIj.js +1 -0
  88. package/dist-web/assets/index-Dq8u7gMb.js +2 -0
  89. package/dist-web/assets/index-ZsZwPLWy.css +1 -0
  90. package/dist-web/assets/index-u_UH6rDY.js +64 -0
  91. package/dist-web/assets/index-y7cxH1Et.css +1 -0
  92. package/dist-web/assets/{people-page-header-Mupn-U_b.js → people-page-header-BdKM1qhX.js} +1 -1
  93. package/dist-web/assets/types-CZnACqaB.js +1 -0
  94. package/dist-web/assets/{vendor-echarts-hJVnODyU.js → vendor-echarts-B-i_56Av.js} +1 -1
  95. package/dist-web/assets/{vendor-echarts-wordcloud-k5ih2Jl4.js → vendor-echarts-wordcloud-Ca8n6qS6.js} +1 -1
  96. package/dist-web/assets/{vendor-nuxt-ui-DaLxYaC4.js → vendor-nuxt-ui-CS1uxE9C.js} +2 -2
  97. package/dist-web/assets/{vendor-reka-ui-CzM4kDQ7.js → vendor-reka-ui-Cta6JPvN.js} +1 -1
  98. package/dist-web/assets/{web-DbKs6-1b.js → web-BDBdpdK7.js} +1 -1
  99. package/dist-web/assets/{webworkerAll-Bhv-hBqR.js → webworkerAll-C3dAOQj4.js} +1 -1
  100. package/dist-web/index.html +4 -4
  101. package/package.json +1 -1
  102. package/dist/chunk-36JGKW6K.mjs.map +0 -1
  103. package/dist/chunk-5EE2EFPE.mjs.map +0 -1
  104. package/dist/chunk-D3DPCDII.mjs.map +0 -1
  105. package/dist/chunk-KBSAVUFV.mjs +0 -161
  106. package/dist/chunk-KBSAVUFV.mjs.map +0 -1
  107. package/dist/chunk-LVEJHB3X.mjs.map +0 -1
  108. package/dist/chunk-M2PXDX4G.mjs.map +0 -1
  109. package/dist/chunk-TCZHG3G7.mjs.map +0 -1
  110. package/dist/chunk-TEX44HNL.mjs.map +0 -1
  111. package/dist/chunk-WV5GSRQM.mjs.map +0 -1
  112. package/dist-web/assets/DebugToolsPanel-D_lFIW6j.css +0 -1
  113. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-F4n0zNX2.js +0 -110
  114. package/dist-web/assets/MessageExportModal-CGcdMOyw.js +0 -1
  115. package/dist-web/assets/PageHeader-Bbn87QZS.css +0 -1
  116. package/dist-web/assets/PageHeader-CZaqOdBQ.js +0 -1
  117. package/dist-web/assets/electron-D9vE5t3H.js +0 -1
  118. package/dist-web/assets/fetch-1pB-HbYw.js +0 -3
  119. package/dist-web/assets/fetch-Apd5OLJw.js +0 -5
  120. package/dist-web/assets/fetch-B8rik0TM.js +0 -17
  121. package/dist-web/assets/fetch-CF_3ZqRa.js +0 -1
  122. package/dist-web/assets/fetch-FSNxSnAp.js +0 -1
  123. package/dist-web/assets/index---rXG1hZ.css +0 -1
  124. package/dist-web/assets/index-B01uUoHE.js +0 -1
  125. package/dist-web/assets/index-B4l3rHie.css +0 -1
  126. package/dist-web/assets/index-BSIyyt0z.js +0 -1
  127. package/dist-web/assets/index-Bh8z441f.js +0 -2
  128. package/dist-web/assets/index-C0rya8v4.js +0 -1
  129. package/dist-web/assets/index-C1p9CbmN.css +0 -1
  130. package/dist-web/assets/index-COpza1A4.css +0 -1
  131. package/dist-web/assets/index-CZbZv2fh.js +0 -64
  132. package/dist-web/assets/index-CqUuHQBQ.js +0 -22
  133. package/dist-web/assets/index-CzeTP5MJ.js +0 -173
  134. package/dist-web/assets/index-DgNxTM_8.js +0 -2
  135. package/dist-web/assets/index-DosG7LmJ.css +0 -1
  136. /package/dist/{chunk-ULNRUS55.mjs.map → chunk-E6W2RURS.mjs.map} +0 -0
  137. /package/dist/{chunk-326OCJOT.mjs.map → chunk-ZVWUR7ET.mjs.map} +0 -0
  138. /package/dist/{http-L4AMELPZ.mjs.map → http-M6NHWJZD.mjs.map} +0 -0
  139. /package/dist/{import-WWCSXGVS.mjs.map → import-SEYHFXS5.mjs.map} +0 -0
  140. /package/dist/{src-MPNBTFOE.mjs.map → src-7OD6RD5V.mjs.map} +0 -0
  141. /package/dist/{stream-import-HIE7PNL4.mjs.map → stream-import-AWEHGQJY.mjs.map} +0 -0
@@ -2830,7 +2830,8 @@ function getChatSessionList(db) {
2830
2830
  cs.message_count as messageCount,
2831
2831
  cs.summary,
2832
2832
  (SELECT mc.message_id FROM message_context mc
2833
- WHERE mc.segment_id = cs.id ORDER BY mc.message_id LIMIT 1) as firstMessageId
2833
+ JOIN message first_msg ON first_msg.id = mc.message_id
2834
+ WHERE mc.segment_id = cs.id ORDER BY first_msg.ts ASC, first_msg.id ASC LIMIT 1) as firstMessageId
2834
2835
  FROM segment cs
2835
2836
  ORDER BY cs.start_ts ASC`
2836
2837
  ).all();
@@ -3899,6 +3900,348 @@ function notGroupSelfMemberCondition(db, memberAlias) {
3899
3900
  )`;
3900
3901
  }
3901
3902
 
3903
+ // ../../packages/core/src/owner/owner-matching.ts
3904
+ var NAME_MATCH_PLATFORMS = /* @__PURE__ */ new Set(["whatsapp", "line", "instagram"]);
3905
+ function isNameMatchPlatform(platform) {
3906
+ return NAME_MATCH_PLATFORMS.has(platform);
3907
+ }
3908
+ var INVISIBLE_CHARS_RE = /[\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g;
3909
+ function normalizeOwnerName(name) {
3910
+ return name.replace(INVISIBLE_CHARS_RE, "").normalize("NFKC").replace(/\s+/g, " ").trim().toLowerCase();
3911
+ }
3912
+ function collectCandidateNames(member) {
3913
+ const names = [
3914
+ member.platformId,
3915
+ member.accountName ?? "",
3916
+ member.groupNickname ?? "",
3917
+ ...member.aliases ?? [],
3918
+ member.displayName ?? ""
3919
+ ];
3920
+ const result = [];
3921
+ const seen = /* @__PURE__ */ new Set();
3922
+ for (const name of names) {
3923
+ if (!name || !name.trim()) continue;
3924
+ if (seen.has(name)) continue;
3925
+ seen.add(name);
3926
+ result.push(name);
3927
+ }
3928
+ return result;
3929
+ }
3930
+ function mergeConfirmedNames(existing, member) {
3931
+ const result = [];
3932
+ const seen = /* @__PURE__ */ new Set();
3933
+ for (const name of [...existing, ...collectCandidateNames(member)]) {
3934
+ if (!name || !name.trim()) continue;
3935
+ if (seen.has(name)) continue;
3936
+ seen.add(name);
3937
+ result.push(name);
3938
+ }
3939
+ return result;
3940
+ }
3941
+ function matchOwnerProfile(platform, profile, members) {
3942
+ const exact = members.find((m) => m.platformId === profile.platformId);
3943
+ if (exact) {
3944
+ return { type: "exact", platformId: exact.platformId };
3945
+ }
3946
+ if (!isNameMatchPlatform(platform)) {
3947
+ return { type: "none" };
3948
+ }
3949
+ const confirmed = new Set(profile.confirmedNames.map(normalizeOwnerName).filter((n) => n.length > 0));
3950
+ if (confirmed.size === 0) {
3951
+ return { type: "none" };
3952
+ }
3953
+ const matched = members.filter(
3954
+ (m) => collectCandidateNames(m).some((name) => confirmed.has(normalizeOwnerName(name)))
3955
+ );
3956
+ if (matched.length === 1) {
3957
+ return { type: "name", platformId: matched[0].platformId };
3958
+ }
3959
+ if (matched.length > 1) {
3960
+ return { type: "ambiguous", platformIds: matched.map((m) => m.platformId) };
3961
+ }
3962
+ return { type: "none" };
3963
+ }
3964
+
3965
+ // ../../packages/core/src/query/contact-identity.ts
3966
+ function shouldScopeContactToSession(platform, contact) {
3967
+ if (isNameMatchPlatform(platform)) return true;
3968
+ return platform.trim().toLowerCase() === "qq" && contact.platformId.trim() === contact.name.trim();
3969
+ }
3970
+ function buildContactKey(platform, platformId, sessionId) {
3971
+ const normalizedPlatform = platform.trim();
3972
+ const normalizedPlatformId = platformId.trim();
3973
+ if (!normalizedPlatform) throw new Error("platform is required");
3974
+ if (!normalizedPlatformId) throw new Error("platformId is required");
3975
+ return sessionId?.trim() ? `${normalizedPlatform}:${sessionId.trim()}:${normalizedPlatformId}` : `${normalizedPlatform}:${normalizedPlatformId}`;
3976
+ }
3977
+
3978
+ // ../../packages/shared-types/index.ts
3979
+ var KNOWN_PLATFORMS = {
3980
+ QQ: "qq",
3981
+ WECHAT: "weixin",
3982
+ DISCORD: "discord",
3983
+ WHATSAPP: "whatsapp",
3984
+ TELEGRAM: "telegram",
3985
+ INSTAGRAM: "instagram",
3986
+ GOOGLE_CHAT: "google-chat",
3987
+ LINE: "line",
3988
+ UNKNOWN: "unknown"
3989
+ };
3990
+ var CONTACTS_TIME_RANGE_PRESETS = ["1y", "2y", "3y", "5y", "all"];
3991
+
3992
+ // ../../packages/core/src/query/global-insight.ts
3993
+ var SYSTEM_MESSAGE_TYPES2 = [80 /* SYSTEM */, 81 /* RECALL */];
3994
+ function getAnnualSummarySessionFacts(db, sessionId, range) {
3995
+ if (!isChatSessionDb(db)) return emptyFacts("not_chat_db");
3996
+ const meta = getSessionMeta(db);
3997
+ if (!meta) return emptyFacts("missing_meta");
3998
+ if (meta.type !== "private" /* PRIVATE */ && meta.type !== "group" /* GROUP */) return emptyFacts("unsupported_type");
3999
+ if (!meta.ownerId?.trim()) return emptyFacts("missing_owner");
4000
+ const owner = resolveOwnerMember(db);
4001
+ if (!owner) return emptyFacts("unresolved_owner");
4002
+ const contacts = getNonSystemMembersForContacts(db).filter((member) => member.id !== owner.id);
4003
+ let privateContact = null;
4004
+ if (meta.type === "private" /* PRIVATE */) {
4005
+ const activeContacts = getActivePrivateContacts(db, contacts, owner.id, range);
4006
+ const candidates = activeContacts.length > 0 ? activeContacts : contacts;
4007
+ if (candidates.length === 0) return emptyFacts("private_missing");
4008
+ if (candidates.length > 1) return emptyFacts("private_ambiguous");
4009
+ privateContact = candidates[0];
4010
+ }
4011
+ const ownerMessagesByDay = rowsToNumberRecord(
4012
+ db.prepare(
4013
+ `SELECT strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as key, COUNT(*) as count
4014
+ FROM message msg
4015
+ WHERE msg.sender_id = ? AND msg.ts >= ? AND msg.ts <= ?
4016
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4017
+ GROUP BY key ORDER BY key`
4018
+ ).all(owner.id, range.startTs, range.endTs)
4019
+ );
4020
+ const messageTypeCounts = rowsToNumberRecord(
4021
+ db.prepare(
4022
+ `SELECT CAST(msg.type AS TEXT) as key, COUNT(*) as count
4023
+ FROM message msg
4024
+ WHERE msg.sender_id = ? AND msg.ts >= ? AND msg.ts <= ?
4025
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4026
+ GROUP BY msg.type ORDER BY msg.type`
4027
+ ).all(owner.id, range.startTs, range.endTs)
4028
+ );
4029
+ const textLengthCounts = rowsToNumberRecord(
4030
+ db.prepare(
4031
+ `SELECT CAST(LENGTH(msg.content) AS TEXT) as key, COUNT(*) as count
4032
+ FROM message msg
4033
+ WHERE msg.sender_id = ? AND msg.ts >= ? AND msg.ts <= ?
4034
+ AND msg.type = ${0 /* TEXT */} AND msg.content IS NOT NULL AND LENGTH(msg.content) > 0
4035
+ GROUP BY LENGTH(msg.content) ORDER BY LENGTH(msg.content)`
4036
+ ).all(owner.id, range.startTs, range.endTs)
4037
+ );
4038
+ const availableDataYears = db.prepare(
4039
+ `SELECT DISTINCT CAST(strftime('%Y', msg.ts, 'unixepoch', 'localtime') AS INTEGER) as year
4040
+ FROM message msg
4041
+ WHERE msg.sender_id = ? AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4042
+ ORDER BY year DESC`
4043
+ ).all(owner.id).map((row) => row.year);
4044
+ return {
4045
+ kind: "analyzed",
4046
+ availableDataYears,
4047
+ ownerMessagesByDay,
4048
+ directContactKeysByDay: meta.type === "private" /* PRIVATE */ && privateContact ? getPrivateDirectContactsByDay(db, sessionId, meta.platform, owner.id, privateContact, range) : getGroupDirectContactsByDay(db, sessionId, meta.platform, owner.id, contacts, range),
4049
+ messageTypeCounts,
4050
+ textLengthCounts
4051
+ };
4052
+ }
4053
+ function aggregateAnnualSummaryFacts(facts, range, elapsedDayCount) {
4054
+ const ownerMessagesByDay = /* @__PURE__ */ new Map();
4055
+ const directContactsByDay = /* @__PURE__ */ new Map();
4056
+ const directContacts = /* @__PURE__ */ new Set();
4057
+ const messageTypes = /* @__PURE__ */ new Map();
4058
+ const textLengths = /* @__PURE__ */ new Map();
4059
+ const availableDataYears = /* @__PURE__ */ new Set();
4060
+ const coverage = {
4061
+ totalSessions: 0,
4062
+ analyzedSessions: 0,
4063
+ missingOwnerSessions: 0,
4064
+ unresolvedOwnerSessions: 0,
4065
+ failedSessions: 0
4066
+ };
4067
+ for (const item of facts) {
4068
+ if (item.kind === "not_chat_db" || item.kind === "missing_meta" || item.kind === "unsupported_type") continue;
4069
+ coverage.totalSessions++;
4070
+ if (item.kind === "missing_owner") {
4071
+ coverage.missingOwnerSessions++;
4072
+ continue;
4073
+ }
4074
+ if (item.kind === "unresolved_owner") {
4075
+ coverage.unresolvedOwnerSessions++;
4076
+ continue;
4077
+ }
4078
+ if (item.kind !== "analyzed") {
4079
+ coverage.failedSessions++;
4080
+ continue;
4081
+ }
4082
+ coverage.analyzedSessions++;
4083
+ item.availableDataYears.forEach((year) => availableDataYears.add(year));
4084
+ mergeNumberRecord(ownerMessagesByDay, item.ownerMessagesByDay);
4085
+ mergeNumberRecord(messageTypes, item.messageTypeCounts, Number);
4086
+ mergeNumberRecord(textLengths, item.textLengthCounts, Number);
4087
+ for (const [date, keys] of Object.entries(item.directContactKeysByDay)) {
4088
+ const daily = directContactsByDay.get(date) ?? /* @__PURE__ */ new Set();
4089
+ keys.forEach((key) => {
4090
+ daily.add(key);
4091
+ directContacts.add(key);
4092
+ });
4093
+ directContactsByDay.set(date, daily);
4094
+ }
4095
+ }
4096
+ const dailyActivity = [...ownerMessagesByDay.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, messageCount]) => ({ date, messageCount }));
4097
+ const sentMessageCount = dailyActivity.reduce((sum, item) => sum + item.messageCount, 0);
4098
+ const dailyDirectContactTotal = [...directContactsByDay.values()].reduce((sum, keys) => sum + keys.size, 0);
4099
+ const years = [...availableDataYears].sort((a, b) => b - a);
4100
+ return {
4101
+ availableDataYears: years,
4102
+ latestDataYear: years[0] ?? null,
4103
+ metrics: {
4104
+ sentMessageCount,
4105
+ activeDayCount: dailyActivity.length,
4106
+ directContactCount: directContacts.size,
4107
+ averageMessagesPerDay: roundAverage(sentMessageCount, elapsedDayCount),
4108
+ averageDirectContactsPerDay: roundAverage(dailyDirectContactTotal, elapsedDayCount)
4109
+ },
4110
+ monthlyActivity: buildMonthlyActivity(range, ownerMessagesByDay),
4111
+ dailyActivity,
4112
+ messageTypes: [...messageTypes.entries()].sort(([a], [b]) => a - b).map(([type, count]) => ({ type, count })),
4113
+ textLength: buildTextLengthSummary(textLengths),
4114
+ coverage
4115
+ };
4116
+ }
4117
+ function getActivePrivateContacts(db, contacts, ownerId, range) {
4118
+ if (contacts.length <= 1) return contacts;
4119
+ const byId = new Map(contacts.map((contact) => [contact.id, contact]));
4120
+ const rows = db.prepare(
4121
+ `SELECT DISTINCT msg.sender_id as senderId FROM message msg
4122
+ WHERE msg.sender_id <> ? AND msg.ts >= ? AND msg.ts <= ?
4123
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})`
4124
+ ).all(ownerId, range.startTs, range.endTs);
4125
+ return rows.map((row) => byId.get(row.senderId)).filter((contact) => Boolean(contact));
4126
+ }
4127
+ function getPrivateDirectContactsByDay(db, sessionId, platform, ownerId, contact, range) {
4128
+ const rows = db.prepare(
4129
+ `SELECT DISTINCT strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as date
4130
+ FROM message msg
4131
+ WHERE msg.sender_id IN (?, ?) AND msg.ts >= ? AND msg.ts <= ?
4132
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4133
+ ORDER BY date`
4134
+ ).all(ownerId, contact.id, range.startTs, range.endTs);
4135
+ const key = buildContactKey(
4136
+ platform,
4137
+ contact.platformId,
4138
+ shouldScopeContactToSession(platform, contact) ? sessionId : void 0
4139
+ );
4140
+ return Object.fromEntries(rows.map((row) => [row.date, [key]]));
4141
+ }
4142
+ function getGroupDirectContactsByDay(db, sessionId, platform, ownerId, contacts, range) {
4143
+ const byId = new Map(contacts.map((contact) => [contact.id, contact]));
4144
+ const rows = db.prepare(
4145
+ `SELECT
4146
+ strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as date,
4147
+ msg.sender_id as replySenderId,
4148
+ target.sender_id as targetSenderId
4149
+ FROM message msg
4150
+ JOIN message target ON msg.reply_to_message_id = target.platform_message_id
4151
+ WHERE msg.ts >= ? AND msg.ts <= ? AND msg.reply_to_message_id IS NOT NULL
4152
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})`
4153
+ ).all(range.startTs, range.endTs);
4154
+ const byDay = /* @__PURE__ */ new Map();
4155
+ for (const row of rows) {
4156
+ const contactId = row.replySenderId === ownerId ? row.targetSenderId : row.targetSenderId === ownerId ? row.replySenderId : null;
4157
+ if (contactId === null) continue;
4158
+ const contact = byId.get(contactId);
4159
+ if (!contact) continue;
4160
+ const key = buildContactKey(
4161
+ platform,
4162
+ contact.platformId,
4163
+ shouldScopeContactToSession(platform, contact) ? sessionId : void 0
4164
+ );
4165
+ const keys = byDay.get(row.date) ?? /* @__PURE__ */ new Set();
4166
+ keys.add(key);
4167
+ byDay.set(row.date, keys);
4168
+ }
4169
+ return Object.fromEntries([...byDay.entries()].map(([date, keys]) => [date, [...keys].sort()]));
4170
+ }
4171
+ function buildMonthlyActivity(range, ownerMessagesByDay) {
4172
+ const counts = /* @__PURE__ */ new Map();
4173
+ for (const [date, count] of ownerMessagesByDay) {
4174
+ const month = date.slice(0, 7);
4175
+ counts.set(month, (counts.get(month) ?? 0) + count);
4176
+ }
4177
+ return listMonths(range).map((month) => ({ month, messageCount: counts.get(month) ?? 0 }));
4178
+ }
4179
+ function listMonths(range) {
4180
+ if (range.mode === "year" && range.year) {
4181
+ return Array.from({ length: 12 }, (_, index) => `${range.year}-${String(index + 1).padStart(2, "0")}`);
4182
+ }
4183
+ const current = new Date(range.startTs * 1e3);
4184
+ current.setDate(1);
4185
+ current.setHours(0, 0, 0, 0);
4186
+ const end = new Date(range.endTs * 1e3);
4187
+ const result = [];
4188
+ while (current <= end) {
4189
+ result.push(`${current.getFullYear()}-${String(current.getMonth() + 1).padStart(2, "0")}`);
4190
+ current.setMonth(current.getMonth() + 1);
4191
+ }
4192
+ return result;
4193
+ }
4194
+ function buildTextLengthSummary(lengths) {
4195
+ const textMessageCount = [...lengths.values()].reduce((sum, count) => sum + count, 0);
4196
+ return {
4197
+ textMessageCount,
4198
+ median: weightedPercentile(lengths, 0.5),
4199
+ p90: weightedPercentile(lengths, 0.9),
4200
+ buckets: [
4201
+ { key: "1-10", count: countLengthRange(lengths, 1, 10) },
4202
+ { key: "11-30", count: countLengthRange(lengths, 11, 30) },
4203
+ { key: "31-100", count: countLengthRange(lengths, 31, 100) },
4204
+ { key: "101-300", count: countLengthRange(lengths, 101, 300) },
4205
+ { key: "300+", count: countLengthRange(lengths, 301, Number.POSITIVE_INFINITY) }
4206
+ ]
4207
+ };
4208
+ }
4209
+ function weightedPercentile(lengths, percentile) {
4210
+ const entries = [...lengths.entries()].sort(([a], [b]) => a - b);
4211
+ const total = entries.reduce((sum, [, count]) => sum + count, 0);
4212
+ if (total === 0) return null;
4213
+ const target = Math.floor((total - 1) * percentile);
4214
+ let seen = 0;
4215
+ for (const [length, count] of entries) {
4216
+ seen += count;
4217
+ if (seen > target) return length;
4218
+ }
4219
+ return entries.at(-1)?.[0] ?? null;
4220
+ }
4221
+ function countLengthRange(lengths, min, max) {
4222
+ let count = 0;
4223
+ for (const [length, value] of lengths) {
4224
+ if (length >= min && length <= max) count += value;
4225
+ }
4226
+ return count;
4227
+ }
4228
+ function rowsToNumberRecord(rows) {
4229
+ return Object.fromEntries(rows.filter((row) => row.key).map((row) => [row.key, row.count]));
4230
+ }
4231
+ function mergeNumberRecord(target, source, mapKey = (key) => key) {
4232
+ for (const [key, value] of Object.entries(source)) {
4233
+ const mapped = mapKey(key);
4234
+ target.set(mapped, (target.get(mapped) ?? 0) + value);
4235
+ }
4236
+ }
4237
+ function roundAverage(total, days) {
4238
+ if (days <= 0) return 0;
4239
+ return Math.round(total / days * 100) / 100;
4240
+ }
4241
+ function emptyFacts(kind) {
4242
+ return { kind, availableDataYears: [] };
4243
+ }
4244
+
3902
4245
  // ../../packages/core/src/query/contact-enablement.ts
3903
4246
  var MIN_PRIVATE_SESSIONS_FOR_CONTACTS = 5;
3904
4247
  var MIN_GROUP_SESSIONS_FOR_CONTACTS = 1;
@@ -5890,20 +6233,6 @@ function getRepeatAnalysis(db, filter) {
5890
6233
  return computeRepeat(messages);
5891
6234
  }
5892
6235
 
5893
- // ../../packages/shared-types/index.ts
5894
- var KNOWN_PLATFORMS = {
5895
- QQ: "qq",
5896
- WECHAT: "weixin",
5897
- DISCORD: "discord",
5898
- WHATSAPP: "whatsapp",
5899
- TELEGRAM: "telegram",
5900
- INSTAGRAM: "instagram",
5901
- GOOGLE_CHAT: "google-chat",
5902
- LINE: "line",
5903
- UNKNOWN: "unknown"
5904
- };
5905
- var CONTACTS_TIME_RANGE_PRESETS = ["1y", "2y", "3y", "5y", "all"];
5906
-
5907
6236
  // ../../packages/core/src/message-type.ts
5908
6237
  var TYPE_STRING_MAP = {
5909
6238
  [0 /* TEXT */]: "text",
@@ -7093,68 +7422,6 @@ function isValidWord(word, locale, minLength, enableStopwords, isStopwordFn) {
7093
7422
  return true;
7094
7423
  }
7095
7424
 
7096
- // ../../packages/core/src/owner/owner-matching.ts
7097
- var NAME_MATCH_PLATFORMS = /* @__PURE__ */ new Set(["whatsapp", "line", "instagram"]);
7098
- function isNameMatchPlatform(platform) {
7099
- return NAME_MATCH_PLATFORMS.has(platform);
7100
- }
7101
- var INVISIBLE_CHARS_RE = /[\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g;
7102
- function normalizeOwnerName(name) {
7103
- return name.replace(INVISIBLE_CHARS_RE, "").normalize("NFKC").replace(/\s+/g, " ").trim().toLowerCase();
7104
- }
7105
- function collectCandidateNames(member) {
7106
- const names = [
7107
- member.platformId,
7108
- member.accountName ?? "",
7109
- member.groupNickname ?? "",
7110
- ...member.aliases ?? [],
7111
- member.displayName ?? ""
7112
- ];
7113
- const result = [];
7114
- const seen = /* @__PURE__ */ new Set();
7115
- for (const name of names) {
7116
- if (!name || !name.trim()) continue;
7117
- if (seen.has(name)) continue;
7118
- seen.add(name);
7119
- result.push(name);
7120
- }
7121
- return result;
7122
- }
7123
- function mergeConfirmedNames(existing, member) {
7124
- const result = [];
7125
- const seen = /* @__PURE__ */ new Set();
7126
- for (const name of [...existing, ...collectCandidateNames(member)]) {
7127
- if (!name || !name.trim()) continue;
7128
- if (seen.has(name)) continue;
7129
- seen.add(name);
7130
- result.push(name);
7131
- }
7132
- return result;
7133
- }
7134
- function matchOwnerProfile(platform, profile, members) {
7135
- const exact = members.find((m) => m.platformId === profile.platformId);
7136
- if (exact) {
7137
- return { type: "exact", platformId: exact.platformId };
7138
- }
7139
- if (!isNameMatchPlatform(platform)) {
7140
- return { type: "none" };
7141
- }
7142
- const confirmed = new Set(profile.confirmedNames.map(normalizeOwnerName).filter((n) => n.length > 0));
7143
- if (confirmed.size === 0) {
7144
- return { type: "none" };
7145
- }
7146
- const matched = members.filter(
7147
- (m) => collectCandidateNames(m).some((name) => confirmed.has(normalizeOwnerName(name)))
7148
- );
7149
- if (matched.length === 1) {
7150
- return { type: "name", platformId: matched[0].platformId };
7151
- }
7152
- if (matched.length > 1) {
7153
- return { type: "ambiguous", platformIds: matched.map((m) => m.platformId) };
7154
- }
7155
- return { type: "none" };
7156
- }
7157
-
7158
7425
  // ../../packages/core/src/import/dedup.ts
7159
7426
  function fnv1a64(input) {
7160
7427
  let h0 = 2166136261;
@@ -8479,21 +8746,132 @@ function getContactsFactsCacheDir(userDataDir) {
8479
8746
  return path16.join(getContactsDir(userDataDir), CONTACTS_FACTS_DIR_NAME);
8480
8747
  }
8481
8748
 
8482
- // ../../packages/node-runtime/src/services/people/relationships/paths.ts
8749
+ // ../../packages/node-runtime/src/services/global-insight/paths.ts
8483
8750
  import path17 from "path";
8751
+ function getGlobalInsightDir(userDataDir) {
8752
+ return path17.join(userDataDir, "insight", "annual-summary");
8753
+ }
8754
+ function getGlobalInsightFactsCacheDir(userDataDir) {
8755
+ return path17.join(getGlobalInsightDir(userDataDir), "facts");
8756
+ }
8757
+
8758
+ // ../../packages/node-runtime/src/services/people/relationships/paths.ts
8759
+ import path18 from "path";
8484
8760
  var PEOPLE_DIR_NAME = "people";
8485
8761
  var RELATIONSHIPS_DIR_NAME = "relationships";
8486
8762
  var RELATIONSHIPS_FACTS_DIR_NAME = "facts";
8487
8763
  function getPeopleRelationshipsDir(userDataDir) {
8488
- return path17.join(userDataDir, PEOPLE_DIR_NAME, RELATIONSHIPS_DIR_NAME);
8764
+ return path18.join(userDataDir, PEOPLE_DIR_NAME, RELATIONSHIPS_DIR_NAME);
8489
8765
  }
8490
8766
  function getPeopleRelationshipsFactsCacheDir(userDataDir) {
8491
- return path17.join(getPeopleRelationshipsDir(userDataDir), RELATIONSHIPS_FACTS_DIR_NAME);
8767
+ return path18.join(getPeopleRelationshipsDir(userDataDir), RELATIONSHIPS_FACTS_DIR_NAME);
8768
+ }
8769
+
8770
+ // ../../packages/node-runtime/src/database-manager.ts
8771
+ import * as fs17 from "fs";
8772
+ import * as path20 from "path";
8773
+
8774
+ // ../../packages/node-runtime/src/services/global-insight/snapshot.ts
8775
+ import fs16 from "fs";
8776
+ import path19 from "path";
8777
+
8778
+ // ../../packages/node-runtime/src/services/global-insight/time-range.ts
8779
+ function normalizeAnnualSummaryRange(input, nowInput = /* @__PURE__ */ new Date()) {
8780
+ const now = new Date(nowInput);
8781
+ const nowTs = Math.floor(now.getTime() / 1e3);
8782
+ if (input.mode === "recent") {
8783
+ const start2 = new Date(now);
8784
+ start2.setHours(0, 0, 0, 0);
8785
+ start2.setDate(start2.getDate() - 364);
8786
+ return {
8787
+ mode: "recent",
8788
+ days: 365,
8789
+ startTs: Math.floor(start2.getTime() / 1e3),
8790
+ endTs: nowTs
8791
+ };
8792
+ }
8793
+ const currentYear = now.getFullYear();
8794
+ const parsedYear = Number(input.year);
8795
+ const year = Number.isInteger(parsedYear) && parsedYear >= 1970 && parsedYear <= currentYear ? parsedYear : currentYear;
8796
+ const start = new Date(year, 0, 1, 0, 0, 0);
8797
+ const end = year === currentYear ? now : new Date(year, 11, 31, 23, 59, 59);
8798
+ return {
8799
+ mode: "year",
8800
+ year,
8801
+ startTs: Math.floor(start.getTime() / 1e3),
8802
+ endTs: Math.floor(end.getTime() / 1e3)
8803
+ };
8804
+ }
8805
+ function getAnnualSummaryElapsedDayCount(range) {
8806
+ const start = new Date(range.startTs * 1e3);
8807
+ const end = new Date(range.endTs * 1e3);
8808
+ const startDay = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
8809
+ const endDay = Date.UTC(end.getFullYear(), end.getMonth(), end.getDate());
8810
+ return Math.max(Math.floor((endDay - startDay) / 864e5) + 1, 0);
8811
+ }
8812
+ function toAnnualSummaryRangeKey(range) {
8813
+ return range.mode === "year" ? `year-${range.year}` : "recent-365";
8814
+ }
8815
+ function toAnnualSummaryLocalDate(range) {
8816
+ const date = new Date(range.endTs * 1e3);
8817
+ return [
8818
+ date.getFullYear(),
8819
+ String(date.getMonth() + 1).padStart(2, "0"),
8820
+ String(date.getDate()).padStart(2, "0")
8821
+ ].join("-");
8822
+ }
8823
+
8824
+ // ../../packages/node-runtime/src/services/global-insight/snapshot.ts
8825
+ var SNAPSHOT_TMP_PREFIX = "annual-summary.tmp-";
8826
+ function getAnnualSummarySnapshotPath(snapshotDir, range) {
8827
+ return path19.join(snapshotDir, `annual-summary-${toAnnualSummaryRangeKey(range)}.json`);
8828
+ }
8829
+ function readAnnualSummarySnapshot(snapshotDir, range, options = {}) {
8830
+ const snapshotPath = getAnnualSummarySnapshotPath(snapshotDir, range);
8831
+ if (!fs16.existsSync(snapshotPath)) return null;
8832
+ try {
8833
+ return JSON.parse(fs16.readFileSync(snapshotPath, "utf-8"));
8834
+ } catch (error) {
8835
+ const backupPath = path19.join(snapshotDir, `annual-summary.corrupt-${options.now?.() ?? Date.now()}.json`);
8836
+ try {
8837
+ fs16.renameSync(snapshotPath, backupPath);
8838
+ } catch (renameError) {
8839
+ appLogger.warn("global-insight", "failed to backup corrupt annual summary snapshot", renameError);
8840
+ }
8841
+ appLogger.warn("global-insight", "annual summary snapshot is corrupt", error);
8842
+ return null;
8843
+ }
8844
+ }
8845
+ function writeAnnualSummarySnapshot(snapshotDir, snapshot) {
8846
+ fs16.mkdirSync(snapshotDir, { recursive: true });
8847
+ const tmpPath = path19.join(snapshotDir, `${SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
8848
+ fs16.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
8849
+ fs16.renameSync(tmpPath, getAnnualSummarySnapshotPath(snapshotDir, snapshot.range));
8850
+ }
8851
+ function cleanupAnnualSummarySnapshotTempFiles(snapshotDir) {
8852
+ if (!fs16.existsSync(snapshotDir)) return;
8853
+ for (const name of fs16.readdirSync(snapshotDir)) {
8854
+ if (!name.startsWith(SNAPSHOT_TMP_PREFIX)) continue;
8855
+ try {
8856
+ fs16.rmSync(path19.join(snapshotDir, name), { force: true });
8857
+ } catch (error) {
8858
+ appLogger.warn("global-insight", "failed to remove annual summary snapshot temp file", error);
8859
+ }
8860
+ }
8861
+ }
8862
+ function deleteAnnualSummarySnapshots(snapshotDir) {
8863
+ if (!fs16.existsSync(snapshotDir)) return;
8864
+ for (const name of fs16.readdirSync(snapshotDir)) {
8865
+ if (!name.startsWith("annual-summary-") && !name.startsWith("annual-summary.")) continue;
8866
+ try {
8867
+ fs16.rmSync(path19.join(snapshotDir, name), { force: true });
8868
+ } catch (error) {
8869
+ appLogger.warn("global-insight", "failed to remove annual summary snapshot", error);
8870
+ }
8871
+ }
8492
8872
  }
8493
8873
 
8494
8874
  // ../../packages/node-runtime/src/database-manager.ts
8495
- import * as fs16 from "fs";
8496
- import * as path18 from "path";
8497
8875
  function createMigrationDeps(overrides) {
8498
8876
  return {
8499
8877
  tokenizeForFts,
@@ -8524,7 +8902,7 @@ var DatabaseManager = class {
8524
8902
  return this.cache.get(sessionId);
8525
8903
  }
8526
8904
  const dbPath = this.getDbPath(sessionId);
8527
- if (!fs16.existsSync(dbPath)) return null;
8905
+ if (!fs17.existsSync(dbPath)) return null;
8528
8906
  this.migrateIfNeeded(dbPath);
8529
8907
  this.assertCompatible();
8530
8908
  const adapter = openBetterSqliteDatabase(dbPath, {
@@ -8570,7 +8948,7 @@ var DatabaseManager = class {
8570
8948
  this.cache.delete(sessionId);
8571
8949
  }
8572
8950
  const dbPath = this.getDbPath(sessionId);
8573
- if (!fs16.existsSync(dbPath)) return null;
8951
+ if (!fs17.existsSync(dbPath)) return null;
8574
8952
  const adapter = openBetterSqliteDatabase(dbPath, {
8575
8953
  readonly: false,
8576
8954
  nativeBinding: this.nativeBinding
@@ -8610,28 +8988,47 @@ var DatabaseManager = class {
8610
8988
  listSessionIds() {
8611
8989
  this.assertCompatible();
8612
8990
  const dbDir = this.pathProvider.getDatabaseDir();
8613
- if (!fs16.existsSync(dbDir)) return [];
8614
- return fs16.readdirSync(dbDir).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", "")).filter((id) => {
8991
+ if (!fs17.existsSync(dbDir)) return [];
8992
+ return fs17.readdirSync(dbDir).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", "")).filter((id) => {
8615
8993
  const db = this.open(id);
8616
8994
  if (!db) return false;
8617
8995
  return isChatSessionDb(db);
8618
8996
  });
8619
8997
  }
8998
+ /**
8999
+ * 只读列举聊天会话 ID,不触发数据库迁移或兼容门禁提升。
9000
+ */
9001
+ listSessionIdsReadonly() {
9002
+ this.assertCompatible();
9003
+ const dbDir = this.pathProvider.getDatabaseDir();
9004
+ if (!fs17.existsSync(dbDir)) return [];
9005
+ return fs17.readdirSync(dbDir).filter((fileName) => fileName.endsWith(".db")).map((fileName) => fileName.replace(".db", "")).filter((sessionId) => {
9006
+ const db = this.openRawSessionDatabase(sessionId, { readonly: true });
9007
+ try {
9008
+ return isChatSessionDb(db);
9009
+ } finally {
9010
+ db.close();
9011
+ }
9012
+ });
9013
+ }
9014
+ getUserDataDir() {
9015
+ return this.pathProvider.getUserDataDir();
9016
+ }
8620
9017
  /**
8621
9018
  * 获取数据库文件路径
8622
9019
  */
8623
9020
  getDbPath(sessionId) {
8624
- return path18.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
9021
+ return path20.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
8625
9022
  }
8626
9023
  openRawSessionDatabase(sessionId, options = {}) {
8627
9024
  this.assertCompatible();
8628
9025
  const dbPath = this.getDbPath(sessionId);
8629
- if (!options.create && !fs16.existsSync(dbPath)) {
9026
+ if (!options.create && !fs17.existsSync(dbPath)) {
8630
9027
  throw new Error(`Session database not found: ${sessionId}`);
8631
9028
  }
8632
9029
  if (!options.readonly) {
8633
9030
  this.close(sessionId);
8634
- fs16.mkdirSync(path18.dirname(dbPath), { recursive: true });
9031
+ fs17.mkdirSync(path20.dirname(dbPath), { recursive: true });
8635
9032
  }
8636
9033
  const adapter = openBetterSqliteDatabase(dbPath, {
8637
9034
  readonly: options.readonly ?? false,
@@ -8649,18 +9046,20 @@ var DatabaseManager = class {
8649
9046
  deleteSessionDatabaseFiles(sessionId) {
8650
9047
  this.close(sessionId);
8651
9048
  const dbPath = this.getDbPath(sessionId);
8652
- const existed = ["", "-wal", "-shm"].some((suffix) => fs16.existsSync(dbPath + suffix));
9049
+ const existed = ["", "-wal", "-shm"].some((suffix) => fs17.existsSync(dbPath + suffix));
8653
9050
  for (const suffix of ["", "-wal", "-shm"]) {
8654
9051
  try {
8655
9052
  const filePath = dbPath + suffix;
8656
- if (fs16.existsSync(filePath)) fs16.unlinkSync(filePath);
9053
+ if (fs17.existsSync(filePath)) fs17.unlinkSync(filePath);
8657
9054
  } catch {
8658
9055
  }
8659
9056
  }
8660
9057
  const cacheDir = this.pathProvider.getCacheDir();
8661
9058
  deleteSessionCache(sessionId, cacheDir);
8662
- deleteSessionCache(sessionId, path18.join(cacheDir, "query"));
9059
+ deleteSessionCache(sessionId, path20.join(cacheDir, "query"));
8663
9060
  deleteSessionCache(sessionId, getContactsFactsCacheDir(this.pathProvider.getUserDataDir()));
9061
+ deleteSessionCache(sessionId, getGlobalInsightFactsCacheDir(this.pathProvider.getUserDataDir()));
9062
+ deleteAnnualSummarySnapshots(getGlobalInsightDir(this.pathProvider.getUserDataDir()));
8664
9063
  deleteSessionCache(sessionId, getPeopleRelationshipsFactsCacheDir(this.pathProvider.getUserDataDir()));
8665
9064
  return existed;
8666
9065
  }
@@ -8698,12 +9097,12 @@ function shouldRepairCompatibilityGate(schemaVersion) {
8698
9097
  }
8699
9098
 
8700
9099
  // ../../packages/node-runtime/src/cache/analytics-cache.ts
8701
- import * as fs17 from "fs";
9100
+ import * as fs18 from "fs";
8702
9101
  function getDbFileVersion(dbPath) {
8703
9102
  const parts = [];
8704
9103
  for (const p of [dbPath, `${dbPath}-wal`]) {
8705
9104
  try {
8706
- const st = fs17.statSync(p);
9105
+ const st = fs18.statSync(p);
8707
9106
  parts.push(`${Math.floor(st.mtimeMs)}:${st.size}`);
8708
9107
  } catch {
8709
9108
  parts.push("-");
@@ -8866,6 +9265,13 @@ export {
8866
9265
  getPrivateContactFacts,
8867
9266
  getGroupContactFacts,
8868
9267
  getGroupRelationshipGraphFacts,
9268
+ isNameMatchPlatform,
9269
+ mergeConfirmedNames,
9270
+ matchOwnerProfile,
9271
+ shouldScopeContactToSession,
9272
+ buildContactKey,
9273
+ getAnnualSummarySessionFacts,
9274
+ aggregateAnnualSummaryFacts,
8869
9275
  shouldEnableContactsEntry,
8870
9276
  computeFriendScores,
8871
9277
  computeNonFriendScores,
@@ -8916,9 +9322,6 @@ export {
8916
9322
  isReasoningModel,
8917
9323
  getThinkingCompat,
8918
9324
  truncateToolResultText,
8919
- isNameMatchPlatform,
8920
- mergeConfirmedNames,
8921
- matchOwnerProfile,
8922
9325
  generateMessageKey,
8923
9326
  getCollidingPlatformIds,
8924
9327
  normalizePlatformId,
@@ -8959,6 +9362,17 @@ export {
8959
9362
  getChatDbMigrations,
8960
9363
  getContactsDir,
8961
9364
  getContactsFactsCacheDir,
9365
+ getGlobalInsightDir,
9366
+ getGlobalInsightFactsCacheDir,
9367
+ normalizeAnnualSummaryRange,
9368
+ getAnnualSummaryElapsedDayCount,
9369
+ toAnnualSummaryRangeKey,
9370
+ toAnnualSummaryLocalDate,
9371
+ getAnnualSummarySnapshotPath,
9372
+ readAnnualSummarySnapshot,
9373
+ writeAnnualSummarySnapshot,
9374
+ cleanupAnnualSummarySnapshotTempFiles,
9375
+ deleteAnnualSummarySnapshots,
8962
9376
  getPeopleRelationshipsDir,
8963
9377
  getPeopleRelationshipsFactsCacheDir,
8964
9378
  DatabaseManager,
@@ -8968,4 +9382,4 @@ export {
8968
9382
  StaticPathProvider,
8969
9383
  createDatabaseManagerAdapter
8970
9384
  };
8971
- //# sourceMappingURL=chunk-LVEJHB3X.mjs.map
9385
+ //# sourceMappingURL=chunk-DQ45LDKZ.mjs.map