chatlab-cli 0.26.2 → 0.26.3
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-BVIG2LCO.mjs → chat-command-D37MMEJ7.mjs} +4 -4
- package/dist/{chunk-6AOEMUCM.mjs → chunk-742TAKEP.mjs} +2 -2
- package/dist/{chunk-3XFHIQIW.mjs → chunk-D5MWER7N.mjs} +2 -2
- package/dist/{chunk-JFSTXSX2.mjs → chunk-GNGZHBKM.mjs} +3 -3
- package/dist/{chunk-GTXX72AQ.mjs → chunk-K5SGXTVJ.mjs} +13 -13
- package/dist/{chunk-GBQQJJKK.mjs → chunk-QMXNJRTT.mjs} +372 -173
- package/dist/chunk-QMXNJRTT.mjs.map +1 -0
- package/dist/{chunk-SCE4YL3M.mjs → chunk-RMITK4IC.mjs} +2 -2
- package/dist/{chunk-QKQRV7RV.mjs → chunk-VCN64OD6.mjs} +2 -2
- package/dist/{chunk-TMZC3SNX.mjs → chunk-YPTJVTVJ.mjs} +1037 -49
- package/dist/chunk-YPTJVTVJ.mjs.map +1 -0
- package/dist/cli.mjs +3 -3
- package/dist/{http-NLFLQDI7.mjs → http-6F6TYWCI.mjs} +8 -8
- package/dist/{import-ILK6MGYR.mjs → import-VYPOMSSA.mjs} +4 -4
- package/dist/index.mjs +8 -8
- package/dist/{mcp-FOLR5XJL.mjs → mcp-AR7L5FA3.mjs} +4 -4
- package/dist/{src-OQN3VE73.mjs → src-6S7JPKHX.mjs} +6 -2
- package/dist/{stream-import-F5QI2HTO.mjs → stream-import-KZFC3XT2.mjs} +3 -3
- package/dist/{update-checker-JIBA7T4U.mjs → update-checker-3N7HQEP2.mjs} +36 -12
- package/dist/update-checker-3N7HQEP2.mjs.map +1 -0
- package/dist-web/assets/{DebugToolsPanel-CrqULdXp.css → DebugToolsPanel-DzZmSzIU.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BTdqmm0y.js +107 -0
- package/dist-web/assets/{MessageExportModal-ttP_JPqO.js → MessageExportModal-CF6yaor7.js} +1 -1
- package/dist-web/assets/{electron-BeJHY587.js → electron-DKVw61Ww.js} +1 -1
- package/dist-web/assets/{fetch-H4B1CK_T.js → fetch-BC8jyJ_U.js} +1 -1
- package/dist-web/assets/{fetch-4s20GRbb.js → fetch-BMdgfBVS.js} +1 -1
- package/dist-web/assets/fetch-BQlEQsqi.js +5 -0
- package/dist-web/assets/{fetch-DtXUkazy.js → fetch-Bh6HC-IR.js} +1 -1
- package/dist-web/assets/{fetch-DBJ7Xkjt.js → fetch-BvVfWR-P.js} +1 -1
- package/dist-web/assets/{fetch-DW8r_JmP.js → fetch-CPeSfqsU.js} +1 -1
- package/dist-web/assets/fetch-CUw-PUYP.js +1 -0
- package/dist-web/assets/{fetch-B7USXx9R.js → fetch-CpYSD089.js} +1 -1
- package/dist-web/assets/{fetch-rtQEc8Bu.js → fetch-D2jNBqs8.js} +1 -1
- package/dist-web/assets/{fetch-BETFYYe1.js → fetch-DqEMAea3.js} +1 -1
- package/dist-web/assets/{index-Dov-rTKE.js → index-BHQnAj6l.js} +1 -1
- package/dist-web/assets/{index-CsxrXMkt.js → index-BwzuCu5R.js} +2 -2
- package/dist-web/assets/index-CG746E15.js +64 -0
- package/dist-web/assets/index-CXoQ_U22.js +173 -0
- package/dist-web/assets/index-DqybGdJH.css +1 -0
- package/dist-web/assets/{index-CjnMyejM.css → index-HgIuP1Td.css} +1 -1
- package/dist-web/assets/{index-CYMTvtEI.js → index-Qh0XLt3R.js} +1 -1
- package/dist-web/assets/{index-Dtm2oajn.css → index-R82N2_0b.css} +1 -1
- package/dist-web/assets/index-wPAmuQZY.js +11 -0
- package/dist-web/assets/{web-1-WNRDnP.js → web-Bx2TiHDk.js} +1 -1
- package/dist-web/favicon.ico +0 -0
- package/dist-web/index.html +3 -3
- package/package.json +1 -1
- package/dist/chunk-GBQQJJKK.mjs.map +0 -1
- package/dist/chunk-TMZC3SNX.mjs.map +0 -1
- package/dist/update-checker-JIBA7T4U.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-D9mCNaYM.js +0 -182
- package/dist-web/assets/electron-Dbml-SPN.js +0 -1
- package/dist-web/assets/fetch-DcEBAz_3.js +0 -1
- package/dist-web/assets/fetch-DsCNr_M0.js +0 -1
- package/dist-web/assets/index-C2ts-hTr.js +0 -173
- package/dist-web/assets/index-DkownpUj.js +0 -163
- package/dist-web/assets/index-LCedyGl2.css +0 -1
- package/dist-web/assets/index-m7v4PP7r.js +0 -11
- /package/dist/{chat-command-BVIG2LCO.mjs.map → chat-command-D37MMEJ7.mjs.map} +0 -0
- /package/dist/{chunk-6AOEMUCM.mjs.map → chunk-742TAKEP.mjs.map} +0 -0
- /package/dist/{chunk-3XFHIQIW.mjs.map → chunk-D5MWER7N.mjs.map} +0 -0
- /package/dist/{chunk-JFSTXSX2.mjs.map → chunk-GNGZHBKM.mjs.map} +0 -0
- /package/dist/{chunk-GTXX72AQ.mjs.map → chunk-K5SGXTVJ.mjs.map} +0 -0
- /package/dist/{chunk-SCE4YL3M.mjs.map → chunk-RMITK4IC.mjs.map} +0 -0
- /package/dist/{chunk-QKQRV7RV.mjs.map → chunk-VCN64OD6.mjs.map} +0 -0
- /package/dist/{http-NLFLQDI7.mjs.map → http-6F6TYWCI.mjs.map} +0 -0
- /package/dist/{import-ILK6MGYR.mjs.map → import-VYPOMSSA.mjs.map} +0 -0
- /package/dist/{mcp-FOLR5XJL.mjs.map → mcp-AR7L5FA3.mjs.map} +0 -0
- /package/dist/{src-OQN3VE73.mjs.map → src-6S7JPKHX.mjs.map} +0 -0
- /package/dist/{stream-import-F5QI2HTO.mjs.map → stream-import-KZFC3XT2.mjs.map} +0 -0
|
@@ -7,16 +7,16 @@ const __dirname = __pathDirname(__filename);
|
|
|
7
7
|
import {
|
|
8
8
|
importData,
|
|
9
9
|
parseFile
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-D5MWER7N.mjs";
|
|
11
11
|
import {
|
|
12
12
|
analyzeIncrementalImport,
|
|
13
13
|
analyzeNewImport,
|
|
14
14
|
incrementalImport,
|
|
15
15
|
streamImport
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-VCN64OD6.mjs";
|
|
17
17
|
import {
|
|
18
18
|
assertCliDataDirCompatible
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-742TAKEP.mjs";
|
|
20
20
|
import {
|
|
21
21
|
getVersion
|
|
22
22
|
} from "./chunk-5ADKYYNA.mjs";
|
|
@@ -27,11 +27,11 @@ import {
|
|
|
27
27
|
closeServerAiLogger,
|
|
28
28
|
createCliRunAgentStream,
|
|
29
29
|
initServerAiLogger
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-GNGZHBKM.mjs";
|
|
31
31
|
import {
|
|
32
32
|
AGENT_TOOL_REGISTRY,
|
|
33
33
|
CoreDataProvider
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-RMITK4IC.mjs";
|
|
35
35
|
import {
|
|
36
36
|
AIChatManager,
|
|
37
37
|
ALL_MIGRATIONS,
|
|
@@ -74,29 +74,41 @@ import {
|
|
|
74
74
|
getAvailableYears,
|
|
75
75
|
getBuiltinModelsByProvider,
|
|
76
76
|
getCatchphraseAnalysis,
|
|
77
|
+
getCheckInAnalysis,
|
|
77
78
|
getClusterGraph,
|
|
78
79
|
getDailyActivity,
|
|
80
|
+
getDbFileVersion,
|
|
79
81
|
getDefaultNodeUserDataDir,
|
|
80
82
|
getDefaultRulesForLocale,
|
|
81
83
|
getDictList,
|
|
84
|
+
getDivingAnalysis,
|
|
85
|
+
getDragonKingAnalysis,
|
|
82
86
|
getHourlyActivity,
|
|
83
87
|
getLanguagePreferenceAnalysis,
|
|
84
88
|
getLaughAnalysis,
|
|
89
|
+
getLongMessageCount,
|
|
85
90
|
getMemberActivity,
|
|
91
|
+
getMemberMonthlyTrend,
|
|
86
92
|
getMembers,
|
|
87
93
|
getMembersDetailed,
|
|
94
|
+
getMemeBattleAnalysis,
|
|
88
95
|
getMentionAnalysis,
|
|
89
96
|
getMentionGraph,
|
|
90
97
|
getMessageLengthDistribution,
|
|
91
98
|
getMessageTypeStats,
|
|
92
99
|
getMonthlyActivity,
|
|
100
|
+
getNightOwlAnalysis,
|
|
101
|
+
getOrComputeAnalysisCache,
|
|
93
102
|
getPendingNodeDataDirMigration,
|
|
94
103
|
getRelationshipStats,
|
|
104
|
+
getRepeatAnalysis,
|
|
95
105
|
getSchemaDetailed,
|
|
96
106
|
getSessionInfo,
|
|
97
107
|
getSessionMeta,
|
|
98
108
|
getSessionOverview,
|
|
99
109
|
getSupportedFormats,
|
|
110
|
+
getTextLengthPercentiles,
|
|
111
|
+
getTextStats,
|
|
100
112
|
getTimeRange,
|
|
101
113
|
getWeekdayActivity,
|
|
102
114
|
getYearlyActivity,
|
|
@@ -123,10 +135,10 @@ import {
|
|
|
123
135
|
verifyCliDataPath,
|
|
124
136
|
writeAuthProfile,
|
|
125
137
|
writeConfigField
|
|
126
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-YPTJVTVJ.mjs";
|
|
127
139
|
|
|
128
140
|
// src/http/index.ts
|
|
129
|
-
import * as
|
|
141
|
+
import * as fs11 from "fs";
|
|
130
142
|
import * as crypto4 from "crypto";
|
|
131
143
|
|
|
132
144
|
// src/http/server.ts
|
|
@@ -451,13 +463,19 @@ function registerSessionRoutes(server2, ctx) {
|
|
|
451
463
|
return preferencesInstance;
|
|
452
464
|
};
|
|
453
465
|
server2.get("/_web/sessions", async () => {
|
|
454
|
-
|
|
466
|
+
const aiChatCounts = ctx.aiChatManager?.getAIChatCountsBySession();
|
|
467
|
+
return session_service_exports.listAnalysisSessions(adapter, {
|
|
468
|
+
enrichSession: aiChatCounts?.size ? (dto) => ({ ...dto, aiConversationCount: aiChatCounts.get(dto.id) ?? 0 }) : void 0
|
|
469
|
+
});
|
|
455
470
|
});
|
|
456
471
|
server2.get("/_web/sessions/:id", async (request) => {
|
|
457
472
|
const session = session_service_exports.getAnalysisSession(adapter, request.params.id);
|
|
458
473
|
if (!session) {
|
|
459
474
|
throw Object.assign(new Error(`Session not found: ${request.params.id}`), { statusCode: 404 });
|
|
460
475
|
}
|
|
476
|
+
if (ctx.aiChatManager) {
|
|
477
|
+
session.aiConversationCount = ctx.aiChatManager.getAIChats(request.params.id).length;
|
|
478
|
+
}
|
|
461
479
|
return session;
|
|
462
480
|
});
|
|
463
481
|
server2.delete("/_web/sessions/:id", async (request, reply) => {
|
|
@@ -589,6 +607,10 @@ function registerPreferencesRoutes(server2, ctx) {
|
|
|
589
607
|
});
|
|
590
608
|
}
|
|
591
609
|
|
|
610
|
+
// ../../packages/http-routes/src/routes/web/analytics.ts
|
|
611
|
+
import * as fs from "fs";
|
|
612
|
+
import * as path2 from "path";
|
|
613
|
+
|
|
592
614
|
// ../../packages/http-routes/src/helpers.ts
|
|
593
615
|
function parseTimeFilter(query) {
|
|
594
616
|
const { startTs, endTs, memberId } = query;
|
|
@@ -600,9 +622,32 @@ function parseTimeFilter(query) {
|
|
|
600
622
|
return filter;
|
|
601
623
|
}
|
|
602
624
|
|
|
625
|
+
// ../../packages/http-routes/src/analytics-cache.ts
|
|
626
|
+
import * as path from "path";
|
|
627
|
+
function canonical(value) {
|
|
628
|
+
if (value === void 0) return "null";
|
|
629
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
630
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
631
|
+
const obj = value;
|
|
632
|
+
const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
633
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${canonical(obj[k])}`).join(",")}}`;
|
|
634
|
+
}
|
|
635
|
+
function buildAnalyticsCacheKey(namespace, params) {
|
|
636
|
+
return `${namespace}:${canonical(params)}`;
|
|
637
|
+
}
|
|
638
|
+
function withAnalyticsCache(ctx, sessionId, namespace, params, compute, options) {
|
|
639
|
+
const queryCacheDir = path.join(ctx.pathProvider.getCacheDir(), "query");
|
|
640
|
+
const dateStr = options?.dailyInvalidate ? `|date:${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}` : "";
|
|
641
|
+
const extraStr = options?.extraVersion ? `|${options.extraVersion}` : "";
|
|
642
|
+
const version = `${ctx.getVersion()}|${getDbFileVersion(ctx.sessionAdapter.getDbPath(sessionId))}${dateStr}${extraStr}`;
|
|
643
|
+
const key = buildAnalyticsCacheKey(namespace, params);
|
|
644
|
+
return getOrComputeAnalysisCache(sessionId, key, queryCacheDir, version, compute);
|
|
645
|
+
}
|
|
646
|
+
|
|
603
647
|
// ../../packages/http-routes/src/routes/web/analytics.ts
|
|
604
648
|
function registerAnalyticsRoutes(server2, ctx) {
|
|
605
649
|
const { sessionAdapter: adapter } = ctx;
|
|
650
|
+
const cached = (name, sessionId, params, compute, options) => withAnalyticsCache(ctx, sessionId, `analytics.${name}`, params, compute, options);
|
|
606
651
|
server2.get("/_web/sessions/:id/years", async (request) => {
|
|
607
652
|
const db = adapter.ensureReadonly(request.params.id);
|
|
608
653
|
return getAvailableYears(db);
|
|
@@ -614,111 +659,252 @@ function registerAnalyticsRoutes(server2, ctx) {
|
|
|
614
659
|
server2.get(
|
|
615
660
|
"/_web/sessions/:id/stats/member-activity",
|
|
616
661
|
async (request) => {
|
|
617
|
-
const
|
|
618
|
-
|
|
662
|
+
const id = request.params.id;
|
|
663
|
+
const filter = parseTimeFilter(request.query);
|
|
664
|
+
return cached("member-activity", id, { ...filter }, () => getMemberActivity(adapter.ensureReadonly(id), filter));
|
|
619
665
|
}
|
|
620
666
|
);
|
|
621
667
|
server2.get(
|
|
622
668
|
"/_web/sessions/:id/stats/hourly",
|
|
623
669
|
async (request) => {
|
|
624
|
-
const
|
|
625
|
-
|
|
670
|
+
const id = request.params.id;
|
|
671
|
+
const filter = parseTimeFilter(request.query);
|
|
672
|
+
return cached("hourly", id, { ...filter }, () => getHourlyActivity(adapter.ensureReadonly(id), filter));
|
|
626
673
|
}
|
|
627
674
|
);
|
|
628
675
|
server2.get(
|
|
629
676
|
"/_web/sessions/:id/stats/daily",
|
|
630
677
|
async (request) => {
|
|
631
|
-
const
|
|
632
|
-
|
|
678
|
+
const id = request.params.id;
|
|
679
|
+
const filter = parseTimeFilter(request.query);
|
|
680
|
+
return cached("daily", id, { ...filter }, () => getDailyActivity(adapter.ensureReadonly(id), filter));
|
|
633
681
|
}
|
|
634
682
|
);
|
|
635
683
|
server2.get(
|
|
636
684
|
"/_web/sessions/:id/stats/weekday",
|
|
637
685
|
async (request) => {
|
|
638
|
-
const
|
|
639
|
-
|
|
686
|
+
const id = request.params.id;
|
|
687
|
+
const filter = parseTimeFilter(request.query);
|
|
688
|
+
return cached("weekday", id, { ...filter }, () => getWeekdayActivity(adapter.ensureReadonly(id), filter));
|
|
640
689
|
}
|
|
641
690
|
);
|
|
642
691
|
server2.get(
|
|
643
692
|
"/_web/sessions/:id/stats/message-types",
|
|
644
693
|
async (request) => {
|
|
645
|
-
const
|
|
646
|
-
|
|
694
|
+
const id = request.params.id;
|
|
695
|
+
const filter = parseTimeFilter(request.query);
|
|
696
|
+
return cached("message-types", id, { ...filter }, () => getMessageTypeStats(adapter.ensureReadonly(id), filter));
|
|
647
697
|
}
|
|
648
698
|
);
|
|
649
699
|
server2.get(
|
|
650
700
|
"/_web/sessions/:id/analytics/relationship",
|
|
651
701
|
async (request) => {
|
|
652
|
-
const
|
|
653
|
-
|
|
702
|
+
const id = request.params.id;
|
|
703
|
+
const filter = parseTimeFilter(request.query);
|
|
704
|
+
return cached("relationship", id, { ...filter }, () => getRelationshipStats(adapter.ensureReadonly(id), filter));
|
|
654
705
|
}
|
|
655
706
|
);
|
|
656
707
|
server2.get(
|
|
657
708
|
"/_web/sessions/:id/analytics/catchphrase",
|
|
658
709
|
async (request) => {
|
|
659
|
-
const
|
|
660
|
-
|
|
710
|
+
const id = request.params.id;
|
|
711
|
+
const filter = parseTimeFilter(request.query);
|
|
712
|
+
return cached("catchphrase", id, { ...filter }, () => getCatchphraseAnalysis(adapter.ensureReadonly(id), filter));
|
|
661
713
|
}
|
|
662
714
|
);
|
|
663
715
|
server2.get(
|
|
664
716
|
"/_web/sessions/:id/analytics/mention",
|
|
665
717
|
async (request) => {
|
|
666
|
-
const
|
|
667
|
-
|
|
718
|
+
const id = request.params.id;
|
|
719
|
+
const filter = parseTimeFilter(request.query);
|
|
720
|
+
return cached("mention", id, { ...filter }, () => getMentionAnalysis(adapter.ensureReadonly(id), filter));
|
|
668
721
|
}
|
|
669
722
|
);
|
|
670
723
|
server2.get(
|
|
671
724
|
"/_web/sessions/:id/analytics/mention-graph",
|
|
672
725
|
async (request) => {
|
|
673
|
-
const
|
|
674
|
-
|
|
726
|
+
const id = request.params.id;
|
|
727
|
+
const filter = parseTimeFilter(request.query);
|
|
728
|
+
return cached("mention-graph", id, { ...filter }, () => getMentionGraph(adapter.ensureReadonly(id), filter));
|
|
675
729
|
}
|
|
676
730
|
);
|
|
677
731
|
server2.get(
|
|
678
732
|
"/_web/sessions/:id/analytics/laugh",
|
|
679
733
|
async (request) => {
|
|
680
|
-
const
|
|
681
|
-
return getLaughAnalysis(db, parseTimeFilter(request.query));
|
|
682
|
-
}
|
|
683
|
-
);
|
|
684
|
-
server2.get(
|
|
685
|
-
"/_web/sessions/:id/analytics/cluster",
|
|
686
|
-
async (request) => {
|
|
687
|
-
const db = adapter.ensureReadonly(request.params.id);
|
|
734
|
+
const id = request.params.id;
|
|
688
735
|
const filter = parseTimeFilter(request.query);
|
|
689
|
-
|
|
690
|
-
return getClusterGraph(db, filter, topEdges ? { topEdges } : void 0);
|
|
736
|
+
return cached("laugh", id, { ...filter }, () => getLaughAnalysis(adapter.ensureReadonly(id), filter));
|
|
691
737
|
}
|
|
692
738
|
);
|
|
739
|
+
server2.get("/_web/sessions/:id/analytics/cluster", async (request) => {
|
|
740
|
+
const id = request.params.id;
|
|
741
|
+
const filter = parseTimeFilter(request.query);
|
|
742
|
+
const options = {};
|
|
743
|
+
if (request.query.topEdges) options.topEdges = parseInt(request.query.topEdges, 10);
|
|
744
|
+
if (request.query.lookAhead) options.lookAhead = parseInt(request.query.lookAhead, 10);
|
|
745
|
+
if (request.query.decaySeconds) options.decaySeconds = parseInt(request.query.decaySeconds, 10);
|
|
746
|
+
const hasOptions = Object.keys(options).length > 0;
|
|
747
|
+
return cached(
|
|
748
|
+
"cluster",
|
|
749
|
+
id,
|
|
750
|
+
{ ...filter, ...options },
|
|
751
|
+
() => getClusterGraph(adapter.ensureReadonly(id), filter, hasOptions ? options : void 0)
|
|
752
|
+
);
|
|
753
|
+
});
|
|
693
754
|
server2.get(
|
|
694
755
|
"/_web/sessions/:id/analytics/language-preference",
|
|
695
756
|
async (request) => {
|
|
696
|
-
const
|
|
757
|
+
const id = request.params.id;
|
|
697
758
|
const filter = parseTimeFilter(request.query);
|
|
698
759
|
const locale = request.query.locale || "zh-CN";
|
|
699
|
-
const
|
|
700
|
-
|
|
760
|
+
const zhDictPath = path2.join(ctx.pathProvider.getSystemDir(), "nlp", "zh-CN.dict");
|
|
761
|
+
let zhDictVersion;
|
|
762
|
+
try {
|
|
763
|
+
const st = fs.statSync(zhDictPath);
|
|
764
|
+
zhDictVersion = `${Math.floor(st.mtimeMs)}:${st.size}`;
|
|
765
|
+
} catch {
|
|
766
|
+
zhDictVersion = "-";
|
|
767
|
+
}
|
|
768
|
+
return cached(
|
|
769
|
+
"language-preference",
|
|
770
|
+
id,
|
|
771
|
+
{ ...filter, locale },
|
|
772
|
+
() => getLanguagePreferenceAnalysis(adapter.ensureReadonly(id), {
|
|
773
|
+
locale,
|
|
774
|
+
timeFilter: filter,
|
|
775
|
+
nlpProvider: createJiebaNlpProvider()
|
|
776
|
+
}),
|
|
777
|
+
{ extraVersion: `dict:${zhDictVersion}` }
|
|
778
|
+
);
|
|
701
779
|
}
|
|
702
780
|
);
|
|
703
781
|
server2.get(
|
|
704
782
|
"/_web/sessions/:id/analytics/monthly-activity",
|
|
705
783
|
async (request) => {
|
|
706
|
-
const
|
|
707
|
-
|
|
784
|
+
const id = request.params.id;
|
|
785
|
+
const filter = parseTimeFilter(request.query);
|
|
786
|
+
return cached("monthly-activity", id, { ...filter }, () => getMonthlyActivity(adapter.ensureReadonly(id), filter));
|
|
708
787
|
}
|
|
709
788
|
);
|
|
710
789
|
server2.get(
|
|
711
790
|
"/_web/sessions/:id/analytics/yearly-activity",
|
|
712
791
|
async (request) => {
|
|
713
|
-
const
|
|
714
|
-
|
|
792
|
+
const id = request.params.id;
|
|
793
|
+
const filter = parseTimeFilter(request.query);
|
|
794
|
+
return cached("yearly-activity", id, { ...filter }, () => getYearlyActivity(adapter.ensureReadonly(id), filter));
|
|
715
795
|
}
|
|
716
796
|
);
|
|
717
797
|
server2.get(
|
|
718
798
|
"/_web/sessions/:id/analytics/message-length-distribution",
|
|
719
799
|
async (request) => {
|
|
720
|
-
const
|
|
721
|
-
|
|
800
|
+
const id = request.params.id;
|
|
801
|
+
const filter = parseTimeFilter(request.query);
|
|
802
|
+
return cached(
|
|
803
|
+
"message-length-distribution",
|
|
804
|
+
id,
|
|
805
|
+
{ ...filter },
|
|
806
|
+
() => getMessageLengthDistribution(adapter.ensureReadonly(id), filter)
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
);
|
|
810
|
+
server2.get(
|
|
811
|
+
"/_web/sessions/:id/analytics/text-stats",
|
|
812
|
+
async (request) => {
|
|
813
|
+
const id = request.params.id;
|
|
814
|
+
const filter = parseTimeFilter(request.query);
|
|
815
|
+
return cached("text-stats", id, { ...filter }, () => getTextStats(adapter.ensureReadonly(id), filter));
|
|
816
|
+
}
|
|
817
|
+
);
|
|
818
|
+
server2.get(
|
|
819
|
+
"/_web/sessions/:id/analytics/long-message-count",
|
|
820
|
+
async (request) => {
|
|
821
|
+
const id = request.params.id;
|
|
822
|
+
const filter = parseTimeFilter(request.query);
|
|
823
|
+
const minLength = request.query.minLength ? parseInt(request.query.minLength, 10) : void 0;
|
|
824
|
+
return cached(
|
|
825
|
+
"long-message-count",
|
|
826
|
+
id,
|
|
827
|
+
{ ...filter, minLength },
|
|
828
|
+
() => getLongMessageCount(adapter.ensureReadonly(id), filter, minLength)
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
);
|
|
832
|
+
server2.get(
|
|
833
|
+
"/_web/sessions/:id/analytics/member-monthly-trend",
|
|
834
|
+
async (request) => {
|
|
835
|
+
const id = request.params.id;
|
|
836
|
+
const filter = parseTimeFilter(request.query);
|
|
837
|
+
return cached(
|
|
838
|
+
"member-monthly-trend",
|
|
839
|
+
id,
|
|
840
|
+
{ ...filter },
|
|
841
|
+
() => getMemberMonthlyTrend(adapter.ensureReadonly(id), filter)
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
);
|
|
845
|
+
server2.get(
|
|
846
|
+
"/_web/sessions/:id/analytics/text-length-percentiles",
|
|
847
|
+
async (request) => {
|
|
848
|
+
const id = request.params.id;
|
|
849
|
+
const filter = parseTimeFilter(request.query);
|
|
850
|
+
return cached(
|
|
851
|
+
"text-length-percentiles",
|
|
852
|
+
id,
|
|
853
|
+
{ ...filter },
|
|
854
|
+
() => getTextLengthPercentiles(adapter.ensureReadonly(id), filter)
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
);
|
|
858
|
+
server2.get(
|
|
859
|
+
"/_web/sessions/:id/analytics/dragon-king",
|
|
860
|
+
async (request) => {
|
|
861
|
+
const id = request.params.id;
|
|
862
|
+
const filter = parseTimeFilter(request.query);
|
|
863
|
+
return cached("dragon-king", id, { ...filter }, () => getDragonKingAnalysis(adapter.ensureReadonly(id), filter));
|
|
864
|
+
}
|
|
865
|
+
);
|
|
866
|
+
server2.get(
|
|
867
|
+
"/_web/sessions/:id/analytics/diving",
|
|
868
|
+
async (request) => {
|
|
869
|
+
const id = request.params.id;
|
|
870
|
+
const filter = parseTimeFilter(request.query);
|
|
871
|
+
return cached("diving", id, { ...filter }, () => getDivingAnalysis(adapter.ensureReadonly(id), filter), {
|
|
872
|
+
dailyInvalidate: true
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
);
|
|
876
|
+
server2.get(
|
|
877
|
+
"/_web/sessions/:id/analytics/check-in",
|
|
878
|
+
async (request) => {
|
|
879
|
+
const id = request.params.id;
|
|
880
|
+
const filter = parseTimeFilter(request.query);
|
|
881
|
+
return cached("check-in", id, { ...filter }, () => getCheckInAnalysis(adapter.ensureReadonly(id), filter));
|
|
882
|
+
}
|
|
883
|
+
);
|
|
884
|
+
server2.get(
|
|
885
|
+
"/_web/sessions/:id/analytics/meme-battle",
|
|
886
|
+
async (request) => {
|
|
887
|
+
const id = request.params.id;
|
|
888
|
+
const filter = parseTimeFilter(request.query);
|
|
889
|
+
return cached("meme-battle", id, { ...filter }, () => getMemeBattleAnalysis(adapter.ensureReadonly(id), filter));
|
|
890
|
+
}
|
|
891
|
+
);
|
|
892
|
+
server2.get(
|
|
893
|
+
"/_web/sessions/:id/analytics/night-owl",
|
|
894
|
+
async (request) => {
|
|
895
|
+
const id = request.params.id;
|
|
896
|
+
const filter = parseTimeFilter(request.query);
|
|
897
|
+
return cached("night-owl", id, { ...filter }, () => getNightOwlAnalysis(adapter.ensureReadonly(id), filter), {
|
|
898
|
+
dailyInvalidate: true
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
);
|
|
902
|
+
server2.get(
|
|
903
|
+
"/_web/sessions/:id/analytics/repeat",
|
|
904
|
+
async (request) => {
|
|
905
|
+
const id = request.params.id;
|
|
906
|
+
const filter = parseTimeFilter(request.query);
|
|
907
|
+
return cached("repeat", id, { ...filter }, () => getRepeatAnalysis(adapter.ensureReadonly(id), filter));
|
|
722
908
|
}
|
|
723
909
|
);
|
|
724
910
|
}
|
|
@@ -823,9 +1009,10 @@ function registerExportRoutes(server2, ctx) {
|
|
|
823
1009
|
}
|
|
824
1010
|
|
|
825
1011
|
// ../../packages/http-routes/src/routes/web/nlp.ts
|
|
826
|
-
import * as
|
|
1012
|
+
import * as fs2 from "fs";
|
|
1013
|
+
import * as path3 from "path";
|
|
827
1014
|
function registerNlpRoutes(server2, ctx) {
|
|
828
|
-
const nlpDir =
|
|
1015
|
+
const nlpDir = path3.join(ctx.pathProvider.getSystemDir(), "nlp");
|
|
829
1016
|
initNlpDir(nlpDir);
|
|
830
1017
|
ensureDefaultDict(nlpDir).catch((err) => console.warn("[NLP] Auto-download zh-CN dict failed:", err));
|
|
831
1018
|
server2.get("/_web/nlp/pos-tags", async () => {
|
|
@@ -849,7 +1036,19 @@ function registerNlpRoutes(server2, ctx) {
|
|
|
849
1036
|
if (!db) {
|
|
850
1037
|
throw Object.assign(new Error(`Session not found: ${params.sessionId}`), { statusCode: 404 });
|
|
851
1038
|
}
|
|
852
|
-
|
|
1039
|
+
const { sessionId, ...keyParams } = params;
|
|
1040
|
+
const effectiveDictId = !params.dictType || params.dictType === "default" ? "zh-CN" : String(params.dictType);
|
|
1041
|
+
const dictFilePath = path3.join(nlpDir, `${effectiveDictId}.dict`);
|
|
1042
|
+
let dictVersion;
|
|
1043
|
+
try {
|
|
1044
|
+
const st = fs2.statSync(dictFilePath);
|
|
1045
|
+
dictVersion = `${Math.floor(st.mtimeMs)}:${st.size}`;
|
|
1046
|
+
} catch {
|
|
1047
|
+
dictVersion = "-";
|
|
1048
|
+
}
|
|
1049
|
+
return withAnalyticsCache(ctx, sessionId, "nlp.word-frequency", keyParams, () => computeWordFrequency(db, params), {
|
|
1050
|
+
extraVersion: `dict:${dictVersion}`
|
|
1051
|
+
});
|
|
853
1052
|
});
|
|
854
1053
|
server2.post(
|
|
855
1054
|
"/_web/nlp/segment",
|
|
@@ -1414,9 +1613,9 @@ function registerAiSummaryRoutes(server2, ctx) {
|
|
|
1414
1613
|
}
|
|
1415
1614
|
|
|
1416
1615
|
// ../../packages/http-routes/src/routes/web/merge.ts
|
|
1417
|
-
import * as
|
|
1616
|
+
import * as fs3 from "fs";
|
|
1418
1617
|
import * as os from "os";
|
|
1419
|
-
import * as
|
|
1618
|
+
import * as path4 from "path";
|
|
1420
1619
|
function ensureDb2(ctx, sessionId) {
|
|
1421
1620
|
const db = ctx.dbManager.open(sessionId);
|
|
1422
1621
|
if (!db) throw sessionNotFound(sessionId);
|
|
@@ -1433,31 +1632,31 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1433
1632
|
if (contentType.includes("multipart/form-data")) {
|
|
1434
1633
|
const data = await request.file();
|
|
1435
1634
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
1436
|
-
const tmpDir =
|
|
1437
|
-
const tmpPath =
|
|
1635
|
+
const tmpDir = fs3.mkdtempSync(path4.join(os.tmpdir(), "chatlab-merge-"));
|
|
1636
|
+
const tmpPath = path4.join(tmpDir, data.filename || "upload");
|
|
1438
1637
|
const chunks = [];
|
|
1439
1638
|
for await (const chunk of data.file) {
|
|
1440
1639
|
chunks.push(chunk);
|
|
1441
1640
|
}
|
|
1442
|
-
|
|
1641
|
+
fs3.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
1443
1642
|
filePath = tmpPath;
|
|
1444
1643
|
cleanupFile = true;
|
|
1445
1644
|
cleanupDir = tmpDir;
|
|
1446
1645
|
} else {
|
|
1447
1646
|
const body = request.body;
|
|
1448
1647
|
if (!body?.filePath) return reply.code(400).send({ error: "Missing filePath in body" });
|
|
1449
|
-
if (!
|
|
1648
|
+
if (!fs3.existsSync(body.filePath)) return reply.code(400).send({ error: "File not found" });
|
|
1450
1649
|
filePath = body.filePath;
|
|
1451
1650
|
}
|
|
1452
1651
|
try {
|
|
1453
1652
|
const result = await streamParseFileInfo(filePath, {
|
|
1454
1653
|
createTempDatabase(sourceFilePath) {
|
|
1455
|
-
return mergeCache.createTempDatabase(
|
|
1654
|
+
return mergeCache.createTempDatabase(path4.basename(sourceFilePath));
|
|
1456
1655
|
},
|
|
1457
1656
|
onProgress() {
|
|
1458
1657
|
}
|
|
1459
1658
|
});
|
|
1460
|
-
const filename =
|
|
1659
|
+
const filename = path4.basename(filePath);
|
|
1461
1660
|
const handle = mergeCache.store(filename, result.tempDbPath);
|
|
1462
1661
|
return {
|
|
1463
1662
|
handle,
|
|
@@ -1471,13 +1670,13 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1471
1670
|
} finally {
|
|
1472
1671
|
if (cleanupFile) {
|
|
1473
1672
|
try {
|
|
1474
|
-
|
|
1673
|
+
fs3.unlinkSync(filePath);
|
|
1475
1674
|
} catch {
|
|
1476
1675
|
}
|
|
1477
1676
|
}
|
|
1478
1677
|
if (cleanupDir) {
|
|
1479
1678
|
try {
|
|
1480
|
-
|
|
1679
|
+
fs3.rmdirSync(cleanupDir);
|
|
1481
1680
|
} catch {
|
|
1482
1681
|
}
|
|
1483
1682
|
}
|
|
@@ -1526,20 +1725,20 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1526
1725
|
return reply.code(501).send({ error: "Import not available on this server" });
|
|
1527
1726
|
}
|
|
1528
1727
|
const jsonData = JSON.stringify(merged.chatLabData);
|
|
1529
|
-
const tmpDir =
|
|
1530
|
-
const safeName =
|
|
1531
|
-
const tmpPath =
|
|
1532
|
-
|
|
1728
|
+
const tmpDir = fs3.mkdtempSync(path4.join(os.tmpdir(), "chatlab-merged-"));
|
|
1729
|
+
const safeName = path4.basename(outputName).replace(/[/\\?%*:|"<>]/g, "_") || "merged";
|
|
1730
|
+
const tmpPath = path4.join(tmpDir, `${safeName}.json`);
|
|
1731
|
+
fs3.writeFileSync(tmpPath, jsonData, "utf-8");
|
|
1533
1732
|
try {
|
|
1534
1733
|
const importResult = await streamImport2(dbManager2, tmpPath);
|
|
1535
1734
|
sessionId = importResult.sessionId;
|
|
1536
1735
|
} finally {
|
|
1537
1736
|
try {
|
|
1538
|
-
|
|
1737
|
+
fs3.unlinkSync(tmpPath);
|
|
1539
1738
|
} catch {
|
|
1540
1739
|
}
|
|
1541
1740
|
try {
|
|
1542
|
-
|
|
1741
|
+
fs3.rmdirSync(tmpDir);
|
|
1543
1742
|
} catch {
|
|
1544
1743
|
}
|
|
1545
1744
|
}
|
|
@@ -1613,16 +1812,16 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1613
1812
|
}
|
|
1614
1813
|
|
|
1615
1814
|
// ../../packages/http-routes/src/routes/web/cache.ts
|
|
1616
|
-
import * as
|
|
1815
|
+
import * as fs4 from "fs";
|
|
1617
1816
|
import * as fsp from "fs/promises";
|
|
1618
|
-
import * as
|
|
1817
|
+
import * as path5 from "path";
|
|
1619
1818
|
async function getDirSize(dirPath) {
|
|
1620
1819
|
let totalSize = 0;
|
|
1621
1820
|
try {
|
|
1622
|
-
if (!
|
|
1821
|
+
if (!fs4.existsSync(dirPath)) return 0;
|
|
1623
1822
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1624
1823
|
for (const file of files) {
|
|
1625
|
-
const filePath =
|
|
1824
|
+
const filePath = path5.join(dirPath, file.name);
|
|
1626
1825
|
if (file.isDirectory()) {
|
|
1627
1826
|
totalSize += await getDirSize(filePath);
|
|
1628
1827
|
} else {
|
|
@@ -1637,10 +1836,10 @@ async function getDirSize(dirPath) {
|
|
|
1637
1836
|
async function getFileCount(dirPath) {
|
|
1638
1837
|
let count = 0;
|
|
1639
1838
|
try {
|
|
1640
|
-
if (!
|
|
1839
|
+
if (!fs4.existsSync(dirPath)) return 0;
|
|
1641
1840
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1642
1841
|
for (const file of files) {
|
|
1643
|
-
const filePath =
|
|
1842
|
+
const filePath = path5.join(dirPath, file.name);
|
|
1644
1843
|
if (file.isDirectory()) {
|
|
1645
1844
|
count += await getFileCount(filePath);
|
|
1646
1845
|
} else {
|
|
@@ -1653,10 +1852,10 @@ async function getFileCount(dirPath) {
|
|
|
1653
1852
|
}
|
|
1654
1853
|
function hasChatLabDatabases(dirPath) {
|
|
1655
1854
|
try {
|
|
1656
|
-
const markerPath =
|
|
1657
|
-
const dbDir =
|
|
1658
|
-
if (!
|
|
1659
|
-
return
|
|
1855
|
+
const markerPath = path5.join(dirPath, ".chatlab");
|
|
1856
|
+
const dbDir = path5.join(dirPath, "databases");
|
|
1857
|
+
if (!fs4.existsSync(markerPath) || !fs4.existsSync(dbDir)) return false;
|
|
1858
|
+
return fs4.readdirSync(dbDir).some((file) => file.endsWith(".db"));
|
|
1660
1859
|
} catch {
|
|
1661
1860
|
return false;
|
|
1662
1861
|
}
|
|
@@ -1702,7 +1901,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1702
1901
|
const results = await Promise.all(
|
|
1703
1902
|
directories.map(async (dir) => {
|
|
1704
1903
|
const [size, fileCount] = await Promise.all([getDirSize(dir.path), getFileCount(dir.path)]);
|
|
1705
|
-
return { ...dir, size, fileCount, exists:
|
|
1904
|
+
return { ...dir, size, fileCount, exists: fs4.existsSync(dir.path) };
|
|
1706
1905
|
})
|
|
1707
1906
|
);
|
|
1708
1907
|
return {
|
|
@@ -1719,10 +1918,10 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1719
1918
|
};
|
|
1720
1919
|
const dirPath = allowedDirs[cacheId];
|
|
1721
1920
|
if (!dirPath) return { success: false, error: "Not allowed to clear this directory" };
|
|
1722
|
-
if (!
|
|
1921
|
+
if (!fs4.existsSync(dirPath)) return { success: true };
|
|
1723
1922
|
const files = await fsp.readdir(dirPath);
|
|
1724
1923
|
for (const file of files) {
|
|
1725
|
-
const filePath =
|
|
1924
|
+
const filePath = path5.join(dirPath, file);
|
|
1726
1925
|
const stat2 = await fsp.stat(filePath);
|
|
1727
1926
|
if (stat2.isDirectory()) {
|
|
1728
1927
|
await fsp.rm(filePath, { recursive: true });
|
|
@@ -1739,7 +1938,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1739
1938
|
defaultPath: ctx.defaultUserDataDir,
|
|
1740
1939
|
isCustom: ctx.isCustomDataDir ?? false,
|
|
1741
1940
|
canSetDataDir: ctx.canSetDataDir ?? Boolean(ctx.setDataDir),
|
|
1742
|
-
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) &&
|
|
1941
|
+
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) && path5.resolve(pp.getUserDataDir()) !== path5.resolve(ctx.defaultUserDataDir ?? "") && hasChatLabDatabases(ctx.defaultUserDataDir ?? ""),
|
|
1743
1942
|
pendingMigration: pending ? {
|
|
1744
1943
|
from: pending.from,
|
|
1745
1944
|
to: pending.to,
|
|
@@ -1756,8 +1955,8 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1756
1955
|
return ctx.setDataDir(targetPath, migrate);
|
|
1757
1956
|
});
|
|
1758
1957
|
server2.get("/_web/cache/latest-import-log", async () => {
|
|
1759
|
-
const importLogDir =
|
|
1760
|
-
if (!
|
|
1958
|
+
const importLogDir = path5.join(pp.getLogsDir(), "import");
|
|
1959
|
+
if (!fs4.existsSync(importLogDir)) {
|
|
1761
1960
|
return { success: false, error: "Log directory not found" };
|
|
1762
1961
|
}
|
|
1763
1962
|
const files = await fsp.readdir(importLogDir);
|
|
@@ -1767,7 +1966,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1767
1966
|
}
|
|
1768
1967
|
const fileStats = await Promise.all(
|
|
1769
1968
|
logFiles.map(async (f) => {
|
|
1770
|
-
const filePath =
|
|
1969
|
+
const filePath = path5.join(importLogDir, f);
|
|
1771
1970
|
const stat2 = await fsp.stat(filePath);
|
|
1772
1971
|
return { name: f, path: filePath, mtime: stat2.mtime.getTime() };
|
|
1773
1972
|
})
|
|
@@ -1791,11 +1990,11 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1791
1990
|
const base64Data = dataUrl.replace(/^data:[^,]+,/, "");
|
|
1792
1991
|
buffer = Buffer.from(base64Data, "base64");
|
|
1793
1992
|
}
|
|
1794
|
-
if (!
|
|
1795
|
-
|
|
1993
|
+
if (!fs4.existsSync(downloadsDir)) {
|
|
1994
|
+
fs4.mkdirSync(downloadsDir, { recursive: true });
|
|
1796
1995
|
}
|
|
1797
|
-
const filePath =
|
|
1798
|
-
|
|
1996
|
+
const filePath = path5.join(downloadsDir, filename);
|
|
1997
|
+
fs4.writeFileSync(filePath, buffer);
|
|
1799
1998
|
return { success: true, filePath };
|
|
1800
1999
|
});
|
|
1801
2000
|
server2.post("/_web/cache/open-dir", async (request, reply) => {
|
|
@@ -1811,7 +2010,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1811
2010
|
};
|
|
1812
2011
|
const dirPath = dirPaths[cacheId];
|
|
1813
2012
|
if (!dirPath) return { success: false, error: "Unknown directory" };
|
|
1814
|
-
if (!
|
|
2013
|
+
if (!fs4.existsSync(dirPath)) {
|
|
1815
2014
|
await fsp.mkdir(dirPath, { recursive: true });
|
|
1816
2015
|
}
|
|
1817
2016
|
try {
|
|
@@ -1948,19 +2147,19 @@ function createServer() {
|
|
|
1948
2147
|
|
|
1949
2148
|
// src/http/routes/web/index.ts
|
|
1950
2149
|
import * as os3 from "os";
|
|
1951
|
-
import * as
|
|
2150
|
+
import * as path8 from "path";
|
|
1952
2151
|
|
|
1953
2152
|
// src/http/routes/web/import.ts
|
|
1954
|
-
import * as
|
|
2153
|
+
import * as fs6 from "fs";
|
|
1955
2154
|
import * as os2 from "os";
|
|
1956
|
-
import * as
|
|
2155
|
+
import * as path6 from "path";
|
|
1957
2156
|
|
|
1958
2157
|
// src/http/routes/web/helpers.ts
|
|
1959
|
-
import * as
|
|
2158
|
+
import * as fs5 from "fs";
|
|
1960
2159
|
function resolveNativeBinding() {
|
|
1961
2160
|
if (process.versions.electron) return void 0;
|
|
1962
2161
|
const nativePath = resolveCliPath("native/better_sqlite3.node");
|
|
1963
|
-
if (
|
|
2162
|
+
if (fs5.existsSync(nativePath)) return nativePath;
|
|
1964
2163
|
return void 0;
|
|
1965
2164
|
}
|
|
1966
2165
|
|
|
@@ -1969,11 +2168,11 @@ var DEMO_BASE_URL = "https://chatlab.fun/assets/demo";
|
|
|
1969
2168
|
function cleanupTemp(...paths) {
|
|
1970
2169
|
for (const p of paths) {
|
|
1971
2170
|
try {
|
|
1972
|
-
const stat2 =
|
|
2171
|
+
const stat2 = fs6.statSync(p);
|
|
1973
2172
|
if (stat2.isDirectory()) {
|
|
1974
|
-
|
|
2173
|
+
fs6.rmSync(p, { recursive: true, force: true });
|
|
1975
2174
|
} else {
|
|
1976
|
-
|
|
2175
|
+
fs6.unlinkSync(p);
|
|
1977
2176
|
}
|
|
1978
2177
|
} catch {
|
|
1979
2178
|
}
|
|
@@ -1986,14 +2185,14 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
1986
2185
|
server2.post("/_web/detect-format", async (request, reply) => {
|
|
1987
2186
|
const data = await request.file();
|
|
1988
2187
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
1989
|
-
const tmpDir =
|
|
1990
|
-
const tmpPath =
|
|
2188
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-detect-"));
|
|
2189
|
+
const tmpPath = path6.join(tmpDir, data.filename || "upload");
|
|
1991
2190
|
try {
|
|
1992
2191
|
const chunks = [];
|
|
1993
2192
|
for await (const chunk of data.file) {
|
|
1994
2193
|
chunks.push(chunk);
|
|
1995
2194
|
}
|
|
1996
|
-
|
|
2195
|
+
fs6.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
1997
2196
|
const format = detectFormat(tmpPath);
|
|
1998
2197
|
const allFormats = detectAllFormats(tmpPath);
|
|
1999
2198
|
return { format, allFormats };
|
|
@@ -2004,14 +2203,14 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2004
2203
|
server2.post("/_web/scan-multi-chat", async (request, reply) => {
|
|
2005
2204
|
const data = await request.file();
|
|
2006
2205
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2007
|
-
const tmpDir =
|
|
2008
|
-
const tmpPath =
|
|
2206
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-scan-"));
|
|
2207
|
+
const tmpPath = path6.join(tmpDir, data.filename || "upload");
|
|
2009
2208
|
try {
|
|
2010
2209
|
const chunks = [];
|
|
2011
2210
|
for await (const chunk of data.file) {
|
|
2012
2211
|
chunks.push(chunk);
|
|
2013
2212
|
}
|
|
2014
|
-
|
|
2213
|
+
fs6.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
2015
2214
|
const chats = await scanMultiChatFile(tmpPath);
|
|
2016
2215
|
return { chats };
|
|
2017
2216
|
} finally {
|
|
@@ -2021,13 +2220,13 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2021
2220
|
server2.post("/_web/import", async (request, reply) => {
|
|
2022
2221
|
const data = await request.file();
|
|
2023
2222
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2024
|
-
const tmpDir =
|
|
2025
|
-
const tmpPath =
|
|
2223
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-import-"));
|
|
2224
|
+
const tmpPath = path6.join(tmpDir, data.filename || "upload");
|
|
2026
2225
|
const chunks = [];
|
|
2027
2226
|
for await (const chunk of data.file) {
|
|
2028
2227
|
chunks.push(chunk);
|
|
2029
2228
|
}
|
|
2030
|
-
|
|
2229
|
+
fs6.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
2031
2230
|
const formatId = data.fields?.formatId?.value;
|
|
2032
2231
|
const chatIndexStr = data.fields?.chatIndex?.value;
|
|
2033
2232
|
const chatIndex = chatIndexStr !== void 0 ? parseInt(chatIndexStr, 10) : void 0;
|
|
@@ -2070,7 +2269,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2070
2269
|
server2.post("/_web/import-directory", async (request, reply) => {
|
|
2071
2270
|
const parts = request.parts();
|
|
2072
2271
|
if (!parts) return reply.code(400).send({ error: "No files uploaded" });
|
|
2073
|
-
const tmpDir =
|
|
2272
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-dir-import-"));
|
|
2074
2273
|
const relativePaths = [];
|
|
2075
2274
|
const fileBuffers = [];
|
|
2076
2275
|
try {
|
|
@@ -2098,10 +2297,10 @@ data: ${JSON.stringify(eventData)}
|
|
|
2098
2297
|
if (segments.length > 1) {
|
|
2099
2298
|
relPath = segments.slice(1).join("/");
|
|
2100
2299
|
}
|
|
2101
|
-
const targetPath =
|
|
2102
|
-
if (!targetPath.startsWith(tmpDir +
|
|
2103
|
-
|
|
2104
|
-
|
|
2300
|
+
const targetPath = path6.resolve(tmpDir, relPath);
|
|
2301
|
+
if (!targetPath.startsWith(tmpDir + path6.sep)) continue;
|
|
2302
|
+
fs6.mkdirSync(path6.dirname(targetPath), { recursive: true });
|
|
2303
|
+
fs6.writeFileSync(targetPath, fileBuffers[i].data);
|
|
2105
2304
|
}
|
|
2106
2305
|
const entryPath = findEntryFileInDirectory(tmpDir);
|
|
2107
2306
|
if (!entryPath) {
|
|
@@ -2146,13 +2345,13 @@ data: ${JSON.stringify({ success: false, error: err instanceof Error ? err.messa
|
|
|
2146
2345
|
const sessionId = request.params.id;
|
|
2147
2346
|
const data = await request.file();
|
|
2148
2347
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2149
|
-
const tmpDir =
|
|
2150
|
-
const tmpPath =
|
|
2348
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-inc-"));
|
|
2349
|
+
const tmpPath = path6.join(tmpDir, data.filename || "upload");
|
|
2151
2350
|
const chunks = [];
|
|
2152
2351
|
for await (const chunk of data.file) {
|
|
2153
2352
|
chunks.push(chunk);
|
|
2154
2353
|
}
|
|
2155
|
-
|
|
2354
|
+
fs6.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
2156
2355
|
reply.raw.writeHead(200, {
|
|
2157
2356
|
"Content-Type": "text/event-stream",
|
|
2158
2357
|
"Cache-Control": "no-cache",
|
|
@@ -2184,13 +2383,13 @@ data: ${JSON.stringify(eventData)}
|
|
|
2184
2383
|
const sessionId = request.params.id;
|
|
2185
2384
|
const data = await request.file();
|
|
2186
2385
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2187
|
-
const tmpDir =
|
|
2188
|
-
const tmpPath =
|
|
2386
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2387
|
+
const tmpPath = path6.join(tmpDir, data.filename || "upload");
|
|
2189
2388
|
const chunks = [];
|
|
2190
2389
|
for await (const chunk of data.file) {
|
|
2191
2390
|
chunks.push(chunk);
|
|
2192
2391
|
}
|
|
2193
|
-
|
|
2392
|
+
fs6.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
2194
2393
|
try {
|
|
2195
2394
|
return await analyzeIncrementalImport(dbManager2, sessionId, tmpPath);
|
|
2196
2395
|
} catch (err) {
|
|
@@ -2202,13 +2401,13 @@ data: ${JSON.stringify(eventData)}
|
|
|
2202
2401
|
server2.post("/_web/import/analyze", async (request, reply) => {
|
|
2203
2402
|
const data = await request.file();
|
|
2204
2403
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2205
|
-
const tmpDir =
|
|
2206
|
-
const tmpPath =
|
|
2404
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2405
|
+
const tmpPath = path6.join(tmpDir, data.filename || "upload");
|
|
2207
2406
|
const chunks = [];
|
|
2208
2407
|
for await (const chunk of data.file) {
|
|
2209
2408
|
chunks.push(chunk);
|
|
2210
2409
|
}
|
|
2211
|
-
|
|
2410
|
+
fs6.writeFileSync(tmpPath, Buffer.concat(chunks));
|
|
2212
2411
|
try {
|
|
2213
2412
|
return await analyzeNewImport(tmpPath);
|
|
2214
2413
|
} catch (err) {
|
|
@@ -2238,17 +2437,17 @@ data: ${JSON.stringify(eventData)}
|
|
|
2238
2437
|
|
|
2239
2438
|
`);
|
|
2240
2439
|
}
|
|
2241
|
-
const tmpDir =
|
|
2440
|
+
const tmpDir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "chatlab-demo-"));
|
|
2242
2441
|
try {
|
|
2243
2442
|
const localPaths = [];
|
|
2244
2443
|
for (let i = 0; i < total; i++) {
|
|
2245
2444
|
sendEvent("progress", { stage: "downloading", current: i + 1, total });
|
|
2246
|
-
const localPath =
|
|
2445
|
+
const localPath = path6.join(tmpDir, DEMO_FILES[i]);
|
|
2247
2446
|
const resp = await fetch(`${DEMO_BASE_URL}/${locale}/${DEMO_FILES[i]}`, {
|
|
2248
2447
|
signal: AbortSignal.timeout(6e4)
|
|
2249
2448
|
});
|
|
2250
2449
|
if (!resp.ok) throw new Error(`Download demo failed (${DEMO_FILES[i]}): ${resp.status}`);
|
|
2251
|
-
|
|
2450
|
+
fs6.writeFileSync(localPath, Buffer.from(await resp.arrayBuffer()));
|
|
2252
2451
|
localPaths.push(localPath);
|
|
2253
2452
|
}
|
|
2254
2453
|
sendEvent("progress", { stage: "importing", current: 1, total });
|
|
@@ -2279,7 +2478,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2279
2478
|
}
|
|
2280
2479
|
|
|
2281
2480
|
// src/http/routes/web/cache.ts
|
|
2282
|
-
import * as
|
|
2481
|
+
import * as path7 from "path";
|
|
2283
2482
|
import { execFile } from "child_process";
|
|
2284
2483
|
function runExecFile(file, args, runner = execFile) {
|
|
2285
2484
|
return new Promise((resolve4, reject) => {
|
|
@@ -2307,7 +2506,7 @@ async function showPathInFolder(filePath, platform = process.platform, runner) {
|
|
|
2307
2506
|
} else if (platform === "win32") {
|
|
2308
2507
|
await runExecFile("explorer.exe", [`/select,${filePath}`], runner);
|
|
2309
2508
|
} else {
|
|
2310
|
-
await runExecFile("xdg-open", [
|
|
2509
|
+
await runExecFile("xdg-open", [path7.dirname(filePath)], runner);
|
|
2311
2510
|
}
|
|
2312
2511
|
}
|
|
2313
2512
|
|
|
@@ -2330,26 +2529,26 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2330
2529
|
const mergeCache = options?.pathProvider ? new MergeSessionCache(options.pathProvider, { nativeBinding: options.nativeBinding }) : null;
|
|
2331
2530
|
mergeCache?.cleanupOrphans();
|
|
2332
2531
|
const fallbackPathProvider = {
|
|
2333
|
-
getSystemDir: () =>
|
|
2334
|
-
getUserDataDir: () =>
|
|
2335
|
-
getDatabaseDir: () =>
|
|
2336
|
-
getAiDataDir: () =>
|
|
2337
|
-
getSettingsDir: () =>
|
|
2338
|
-
getCacheDir: () =>
|
|
2339
|
-
getTempDir: () =>
|
|
2340
|
-
getLogsDir: () =>
|
|
2341
|
-
getDownloadsDir: () =>
|
|
2532
|
+
getSystemDir: () => path8.join(os3.homedir(), ".chatlab"),
|
|
2533
|
+
getUserDataDir: () => path8.join(os3.homedir(), ".chatlab", "data"),
|
|
2534
|
+
getDatabaseDir: () => path8.join(os3.homedir(), ".chatlab", "data", "databases"),
|
|
2535
|
+
getAiDataDir: () => path8.join(os3.homedir(), ".chatlab", "ai"),
|
|
2536
|
+
getSettingsDir: () => path8.join(os3.homedir(), ".chatlab", "settings"),
|
|
2537
|
+
getCacheDir: () => path8.join(os3.homedir(), ".chatlab", "cache"),
|
|
2538
|
+
getTempDir: () => path8.join(os3.homedir(), ".chatlab", "temp"),
|
|
2539
|
+
getLogsDir: () => path8.join(os3.homedir(), ".chatlab", "logs"),
|
|
2540
|
+
getDownloadsDir: () => path8.join(os3.homedir(), "Downloads")
|
|
2342
2541
|
};
|
|
2343
2542
|
const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
|
|
2344
2543
|
const ai = options?.aiContext;
|
|
2345
2544
|
const cliStreamImport = async (dm, filePath) => {
|
|
2346
|
-
const { streamImport: streamImport2 } = await import("./stream-import-
|
|
2545
|
+
const { streamImport: streamImport2 } = await import("./stream-import-KZFC3XT2.mjs");
|
|
2347
2546
|
const result = await streamImport2(dm, filePath);
|
|
2348
2547
|
if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
|
|
2349
2548
|
return { sessionId: result.sessionId };
|
|
2350
2549
|
};
|
|
2351
2550
|
const defaultUserDataDir = getDefaultNodeUserDataDir();
|
|
2352
|
-
const isCustom =
|
|
2551
|
+
const isCustom = path8.resolve(resolvedPathProvider.getUserDataDir()) !== path8.resolve(defaultUserDataDir);
|
|
2353
2552
|
registerSharedRoutes(
|
|
2354
2553
|
server2,
|
|
2355
2554
|
{
|
|
@@ -2440,31 +2639,31 @@ function registerProxyRoutes(server2) {
|
|
|
2440
2639
|
}
|
|
2441
2640
|
|
|
2442
2641
|
// src/ai/manager-factory.ts
|
|
2443
|
-
import * as
|
|
2444
|
-
import * as
|
|
2642
|
+
import * as fs7 from "fs";
|
|
2643
|
+
import * as path9 from "path";
|
|
2445
2644
|
import { createHash, randomUUID } from "crypto";
|
|
2446
2645
|
var nodeFs = {
|
|
2447
2646
|
ensureDir(dir) {
|
|
2448
|
-
if (!
|
|
2647
|
+
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
2449
2648
|
},
|
|
2450
2649
|
listFiles(dir, ext) {
|
|
2451
|
-
if (!
|
|
2452
|
-
return
|
|
2650
|
+
if (!fs7.existsSync(dir)) return [];
|
|
2651
|
+
return fs7.readdirSync(dir).filter((f) => f.endsWith(ext));
|
|
2453
2652
|
},
|
|
2454
2653
|
readFile(filePath) {
|
|
2455
|
-
return
|
|
2654
|
+
return fs7.readFileSync(filePath, "utf-8");
|
|
2456
2655
|
},
|
|
2457
2656
|
writeFile(filePath, content) {
|
|
2458
|
-
|
|
2657
|
+
fs7.writeFileSync(filePath, content, "utf-8");
|
|
2459
2658
|
},
|
|
2460
2659
|
deleteFile(filePath) {
|
|
2461
|
-
if (
|
|
2660
|
+
if (fs7.existsSync(filePath)) fs7.unlinkSync(filePath);
|
|
2462
2661
|
},
|
|
2463
2662
|
fileExists(filePath) {
|
|
2464
|
-
return
|
|
2663
|
+
return fs7.existsSync(filePath);
|
|
2465
2664
|
},
|
|
2466
2665
|
joinPath(...parts) {
|
|
2467
|
-
return
|
|
2666
|
+
return path9.join(...parts);
|
|
2468
2667
|
}
|
|
2469
2668
|
};
|
|
2470
2669
|
var managerCache = /* @__PURE__ */ new Map();
|
|
@@ -2474,13 +2673,13 @@ function getAssistantManager(aiDataDir) {
|
|
|
2474
2673
|
cached = {
|
|
2475
2674
|
assistant: new AssistantManager({
|
|
2476
2675
|
fs: nodeFs,
|
|
2477
|
-
assistantsDir:
|
|
2676
|
+
assistantsDir: path9.join(aiDataDir, "assistants"),
|
|
2478
2677
|
builtinRawConfigs: [],
|
|
2479
2678
|
generateId: () => `custom_${randomUUID().replace(/-/g, "").slice(0, 12)}`
|
|
2480
2679
|
}),
|
|
2481
2680
|
skill: new SkillManagerCore({
|
|
2482
2681
|
fs: nodeFs,
|
|
2483
|
-
skillsDir:
|
|
2682
|
+
skillsDir: path9.join(aiDataDir, "skills"),
|
|
2484
2683
|
builtinRawSkills: [],
|
|
2485
2684
|
contentHash: (content) => createHash("md5").update(content).digest("hex")
|
|
2486
2685
|
})
|
|
@@ -2504,8 +2703,8 @@ var noop = () => {
|
|
|
2504
2703
|
var NOOP_LOGGER = { info: noop, warn: noop, error: noop };
|
|
2505
2704
|
|
|
2506
2705
|
// ../../packages/sync/src/data-source-manager.ts
|
|
2507
|
-
import * as
|
|
2508
|
-
import * as
|
|
2706
|
+
import * as fs8 from "fs";
|
|
2707
|
+
import * as path10 from "path";
|
|
2509
2708
|
import * as crypto from "crypto";
|
|
2510
2709
|
var CONFIG_FILE = "data-sources.json";
|
|
2511
2710
|
function generateId(prefix = "ds") {
|
|
@@ -2533,17 +2732,17 @@ var DataSourceManager = class {
|
|
|
2533
2732
|
this.logger = logger ?? NOOP_LOGGER;
|
|
2534
2733
|
}
|
|
2535
2734
|
getConfigPath() {
|
|
2536
|
-
return
|
|
2735
|
+
return path10.join(this.configDir, CONFIG_FILE);
|
|
2537
2736
|
}
|
|
2538
2737
|
ensureDir() {
|
|
2539
|
-
|
|
2738
|
+
fs8.mkdirSync(this.configDir, { recursive: true });
|
|
2540
2739
|
}
|
|
2541
2740
|
// ==================== Load / Save ====================
|
|
2542
2741
|
loadAll() {
|
|
2543
2742
|
try {
|
|
2544
2743
|
const filePath = this.getConfigPath();
|
|
2545
|
-
if (
|
|
2546
|
-
const raw =
|
|
2744
|
+
if (fs8.existsSync(filePath)) {
|
|
2745
|
+
const raw = fs8.readFileSync(filePath, "utf-8");
|
|
2547
2746
|
const parsed = JSON.parse(raw);
|
|
2548
2747
|
if (!isValidDataSourceArray(parsed)) {
|
|
2549
2748
|
this.logger.warn("[DataSource] Incompatible config format detected, returning empty.");
|
|
@@ -2562,7 +2761,7 @@ var DataSourceManager = class {
|
|
|
2562
2761
|
saveAll(sources) {
|
|
2563
2762
|
try {
|
|
2564
2763
|
this.ensureDir();
|
|
2565
|
-
|
|
2764
|
+
fs8.writeFileSync(this.getConfigPath(), JSON.stringify(sources, null, 2), "utf-8");
|
|
2566
2765
|
} catch (err) {
|
|
2567
2766
|
this.logger.error("[DataSource] Failed to save config", err);
|
|
2568
2767
|
}
|
|
@@ -2687,7 +2886,7 @@ function parseRemoteSessionsResponse(body) {
|
|
|
2687
2886
|
}
|
|
2688
2887
|
|
|
2689
2888
|
// ../../packages/sync/src/pull-engine.ts
|
|
2690
|
-
import * as
|
|
2889
|
+
import * as fs9 from "fs";
|
|
2691
2890
|
import * as crypto2 from "crypto";
|
|
2692
2891
|
var MAX_PAGES_PER_PULL = 5e3;
|
|
2693
2892
|
var PULL_OVERLAP_SECONDS = 60;
|
|
@@ -2707,7 +2906,7 @@ function parseSyncFromFile(filePath) {
|
|
|
2707
2906
|
try {
|
|
2708
2907
|
const isJsonl = filePath.endsWith(".jsonl");
|
|
2709
2908
|
if (isJsonl) {
|
|
2710
|
-
const content =
|
|
2909
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
2711
2910
|
const lines = content.trimEnd().split("\n");
|
|
2712
2911
|
for (let i = lines.length - 1; i >= Math.max(0, lines.length - 5); i--) {
|
|
2713
2912
|
try {
|
|
@@ -2726,7 +2925,7 @@ function parseSyncFromFile(filePath) {
|
|
|
2726
2925
|
}
|
|
2727
2926
|
return null;
|
|
2728
2927
|
}
|
|
2729
|
-
const raw =
|
|
2928
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
2730
2929
|
const parsed = JSON.parse(raw);
|
|
2731
2930
|
if (parsed.sync && typeof parsed.sync === "object") {
|
|
2732
2931
|
const s = parsed.sync;
|
|
@@ -2740,7 +2939,7 @@ function parseSyncFromFile(filePath) {
|
|
|
2740
2939
|
function fileContainsMessages(filePath) {
|
|
2741
2940
|
try {
|
|
2742
2941
|
if (filePath.endsWith(".jsonl")) {
|
|
2743
|
-
const content =
|
|
2942
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
2744
2943
|
for (const line of content.split("\n")) {
|
|
2745
2944
|
const trimmed = line.trim();
|
|
2746
2945
|
if (!trimmed) continue;
|
|
@@ -2753,7 +2952,7 @@ function fileContainsMessages(filePath) {
|
|
|
2753
2952
|
}
|
|
2754
2953
|
return false;
|
|
2755
2954
|
}
|
|
2756
|
-
const raw =
|
|
2955
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
2757
2956
|
const parsed = JSON.parse(raw);
|
|
2758
2957
|
return Array.isArray(parsed.messages) && parsed.messages.length > 0;
|
|
2759
2958
|
} catch {
|
|
@@ -2762,7 +2961,7 @@ function fileContainsMessages(filePath) {
|
|
|
2762
2961
|
}
|
|
2763
2962
|
function cleanupTempFile(filePath) {
|
|
2764
2963
|
try {
|
|
2765
|
-
if (
|
|
2964
|
+
if (fs9.existsSync(filePath)) fs9.unlinkSync(filePath);
|
|
2766
2965
|
} catch {
|
|
2767
2966
|
}
|
|
2768
2967
|
}
|
|
@@ -2824,7 +3023,7 @@ var PullEngine = class {
|
|
|
2824
3023
|
limit: ds.pullLimit
|
|
2825
3024
|
});
|
|
2826
3025
|
try {
|
|
2827
|
-
const stat2 =
|
|
3026
|
+
const stat2 = fs9.statSync(tempFile);
|
|
2828
3027
|
this.logger.info(`[Pull] "${sess.name}" page ${pageCount}: fetched ${stat2.size} bytes`);
|
|
2829
3028
|
const sync0 = parseSyncFromFile(tempFile);
|
|
2830
3029
|
if (stat2.size < 1024) {
|
|
@@ -2842,7 +3041,7 @@ var PullEngine = class {
|
|
|
2842
3041
|
since,
|
|
2843
3042
|
limit: ds.pullLimit
|
|
2844
3043
|
});
|
|
2845
|
-
const retryStat =
|
|
3044
|
+
const retryStat = fs9.statSync(retryFile);
|
|
2846
3045
|
this.logger.info(`[Pull] "${sess.name}" retry ${ri + 1}: fetched ${retryStat.size} bytes`);
|
|
2847
3046
|
const retrySync = parseSyncFromFile(retryFile);
|
|
2848
3047
|
if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {
|
|
@@ -3123,13 +3322,13 @@ function reloadTimer(dsId, skipInitialPull = false) {
|
|
|
3123
3322
|
}
|
|
3124
3323
|
|
|
3125
3324
|
// src/sync/adapters.ts
|
|
3126
|
-
import * as
|
|
3325
|
+
import * as fs10 from "fs";
|
|
3127
3326
|
import * as os4 from "os";
|
|
3128
|
-
import * as
|
|
3327
|
+
import * as path11 from "path";
|
|
3129
3328
|
import * as crypto3 from "crypto";
|
|
3130
3329
|
function getTempFilePath(ext) {
|
|
3131
3330
|
const id = crypto3.randomBytes(8).toString("hex");
|
|
3132
|
-
return
|
|
3331
|
+
return path11.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
|
|
3133
3332
|
}
|
|
3134
3333
|
var NodeFetcher = class {
|
|
3135
3334
|
async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
|
|
@@ -3146,7 +3345,7 @@ var NodeFetcher = class {
|
|
|
3146
3345
|
const isJsonl = contentType.includes("ndjson") || contentType.includes("jsonl");
|
|
3147
3346
|
const tempFile = getTempFilePath(isJsonl ? ".jsonl" : ".json");
|
|
3148
3347
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
3149
|
-
|
|
3348
|
+
fs10.writeFileSync(tempFile, buffer);
|
|
3150
3349
|
return tempFile;
|
|
3151
3350
|
}
|
|
3152
3351
|
};
|
|
@@ -3159,7 +3358,7 @@ var DirectImporter = class {
|
|
|
3159
3358
|
}
|
|
3160
3359
|
sessionExists(sessionId) {
|
|
3161
3360
|
const dbPath = this.dbManager.getDbPath(sessionId);
|
|
3162
|
-
if (!
|
|
3361
|
+
if (!fs10.existsSync(dbPath)) return false;
|
|
3163
3362
|
try {
|
|
3164
3363
|
const db = this.dbManager.openRawSessionDatabase(sessionId, { readonly: true });
|
|
3165
3364
|
const row = db.prepare("SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name='message'").get();
|
|
@@ -3167,7 +3366,7 @@ var DirectImporter = class {
|
|
|
3167
3366
|
if (row.cnt === 0) {
|
|
3168
3367
|
this.logger.warn(`[DirectImporter] DB file exists but has no message table: ${sessionId}, removing`);
|
|
3169
3368
|
try {
|
|
3170
|
-
|
|
3369
|
+
fs10.unlinkSync(dbPath);
|
|
3171
3370
|
} catch {
|
|
3172
3371
|
}
|
|
3173
3372
|
return false;
|
|
@@ -3177,7 +3376,7 @@ var DirectImporter = class {
|
|
|
3177
3376
|
if (error instanceof DataDirCompatibilityError) throw error;
|
|
3178
3377
|
this.logger.warn(`[DirectImporter] Cannot validate DB file: ${sessionId}, removing`);
|
|
3179
3378
|
try {
|
|
3180
|
-
|
|
3379
|
+
fs10.unlinkSync(dbPath);
|
|
3181
3380
|
} catch {
|
|
3182
3381
|
}
|
|
3183
3382
|
return false;
|
|
@@ -3382,21 +3581,21 @@ function createFileConfigStorage(aiDataDir) {
|
|
|
3382
3581
|
return {
|
|
3383
3582
|
readJson(key) {
|
|
3384
3583
|
try {
|
|
3385
|
-
return JSON.parse(
|
|
3584
|
+
return JSON.parse(fs11.readFileSync(`${aiDataDir}/${key}.json`, "utf-8"));
|
|
3386
3585
|
} catch {
|
|
3387
3586
|
return null;
|
|
3388
3587
|
}
|
|
3389
3588
|
},
|
|
3390
3589
|
writeJson(key, data) {
|
|
3391
|
-
if (!
|
|
3392
|
-
|
|
3590
|
+
if (!fs11.existsSync(aiDataDir)) fs11.mkdirSync(aiDataDir, { recursive: true });
|
|
3591
|
+
fs11.writeFileSync(`${aiDataDir}/${key}.json`, JSON.stringify(data, null, 2), "utf-8");
|
|
3393
3592
|
}
|
|
3394
3593
|
};
|
|
3395
3594
|
}
|
|
3396
3595
|
function resolveNativeBinding2() {
|
|
3397
3596
|
if (process.versions.electron) return void 0;
|
|
3398
3597
|
const nativePath = resolveCliPath("native/better_sqlite3.node");
|
|
3399
|
-
if (
|
|
3598
|
+
if (fs11.existsSync(nativePath)) return nativePath;
|
|
3400
3599
|
return void 0;
|
|
3401
3600
|
}
|
|
3402
3601
|
function ensureToken(config) {
|
|
@@ -3482,7 +3681,7 @@ async function startHttpServer(options) {
|
|
|
3482
3681
|
}
|
|
3483
3682
|
});
|
|
3484
3683
|
initSync(server, dbManager, pathProvider, { port, host, token });
|
|
3485
|
-
if (options?.webRoot &&
|
|
3684
|
+
if (options?.webRoot && fs11.existsSync(options.webRoot)) {
|
|
3486
3685
|
registerProxyRoutes(server);
|
|
3487
3686
|
const fastifyStatic = await import("@fastify/static");
|
|
3488
3687
|
await server.register(fastifyStatic.default, {
|
|
@@ -3523,4 +3722,4 @@ export {
|
|
|
3523
3722
|
startHttpServer,
|
|
3524
3723
|
stopHttpServer
|
|
3525
3724
|
};
|
|
3526
|
-
//# sourceMappingURL=chunk-
|
|
3725
|
+
//# sourceMappingURL=chunk-QMXNJRTT.mjs.map
|