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.
- package/dist/{chat-command-VBDMWOKL.mjs → chat-command-MOETAGU5.mjs} +9 -8
- package/dist/{chat-command-VBDMWOKL.mjs.map → chat-command-MOETAGU5.mjs.map} +1 -1
- package/dist/{chunk-M2PXDX4G.mjs → chunk-2IXPWPLR.mjs} +168 -77
- package/dist/chunk-2IXPWPLR.mjs.map +1 -0
- package/dist/{chunk-TCZHG3G7.mjs → chunk-3VMKS7PU.mjs} +44 -5
- package/dist/chunk-3VMKS7PU.mjs.map +1 -0
- package/dist/{chunk-TEX44HNL.mjs → chunk-7HBVGVOB.mjs} +5 -15
- package/dist/chunk-7HBVGVOB.mjs.map +1 -0
- package/dist/{chunk-LVEJHB3X.mjs → chunk-DQ45LDKZ.mjs} +512 -98
- package/dist/chunk-DQ45LDKZ.mjs.map +1 -0
- package/dist/{chunk-ULNRUS55.mjs → chunk-E6W2RURS.mjs} +3 -3
- package/dist/{chunk-36JGKW6K.mjs → chunk-KCPGEILH.mjs} +1503 -530
- package/dist/chunk-KCPGEILH.mjs.map +1 -0
- package/dist/{chunk-WV5GSRQM.mjs → chunk-LJXSUN25.mjs} +5 -15
- package/dist/chunk-LJXSUN25.mjs.map +1 -0
- package/dist/chunk-N5AGDT7I.mjs +268 -0
- package/dist/chunk-N5AGDT7I.mjs.map +1 -0
- package/dist/{chunk-D3DPCDII.mjs → chunk-SZEBCNBB.mjs} +193 -79
- package/dist/chunk-SZEBCNBB.mjs.map +1 -0
- package/dist/{chunk-5EE2EFPE.mjs → chunk-VOVLPSG6.mjs} +29 -52
- package/dist/chunk-VOVLPSG6.mjs.map +1 -0
- package/dist/chunk-YAQLYL52.mjs +14 -0
- package/dist/chunk-YAQLYL52.mjs.map +1 -0
- package/dist/{chunk-326OCJOT.mjs → chunk-ZVWUR7ET.mjs} +2 -2
- package/dist/cli.mjs +10 -7
- package/dist/contacts-worker.mjs +2 -2
- package/dist/global-insight-worker.mjs +179 -0
- package/dist/global-insight-worker.mjs.map +1 -0
- package/dist/{http-L4AMELPZ.mjs → http-M6NHWJZD.mjs} +12 -11
- package/dist/{import-WWCSXGVS.mjs → import-SEYHFXS5.mjs} +12 -7
- package/dist/index.mjs +13 -12
- package/dist/{mcp-A4M3LT5O.mjs → mcp-MIPFYRLV.mjs} +12 -11
- package/dist/{mcp-A4M3LT5O.mjs.map → mcp-MIPFYRLV.mjs.map} +1 -1
- package/dist/people-relationships-worker.mjs +2 -2
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-MPNBTFOE.mjs → src-7OD6RD5V.mjs} +38 -6
- package/dist/{stream-import-HIE7PNL4.mjs → stream-import-AWEHGQJY.mjs} +12 -7
- package/dist/{worker-runtime-BJXO24XX.mjs → worker-runtime-TGYMASIE.mjs} +6 -5
- package/dist/{worker-runtime-BJXO24XX.mjs.map → worker-runtime-TGYMASIE.mjs.map} +1 -1
- package/dist-web/assets/ActionToolsPanel-fAio70bI.css +1 -0
- package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-CkDGVRXe.js +110 -0
- package/dist-web/assets/{BufferResource-q3rzaWWd.js → BufferResource-CHI62pIA.js} +1 -1
- package/dist-web/assets/{CanvasRenderer-BRk1y8tp.js → CanvasRenderer-OZRoiF0j.js} +1 -1
- package/dist-web/assets/{EChartWordcloud-Clg60FMo.js → EChartWordcloud-DU3ZYdgz.js} +1 -1
- package/dist-web/assets/{Filter-BJwode73.js → Filter-DNb5VErW.js} +1 -1
- 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
- package/dist-web/assets/MessageExportModal-CqP-w7HP.js +1 -0
- package/dist-web/assets/PageHeader-Ck8ULyZH.js +1 -0
- package/dist-web/assets/PageHeader-XIXMTomn.css +1 -0
- package/dist-web/assets/{RelationshipGalaxyCanvas-CORMD7vL.js → RelationshipGalaxyCanvas-ioRNObb5.js} +3 -3
- package/dist-web/assets/{RelationshipGalaxyThreeCanvas-B_w_P4ob.js → RelationshipGalaxyThreeCanvas-L1Y43p1A.js} +1 -1
- package/dist-web/assets/{RenderTargetSystem-CGhV9R9E.js → RenderTargetSystem-fJ7D7Chv.js} +1 -1
- package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BoZyssJF.js +1 -0
- package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-7SEaCxDL.js +1 -0
- package/dist-web/assets/{WebGLRenderer-CAokTE5X.js → WebGLRenderer-BD3ZUtxH.js} +1 -1
- package/dist-web/assets/{WebGPURenderer-DzP4ggSy.js → WebGPURenderer-DZXYsT6D.js} +1 -1
- package/dist-web/assets/annual-summary-time-range-DVLXK1r4.js +1 -0
- package/dist-web/assets/base-DTElkJcC.js +1 -0
- package/dist-web/assets/{browserAll-CAZCK6dd.js → browserAll-ChT6N6a9.js} +1 -1
- package/dist-web/assets/dateFormat-D9WibwOu.js +1 -0
- package/dist-web/assets/{electron-CkPDbAaS.js → electron-CIzyGxH_.js} +1 -1
- package/dist-web/assets/electron-hcWiB7Gg.js +1 -0
- package/dist-web/assets/fetch-Avtnh8cJ.js +3 -0
- package/dist-web/assets/{fetch-DQ9UNNAy.js → fetch-BFnrBahy.js} +1 -1
- package/dist-web/assets/fetch-C9rx2isC.js +31 -0
- package/dist-web/assets/fetch-Ccq_0ecb.js +1 -0
- package/dist-web/assets/{fetch-BIEXkvDq.js → fetch-CuiQUcO_.js} +1 -1
- package/dist-web/assets/{fetch-LX9jrJCC.js → fetch-CyKILLnB.js} +1 -1
- package/dist-web/assets/fetch-Dd6t3p1r.js +6 -0
- package/dist-web/assets/{fetch--UbRoBT7.js → fetch-DnGx-1_t.js} +1 -1
- package/dist-web/assets/{fetch-wqMSiaK3.js → fetch-qC7om4QG.js} +1 -1
- package/dist-web/assets/fetch-wSSfDBdV.js +1 -0
- package/dist-web/assets/index-BH9jI5kV.js +173 -0
- package/dist-web/assets/index-BWtNqcYK.js +22 -0
- package/dist-web/assets/index-BfO_LpDv.css +1 -0
- package/dist-web/assets/index-Bkq7-GBp.js +1 -0
- package/dist-web/assets/index-Bqr-LkS1.css +1 -0
- package/dist-web/assets/index-ByUaiVQK.css +1 -0
- package/dist-web/assets/index-C6qtsaP7.js +1 -0
- package/dist-web/assets/index-C_0GHEcb.css +1 -0
- package/dist-web/assets/index-ChFGuu70.js +1 -0
- package/dist-web/assets/{index-S-YQRH1E.js → index-CiS20iAR.js} +1 -1
- package/dist-web/assets/index-CqD6u57u.js +1 -0
- package/dist-web/assets/index-CzDG8LVr.js +2 -0
- package/dist-web/assets/index-D0Euk-vQ.js +1 -0
- package/dist-web/assets/index-D26BWhHz.js +1 -0
- package/dist-web/assets/index-DXHYzIIj.js +1 -0
- package/dist-web/assets/index-Dq8u7gMb.js +2 -0
- package/dist-web/assets/index-ZsZwPLWy.css +1 -0
- package/dist-web/assets/index-u_UH6rDY.js +64 -0
- package/dist-web/assets/index-y7cxH1Et.css +1 -0
- package/dist-web/assets/{people-page-header-Mupn-U_b.js → people-page-header-BdKM1qhX.js} +1 -1
- package/dist-web/assets/types-CZnACqaB.js +1 -0
- package/dist-web/assets/{vendor-echarts-hJVnODyU.js → vendor-echarts-B-i_56Av.js} +1 -1
- package/dist-web/assets/{vendor-echarts-wordcloud-k5ih2Jl4.js → vendor-echarts-wordcloud-Ca8n6qS6.js} +1 -1
- package/dist-web/assets/{vendor-nuxt-ui-DaLxYaC4.js → vendor-nuxt-ui-CS1uxE9C.js} +2 -2
- package/dist-web/assets/{vendor-reka-ui-CzM4kDQ7.js → vendor-reka-ui-Cta6JPvN.js} +1 -1
- package/dist-web/assets/{web-DbKs6-1b.js → web-BDBdpdK7.js} +1 -1
- package/dist-web/assets/{webworkerAll-Bhv-hBqR.js → webworkerAll-C3dAOQj4.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-36JGKW6K.mjs.map +0 -1
- package/dist/chunk-5EE2EFPE.mjs.map +0 -1
- package/dist/chunk-D3DPCDII.mjs.map +0 -1
- package/dist/chunk-KBSAVUFV.mjs +0 -161
- package/dist/chunk-KBSAVUFV.mjs.map +0 -1
- package/dist/chunk-LVEJHB3X.mjs.map +0 -1
- package/dist/chunk-M2PXDX4G.mjs.map +0 -1
- package/dist/chunk-TCZHG3G7.mjs.map +0 -1
- package/dist/chunk-TEX44HNL.mjs.map +0 -1
- package/dist/chunk-WV5GSRQM.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel-D_lFIW6j.css +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-F4n0zNX2.js +0 -110
- package/dist-web/assets/MessageExportModal-CGcdMOyw.js +0 -1
- package/dist-web/assets/PageHeader-Bbn87QZS.css +0 -1
- package/dist-web/assets/PageHeader-CZaqOdBQ.js +0 -1
- package/dist-web/assets/electron-D9vE5t3H.js +0 -1
- package/dist-web/assets/fetch-1pB-HbYw.js +0 -3
- package/dist-web/assets/fetch-Apd5OLJw.js +0 -5
- package/dist-web/assets/fetch-B8rik0TM.js +0 -17
- package/dist-web/assets/fetch-CF_3ZqRa.js +0 -1
- package/dist-web/assets/fetch-FSNxSnAp.js +0 -1
- package/dist-web/assets/index---rXG1hZ.css +0 -1
- package/dist-web/assets/index-B01uUoHE.js +0 -1
- package/dist-web/assets/index-B4l3rHie.css +0 -1
- package/dist-web/assets/index-BSIyyt0z.js +0 -1
- package/dist-web/assets/index-Bh8z441f.js +0 -2
- package/dist-web/assets/index-C0rya8v4.js +0 -1
- package/dist-web/assets/index-C1p9CbmN.css +0 -1
- package/dist-web/assets/index-COpza1A4.css +0 -1
- package/dist-web/assets/index-CZbZv2fh.js +0 -64
- package/dist-web/assets/index-CqUuHQBQ.js +0 -22
- package/dist-web/assets/index-CzeTP5MJ.js +0 -173
- package/dist-web/assets/index-DgNxTM_8.js +0 -2
- package/dist-web/assets/index-DosG7LmJ.css +0 -1
- /package/dist/{chunk-ULNRUS55.mjs.map → chunk-E6W2RURS.mjs.map} +0 -0
- /package/dist/{chunk-326OCJOT.mjs.map → chunk-ZVWUR7ET.mjs.map} +0 -0
- /package/dist/{http-L4AMELPZ.mjs.map → http-M6NHWJZD.mjs.map} +0 -0
- /package/dist/{import-WWCSXGVS.mjs.map → import-SEYHFXS5.mjs.map} +0 -0
- /package/dist/{src-MPNBTFOE.mjs.map → src-7OD6RD5V.mjs.map} +0 -0
- /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
|
-
|
|
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/
|
|
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
|
|
8764
|
+
return path18.join(userDataDir, PEOPLE_DIR_NAME, RELATIONSHIPS_DIR_NAME);
|
|
8489
8765
|
}
|
|
8490
8766
|
function getPeopleRelationshipsFactsCacheDir(userDataDir) {
|
|
8491
|
-
return
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
8614
|
-
return
|
|
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
|
|
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 && !
|
|
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
|
-
|
|
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) =>
|
|
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 (
|
|
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,
|
|
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
|
|
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 =
|
|
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-
|
|
9385
|
+
//# sourceMappingURL=chunk-DQ45LDKZ.mjs.map
|