chatlab-cli 0.30.2 → 0.31.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 (136) hide show
  1. package/dist/{chat-command-VBDMWOKL.mjs → chat-command-CHV7RLBH.mjs} +9 -8
  2. package/dist/{chat-command-VBDMWOKL.mjs.map → chat-command-CHV7RLBH.mjs.map} +1 -1
  3. package/dist/{chunk-326OCJOT.mjs → chunk-DA5T64RY.mjs} +2 -2
  4. package/dist/{chunk-M2PXDX4G.mjs → chunk-DBBL74RK.mjs} +31 -22
  5. package/dist/chunk-DBBL74RK.mjs.map +1 -0
  6. package/dist/{chunk-KBSAVUFV.mjs → chunk-EXD2SXWL.mjs} +89 -15
  7. package/dist/chunk-EXD2SXWL.mjs.map +1 -0
  8. package/dist/{chunk-D3DPCDII.mjs → chunk-JH5RAJT2.mjs} +83 -34
  9. package/dist/chunk-JH5RAJT2.mjs.map +1 -0
  10. package/dist/{chunk-5EE2EFPE.mjs → chunk-RD335EMA.mjs} +4 -4
  11. package/dist/{chunk-WV5GSRQM.mjs → chunk-RDCUGC24.mjs} +5 -15
  12. package/dist/chunk-RDCUGC24.mjs.map +1 -0
  13. package/dist/{chunk-TEX44HNL.mjs → chunk-SNCXU2QL.mjs} +5 -15
  14. package/dist/chunk-SNCXU2QL.mjs.map +1 -0
  15. package/dist/{chunk-36JGKW6K.mjs → chunk-T64GA5HP.mjs} +1134 -364
  16. package/dist/chunk-T64GA5HP.mjs.map +1 -0
  17. package/dist/{chunk-LVEJHB3X.mjs → chunk-UWWFOEGF.mjs} +494 -97
  18. package/dist/chunk-UWWFOEGF.mjs.map +1 -0
  19. package/dist/{chunk-ULNRUS55.mjs → chunk-WQCY45U2.mjs} +3 -3
  20. package/dist/chunk-YAQLYL52.mjs +14 -0
  21. package/dist/chunk-YAQLYL52.mjs.map +1 -0
  22. package/dist/{chunk-TCZHG3G7.mjs → chunk-YPQ72HMX.mjs} +2 -2
  23. package/dist/cli.mjs +8 -7
  24. package/dist/contacts-worker.mjs +2 -2
  25. package/dist/global-insight-worker.mjs +179 -0
  26. package/dist/global-insight-worker.mjs.map +1 -0
  27. package/dist/{http-L4AMELPZ.mjs → http-3B5ARN7A.mjs} +12 -11
  28. package/dist/{import-WWCSXGVS.mjs → import-2DZGNSEX.mjs} +10 -7
  29. package/dist/index.mjs +12 -11
  30. package/dist/{mcp-A4M3LT5O.mjs → mcp-44I6FUUQ.mjs} +12 -11
  31. package/dist/{mcp-A4M3LT5O.mjs.map → mcp-44I6FUUQ.mjs.map} +1 -1
  32. package/dist/people-relationships-worker.mjs +2 -2
  33. package/dist/semantic-index-worker.mjs +1 -1
  34. package/dist/{src-MPNBTFOE.mjs → src-R3QX6L3L.mjs} +26 -6
  35. package/dist/{stream-import-HIE7PNL4.mjs → stream-import-VUEL2TTU.mjs} +10 -7
  36. package/dist/{worker-runtime-BJXO24XX.mjs → worker-runtime-GJAOIIZW.mjs} +6 -5
  37. package/dist/{worker-runtime-BJXO24XX.mjs.map → worker-runtime-GJAOIIZW.mjs.map} +1 -1
  38. package/dist-web/assets/ActionToolsPanel-fAio70bI.css +1 -0
  39. package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-CdJT0t2f.js +110 -0
  40. package/dist-web/assets/{BufferResource-q3rzaWWd.js → BufferResource-BPGkshPa.js} +1 -1
  41. package/dist-web/assets/{CanvasRenderer-BRk1y8tp.js → CanvasRenderer-DTKkZhq4.js} +1 -1
  42. package/dist-web/assets/{EChartWordcloud-Clg60FMo.js → EChartWordcloud-DU3ZYdgz.js} +1 -1
  43. package/dist-web/assets/{Filter-BJwode73.js → Filter-CHXKzS2l.js} +1 -1
  44. 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
  45. package/dist-web/assets/MessageExportModal-h-zl0dx1.js +1 -0
  46. package/dist-web/assets/PageHeader-CK0hTsdx.js +1 -0
  47. package/dist-web/assets/PageHeader-XIXMTomn.css +1 -0
  48. package/dist-web/assets/{RelationshipGalaxyCanvas-CORMD7vL.js → RelationshipGalaxyCanvas-Dwdy5flh.js} +3 -3
  49. package/dist-web/assets/{RelationshipGalaxyThreeCanvas-B_w_P4ob.js → RelationshipGalaxyThreeCanvas-CtY4TGen.js} +1 -1
  50. package/dist-web/assets/{RenderTargetSystem-CGhV9R9E.js → RenderTargetSystem-BE56mKRG.js} +1 -1
  51. package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BoZyssJF.js +1 -0
  52. package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-27hMyAUE.js +1 -0
  53. package/dist-web/assets/{WebGLRenderer-CAokTE5X.js → WebGLRenderer-Dm18dxOf.js} +1 -1
  54. package/dist-web/assets/{WebGPURenderer-DzP4ggSy.js → WebGPURenderer-BF6TF-is.js} +1 -1
  55. package/dist-web/assets/annual-summary-time-range-DVLXK1r4.js +1 -0
  56. package/dist-web/assets/base-CFPyD9Gy.js +1 -0
  57. package/dist-web/assets/{browserAll-CAZCK6dd.js → browserAll-Cn_CfkXl.js} +1 -1
  58. package/dist-web/assets/dateFormat-BcqNKTQ1.js +1 -0
  59. package/dist-web/assets/{electron-CkPDbAaS.js → electron-B6xOabTq.js} +1 -1
  60. package/dist-web/assets/electron-hcWiB7Gg.js +1 -0
  61. package/dist-web/assets/fetch-BPkgnY0R.js +1 -0
  62. package/dist-web/assets/{fetch-LX9jrJCC.js → fetch-BRXmDI_2.js} +1 -1
  63. package/dist-web/assets/{fetch-Apd5OLJw.js → fetch-BUm1isWe.js} +1 -1
  64. package/dist-web/assets/{fetch-B8rik0TM.js → fetch-CBOJwwJp.js} +3 -3
  65. package/dist-web/assets/{fetch-wqMSiaK3.js → fetch-CEhUu1Yu.js} +1 -1
  66. package/dist-web/assets/fetch-C_EfVFJi.js +3 -0
  67. package/dist-web/assets/{fetch-DQ9UNNAy.js → fetch-DL_u25Ui.js} +1 -1
  68. package/dist-web/assets/{fetch-BIEXkvDq.js → fetch-DMLq3xPG.js} +1 -1
  69. package/dist-web/assets/{fetch--UbRoBT7.js → fetch-DylpNKCR.js} +1 -1
  70. package/dist-web/assets/fetch-etgwVKIw.js +1 -0
  71. package/dist-web/assets/index-0x1QPzKZ.js +1 -0
  72. package/dist-web/assets/index-B5S9FnfP.js +1 -0
  73. package/dist-web/assets/index-BS6loLHW.js +1 -0
  74. package/dist-web/assets/index-BfO_LpDv.css +1 -0
  75. package/dist-web/assets/index-BrTlAl8b.js +1 -0
  76. package/dist-web/assets/index-ByUaiVQK.css +1 -0
  77. package/dist-web/assets/{index-S-YQRH1E.js → index-C3TnydSt.js} +1 -1
  78. package/dist-web/assets/index-CAWO10k1.js +2 -0
  79. package/dist-web/assets/index-C_0GHEcb.css +1 -0
  80. package/dist-web/assets/index-Chm17wNe.js +2 -0
  81. package/dist-web/assets/index-DAr_2DlV.js +173 -0
  82. package/dist-web/assets/index-Em6upenM.js +64 -0
  83. package/dist-web/assets/index-FoTy2Cce.js +1 -0
  84. package/dist-web/assets/index-YADL4XIp.js +22 -0
  85. package/dist-web/assets/index-ZsZwPLWy.css +1 -0
  86. package/dist-web/assets/index-_6lck7Bv.css +1 -0
  87. package/dist-web/assets/index-aMIgqj43.js +1 -0
  88. package/dist-web/assets/index-y7cxH1Et.css +1 -0
  89. package/dist-web/assets/index-zZVsV5HB.js +1 -0
  90. package/dist-web/assets/{people-page-header-Mupn-U_b.js → people-page-header-BdKM1qhX.js} +1 -1
  91. package/dist-web/assets/types-CZnACqaB.js +1 -0
  92. package/dist-web/assets/{vendor-echarts-hJVnODyU.js → vendor-echarts-B-i_56Av.js} +1 -1
  93. package/dist-web/assets/{vendor-echarts-wordcloud-k5ih2Jl4.js → vendor-echarts-wordcloud-Ca8n6qS6.js} +1 -1
  94. package/dist-web/assets/{vendor-nuxt-ui-DaLxYaC4.js → vendor-nuxt-ui-CS1uxE9C.js} +2 -2
  95. package/dist-web/assets/{vendor-reka-ui-CzM4kDQ7.js → vendor-reka-ui-Cta6JPvN.js} +1 -1
  96. package/dist-web/assets/{web-DbKs6-1b.js → web-BUZ-dZy0.js} +1 -1
  97. package/dist-web/assets/{webworkerAll-Bhv-hBqR.js → webworkerAll-BKGP--A4.js} +1 -1
  98. package/dist-web/index.html +4 -4
  99. package/package.json +1 -1
  100. package/dist/chunk-36JGKW6K.mjs.map +0 -1
  101. package/dist/chunk-D3DPCDII.mjs.map +0 -1
  102. package/dist/chunk-KBSAVUFV.mjs.map +0 -1
  103. package/dist/chunk-LVEJHB3X.mjs.map +0 -1
  104. package/dist/chunk-M2PXDX4G.mjs.map +0 -1
  105. package/dist/chunk-TEX44HNL.mjs.map +0 -1
  106. package/dist/chunk-WV5GSRQM.mjs.map +0 -1
  107. package/dist-web/assets/DebugToolsPanel-D_lFIW6j.css +0 -1
  108. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-F4n0zNX2.js +0 -110
  109. package/dist-web/assets/MessageExportModal-CGcdMOyw.js +0 -1
  110. package/dist-web/assets/PageHeader-Bbn87QZS.css +0 -1
  111. package/dist-web/assets/PageHeader-CZaqOdBQ.js +0 -1
  112. package/dist-web/assets/electron-D9vE5t3H.js +0 -1
  113. package/dist-web/assets/fetch-1pB-HbYw.js +0 -3
  114. package/dist-web/assets/fetch-CF_3ZqRa.js +0 -1
  115. package/dist-web/assets/fetch-FSNxSnAp.js +0 -1
  116. package/dist-web/assets/index---rXG1hZ.css +0 -1
  117. package/dist-web/assets/index-B01uUoHE.js +0 -1
  118. package/dist-web/assets/index-B4l3rHie.css +0 -1
  119. package/dist-web/assets/index-BSIyyt0z.js +0 -1
  120. package/dist-web/assets/index-Bh8z441f.js +0 -2
  121. package/dist-web/assets/index-C0rya8v4.js +0 -1
  122. package/dist-web/assets/index-C1p9CbmN.css +0 -1
  123. package/dist-web/assets/index-COpza1A4.css +0 -1
  124. package/dist-web/assets/index-CZbZv2fh.js +0 -64
  125. package/dist-web/assets/index-CqUuHQBQ.js +0 -22
  126. package/dist-web/assets/index-CzeTP5MJ.js +0 -173
  127. package/dist-web/assets/index-DgNxTM_8.js +0 -2
  128. package/dist-web/assets/index-DosG7LmJ.css +0 -1
  129. /package/dist/{chunk-326OCJOT.mjs.map → chunk-DA5T64RY.mjs.map} +0 -0
  130. /package/dist/{chunk-5EE2EFPE.mjs.map → chunk-RD335EMA.mjs.map} +0 -0
  131. /package/dist/{chunk-ULNRUS55.mjs.map → chunk-WQCY45U2.mjs.map} +0 -0
  132. /package/dist/{chunk-TCZHG3G7.mjs.map → chunk-YPQ72HMX.mjs.map} +0 -0
  133. /package/dist/{http-L4AMELPZ.mjs.map → http-3B5ARN7A.mjs.map} +0 -0
  134. /package/dist/{import-WWCSXGVS.mjs.map → import-2DZGNSEX.mjs.map} +0 -0
  135. /package/dist/{src-MPNBTFOE.mjs.map → src-R3QX6L3L.mjs.map} +0 -0
  136. /package/dist/{stream-import-HIE7PNL4.mjs.map → stream-import-VUEL2TTU.mjs.map} +0 -0
@@ -3899,6 +3899,348 @@ function notGroupSelfMemberCondition(db, memberAlias) {
3899
3899
  )`;
3900
3900
  }
3901
3901
 
3902
+ // ../../packages/core/src/owner/owner-matching.ts
3903
+ var NAME_MATCH_PLATFORMS = /* @__PURE__ */ new Set(["whatsapp", "line", "instagram"]);
3904
+ function isNameMatchPlatform(platform) {
3905
+ return NAME_MATCH_PLATFORMS.has(platform);
3906
+ }
3907
+ var INVISIBLE_CHARS_RE = /[\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g;
3908
+ function normalizeOwnerName(name) {
3909
+ return name.replace(INVISIBLE_CHARS_RE, "").normalize("NFKC").replace(/\s+/g, " ").trim().toLowerCase();
3910
+ }
3911
+ function collectCandidateNames(member) {
3912
+ const names = [
3913
+ member.platformId,
3914
+ member.accountName ?? "",
3915
+ member.groupNickname ?? "",
3916
+ ...member.aliases ?? [],
3917
+ member.displayName ?? ""
3918
+ ];
3919
+ const result = [];
3920
+ const seen = /* @__PURE__ */ new Set();
3921
+ for (const name of names) {
3922
+ if (!name || !name.trim()) continue;
3923
+ if (seen.has(name)) continue;
3924
+ seen.add(name);
3925
+ result.push(name);
3926
+ }
3927
+ return result;
3928
+ }
3929
+ function mergeConfirmedNames(existing, member) {
3930
+ const result = [];
3931
+ const seen = /* @__PURE__ */ new Set();
3932
+ for (const name of [...existing, ...collectCandidateNames(member)]) {
3933
+ if (!name || !name.trim()) continue;
3934
+ if (seen.has(name)) continue;
3935
+ seen.add(name);
3936
+ result.push(name);
3937
+ }
3938
+ return result;
3939
+ }
3940
+ function matchOwnerProfile(platform, profile, members) {
3941
+ const exact = members.find((m) => m.platformId === profile.platformId);
3942
+ if (exact) {
3943
+ return { type: "exact", platformId: exact.platformId };
3944
+ }
3945
+ if (!isNameMatchPlatform(platform)) {
3946
+ return { type: "none" };
3947
+ }
3948
+ const confirmed = new Set(profile.confirmedNames.map(normalizeOwnerName).filter((n) => n.length > 0));
3949
+ if (confirmed.size === 0) {
3950
+ return { type: "none" };
3951
+ }
3952
+ const matched = members.filter(
3953
+ (m) => collectCandidateNames(m).some((name) => confirmed.has(normalizeOwnerName(name)))
3954
+ );
3955
+ if (matched.length === 1) {
3956
+ return { type: "name", platformId: matched[0].platformId };
3957
+ }
3958
+ if (matched.length > 1) {
3959
+ return { type: "ambiguous", platformIds: matched.map((m) => m.platformId) };
3960
+ }
3961
+ return { type: "none" };
3962
+ }
3963
+
3964
+ // ../../packages/core/src/query/contact-identity.ts
3965
+ function shouldScopeContactToSession(platform, contact) {
3966
+ if (isNameMatchPlatform(platform)) return true;
3967
+ return platform.trim().toLowerCase() === "qq" && contact.platformId.trim() === contact.name.trim();
3968
+ }
3969
+ function buildContactKey(platform, platformId, sessionId) {
3970
+ const normalizedPlatform = platform.trim();
3971
+ const normalizedPlatformId = platformId.trim();
3972
+ if (!normalizedPlatform) throw new Error("platform is required");
3973
+ if (!normalizedPlatformId) throw new Error("platformId is required");
3974
+ return sessionId?.trim() ? `${normalizedPlatform}:${sessionId.trim()}:${normalizedPlatformId}` : `${normalizedPlatform}:${normalizedPlatformId}`;
3975
+ }
3976
+
3977
+ // ../../packages/shared-types/index.ts
3978
+ var KNOWN_PLATFORMS = {
3979
+ QQ: "qq",
3980
+ WECHAT: "weixin",
3981
+ DISCORD: "discord",
3982
+ WHATSAPP: "whatsapp",
3983
+ TELEGRAM: "telegram",
3984
+ INSTAGRAM: "instagram",
3985
+ GOOGLE_CHAT: "google-chat",
3986
+ LINE: "line",
3987
+ UNKNOWN: "unknown"
3988
+ };
3989
+ var CONTACTS_TIME_RANGE_PRESETS = ["1y", "2y", "3y", "5y", "all"];
3990
+
3991
+ // ../../packages/core/src/query/global-insight.ts
3992
+ var SYSTEM_MESSAGE_TYPES2 = [80 /* SYSTEM */, 81 /* RECALL */];
3993
+ function getAnnualSummarySessionFacts(db, sessionId, range) {
3994
+ if (!isChatSessionDb(db)) return emptyFacts("not_chat_db");
3995
+ const meta = getSessionMeta(db);
3996
+ if (!meta) return emptyFacts("missing_meta");
3997
+ if (meta.type !== "private" /* PRIVATE */ && meta.type !== "group" /* GROUP */) return emptyFacts("unsupported_type");
3998
+ if (!meta.ownerId?.trim()) return emptyFacts("missing_owner");
3999
+ const owner = resolveOwnerMember(db);
4000
+ if (!owner) return emptyFacts("unresolved_owner");
4001
+ const contacts = getNonSystemMembersForContacts(db).filter((member) => member.id !== owner.id);
4002
+ let privateContact = null;
4003
+ if (meta.type === "private" /* PRIVATE */) {
4004
+ const activeContacts = getActivePrivateContacts(db, contacts, owner.id, range);
4005
+ const candidates = activeContacts.length > 0 ? activeContacts : contacts;
4006
+ if (candidates.length === 0) return emptyFacts("private_missing");
4007
+ if (candidates.length > 1) return emptyFacts("private_ambiguous");
4008
+ privateContact = candidates[0];
4009
+ }
4010
+ const ownerMessagesByDay = rowsToNumberRecord(
4011
+ db.prepare(
4012
+ `SELECT strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as key, COUNT(*) as count
4013
+ FROM message msg
4014
+ WHERE msg.sender_id = ? AND msg.ts >= ? AND msg.ts <= ?
4015
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4016
+ GROUP BY key ORDER BY key`
4017
+ ).all(owner.id, range.startTs, range.endTs)
4018
+ );
4019
+ const messageTypeCounts = rowsToNumberRecord(
4020
+ db.prepare(
4021
+ `SELECT CAST(msg.type AS TEXT) as key, COUNT(*) as count
4022
+ FROM message msg
4023
+ WHERE msg.sender_id = ? AND msg.ts >= ? AND msg.ts <= ?
4024
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4025
+ GROUP BY msg.type ORDER BY msg.type`
4026
+ ).all(owner.id, range.startTs, range.endTs)
4027
+ );
4028
+ const textLengthCounts = rowsToNumberRecord(
4029
+ db.prepare(
4030
+ `SELECT CAST(LENGTH(msg.content) AS TEXT) as key, COUNT(*) as count
4031
+ FROM message msg
4032
+ WHERE msg.sender_id = ? AND msg.ts >= ? AND msg.ts <= ?
4033
+ AND msg.type = ${0 /* TEXT */} AND msg.content IS NOT NULL AND LENGTH(msg.content) > 0
4034
+ GROUP BY LENGTH(msg.content) ORDER BY LENGTH(msg.content)`
4035
+ ).all(owner.id, range.startTs, range.endTs)
4036
+ );
4037
+ const availableDataYears = db.prepare(
4038
+ `SELECT DISTINCT CAST(strftime('%Y', msg.ts, 'unixepoch', 'localtime') AS INTEGER) as year
4039
+ FROM message msg
4040
+ WHERE msg.sender_id = ? AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4041
+ ORDER BY year DESC`
4042
+ ).all(owner.id).map((row) => row.year);
4043
+ return {
4044
+ kind: "analyzed",
4045
+ availableDataYears,
4046
+ ownerMessagesByDay,
4047
+ directContactKeysByDay: meta.type === "private" /* PRIVATE */ && privateContact ? getPrivateDirectContactsByDay(db, sessionId, meta.platform, owner.id, privateContact, range) : getGroupDirectContactsByDay(db, sessionId, meta.platform, owner.id, contacts, range),
4048
+ messageTypeCounts,
4049
+ textLengthCounts
4050
+ };
4051
+ }
4052
+ function aggregateAnnualSummaryFacts(facts, range, elapsedDayCount) {
4053
+ const ownerMessagesByDay = /* @__PURE__ */ new Map();
4054
+ const directContactsByDay = /* @__PURE__ */ new Map();
4055
+ const directContacts = /* @__PURE__ */ new Set();
4056
+ const messageTypes = /* @__PURE__ */ new Map();
4057
+ const textLengths = /* @__PURE__ */ new Map();
4058
+ const availableDataYears = /* @__PURE__ */ new Set();
4059
+ const coverage = {
4060
+ totalSessions: 0,
4061
+ analyzedSessions: 0,
4062
+ missingOwnerSessions: 0,
4063
+ unresolvedOwnerSessions: 0,
4064
+ failedSessions: 0
4065
+ };
4066
+ for (const item of facts) {
4067
+ if (item.kind === "not_chat_db" || item.kind === "missing_meta" || item.kind === "unsupported_type") continue;
4068
+ coverage.totalSessions++;
4069
+ if (item.kind === "missing_owner") {
4070
+ coverage.missingOwnerSessions++;
4071
+ continue;
4072
+ }
4073
+ if (item.kind === "unresolved_owner") {
4074
+ coverage.unresolvedOwnerSessions++;
4075
+ continue;
4076
+ }
4077
+ if (item.kind !== "analyzed") {
4078
+ coverage.failedSessions++;
4079
+ continue;
4080
+ }
4081
+ coverage.analyzedSessions++;
4082
+ item.availableDataYears.forEach((year) => availableDataYears.add(year));
4083
+ mergeNumberRecord(ownerMessagesByDay, item.ownerMessagesByDay);
4084
+ mergeNumberRecord(messageTypes, item.messageTypeCounts, Number);
4085
+ mergeNumberRecord(textLengths, item.textLengthCounts, Number);
4086
+ for (const [date, keys] of Object.entries(item.directContactKeysByDay)) {
4087
+ const daily = directContactsByDay.get(date) ?? /* @__PURE__ */ new Set();
4088
+ keys.forEach((key) => {
4089
+ daily.add(key);
4090
+ directContacts.add(key);
4091
+ });
4092
+ directContactsByDay.set(date, daily);
4093
+ }
4094
+ }
4095
+ const dailyActivity = [...ownerMessagesByDay.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, messageCount]) => ({ date, messageCount }));
4096
+ const sentMessageCount = dailyActivity.reduce((sum, item) => sum + item.messageCount, 0);
4097
+ const dailyDirectContactTotal = [...directContactsByDay.values()].reduce((sum, keys) => sum + keys.size, 0);
4098
+ const years = [...availableDataYears].sort((a, b) => b - a);
4099
+ return {
4100
+ availableDataYears: years,
4101
+ latestDataYear: years[0] ?? null,
4102
+ metrics: {
4103
+ sentMessageCount,
4104
+ activeDayCount: dailyActivity.length,
4105
+ directContactCount: directContacts.size,
4106
+ averageMessagesPerDay: roundAverage(sentMessageCount, elapsedDayCount),
4107
+ averageDirectContactsPerDay: roundAverage(dailyDirectContactTotal, elapsedDayCount)
4108
+ },
4109
+ monthlyActivity: buildMonthlyActivity(range, ownerMessagesByDay),
4110
+ dailyActivity,
4111
+ messageTypes: [...messageTypes.entries()].sort(([a], [b]) => a - b).map(([type, count]) => ({ type, count })),
4112
+ textLength: buildTextLengthSummary(textLengths),
4113
+ coverage
4114
+ };
4115
+ }
4116
+ function getActivePrivateContacts(db, contacts, ownerId, range) {
4117
+ if (contacts.length <= 1) return contacts;
4118
+ const byId = new Map(contacts.map((contact) => [contact.id, contact]));
4119
+ const rows = db.prepare(
4120
+ `SELECT DISTINCT msg.sender_id as senderId FROM message msg
4121
+ WHERE msg.sender_id <> ? AND msg.ts >= ? AND msg.ts <= ?
4122
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})`
4123
+ ).all(ownerId, range.startTs, range.endTs);
4124
+ return rows.map((row) => byId.get(row.senderId)).filter((contact) => Boolean(contact));
4125
+ }
4126
+ function getPrivateDirectContactsByDay(db, sessionId, platform, ownerId, contact, range) {
4127
+ const rows = db.prepare(
4128
+ `SELECT DISTINCT strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as date
4129
+ FROM message msg
4130
+ WHERE msg.sender_id IN (?, ?) AND msg.ts >= ? AND msg.ts <= ?
4131
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})
4132
+ ORDER BY date`
4133
+ ).all(ownerId, contact.id, range.startTs, range.endTs);
4134
+ const key = buildContactKey(
4135
+ platform,
4136
+ contact.platformId,
4137
+ shouldScopeContactToSession(platform, contact) ? sessionId : void 0
4138
+ );
4139
+ return Object.fromEntries(rows.map((row) => [row.date, [key]]));
4140
+ }
4141
+ function getGroupDirectContactsByDay(db, sessionId, platform, ownerId, contacts, range) {
4142
+ const byId = new Map(contacts.map((contact) => [contact.id, contact]));
4143
+ const rows = db.prepare(
4144
+ `SELECT
4145
+ strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as date,
4146
+ msg.sender_id as replySenderId,
4147
+ target.sender_id as targetSenderId
4148
+ FROM message msg
4149
+ JOIN message target ON msg.reply_to_message_id = target.platform_message_id
4150
+ WHERE msg.ts >= ? AND msg.ts <= ? AND msg.reply_to_message_id IS NOT NULL
4151
+ AND msg.type NOT IN (${SYSTEM_MESSAGE_TYPES2.join(", ")})`
4152
+ ).all(range.startTs, range.endTs);
4153
+ const byDay = /* @__PURE__ */ new Map();
4154
+ for (const row of rows) {
4155
+ const contactId = row.replySenderId === ownerId ? row.targetSenderId : row.targetSenderId === ownerId ? row.replySenderId : null;
4156
+ if (contactId === null) continue;
4157
+ const contact = byId.get(contactId);
4158
+ if (!contact) continue;
4159
+ const key = buildContactKey(
4160
+ platform,
4161
+ contact.platformId,
4162
+ shouldScopeContactToSession(platform, contact) ? sessionId : void 0
4163
+ );
4164
+ const keys = byDay.get(row.date) ?? /* @__PURE__ */ new Set();
4165
+ keys.add(key);
4166
+ byDay.set(row.date, keys);
4167
+ }
4168
+ return Object.fromEntries([...byDay.entries()].map(([date, keys]) => [date, [...keys].sort()]));
4169
+ }
4170
+ function buildMonthlyActivity(range, ownerMessagesByDay) {
4171
+ const counts = /* @__PURE__ */ new Map();
4172
+ for (const [date, count] of ownerMessagesByDay) {
4173
+ const month = date.slice(0, 7);
4174
+ counts.set(month, (counts.get(month) ?? 0) + count);
4175
+ }
4176
+ return listMonths(range).map((month) => ({ month, messageCount: counts.get(month) ?? 0 }));
4177
+ }
4178
+ function listMonths(range) {
4179
+ if (range.mode === "year" && range.year) {
4180
+ return Array.from({ length: 12 }, (_, index) => `${range.year}-${String(index + 1).padStart(2, "0")}`);
4181
+ }
4182
+ const current = new Date(range.startTs * 1e3);
4183
+ current.setDate(1);
4184
+ current.setHours(0, 0, 0, 0);
4185
+ const end = new Date(range.endTs * 1e3);
4186
+ const result = [];
4187
+ while (current <= end) {
4188
+ result.push(`${current.getFullYear()}-${String(current.getMonth() + 1).padStart(2, "0")}`);
4189
+ current.setMonth(current.getMonth() + 1);
4190
+ }
4191
+ return result;
4192
+ }
4193
+ function buildTextLengthSummary(lengths) {
4194
+ const textMessageCount = [...lengths.values()].reduce((sum, count) => sum + count, 0);
4195
+ return {
4196
+ textMessageCount,
4197
+ median: weightedPercentile(lengths, 0.5),
4198
+ p90: weightedPercentile(lengths, 0.9),
4199
+ buckets: [
4200
+ { key: "1-10", count: countLengthRange(lengths, 1, 10) },
4201
+ { key: "11-30", count: countLengthRange(lengths, 11, 30) },
4202
+ { key: "31-100", count: countLengthRange(lengths, 31, 100) },
4203
+ { key: "101-300", count: countLengthRange(lengths, 101, 300) },
4204
+ { key: "300+", count: countLengthRange(lengths, 301, Number.POSITIVE_INFINITY) }
4205
+ ]
4206
+ };
4207
+ }
4208
+ function weightedPercentile(lengths, percentile) {
4209
+ const entries = [...lengths.entries()].sort(([a], [b]) => a - b);
4210
+ const total = entries.reduce((sum, [, count]) => sum + count, 0);
4211
+ if (total === 0) return null;
4212
+ const target = Math.floor((total - 1) * percentile);
4213
+ let seen = 0;
4214
+ for (const [length, count] of entries) {
4215
+ seen += count;
4216
+ if (seen > target) return length;
4217
+ }
4218
+ return entries.at(-1)?.[0] ?? null;
4219
+ }
4220
+ function countLengthRange(lengths, min, max) {
4221
+ let count = 0;
4222
+ for (const [length, value] of lengths) {
4223
+ if (length >= min && length <= max) count += value;
4224
+ }
4225
+ return count;
4226
+ }
4227
+ function rowsToNumberRecord(rows) {
4228
+ return Object.fromEntries(rows.filter((row) => row.key).map((row) => [row.key, row.count]));
4229
+ }
4230
+ function mergeNumberRecord(target, source, mapKey = (key) => key) {
4231
+ for (const [key, value] of Object.entries(source)) {
4232
+ const mapped = mapKey(key);
4233
+ target.set(mapped, (target.get(mapped) ?? 0) + value);
4234
+ }
4235
+ }
4236
+ function roundAverage(total, days) {
4237
+ if (days <= 0) return 0;
4238
+ return Math.round(total / days * 100) / 100;
4239
+ }
4240
+ function emptyFacts(kind) {
4241
+ return { kind, availableDataYears: [] };
4242
+ }
4243
+
3902
4244
  // ../../packages/core/src/query/contact-enablement.ts
3903
4245
  var MIN_PRIVATE_SESSIONS_FOR_CONTACTS = 5;
3904
4246
  var MIN_GROUP_SESSIONS_FOR_CONTACTS = 1;
@@ -5890,20 +6232,6 @@ function getRepeatAnalysis(db, filter) {
5890
6232
  return computeRepeat(messages);
5891
6233
  }
5892
6234
 
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
6235
  // ../../packages/core/src/message-type.ts
5908
6236
  var TYPE_STRING_MAP = {
5909
6237
  [0 /* TEXT */]: "text",
@@ -7093,68 +7421,6 @@ function isValidWord(word, locale, minLength, enableStopwords, isStopwordFn) {
7093
7421
  return true;
7094
7422
  }
7095
7423
 
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
7424
  // ../../packages/core/src/import/dedup.ts
7159
7425
  function fnv1a64(input) {
7160
7426
  let h0 = 2166136261;
@@ -8479,21 +8745,132 @@ function getContactsFactsCacheDir(userDataDir) {
8479
8745
  return path16.join(getContactsDir(userDataDir), CONTACTS_FACTS_DIR_NAME);
8480
8746
  }
8481
8747
 
8482
- // ../../packages/node-runtime/src/services/people/relationships/paths.ts
8748
+ // ../../packages/node-runtime/src/services/global-insight/paths.ts
8483
8749
  import path17 from "path";
8750
+ function getGlobalInsightDir(userDataDir) {
8751
+ return path17.join(userDataDir, "insight", "annual-summary");
8752
+ }
8753
+ function getGlobalInsightFactsCacheDir(userDataDir) {
8754
+ return path17.join(getGlobalInsightDir(userDataDir), "facts");
8755
+ }
8756
+
8757
+ // ../../packages/node-runtime/src/services/people/relationships/paths.ts
8758
+ import path18 from "path";
8484
8759
  var PEOPLE_DIR_NAME = "people";
8485
8760
  var RELATIONSHIPS_DIR_NAME = "relationships";
8486
8761
  var RELATIONSHIPS_FACTS_DIR_NAME = "facts";
8487
8762
  function getPeopleRelationshipsDir(userDataDir) {
8488
- return path17.join(userDataDir, PEOPLE_DIR_NAME, RELATIONSHIPS_DIR_NAME);
8763
+ return path18.join(userDataDir, PEOPLE_DIR_NAME, RELATIONSHIPS_DIR_NAME);
8489
8764
  }
8490
8765
  function getPeopleRelationshipsFactsCacheDir(userDataDir) {
8491
- return path17.join(getPeopleRelationshipsDir(userDataDir), RELATIONSHIPS_FACTS_DIR_NAME);
8766
+ return path18.join(getPeopleRelationshipsDir(userDataDir), RELATIONSHIPS_FACTS_DIR_NAME);
8767
+ }
8768
+
8769
+ // ../../packages/node-runtime/src/database-manager.ts
8770
+ import * as fs17 from "fs";
8771
+ import * as path20 from "path";
8772
+
8773
+ // ../../packages/node-runtime/src/services/global-insight/snapshot.ts
8774
+ import fs16 from "fs";
8775
+ import path19 from "path";
8776
+
8777
+ // ../../packages/node-runtime/src/services/global-insight/time-range.ts
8778
+ function normalizeAnnualSummaryRange(input, nowInput = /* @__PURE__ */ new Date()) {
8779
+ const now = new Date(nowInput);
8780
+ const nowTs = Math.floor(now.getTime() / 1e3);
8781
+ if (input.mode === "recent") {
8782
+ const start2 = new Date(now);
8783
+ start2.setHours(0, 0, 0, 0);
8784
+ start2.setDate(start2.getDate() - 364);
8785
+ return {
8786
+ mode: "recent",
8787
+ days: 365,
8788
+ startTs: Math.floor(start2.getTime() / 1e3),
8789
+ endTs: nowTs
8790
+ };
8791
+ }
8792
+ const currentYear = now.getFullYear();
8793
+ const parsedYear = Number(input.year);
8794
+ const year = Number.isInteger(parsedYear) && parsedYear >= 1970 && parsedYear <= currentYear ? parsedYear : currentYear;
8795
+ const start = new Date(year, 0, 1, 0, 0, 0);
8796
+ const end = year === currentYear ? now : new Date(year, 11, 31, 23, 59, 59);
8797
+ return {
8798
+ mode: "year",
8799
+ year,
8800
+ startTs: Math.floor(start.getTime() / 1e3),
8801
+ endTs: Math.floor(end.getTime() / 1e3)
8802
+ };
8803
+ }
8804
+ function getAnnualSummaryElapsedDayCount(range) {
8805
+ const start = new Date(range.startTs * 1e3);
8806
+ const end = new Date(range.endTs * 1e3);
8807
+ const startDay = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
8808
+ const endDay = Date.UTC(end.getFullYear(), end.getMonth(), end.getDate());
8809
+ return Math.max(Math.floor((endDay - startDay) / 864e5) + 1, 0);
8810
+ }
8811
+ function toAnnualSummaryRangeKey(range) {
8812
+ return range.mode === "year" ? `year-${range.year}` : "recent-365";
8813
+ }
8814
+ function toAnnualSummaryLocalDate(range) {
8815
+ const date = new Date(range.endTs * 1e3);
8816
+ return [
8817
+ date.getFullYear(),
8818
+ String(date.getMonth() + 1).padStart(2, "0"),
8819
+ String(date.getDate()).padStart(2, "0")
8820
+ ].join("-");
8821
+ }
8822
+
8823
+ // ../../packages/node-runtime/src/services/global-insight/snapshot.ts
8824
+ var SNAPSHOT_TMP_PREFIX = "annual-summary.tmp-";
8825
+ function getAnnualSummarySnapshotPath(snapshotDir, range) {
8826
+ return path19.join(snapshotDir, `annual-summary-${toAnnualSummaryRangeKey(range)}.json`);
8827
+ }
8828
+ function readAnnualSummarySnapshot(snapshotDir, range, options = {}) {
8829
+ const snapshotPath = getAnnualSummarySnapshotPath(snapshotDir, range);
8830
+ if (!fs16.existsSync(snapshotPath)) return null;
8831
+ try {
8832
+ return JSON.parse(fs16.readFileSync(snapshotPath, "utf-8"));
8833
+ } catch (error) {
8834
+ const backupPath = path19.join(snapshotDir, `annual-summary.corrupt-${options.now?.() ?? Date.now()}.json`);
8835
+ try {
8836
+ fs16.renameSync(snapshotPath, backupPath);
8837
+ } catch (renameError) {
8838
+ appLogger.warn("global-insight", "failed to backup corrupt annual summary snapshot", renameError);
8839
+ }
8840
+ appLogger.warn("global-insight", "annual summary snapshot is corrupt", error);
8841
+ return null;
8842
+ }
8843
+ }
8844
+ function writeAnnualSummarySnapshot(snapshotDir, snapshot) {
8845
+ fs16.mkdirSync(snapshotDir, { recursive: true });
8846
+ const tmpPath = path19.join(snapshotDir, `${SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
8847
+ fs16.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
8848
+ fs16.renameSync(tmpPath, getAnnualSummarySnapshotPath(snapshotDir, snapshot.range));
8849
+ }
8850
+ function cleanupAnnualSummarySnapshotTempFiles(snapshotDir) {
8851
+ if (!fs16.existsSync(snapshotDir)) return;
8852
+ for (const name of fs16.readdirSync(snapshotDir)) {
8853
+ if (!name.startsWith(SNAPSHOT_TMP_PREFIX)) continue;
8854
+ try {
8855
+ fs16.rmSync(path19.join(snapshotDir, name), { force: true });
8856
+ } catch (error) {
8857
+ appLogger.warn("global-insight", "failed to remove annual summary snapshot temp file", error);
8858
+ }
8859
+ }
8860
+ }
8861
+ function deleteAnnualSummarySnapshots(snapshotDir) {
8862
+ if (!fs16.existsSync(snapshotDir)) return;
8863
+ for (const name of fs16.readdirSync(snapshotDir)) {
8864
+ if (!name.startsWith("annual-summary-") && !name.startsWith("annual-summary.")) continue;
8865
+ try {
8866
+ fs16.rmSync(path19.join(snapshotDir, name), { force: true });
8867
+ } catch (error) {
8868
+ appLogger.warn("global-insight", "failed to remove annual summary snapshot", error);
8869
+ }
8870
+ }
8492
8871
  }
8493
8872
 
8494
8873
  // ../../packages/node-runtime/src/database-manager.ts
8495
- import * as fs16 from "fs";
8496
- import * as path18 from "path";
8497
8874
  function createMigrationDeps(overrides) {
8498
8875
  return {
8499
8876
  tokenizeForFts,
@@ -8524,7 +8901,7 @@ var DatabaseManager = class {
8524
8901
  return this.cache.get(sessionId);
8525
8902
  }
8526
8903
  const dbPath = this.getDbPath(sessionId);
8527
- if (!fs16.existsSync(dbPath)) return null;
8904
+ if (!fs17.existsSync(dbPath)) return null;
8528
8905
  this.migrateIfNeeded(dbPath);
8529
8906
  this.assertCompatible();
8530
8907
  const adapter = openBetterSqliteDatabase(dbPath, {
@@ -8570,7 +8947,7 @@ var DatabaseManager = class {
8570
8947
  this.cache.delete(sessionId);
8571
8948
  }
8572
8949
  const dbPath = this.getDbPath(sessionId);
8573
- if (!fs16.existsSync(dbPath)) return null;
8950
+ if (!fs17.existsSync(dbPath)) return null;
8574
8951
  const adapter = openBetterSqliteDatabase(dbPath, {
8575
8952
  readonly: false,
8576
8953
  nativeBinding: this.nativeBinding
@@ -8610,28 +8987,31 @@ var DatabaseManager = class {
8610
8987
  listSessionIds() {
8611
8988
  this.assertCompatible();
8612
8989
  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) => {
8990
+ if (!fs17.existsSync(dbDir)) return [];
8991
+ return fs17.readdirSync(dbDir).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", "")).filter((id) => {
8615
8992
  const db = this.open(id);
8616
8993
  if (!db) return false;
8617
8994
  return isChatSessionDb(db);
8618
8995
  });
8619
8996
  }
8997
+ getUserDataDir() {
8998
+ return this.pathProvider.getUserDataDir();
8999
+ }
8620
9000
  /**
8621
9001
  * 获取数据库文件路径
8622
9002
  */
8623
9003
  getDbPath(sessionId) {
8624
- return path18.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
9004
+ return path20.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
8625
9005
  }
8626
9006
  openRawSessionDatabase(sessionId, options = {}) {
8627
9007
  this.assertCompatible();
8628
9008
  const dbPath = this.getDbPath(sessionId);
8629
- if (!options.create && !fs16.existsSync(dbPath)) {
9009
+ if (!options.create && !fs17.existsSync(dbPath)) {
8630
9010
  throw new Error(`Session database not found: ${sessionId}`);
8631
9011
  }
8632
9012
  if (!options.readonly) {
8633
9013
  this.close(sessionId);
8634
- fs16.mkdirSync(path18.dirname(dbPath), { recursive: true });
9014
+ fs17.mkdirSync(path20.dirname(dbPath), { recursive: true });
8635
9015
  }
8636
9016
  const adapter = openBetterSqliteDatabase(dbPath, {
8637
9017
  readonly: options.readonly ?? false,
@@ -8649,18 +9029,20 @@ var DatabaseManager = class {
8649
9029
  deleteSessionDatabaseFiles(sessionId) {
8650
9030
  this.close(sessionId);
8651
9031
  const dbPath = this.getDbPath(sessionId);
8652
- const existed = ["", "-wal", "-shm"].some((suffix) => fs16.existsSync(dbPath + suffix));
9032
+ const existed = ["", "-wal", "-shm"].some((suffix) => fs17.existsSync(dbPath + suffix));
8653
9033
  for (const suffix of ["", "-wal", "-shm"]) {
8654
9034
  try {
8655
9035
  const filePath = dbPath + suffix;
8656
- if (fs16.existsSync(filePath)) fs16.unlinkSync(filePath);
9036
+ if (fs17.existsSync(filePath)) fs17.unlinkSync(filePath);
8657
9037
  } catch {
8658
9038
  }
8659
9039
  }
8660
9040
  const cacheDir = this.pathProvider.getCacheDir();
8661
9041
  deleteSessionCache(sessionId, cacheDir);
8662
- deleteSessionCache(sessionId, path18.join(cacheDir, "query"));
9042
+ deleteSessionCache(sessionId, path20.join(cacheDir, "query"));
8663
9043
  deleteSessionCache(sessionId, getContactsFactsCacheDir(this.pathProvider.getUserDataDir()));
9044
+ deleteSessionCache(sessionId, getGlobalInsightFactsCacheDir(this.pathProvider.getUserDataDir()));
9045
+ deleteAnnualSummarySnapshots(getGlobalInsightDir(this.pathProvider.getUserDataDir()));
8664
9046
  deleteSessionCache(sessionId, getPeopleRelationshipsFactsCacheDir(this.pathProvider.getUserDataDir()));
8665
9047
  return existed;
8666
9048
  }
@@ -8698,12 +9080,12 @@ function shouldRepairCompatibilityGate(schemaVersion) {
8698
9080
  }
8699
9081
 
8700
9082
  // ../../packages/node-runtime/src/cache/analytics-cache.ts
8701
- import * as fs17 from "fs";
9083
+ import * as fs18 from "fs";
8702
9084
  function getDbFileVersion(dbPath) {
8703
9085
  const parts = [];
8704
9086
  for (const p of [dbPath, `${dbPath}-wal`]) {
8705
9087
  try {
8706
- const st = fs17.statSync(p);
9088
+ const st = fs18.statSync(p);
8707
9089
  parts.push(`${Math.floor(st.mtimeMs)}:${st.size}`);
8708
9090
  } catch {
8709
9091
  parts.push("-");
@@ -8866,6 +9248,13 @@ export {
8866
9248
  getPrivateContactFacts,
8867
9249
  getGroupContactFacts,
8868
9250
  getGroupRelationshipGraphFacts,
9251
+ isNameMatchPlatform,
9252
+ mergeConfirmedNames,
9253
+ matchOwnerProfile,
9254
+ shouldScopeContactToSession,
9255
+ buildContactKey,
9256
+ getAnnualSummarySessionFacts,
9257
+ aggregateAnnualSummaryFacts,
8869
9258
  shouldEnableContactsEntry,
8870
9259
  computeFriendScores,
8871
9260
  computeNonFriendScores,
@@ -8916,9 +9305,6 @@ export {
8916
9305
  isReasoningModel,
8917
9306
  getThinkingCompat,
8918
9307
  truncateToolResultText,
8919
- isNameMatchPlatform,
8920
- mergeConfirmedNames,
8921
- matchOwnerProfile,
8922
9308
  generateMessageKey,
8923
9309
  getCollidingPlatformIds,
8924
9310
  normalizePlatformId,
@@ -8959,6 +9345,17 @@ export {
8959
9345
  getChatDbMigrations,
8960
9346
  getContactsDir,
8961
9347
  getContactsFactsCacheDir,
9348
+ getGlobalInsightDir,
9349
+ getGlobalInsightFactsCacheDir,
9350
+ normalizeAnnualSummaryRange,
9351
+ getAnnualSummaryElapsedDayCount,
9352
+ toAnnualSummaryRangeKey,
9353
+ toAnnualSummaryLocalDate,
9354
+ getAnnualSummarySnapshotPath,
9355
+ readAnnualSummarySnapshot,
9356
+ writeAnnualSummarySnapshot,
9357
+ cleanupAnnualSummarySnapshotTempFiles,
9358
+ deleteAnnualSummarySnapshots,
8962
9359
  getPeopleRelationshipsDir,
8963
9360
  getPeopleRelationshipsFactsCacheDir,
8964
9361
  DatabaseManager,
@@ -8968,4 +9365,4 @@ export {
8968
9365
  StaticPathProvider,
8969
9366
  createDatabaseManagerAdapter
8970
9367
  };
8971
- //# sourceMappingURL=chunk-LVEJHB3X.mjs.map
9368
+ //# sourceMappingURL=chunk-UWWFOEGF.mjs.map