chatlab-cli 0.27.0 → 0.27.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-SKGPS3PG.mjs → chat-command-B7POB3C3.mjs} +5 -4
- package/dist/{chat-command-SKGPS3PG.mjs.map → chat-command-B7POB3C3.mjs.map} +1 -1
- package/dist/{chunk-MJITS5CE.mjs → chunk-3FUF3PEY.mjs} +15 -13
- package/dist/{chunk-MJITS5CE.mjs.map → chunk-3FUF3PEY.mjs.map} +1 -1
- package/dist/{chunk-FHLPXRDL.mjs → chunk-3JNVGW62.mjs} +2 -2
- package/dist/{chunk-KCFVHVO4.mjs → chunk-I7BHOZPX.mjs} +11202 -17966
- package/dist/chunk-I7BHOZPX.mjs.map +1 -0
- package/dist/chunk-N3G43SCQ.mjs +7337 -0
- package/dist/chunk-N3G43SCQ.mjs.map +1 -0
- package/dist/{chunk-7LPVQR77.mjs → chunk-RJ4D4QWK.mjs} +4 -4
- package/dist/chunk-RJ4D4QWK.mjs.map +1 -0
- package/dist/{chunk-6FXGC6HE.mjs → chunk-SAE2H2LN.mjs} +7 -5
- package/dist/{chunk-6FXGC6HE.mjs.map → chunk-SAE2H2LN.mjs.map} +1 -1
- package/dist/{chunk-3HOTLLFC.mjs → chunk-SIVERPF5.mjs} +215 -130
- package/dist/chunk-SIVERPF5.mjs.map +1 -0
- package/dist/{chunk-M6ABWESL.mjs → chunk-WQMKKUSD.mjs} +5 -5
- package/dist/chunk-WQMKKUSD.mjs.map +1 -0
- package/dist/{chunk-UBJHT3BU.mjs → chunk-YUFYTDRH.mjs} +6 -4
- package/dist/{chunk-UBJHT3BU.mjs.map → chunk-YUFYTDRH.mjs.map} +1 -1
- package/dist/cli.mjs +4 -3
- package/dist/{http-CPFUTIUB.mjs → http-A54ZBBAY.mjs} +9 -8
- package/dist/{import-UJXKIKYN.mjs → import-EA3TB3S2.mjs} +5 -4
- package/dist/index.mjs +9 -8
- package/dist/{mcp-SW4DTCWJ.mjs → mcp-DJDOWHH3.mjs} +8 -6
- package/dist/{mcp-SW4DTCWJ.mjs.map → mcp-DJDOWHH3.mjs.map} +1 -1
- package/dist/semantic-index-worker.mjs +34 -0
- package/dist/semantic-index-worker.mjs.map +1 -0
- package/dist/{src-M3MO3LEL.mjs → src-EKPMJRG6.mjs} +57 -41
- package/dist/{stream-import-4VDJZHMY.mjs → stream-import-FQFNRQ2B.mjs} +4 -3
- package/dist/worker-runtime-UH2OBO3T.mjs +71 -0
- package/dist/worker-runtime-UH2OBO3T.mjs.map +1 -0
- package/dist-web/assets/{DebugToolsPanel-DzZmSzIU.css → DebugToolsPanel-DFw6_G5V.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-NL1sTF6i.js +110 -0
- package/dist-web/assets/{MessageExportModal-DCB-mzf2.js → MessageExportModal-B60rvfCh.js} +1 -1
- package/dist-web/assets/{electron-DDUv0ohD.js → electron-BRUg9LnY.js} +1 -1
- package/dist-web/assets/{fetch-C1aC5Fd1.js → fetch-BIpjJHxj.js} +1 -1
- package/dist-web/assets/{fetch-D8Ng59an.js → fetch-BRsMdFcn.js} +1 -1
- package/dist-web/assets/{fetch-Ckang-F8.js → fetch-C-m3IysH.js} +1 -1
- package/dist-web/assets/{fetch-Ck4rGxkO.js → fetch-Cma-mZjd.js} +1 -1
- package/dist-web/assets/{fetch-Bry8iJpq.js → fetch-DE8gj5Ke.js} +1 -1
- package/dist-web/assets/{fetch-C69hj3wS.js → fetch-DLAp7h55.js} +1 -1
- package/dist-web/assets/{fetch-B9Oy0bcD.js → fetch-DNSaxRnL.js} +1 -1
- package/dist-web/assets/{fetch-B3gsbY_U.js → fetch-DOEbyLSD.js} +1 -1
- package/dist-web/assets/{fetch-CwHncc6x.js → fetch-DSN-QYZE.js} +1 -1
- package/dist-web/assets/{fetch-DOtBAxUS.js → fetch-woAa3H2L.js} +1 -1
- package/dist-web/assets/{index-C16V6EoP.js → index-B3mDjury.js} +9 -9
- package/dist-web/assets/{index-D-J8dY7w.js → index-B9I-Y3fR.js} +1 -1
- package/dist-web/assets/index-GAU7LI1r.js +173 -0
- package/dist-web/assets/{index-zAi37ZQ4.js → index-iwqJDVMJ.js} +2 -2
- package/dist-web/assets/{index-BfFj8Evo.js → index-o6veAyTB.js} +3 -3
- package/dist-web/assets/{index-Bd9j73nw.js → index-r_zHR2t9.js} +1 -1
- package/dist-web/assets/{web-DKFeBb_F.js → web-C2UtGskd.js} +1 -1
- package/dist-web/index.html +1 -1
- package/package.json +1 -1
- package/dist/chunk-3HOTLLFC.mjs.map +0 -1
- package/dist/chunk-7LPVQR77.mjs.map +0 -1
- package/dist/chunk-KCFVHVO4.mjs.map +0 -1
- package/dist/chunk-M6ABWESL.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-C8mwzxDa.js +0 -110
- package/dist-web/assets/index-B40SKtW8.js +0 -173
- /package/dist/{chunk-FHLPXRDL.mjs.map → chunk-3JNVGW62.mjs.map} +0 -0
- /package/dist/{http-CPFUTIUB.mjs.map → http-A54ZBBAY.mjs.map} +0 -0
- /package/dist/{import-UJXKIKYN.mjs.map → import-EA3TB3S2.mjs.map} +0 -0
- /package/dist/{src-M3MO3LEL.mjs.map → src-EKPMJRG6.mjs.map} +0 -0
- /package/dist/{stream-import-4VDJZHMY.mjs.map → stream-import-FQFNRQ2B.mjs.map} +0 -0
|
@@ -8,30 +8,52 @@ import {
|
|
|
8
8
|
closeServerAiLogger,
|
|
9
9
|
createCliRunAgentStream,
|
|
10
10
|
initServerAiLogger
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
importData,
|
|
14
|
-
parseFile
|
|
15
|
-
} from "./chunk-UBJHT3BU.mjs";
|
|
16
|
-
import {
|
|
17
|
-
analyzeIncrementalImport,
|
|
18
|
-
analyzeNewImport,
|
|
19
|
-
incrementalImport,
|
|
20
|
-
streamImport
|
|
21
|
-
} from "./chunk-6FXGC6HE.mjs";
|
|
11
|
+
} from "./chunk-RJ4D4QWK.mjs";
|
|
22
12
|
import {
|
|
23
13
|
AGENT_TOOL_REGISTRY,
|
|
24
14
|
CoreDataProvider
|
|
25
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-WQMKKUSD.mjs";
|
|
26
16
|
import {
|
|
27
17
|
assertCliDataDirCompatible
|
|
28
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-3JNVGW62.mjs";
|
|
29
19
|
import {
|
|
30
20
|
getVersion
|
|
31
21
|
} from "./chunk-5ADKYYNA.mjs";
|
|
32
22
|
import {
|
|
33
23
|
resolveCliPath
|
|
34
24
|
} from "./chunk-FJ35V3TE.mjs";
|
|
25
|
+
import {
|
|
26
|
+
importData,
|
|
27
|
+
parseFile
|
|
28
|
+
} from "./chunk-YUFYTDRH.mjs";
|
|
29
|
+
import {
|
|
30
|
+
analyzeIncrementalImport,
|
|
31
|
+
analyzeNewImport,
|
|
32
|
+
incrementalImport,
|
|
33
|
+
streamImport
|
|
34
|
+
} from "./chunk-SAE2H2LN.mjs";
|
|
35
|
+
import {
|
|
36
|
+
NodePathProvider,
|
|
37
|
+
PreferencesManager,
|
|
38
|
+
applyPendingNodeDataDirMigrationIfNeeded,
|
|
39
|
+
buildMergedOutput,
|
|
40
|
+
checkConflictsFromSources,
|
|
41
|
+
createJiebaNlpProvider,
|
|
42
|
+
createNodeDataDirSwitch,
|
|
43
|
+
createSemanticIndexWorkerRuntimeClient,
|
|
44
|
+
detectAllFormats,
|
|
45
|
+
detectFormat,
|
|
46
|
+
findEntryFileInDirectory,
|
|
47
|
+
getDbFileVersion,
|
|
48
|
+
getDefaultNodeUserDataDir,
|
|
49
|
+
getOrComputeAnalysisCache,
|
|
50
|
+
getPendingNodeDataDirMigration,
|
|
51
|
+
getSupportedFormats,
|
|
52
|
+
hasPendingElectronDataWarning,
|
|
53
|
+
scanMultiChatFile,
|
|
54
|
+
serializeChatLabToJsonl,
|
|
55
|
+
streamParseFileInfo
|
|
56
|
+
} from "./chunk-N3G43SCQ.mjs";
|
|
35
57
|
import {
|
|
36
58
|
AIChatManager,
|
|
37
59
|
ALL_MIGRATIONS,
|
|
@@ -46,24 +68,16 @@ import {
|
|
|
46
68
|
LLMConfigStore,
|
|
47
69
|
MergeSessionCache,
|
|
48
70
|
MigrationRunner,
|
|
49
|
-
NodePathProvider,
|
|
50
71
|
POS_TAG_DEFINITIONS,
|
|
51
|
-
|
|
72
|
+
SEMANTIC_INDEX_CONFIG_FILE,
|
|
73
|
+
SemanticIndexConfigStore,
|
|
52
74
|
SkillManagerCore,
|
|
53
75
|
TempDbWriter,
|
|
54
|
-
applyPendingNodeDataDirMigrationIfNeeded,
|
|
55
|
-
buildMergedOutput,
|
|
56
76
|
buildPiModel,
|
|
57
|
-
checkConflictsFromSources,
|
|
58
77
|
computeWordFrequency,
|
|
59
78
|
countMessagesTokens,
|
|
60
79
|
createDatabaseManagerAdapter,
|
|
61
|
-
createJiebaNlpProvider,
|
|
62
|
-
createNodeDataDirSwitch,
|
|
63
|
-
createSemanticIndexService,
|
|
64
80
|
deleteDict,
|
|
65
|
-
detectAllFormats,
|
|
66
|
-
detectFormat,
|
|
67
81
|
downloadDict,
|
|
68
82
|
ensureDefaultDict,
|
|
69
83
|
executeReadonlySql,
|
|
@@ -71,15 +85,12 @@ import {
|
|
|
71
85
|
exportSessionToJson,
|
|
72
86
|
export_service_exports,
|
|
73
87
|
fetchRemoteModels,
|
|
74
|
-
findEntryFileInDirectory,
|
|
75
88
|
getAvailableYears,
|
|
76
89
|
getBuiltinModelsByProvider,
|
|
77
90
|
getCatchphraseAnalysis,
|
|
78
91
|
getCheckInAnalysis,
|
|
79
92
|
getClusterGraph,
|
|
80
93
|
getDailyActivity,
|
|
81
|
-
getDbFileVersion,
|
|
82
|
-
getDefaultNodeUserDataDir,
|
|
83
94
|
getDefaultRulesForLocale,
|
|
84
95
|
getDictList,
|
|
85
96
|
getDivingAnalysis,
|
|
@@ -99,44 +110,40 @@ import {
|
|
|
99
110
|
getMessageTypeStats,
|
|
100
111
|
getMonthlyActivity,
|
|
101
112
|
getNightOwlAnalysis,
|
|
102
|
-
getOrComputeAnalysisCache,
|
|
103
|
-
getPendingNodeDataDirMigration,
|
|
104
113
|
getRelationshipStats,
|
|
105
114
|
getRepeatAnalysis,
|
|
106
115
|
getSchemaDetailed,
|
|
107
116
|
getSessionInfo,
|
|
108
117
|
getSessionMeta,
|
|
109
118
|
getSessionOverview,
|
|
110
|
-
getSupportedFormats,
|
|
111
119
|
getTextLengthPercentiles,
|
|
112
120
|
getTextStats,
|
|
113
121
|
getTimeRange,
|
|
114
122
|
getWeekdayActivity,
|
|
115
123
|
getYearlyActivity,
|
|
116
|
-
hasPendingElectronDataWarning,
|
|
117
124
|
initNlpDir,
|
|
118
125
|
isDictDownloaded,
|
|
119
126
|
isNewerStableVersion,
|
|
127
|
+
isSemanticIndexConfigured,
|
|
120
128
|
loadConfig,
|
|
121
129
|
member_service_exports,
|
|
122
130
|
mergeRulesForLocale,
|
|
123
131
|
owner_profile_service_exports,
|
|
132
|
+
persistSemanticIndexConfig,
|
|
124
133
|
queryMessages,
|
|
125
134
|
resolveApiKey,
|
|
135
|
+
resolveSemanticIndexApiKeySet,
|
|
126
136
|
runSimpleLlmStream,
|
|
127
|
-
scanMultiChatFile,
|
|
128
137
|
segmentText,
|
|
129
|
-
serializeChatLabToJsonl,
|
|
130
138
|
session_index_service_exports,
|
|
131
139
|
session_service_exports,
|
|
132
|
-
streamParseFileInfo,
|
|
133
140
|
stripAvatarFields,
|
|
134
141
|
summary_service_exports,
|
|
135
142
|
validateApiKey,
|
|
136
143
|
verifyCliDataPath,
|
|
137
144
|
writeAuthProfile,
|
|
138
145
|
writeConfigField
|
|
139
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-I7BHOZPX.mjs";
|
|
140
147
|
|
|
141
148
|
// src/http/index.ts
|
|
142
149
|
import * as fs11 from "fs";
|
|
@@ -1618,34 +1625,63 @@ function registerAiSummaryRoutes(server2, ctx) {
|
|
|
1618
1625
|
}
|
|
1619
1626
|
|
|
1620
1627
|
// ../../packages/http-routes/src/routes/web/ai-semantic-index.ts
|
|
1628
|
+
import path4 from "path";
|
|
1621
1629
|
function registerSemanticIndexRoutes(server2, ctx) {
|
|
1622
1630
|
const service = ctx.semanticIndexService;
|
|
1623
|
-
if (!service)
|
|
1631
|
+
if (!service) {
|
|
1632
|
+
if (ctx.aiDataDir) {
|
|
1633
|
+
const configStore = new SemanticIndexConfigStore(path4.join(ctx.aiDataDir, SEMANTIC_INDEX_CONFIG_FILE));
|
|
1634
|
+
const configResponse = (config) => ({
|
|
1635
|
+
config,
|
|
1636
|
+
apiKeySet: resolveSemanticIndexApiKeySet(config, ctx.resolveApiKey),
|
|
1637
|
+
configured: isSemanticIndexConfigured(config)
|
|
1638
|
+
});
|
|
1639
|
+
server2.get("/_web/ai/semantic-index/config", async () => configResponse(configStore.get()));
|
|
1640
|
+
server2.put(
|
|
1641
|
+
"/_web/ai/semantic-index/config",
|
|
1642
|
+
async (request) => {
|
|
1643
|
+
const config = persistSemanticIndexConfig(configStore, request.body.config, {
|
|
1644
|
+
apiKey: request.body.apiKey,
|
|
1645
|
+
writeAuthProfile: ctx.writeAuthProfile
|
|
1646
|
+
});
|
|
1647
|
+
return configResponse(config);
|
|
1648
|
+
}
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1651
|
+
server2.get("/_web/ai/semantic-index/enabled", async () => ({ sessions: [] }));
|
|
1652
|
+
server2.get("/_web/ai/semantic-index/status", async () => ({ status: null }));
|
|
1653
|
+
server2.post("/_web/ai/semantic-index/status", async () => ({ sessions: [] }));
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1624
1656
|
server2.get("/_web/ai/semantic-index/config", async () => {
|
|
1625
|
-
return {
|
|
1657
|
+
return {
|
|
1658
|
+
config: await service.getConfig(),
|
|
1659
|
+
apiKeySet: await service.hasApiKey(),
|
|
1660
|
+
configured: await service.isConfigured()
|
|
1661
|
+
};
|
|
1626
1662
|
});
|
|
1627
1663
|
server2.put(
|
|
1628
1664
|
"/_web/ai/semantic-index/config",
|
|
1629
1665
|
async (request) => {
|
|
1630
|
-
const config = service.setConfig(request.body.config, { apiKey: request.body.apiKey });
|
|
1631
|
-
return { config, apiKeySet: service.hasApiKey(), configured: service.isConfigured() };
|
|
1666
|
+
const config = await service.setConfig(request.body.config, { apiKey: request.body.apiKey });
|
|
1667
|
+
return { config, apiKeySet: await service.hasApiKey(), configured: await service.isConfigured() };
|
|
1632
1668
|
}
|
|
1633
1669
|
);
|
|
1634
1670
|
server2.get("/_web/ai/semantic-index/enabled", async () => {
|
|
1635
|
-
return { sessions: service.listEnabledStatuses() };
|
|
1671
|
+
return { sessions: await service.listEnabledStatuses() };
|
|
1636
1672
|
});
|
|
1637
1673
|
server2.get("/_web/ai/semantic-index/status", async (request) => {
|
|
1638
|
-
return { status: service.status(request.query.sessionId) };
|
|
1674
|
+
return { status: await service.status(request.query.sessionId) };
|
|
1639
1675
|
});
|
|
1640
1676
|
server2.post("/_web/ai/semantic-index/status", async (request) => {
|
|
1641
|
-
return { sessions: service.statusForSessions(request.body.sessionIds ?? []) };
|
|
1677
|
+
return { sessions: await service.statusForSessions(request.body.sessionIds ?? []) };
|
|
1642
1678
|
});
|
|
1643
|
-
const sessionAction = (
|
|
1644
|
-
server2.post(
|
|
1679
|
+
const sessionAction = (path13, action) => {
|
|
1680
|
+
server2.post(path13, async (request, reply) => {
|
|
1645
1681
|
const { sessionId } = request.body;
|
|
1646
1682
|
if (!sessionId) return reply.code(400).send({ error: "sessionId is required" });
|
|
1647
1683
|
await action(sessionId);
|
|
1648
|
-
return { status: service.status(sessionId) };
|
|
1684
|
+
return { status: await service.status(sessionId) };
|
|
1649
1685
|
});
|
|
1650
1686
|
};
|
|
1651
1687
|
sessionAction("/_web/ai/semantic-index/enable", (id) => service.enable(id));
|
|
@@ -1655,11 +1691,11 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1655
1691
|
sessionAction("/_web/ai/semantic-index/cancel", (id) => service.cancel(id));
|
|
1656
1692
|
sessionAction("/_web/ai/semantic-index/rebuild", (id) => service.rebuild(id));
|
|
1657
1693
|
server2.post("/_web/ai/semantic-index/build-pending", async () => {
|
|
1658
|
-
service.buildAllPending();
|
|
1659
|
-
return { sessions: service.listEnabledStatuses() };
|
|
1694
|
+
await service.buildAllPending();
|
|
1695
|
+
return { sessions: await service.listEnabledStatuses() };
|
|
1660
1696
|
});
|
|
1661
1697
|
server2.post("/_web/ai/semantic-index/cleanup", async () => {
|
|
1662
|
-
return service.cleanupUnused();
|
|
1698
|
+
return await service.cleanupUnused();
|
|
1663
1699
|
});
|
|
1664
1700
|
server2.post(
|
|
1665
1701
|
"/_web/ai/semantic-index/search",
|
|
@@ -1674,7 +1710,7 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1674
1710
|
// ../../packages/http-routes/src/routes/web/merge.ts
|
|
1675
1711
|
import * as fs3 from "fs";
|
|
1676
1712
|
import * as os from "os";
|
|
1677
|
-
import * as
|
|
1713
|
+
import * as path5 from "path";
|
|
1678
1714
|
function ensureDb2(ctx, sessionId) {
|
|
1679
1715
|
const db = ctx.dbManager.open(sessionId);
|
|
1680
1716
|
if (!db) throw sessionNotFound(sessionId);
|
|
@@ -1691,8 +1727,8 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1691
1727
|
if (contentType.includes("multipart/form-data")) {
|
|
1692
1728
|
const data = await request.file();
|
|
1693
1729
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
1694
|
-
const tmpDir = fs3.mkdtempSync(
|
|
1695
|
-
const tmpPath =
|
|
1730
|
+
const tmpDir = fs3.mkdtempSync(path5.join(os.tmpdir(), "chatlab-merge-"));
|
|
1731
|
+
const tmpPath = path5.join(tmpDir, data.filename || "upload");
|
|
1696
1732
|
const chunks = [];
|
|
1697
1733
|
for await (const chunk of data.file) {
|
|
1698
1734
|
chunks.push(chunk);
|
|
@@ -1710,12 +1746,12 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1710
1746
|
try {
|
|
1711
1747
|
const result = await streamParseFileInfo(filePath, {
|
|
1712
1748
|
createTempDatabase(sourceFilePath) {
|
|
1713
|
-
return mergeCache.createTempDatabase(
|
|
1749
|
+
return mergeCache.createTempDatabase(path5.basename(sourceFilePath));
|
|
1714
1750
|
},
|
|
1715
1751
|
onProgress() {
|
|
1716
1752
|
}
|
|
1717
1753
|
});
|
|
1718
|
-
const filename =
|
|
1754
|
+
const filename = path5.basename(filePath);
|
|
1719
1755
|
const handle = mergeCache.store(filename, result.tempDbPath);
|
|
1720
1756
|
return {
|
|
1721
1757
|
handle,
|
|
@@ -1784,9 +1820,9 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1784
1820
|
return reply.code(501).send({ error: "Import not available on this server" });
|
|
1785
1821
|
}
|
|
1786
1822
|
const jsonData = JSON.stringify(merged.chatLabData);
|
|
1787
|
-
const tmpDir = fs3.mkdtempSync(
|
|
1788
|
-
const safeName =
|
|
1789
|
-
const tmpPath =
|
|
1823
|
+
const tmpDir = fs3.mkdtempSync(path5.join(os.tmpdir(), "chatlab-merged-"));
|
|
1824
|
+
const safeName = path5.basename(outputName).replace(/[/\\?%*:|"<>]/g, "_") || "merged";
|
|
1825
|
+
const tmpPath = path5.join(tmpDir, `${safeName}.json`);
|
|
1790
1826
|
fs3.writeFileSync(tmpPath, jsonData, "utf-8");
|
|
1791
1827
|
try {
|
|
1792
1828
|
const importResult = await streamImport2(dbManager2, tmpPath);
|
|
@@ -1873,14 +1909,14 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1873
1909
|
// ../../packages/http-routes/src/routes/web/cache.ts
|
|
1874
1910
|
import * as fs4 from "fs";
|
|
1875
1911
|
import * as fsp from "fs/promises";
|
|
1876
|
-
import * as
|
|
1912
|
+
import * as path6 from "path";
|
|
1877
1913
|
async function getDirSize(dirPath) {
|
|
1878
1914
|
let totalSize = 0;
|
|
1879
1915
|
try {
|
|
1880
1916
|
if (!fs4.existsSync(dirPath)) return 0;
|
|
1881
1917
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1882
1918
|
for (const file of files) {
|
|
1883
|
-
const filePath =
|
|
1919
|
+
const filePath = path6.join(dirPath, file.name);
|
|
1884
1920
|
if (file.isDirectory()) {
|
|
1885
1921
|
totalSize += await getDirSize(filePath);
|
|
1886
1922
|
} else {
|
|
@@ -1898,7 +1934,7 @@ async function getFileCount(dirPath) {
|
|
|
1898
1934
|
if (!fs4.existsSync(dirPath)) return 0;
|
|
1899
1935
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1900
1936
|
for (const file of files) {
|
|
1901
|
-
const filePath =
|
|
1937
|
+
const filePath = path6.join(dirPath, file.name);
|
|
1902
1938
|
if (file.isDirectory()) {
|
|
1903
1939
|
count += await getFileCount(filePath);
|
|
1904
1940
|
} else {
|
|
@@ -1911,8 +1947,8 @@ async function getFileCount(dirPath) {
|
|
|
1911
1947
|
}
|
|
1912
1948
|
function hasChatLabDatabases(dirPath) {
|
|
1913
1949
|
try {
|
|
1914
|
-
const markerPath =
|
|
1915
|
-
const dbDir =
|
|
1950
|
+
const markerPath = path6.join(dirPath, ".chatlab");
|
|
1951
|
+
const dbDir = path6.join(dirPath, "databases");
|
|
1916
1952
|
if (!fs4.existsSync(markerPath) || !fs4.existsSync(dbDir)) return false;
|
|
1917
1953
|
return fs4.readdirSync(dbDir).some((file) => file.endsWith(".db"));
|
|
1918
1954
|
} catch {
|
|
@@ -1980,7 +2016,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1980
2016
|
if (!fs4.existsSync(dirPath)) return { success: true };
|
|
1981
2017
|
const files = await fsp.readdir(dirPath);
|
|
1982
2018
|
for (const file of files) {
|
|
1983
|
-
const filePath =
|
|
2019
|
+
const filePath = path6.join(dirPath, file);
|
|
1984
2020
|
const stat2 = await fsp.stat(filePath);
|
|
1985
2021
|
if (stat2.isDirectory()) {
|
|
1986
2022
|
await fsp.rm(filePath, { recursive: true });
|
|
@@ -1997,7 +2033,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1997
2033
|
defaultPath: ctx.defaultUserDataDir,
|
|
1998
2034
|
isCustom: ctx.isCustomDataDir ?? false,
|
|
1999
2035
|
canSetDataDir: ctx.canSetDataDir ?? Boolean(ctx.setDataDir),
|
|
2000
|
-
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) &&
|
|
2036
|
+
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) && path6.resolve(pp.getUserDataDir()) !== path6.resolve(ctx.defaultUserDataDir ?? "") && hasChatLabDatabases(ctx.defaultUserDataDir ?? ""),
|
|
2001
2037
|
pendingMigration: pending ? {
|
|
2002
2038
|
from: pending.from,
|
|
2003
2039
|
to: pending.to,
|
|
@@ -2014,7 +2050,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2014
2050
|
return ctx.setDataDir(targetPath, migrate);
|
|
2015
2051
|
});
|
|
2016
2052
|
server2.get("/_web/cache/latest-import-log", async () => {
|
|
2017
|
-
const importLogDir =
|
|
2053
|
+
const importLogDir = path6.join(pp.getLogsDir(), "import");
|
|
2018
2054
|
if (!fs4.existsSync(importLogDir)) {
|
|
2019
2055
|
return { success: false, error: "Log directory not found" };
|
|
2020
2056
|
}
|
|
@@ -2025,7 +2061,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2025
2061
|
}
|
|
2026
2062
|
const fileStats = await Promise.all(
|
|
2027
2063
|
logFiles.map(async (f) => {
|
|
2028
|
-
const filePath =
|
|
2064
|
+
const filePath = path6.join(importLogDir, f);
|
|
2029
2065
|
const stat2 = await fsp.stat(filePath);
|
|
2030
2066
|
return { name: f, path: filePath, mtime: stat2.mtime.getTime() };
|
|
2031
2067
|
})
|
|
@@ -2052,7 +2088,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2052
2088
|
if (!fs4.existsSync(downloadsDir)) {
|
|
2053
2089
|
fs4.mkdirSync(downloadsDir, { recursive: true });
|
|
2054
2090
|
}
|
|
2055
|
-
const filePath =
|
|
2091
|
+
const filePath = path6.join(downloadsDir, filename);
|
|
2056
2092
|
fs4.writeFileSync(filePath, buffer);
|
|
2057
2093
|
return { success: true, filePath };
|
|
2058
2094
|
});
|
|
@@ -2207,12 +2243,12 @@ function createServer() {
|
|
|
2207
2243
|
|
|
2208
2244
|
// src/http/routes/web/index.ts
|
|
2209
2245
|
import * as os3 from "os";
|
|
2210
|
-
import * as
|
|
2246
|
+
import * as path9 from "path";
|
|
2211
2247
|
|
|
2212
2248
|
// src/http/routes/web/import.ts
|
|
2213
2249
|
import * as fs6 from "fs";
|
|
2214
2250
|
import * as os2 from "os";
|
|
2215
|
-
import * as
|
|
2251
|
+
import * as path7 from "path";
|
|
2216
2252
|
|
|
2217
2253
|
// src/http/routes/web/helpers.ts
|
|
2218
2254
|
import * as fs5 from "fs";
|
|
@@ -2245,8 +2281,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2245
2281
|
server2.post("/_web/detect-format", async (request, reply) => {
|
|
2246
2282
|
const data = await request.file();
|
|
2247
2283
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2248
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2249
|
-
const tmpPath =
|
|
2284
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-detect-"));
|
|
2285
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2250
2286
|
try {
|
|
2251
2287
|
const chunks = [];
|
|
2252
2288
|
for await (const chunk of data.file) {
|
|
@@ -2263,8 +2299,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2263
2299
|
server2.post("/_web/scan-multi-chat", async (request, reply) => {
|
|
2264
2300
|
const data = await request.file();
|
|
2265
2301
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2266
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2267
|
-
const tmpPath =
|
|
2302
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-scan-"));
|
|
2303
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2268
2304
|
try {
|
|
2269
2305
|
const chunks = [];
|
|
2270
2306
|
for await (const chunk of data.file) {
|
|
@@ -2280,8 +2316,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2280
2316
|
server2.post("/_web/import", async (request, reply) => {
|
|
2281
2317
|
const data = await request.file();
|
|
2282
2318
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2283
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2284
|
-
const tmpPath =
|
|
2319
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-import-"));
|
|
2320
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2285
2321
|
const chunks = [];
|
|
2286
2322
|
for await (const chunk of data.file) {
|
|
2287
2323
|
chunks.push(chunk);
|
|
@@ -2329,7 +2365,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2329
2365
|
server2.post("/_web/import-directory", async (request, reply) => {
|
|
2330
2366
|
const parts = request.parts();
|
|
2331
2367
|
if (!parts) return reply.code(400).send({ error: "No files uploaded" });
|
|
2332
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2368
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-dir-import-"));
|
|
2333
2369
|
const relativePaths = [];
|
|
2334
2370
|
const fileBuffers = [];
|
|
2335
2371
|
try {
|
|
@@ -2357,9 +2393,9 @@ data: ${JSON.stringify(eventData)}
|
|
|
2357
2393
|
if (segments.length > 1) {
|
|
2358
2394
|
relPath = segments.slice(1).join("/");
|
|
2359
2395
|
}
|
|
2360
|
-
const targetPath =
|
|
2361
|
-
if (!targetPath.startsWith(tmpDir +
|
|
2362
|
-
fs6.mkdirSync(
|
|
2396
|
+
const targetPath = path7.resolve(tmpDir, relPath);
|
|
2397
|
+
if (!targetPath.startsWith(tmpDir + path7.sep)) continue;
|
|
2398
|
+
fs6.mkdirSync(path7.dirname(targetPath), { recursive: true });
|
|
2363
2399
|
fs6.writeFileSync(targetPath, fileBuffers[i].data);
|
|
2364
2400
|
}
|
|
2365
2401
|
const entryPath = findEntryFileInDirectory(tmpDir);
|
|
@@ -2405,8 +2441,8 @@ data: ${JSON.stringify({ success: false, error: err instanceof Error ? err.messa
|
|
|
2405
2441
|
const sessionId = request.params.id;
|
|
2406
2442
|
const data = await request.file();
|
|
2407
2443
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2408
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2409
|
-
const tmpPath =
|
|
2444
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-inc-"));
|
|
2445
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2410
2446
|
const chunks = [];
|
|
2411
2447
|
for await (const chunk of data.file) {
|
|
2412
2448
|
chunks.push(chunk);
|
|
@@ -2443,8 +2479,8 @@ data: ${JSON.stringify(eventData)}
|
|
|
2443
2479
|
const sessionId = request.params.id;
|
|
2444
2480
|
const data = await request.file();
|
|
2445
2481
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2446
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2447
|
-
const tmpPath =
|
|
2482
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2483
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2448
2484
|
const chunks = [];
|
|
2449
2485
|
for await (const chunk of data.file) {
|
|
2450
2486
|
chunks.push(chunk);
|
|
@@ -2461,8 +2497,8 @@ data: ${JSON.stringify(eventData)}
|
|
|
2461
2497
|
server2.post("/_web/import/analyze", async (request, reply) => {
|
|
2462
2498
|
const data = await request.file();
|
|
2463
2499
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2464
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2465
|
-
const tmpPath =
|
|
2500
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2501
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2466
2502
|
const chunks = [];
|
|
2467
2503
|
for await (const chunk of data.file) {
|
|
2468
2504
|
chunks.push(chunk);
|
|
@@ -2497,12 +2533,12 @@ data: ${JSON.stringify(eventData)}
|
|
|
2497
2533
|
|
|
2498
2534
|
`);
|
|
2499
2535
|
}
|
|
2500
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2536
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-demo-"));
|
|
2501
2537
|
try {
|
|
2502
2538
|
const localPaths = [];
|
|
2503
2539
|
for (let i = 0; i < total; i++) {
|
|
2504
2540
|
sendEvent("progress", { stage: "downloading", current: i + 1, total });
|
|
2505
|
-
const localPath =
|
|
2541
|
+
const localPath = path7.join(tmpDir, DEMO_FILES[i]);
|
|
2506
2542
|
const resp = await fetch(`${DEMO_BASE_URL}/${locale}/${DEMO_FILES[i]}`, {
|
|
2507
2543
|
signal: AbortSignal.timeout(6e4)
|
|
2508
2544
|
});
|
|
@@ -2538,7 +2574,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2538
2574
|
}
|
|
2539
2575
|
|
|
2540
2576
|
// src/http/routes/web/cache.ts
|
|
2541
|
-
import * as
|
|
2577
|
+
import * as path8 from "path";
|
|
2542
2578
|
import { execFile } from "child_process";
|
|
2543
2579
|
function runExecFile(file, args, runner = execFile) {
|
|
2544
2580
|
return new Promise((resolve4, reject) => {
|
|
@@ -2566,7 +2602,7 @@ async function showPathInFolder(filePath, platform = process.platform, runner) {
|
|
|
2566
2602
|
} else if (platform === "win32") {
|
|
2567
2603
|
await runExecFile("explorer.exe", [`/select,${filePath}`], runner);
|
|
2568
2604
|
} else {
|
|
2569
|
-
await runExecFile("xdg-open", [
|
|
2605
|
+
await runExecFile("xdg-open", [path8.dirname(filePath)], runner);
|
|
2570
2606
|
}
|
|
2571
2607
|
}
|
|
2572
2608
|
|
|
@@ -2589,42 +2625,28 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2589
2625
|
const mergeCache = options?.pathProvider ? new MergeSessionCache(options.pathProvider, { nativeBinding: options.nativeBinding }) : null;
|
|
2590
2626
|
mergeCache?.cleanupOrphans();
|
|
2591
2627
|
const fallbackPathProvider = {
|
|
2592
|
-
getSystemDir: () =>
|
|
2593
|
-
getUserDataDir: () =>
|
|
2594
|
-
getDatabaseDir: () =>
|
|
2595
|
-
getVectorDir: () =>
|
|
2596
|
-
getAiDataDir: () =>
|
|
2597
|
-
getSettingsDir: () =>
|
|
2598
|
-
getCacheDir: () =>
|
|
2599
|
-
getTempDir: () =>
|
|
2600
|
-
getLogsDir: () =>
|
|
2601
|
-
getDownloadsDir: () =>
|
|
2628
|
+
getSystemDir: () => path9.join(os3.homedir(), ".chatlab"),
|
|
2629
|
+
getUserDataDir: () => path9.join(os3.homedir(), ".chatlab", "data"),
|
|
2630
|
+
getDatabaseDir: () => path9.join(os3.homedir(), ".chatlab", "data", "databases"),
|
|
2631
|
+
getVectorDir: () => path9.join(os3.homedir(), ".chatlab", "data", "vector"),
|
|
2632
|
+
getAiDataDir: () => path9.join(os3.homedir(), ".chatlab", "ai"),
|
|
2633
|
+
getSettingsDir: () => path9.join(os3.homedir(), ".chatlab", "settings"),
|
|
2634
|
+
getCacheDir: () => path9.join(os3.homedir(), ".chatlab", "cache"),
|
|
2635
|
+
getTempDir: () => path9.join(os3.homedir(), ".chatlab", "temp"),
|
|
2636
|
+
getLogsDir: () => path9.join(os3.homedir(), ".chatlab", "logs"),
|
|
2637
|
+
getDownloadsDir: () => path9.join(os3.homedir(), "Downloads")
|
|
2602
2638
|
};
|
|
2603
2639
|
const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
|
|
2604
2640
|
const ai = options?.aiContext;
|
|
2605
2641
|
const cliStreamImport = async (dm, filePath) => {
|
|
2606
|
-
const { streamImport: streamImport2 } = await import("./stream-import-
|
|
2642
|
+
const { streamImport: streamImport2 } = await import("./stream-import-FQFNRQ2B.mjs");
|
|
2607
2643
|
const result = await streamImport2(dm, filePath);
|
|
2608
2644
|
if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
|
|
2609
2645
|
return { sessionId: result.sessionId };
|
|
2610
2646
|
};
|
|
2611
2647
|
const defaultUserDataDir = getDefaultNodeUserDataDir();
|
|
2612
|
-
const isCustom =
|
|
2613
|
-
|
|
2614
|
-
if (!semanticIndexService) {
|
|
2615
|
-
try {
|
|
2616
|
-
semanticIndexService = createSemanticIndexService({
|
|
2617
|
-
pathProvider: resolvedPathProvider,
|
|
2618
|
-
sessionAdapter: adapter,
|
|
2619
|
-
nativeBinding: options?.nativeBinding
|
|
2620
|
-
});
|
|
2621
|
-
semanticIndexService.recover();
|
|
2622
|
-
server2.addHook("onClose", async () => semanticIndexService?.close());
|
|
2623
|
-
} catch (err) {
|
|
2624
|
-
console.warn("[semantic-index] service unavailable:", err instanceof Error ? err.message : String(err));
|
|
2625
|
-
semanticIndexService = void 0;
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2648
|
+
const isCustom = path9.resolve(resolvedPathProvider.getUserDataDir()) !== path9.resolve(defaultUserDataDir);
|
|
2649
|
+
const semanticIndexService = options?.semanticIndexService;
|
|
2628
2650
|
registerSharedRoutes(
|
|
2629
2651
|
server2,
|
|
2630
2652
|
{
|
|
@@ -2717,7 +2739,7 @@ function registerProxyRoutes(server2) {
|
|
|
2717
2739
|
|
|
2718
2740
|
// src/ai/manager-factory.ts
|
|
2719
2741
|
import * as fs7 from "fs";
|
|
2720
|
-
import * as
|
|
2742
|
+
import * as path10 from "path";
|
|
2721
2743
|
import { createHash, randomUUID } from "crypto";
|
|
2722
2744
|
var nodeFs = {
|
|
2723
2745
|
ensureDir(dir) {
|
|
@@ -2740,7 +2762,7 @@ var nodeFs = {
|
|
|
2740
2762
|
return fs7.existsSync(filePath);
|
|
2741
2763
|
},
|
|
2742
2764
|
joinPath(...parts) {
|
|
2743
|
-
return
|
|
2765
|
+
return path10.join(...parts);
|
|
2744
2766
|
}
|
|
2745
2767
|
};
|
|
2746
2768
|
var managerCache = /* @__PURE__ */ new Map();
|
|
@@ -2750,13 +2772,13 @@ function getAssistantManager(aiDataDir) {
|
|
|
2750
2772
|
cached = {
|
|
2751
2773
|
assistant: new AssistantManager({
|
|
2752
2774
|
fs: nodeFs,
|
|
2753
|
-
assistantsDir:
|
|
2775
|
+
assistantsDir: path10.join(aiDataDir, "assistants"),
|
|
2754
2776
|
builtinRawConfigs: [],
|
|
2755
2777
|
generateId: () => `custom_${randomUUID().replace(/-/g, "").slice(0, 12)}`
|
|
2756
2778
|
}),
|
|
2757
2779
|
skill: new SkillManagerCore({
|
|
2758
2780
|
fs: nodeFs,
|
|
2759
|
-
skillsDir:
|
|
2781
|
+
skillsDir: path10.join(aiDataDir, "skills"),
|
|
2760
2782
|
builtinRawSkills: [],
|
|
2761
2783
|
contentHash: (content) => createHash("md5").update(content).digest("hex")
|
|
2762
2784
|
})
|
|
@@ -2781,7 +2803,7 @@ var NOOP_LOGGER = { info: noop, warn: noop, error: noop };
|
|
|
2781
2803
|
|
|
2782
2804
|
// ../../packages/sync/src/data-source-manager.ts
|
|
2783
2805
|
import * as fs8 from "fs";
|
|
2784
|
-
import * as
|
|
2806
|
+
import * as path11 from "path";
|
|
2785
2807
|
import * as crypto from "crypto";
|
|
2786
2808
|
var CONFIG_FILE = "data-sources.json";
|
|
2787
2809
|
function generateId(prefix = "ds") {
|
|
@@ -2809,7 +2831,7 @@ var DataSourceManager = class {
|
|
|
2809
2831
|
this.logger = logger ?? NOOP_LOGGER;
|
|
2810
2832
|
}
|
|
2811
2833
|
getConfigPath() {
|
|
2812
|
-
return
|
|
2834
|
+
return path11.join(this.configDir, CONFIG_FILE);
|
|
2813
2835
|
}
|
|
2814
2836
|
ensureDir() {
|
|
2815
2837
|
fs8.mkdirSync(this.configDir, { recursive: true });
|
|
@@ -3036,6 +3058,41 @@ function fileContainsMessages(filePath) {
|
|
|
3036
3058
|
return false;
|
|
3037
3059
|
}
|
|
3038
3060
|
}
|
|
3061
|
+
function getMaxMessageTimestampFromFile(filePath) {
|
|
3062
|
+
try {
|
|
3063
|
+
let maxTs = null;
|
|
3064
|
+
const visitTimestamp = (value) => {
|
|
3065
|
+
const ts = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
|
|
3066
|
+
if (typeof ts === "number" && Number.isFinite(ts)) {
|
|
3067
|
+
maxTs = maxTs === null ? ts : Math.max(maxTs, ts);
|
|
3068
|
+
}
|
|
3069
|
+
};
|
|
3070
|
+
if (filePath.endsWith(".jsonl")) {
|
|
3071
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
3072
|
+
for (const line of content.split("\n")) {
|
|
3073
|
+
const trimmed = line.trim();
|
|
3074
|
+
if (!trimmed) continue;
|
|
3075
|
+
try {
|
|
3076
|
+
const obj = JSON.parse(trimmed);
|
|
3077
|
+
if (obj._type === "message") visitTimestamp(obj.timestamp);
|
|
3078
|
+
} catch {
|
|
3079
|
+
continue;
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
return maxTs;
|
|
3083
|
+
}
|
|
3084
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
3085
|
+
const parsed = JSON.parse(raw);
|
|
3086
|
+
if (Array.isArray(parsed.messages)) {
|
|
3087
|
+
for (const message of parsed.messages) {
|
|
3088
|
+
visitTimestamp(message?.timestamp);
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
return maxTs;
|
|
3092
|
+
} catch {
|
|
3093
|
+
return null;
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3039
3096
|
function cleanupTempFile(filePath) {
|
|
3040
3097
|
try {
|
|
3041
3098
|
if (fs9.existsSync(filePath)) fs9.unlinkSync(filePath);
|
|
@@ -3089,6 +3146,8 @@ var PullEngine = class {
|
|
|
3089
3146
|
this.logger.info(`[Pull] Pulling "${sess.name}" from ${ds.baseUrl}`);
|
|
3090
3147
|
let totalNewMessages = 0;
|
|
3091
3148
|
let since = sess.lastPullAt;
|
|
3149
|
+
let offset;
|
|
3150
|
+
let nextPullSince = sess.lastPullAt;
|
|
3092
3151
|
let pageCount = 0;
|
|
3093
3152
|
let resyncAttempted = false;
|
|
3094
3153
|
this.progressMap.set(sess.id, { sessionId: sess.id, sessionName: sess.name, current: 0, pages: 0, done: false });
|
|
@@ -3097,6 +3156,7 @@ var PullEngine = class {
|
|
|
3097
3156
|
pageCount++;
|
|
3098
3157
|
const tempFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
3099
3158
|
since,
|
|
3159
|
+
offset,
|
|
3100
3160
|
limit: ds.pullLimit
|
|
3101
3161
|
});
|
|
3102
3162
|
try {
|
|
@@ -3106,6 +3166,7 @@ var PullEngine = class {
|
|
|
3106
3166
|
if (stat2.size < 1024) {
|
|
3107
3167
|
if (!fileContainsMessages(tempFile) && sync0?.hasMore === false) {
|
|
3108
3168
|
cleanupTempFile(tempFile);
|
|
3169
|
+
if (sync0?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, sync0.nextSince);
|
|
3109
3170
|
const retryDelays = [2e3, 3e3, 5e3];
|
|
3110
3171
|
let retrySuccess = false;
|
|
3111
3172
|
let retryHasMore = false;
|
|
@@ -3116,21 +3177,26 @@ var PullEngine = class {
|
|
|
3116
3177
|
await new Promise((r) => setTimeout(r, retryDelays[ri]));
|
|
3117
3178
|
const retryFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
3118
3179
|
since,
|
|
3180
|
+
offset,
|
|
3119
3181
|
limit: ds.pullLimit
|
|
3120
3182
|
});
|
|
3121
3183
|
const retryStat = fs9.statSync(retryFile);
|
|
3122
3184
|
this.logger.info(`[Pull] "${sess.name}" retry ${ri + 1}: fetched ${retryStat.size} bytes`);
|
|
3123
3185
|
const retrySync = parseSyncFromFile(retryFile);
|
|
3124
3186
|
if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {
|
|
3187
|
+
if (retrySync.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, retrySync.nextSince);
|
|
3125
3188
|
cleanupTempFile(retryFile);
|
|
3126
3189
|
continue;
|
|
3127
3190
|
}
|
|
3191
|
+
const retryMaxTs = getMaxMessageTimestampFromFile(retryFile);
|
|
3128
3192
|
const retryResult = await this.importTempFile(ds.baseUrl, sess, retryFile);
|
|
3129
3193
|
cleanupTempFile(retryFile);
|
|
3130
3194
|
if (retryResult.needFullResync && !resyncAttempted) {
|
|
3131
3195
|
resyncAttempted = true;
|
|
3132
3196
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
3133
3197
|
since = 0;
|
|
3198
|
+
offset = void 0;
|
|
3199
|
+
nextPullSince = 0;
|
|
3134
3200
|
pageCount = 0;
|
|
3135
3201
|
sess.targetSessionId = "";
|
|
3136
3202
|
sess.lastPullAt = 0;
|
|
@@ -3167,6 +3233,8 @@ var PullEngine = class {
|
|
|
3167
3233
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: retryResult.sessionId });
|
|
3168
3234
|
}
|
|
3169
3235
|
totalNewMessages += retryResult.newMessageCount;
|
|
3236
|
+
if (retryMaxTs !== null) nextPullSince = Math.max(nextPullSince, retryMaxTs);
|
|
3237
|
+
if (retrySync?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, retrySync.nextSince);
|
|
3170
3238
|
this.progressMap.set(sess.id, {
|
|
3171
3239
|
sessionId: sess.id,
|
|
3172
3240
|
sessionName: sess.name,
|
|
@@ -3176,6 +3244,9 @@ var PullEngine = class {
|
|
|
3176
3244
|
});
|
|
3177
3245
|
if (retrySync?.hasMore && retrySync.nextSince !== void 0) {
|
|
3178
3246
|
since = retrySync.nextSince;
|
|
3247
|
+
offset = void 0;
|
|
3248
|
+
} else if (retrySync?.hasMore && retrySync.nextOffset !== void 0) {
|
|
3249
|
+
offset = retrySync.nextOffset;
|
|
3179
3250
|
}
|
|
3180
3251
|
retryHasMore = !!retrySync?.hasMore;
|
|
3181
3252
|
retrySuccess = true;
|
|
@@ -3191,12 +3262,15 @@ var PullEngine = class {
|
|
|
3191
3262
|
break;
|
|
3192
3263
|
}
|
|
3193
3264
|
const sync = sync0;
|
|
3265
|
+
const maxMessageTs = getMaxMessageTimestampFromFile(tempFile);
|
|
3194
3266
|
const result = await this.importTempFile(ds.baseUrl, sess, tempFile);
|
|
3195
3267
|
cleanupTempFile(tempFile);
|
|
3196
3268
|
if (result.needFullResync && !resyncAttempted) {
|
|
3197
3269
|
resyncAttempted = true;
|
|
3198
3270
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
3199
3271
|
since = 0;
|
|
3272
|
+
offset = void 0;
|
|
3273
|
+
nextPullSince = 0;
|
|
3200
3274
|
pageCount = 0;
|
|
3201
3275
|
sess.targetSessionId = "";
|
|
3202
3276
|
sess.lastPullAt = 0;
|
|
@@ -3231,6 +3305,7 @@ var PullEngine = class {
|
|
|
3231
3305
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: result.sessionId });
|
|
3232
3306
|
}
|
|
3233
3307
|
totalNewMessages += result.newMessageCount;
|
|
3308
|
+
if (maxMessageTs !== null) nextPullSince = Math.max(nextPullSince, maxMessageTs);
|
|
3234
3309
|
this.progressMap.set(sess.id, {
|
|
3235
3310
|
sessionId: sess.id,
|
|
3236
3311
|
sessionName: sess.name,
|
|
@@ -3238,8 +3313,17 @@ var PullEngine = class {
|
|
|
3238
3313
|
pages: pageCount,
|
|
3239
3314
|
done: false
|
|
3240
3315
|
});
|
|
3316
|
+
if (sync?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, sync.nextSince);
|
|
3241
3317
|
if (!sync || !sync.hasMore) break;
|
|
3242
|
-
if (sync.nextSince !== void 0)
|
|
3318
|
+
if (sync.nextSince !== void 0) {
|
|
3319
|
+
since = sync.nextSince;
|
|
3320
|
+
offset = void 0;
|
|
3321
|
+
} else if (sync.nextOffset !== void 0) {
|
|
3322
|
+
offset = sync.nextOffset;
|
|
3323
|
+
} else {
|
|
3324
|
+
this.logger.warn(`[Pull] "${sess.name}" returned hasMore=true without nextSince or nextOffset, stopping`);
|
|
3325
|
+
break;
|
|
3326
|
+
}
|
|
3243
3327
|
} catch (importErr) {
|
|
3244
3328
|
cleanupTempFile(tempFile);
|
|
3245
3329
|
throw importErr;
|
|
@@ -3248,8 +3332,9 @@ var PullEngine = class {
|
|
|
3248
3332
|
if (pageCount >= MAX_PAGES_PER_PULL) {
|
|
3249
3333
|
this.logger.warn(`[Pull] "${sess.name}" reached page limit (${MAX_PAGES_PER_PULL}), data may be incomplete`);
|
|
3250
3334
|
}
|
|
3335
|
+
const savedLastPullAt = Math.max(sess.lastPullAt, Math.max(0, nextPullSince - PULL_OVERLAP_SECONDS));
|
|
3251
3336
|
this.dsManager.updateSession(sourceId, sess.id, {
|
|
3252
|
-
lastPullAt:
|
|
3337
|
+
lastPullAt: savedLastPullAt,
|
|
3253
3338
|
lastStatus: "success",
|
|
3254
3339
|
lastNewMessages: totalNewMessages,
|
|
3255
3340
|
lastError: ""
|
|
@@ -3401,11 +3486,11 @@ function reloadTimer(dsId, skipInitialPull = false) {
|
|
|
3401
3486
|
// src/sync/adapters.ts
|
|
3402
3487
|
import * as fs10 from "fs";
|
|
3403
3488
|
import * as os4 from "os";
|
|
3404
|
-
import * as
|
|
3489
|
+
import * as path12 from "path";
|
|
3405
3490
|
import * as crypto3 from "crypto";
|
|
3406
3491
|
function getTempFilePath(ext) {
|
|
3407
3492
|
const id = crypto3.randomBytes(8).toString("hex");
|
|
3408
|
-
return
|
|
3493
|
+
return path12.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
|
|
3409
3494
|
}
|
|
3410
3495
|
var NodeFetcher = class {
|
|
3411
3496
|
async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
|
|
@@ -3745,15 +3830,15 @@ async function startHttpServer(options) {
|
|
|
3745
3830
|
});
|
|
3746
3831
|
let semanticIndexService;
|
|
3747
3832
|
try {
|
|
3748
|
-
semanticIndexService =
|
|
3833
|
+
semanticIndexService = createSemanticIndexWorkerRuntimeClient({
|
|
3749
3834
|
pathProvider,
|
|
3750
|
-
|
|
3751
|
-
nativeBinding
|
|
3835
|
+
runtime,
|
|
3836
|
+
nativeBinding,
|
|
3837
|
+
workerEntryUrl: import.meta.url.endsWith(".ts") ? void 0 : new URL("./semantic-index-worker.mjs", import.meta.url)
|
|
3752
3838
|
});
|
|
3753
|
-
semanticIndexService.recover();
|
|
3754
3839
|
server.addHook("onClose", async () => semanticIndexService?.close());
|
|
3755
3840
|
} catch (err) {
|
|
3756
|
-
console.warn("[semantic-index]
|
|
3841
|
+
console.warn("[semantic-index] worker client unavailable:", err instanceof Error ? err.message : String(err));
|
|
3757
3842
|
semanticIndexService = void 0;
|
|
3758
3843
|
}
|
|
3759
3844
|
registerWebRoutes(server, dbManager, {
|
|
@@ -3813,4 +3898,4 @@ export {
|
|
|
3813
3898
|
startHttpServer,
|
|
3814
3899
|
stopHttpServer
|
|
3815
3900
|
};
|
|
3816
|
-
//# sourceMappingURL=chunk-
|
|
3901
|
+
//# sourceMappingURL=chunk-SIVERPF5.mjs.map
|