chatlab-cli 0.26.3 → 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/README.md +10 -4
- package/dist/{chat-command-D37MMEJ7.mjs → chat-command-B7POB3C3.mjs} +6 -5
- package/dist/{chat-command-D37MMEJ7.mjs.map → chat-command-B7POB3C3.mjs.map} +1 -1
- package/dist/{chunk-K5SGXTVJ.mjs → chunk-3FUF3PEY.mjs} +21 -19
- package/dist/{chunk-K5SGXTVJ.mjs.map → chunk-3FUF3PEY.mjs.map} +1 -1
- package/dist/{chunk-742TAKEP.mjs → chunk-3JNVGW62.mjs} +2 -2
- package/dist/{chunk-VSOWNKPA.mjs → chunk-GFHSSCCR.mjs} +11 -1
- package/dist/{chunk-YPTJVTVJ.mjs → chunk-I7BHOZPX.mjs} +13159 -19038
- 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-GNGZHBKM.mjs → chunk-RJ4D4QWK.mjs} +42 -7
- package/dist/chunk-RJ4D4QWK.mjs.map +1 -0
- package/dist/{chunk-VCN64OD6.mjs → chunk-SAE2H2LN.mjs} +7 -5
- package/dist/{chunk-VCN64OD6.mjs.map → chunk-SAE2H2LN.mjs.map} +1 -1
- package/dist/{chunk-QMXNJRTT.mjs → chunk-SIVERPF5.mjs} +280 -104
- package/dist/chunk-SIVERPF5.mjs.map +1 -0
- package/dist/{chunk-RMITK4IC.mjs → chunk-WQMKKUSD.mjs} +468 -118
- package/dist/chunk-WQMKKUSD.mjs.map +1 -0
- package/dist/{chunk-D5MWER7N.mjs → chunk-YUFYTDRH.mjs} +6 -4
- package/dist/{chunk-D5MWER7N.mjs.map → chunk-YUFYTDRH.mjs.map} +1 -1
- package/dist/cli.mjs +5 -4
- package/dist/{http-6F6TYWCI.mjs → http-A54ZBBAY.mjs} +10 -9
- package/dist/{import-VYPOMSSA.mjs → import-EA3TB3S2.mjs} +6 -5
- package/dist/index.mjs +10 -9
- package/dist/{mcp-AR7L5FA3.mjs → mcp-DJDOWHH3.mjs} +11 -9
- package/dist/{mcp-AR7L5FA3.mjs.map → mcp-DJDOWHH3.mjs.map} +1 -1
- package/dist/onnxruntime_binding-6Q6HXASN.node +0 -0
- package/dist/onnxruntime_binding-EKZT2NRK.node +0 -0
- package/dist/onnxruntime_binding-P6S7V3CI.node +0 -0
- package/dist/onnxruntime_binding-PJNNIIUO.node +0 -0
- package/dist/onnxruntime_binding-UN6SPTQK.node +0 -0
- package/dist/semantic-index-worker.mjs +34 -0
- package/dist/semantic-index-worker.mjs.map +1 -0
- package/dist/{service-KZTHBDQ5.mjs → service-KGL3RAIA.mjs} +2 -2
- package/dist/{src-6S7JPKHX.mjs → src-EKPMJRG6.mjs} +65 -109
- package/dist/{stream-import-KZFC3XT2.mjs → stream-import-FQFNRQ2B.mjs} +5 -4
- package/dist/transformers.node-PUMHAODN.mjs +42889 -0
- package/dist/transformers.node-PUMHAODN.mjs.map +1 -0
- package/dist/{update-checker-3N7HQEP2.mjs → update-checker-LGMTEKMT.mjs} +2 -2
- 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-CF6yaor7.js → MessageExportModal-B60rvfCh.js} +1 -1
- package/dist-web/assets/{electron-DKVw61Ww.js → electron-BRUg9LnY.js} +1 -1
- package/dist-web/assets/{fetch-CUw-PUYP.js → fetch-BIpjJHxj.js} +1 -1
- package/dist-web/assets/{fetch-BMdgfBVS.js → fetch-BRsMdFcn.js} +1 -1
- package/dist-web/assets/{fetch-CPeSfqsU.js → fetch-C-m3IysH.js} +1 -1
- package/dist-web/assets/{fetch-CpYSD089.js → fetch-Cma-mZjd.js} +1 -1
- package/dist-web/assets/{fetch-D2jNBqs8.js → fetch-DE8gj5Ke.js} +1 -1
- package/dist-web/assets/{fetch-DqEMAea3.js → fetch-DLAp7h55.js} +1 -1
- package/dist-web/assets/{fetch-BvVfWR-P.js → fetch-DNSaxRnL.js} +1 -1
- package/dist-web/assets/{fetch-BC8jyJ_U.js → fetch-DOEbyLSD.js} +1 -1
- package/dist-web/assets/{fetch-BQlEQsqi.js → fetch-DSN-QYZE.js} +1 -1
- package/dist-web/assets/{fetch-Bh6HC-IR.js → fetch-woAa3H2L.js} +1 -1
- package/dist-web/assets/index-B3mDjury.js +11 -0
- package/dist-web/assets/{index-Qh0XLt3R.js → index-B9I-Y3fR.js} +1 -1
- package/dist-web/assets/{index-DqybGdJH.css → index-BX3tqfLz.css} +1 -1
- package/dist-web/assets/index-GAU7LI1r.js +173 -0
- package/dist-web/assets/index-I3SWZjnW.css +1 -0
- package/dist-web/assets/index-YmzTgkb2.css +1 -0
- package/dist-web/assets/index-iwqJDVMJ.js +2 -0
- package/dist-web/assets/index-o6veAyTB.js +64 -0
- package/dist-web/assets/{index-BHQnAj6l.js → index-r_zHR2t9.js} +1 -1
- package/dist-web/assets/{web-Bx2TiHDk.js → web-C2UtGskd.js} +1 -1
- package/dist-web/index.html +2 -2
- package/package.json +1 -1
- package/dist/chunk-GNGZHBKM.mjs.map +0 -1
- package/dist/chunk-QMXNJRTT.mjs.map +0 -1
- package/dist/chunk-RMITK4IC.mjs.map +0 -1
- package/dist/chunk-YPTJVTVJ.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BTdqmm0y.js +0 -107
- package/dist-web/assets/index-BwzuCu5R.js +0 -2
- package/dist-web/assets/index-CG746E15.js +0 -64
- package/dist-web/assets/index-CXoQ_U22.js +0 -173
- package/dist-web/assets/index-HgIuP1Td.css +0 -1
- package/dist-web/assets/index-R82N2_0b.css +0 -1
- package/dist-web/assets/index-wPAmuQZY.js +0 -11
- /package/dist/{chunk-742TAKEP.mjs.map → chunk-3JNVGW62.mjs.map} +0 -0
- /package/dist/{chunk-VSOWNKPA.mjs.map → chunk-GFHSSCCR.mjs.map} +0 -0
- /package/dist/{http-6F6TYWCI.mjs.map → http-A54ZBBAY.mjs.map} +0 -0
- /package/dist/{import-VYPOMSSA.mjs.map → import-EA3TB3S2.mjs.map} +0 -0
- /package/dist/{service-KZTHBDQ5.mjs.map → service-KGL3RAIA.mjs.map} +0 -0
- /package/dist/{src-6S7JPKHX.mjs.map → src-EKPMJRG6.mjs.map} +0 -0
- /package/dist/{stream-import-KZFC3XT2.mjs.map → stream-import-FQFNRQ2B.mjs.map} +0 -0
- /package/dist/{update-checker-3N7HQEP2.mjs.map → update-checker-LGMTEKMT.mjs.map} +0 -0
|
@@ -5,18 +5,17 @@ const require = __createRequire(import.meta.url);
|
|
|
5
5
|
const __filename = __fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = __pathDirname(__filename);
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
closeServerAiLogger,
|
|
9
|
+
createCliRunAgentStream,
|
|
10
|
+
initServerAiLogger
|
|
11
|
+
} from "./chunk-RJ4D4QWK.mjs";
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
streamImport
|
|
16
|
-
} from "./chunk-VCN64OD6.mjs";
|
|
13
|
+
AGENT_TOOL_REGISTRY,
|
|
14
|
+
CoreDataProvider
|
|
15
|
+
} from "./chunk-WQMKKUSD.mjs";
|
|
17
16
|
import {
|
|
18
17
|
assertCliDataDirCompatible
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-3JNVGW62.mjs";
|
|
20
19
|
import {
|
|
21
20
|
getVersion
|
|
22
21
|
} from "./chunk-5ADKYYNA.mjs";
|
|
@@ -24,14 +23,37 @@ import {
|
|
|
24
23
|
resolveCliPath
|
|
25
24
|
} from "./chunk-FJ35V3TE.mjs";
|
|
26
25
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} from "./chunk-GNGZHBKM.mjs";
|
|
26
|
+
importData,
|
|
27
|
+
parseFile
|
|
28
|
+
} from "./chunk-YUFYTDRH.mjs";
|
|
31
29
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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,23 +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
80
|
deleteDict,
|
|
64
|
-
detectAllFormats,
|
|
65
|
-
detectFormat,
|
|
66
81
|
downloadDict,
|
|
67
82
|
ensureDefaultDict,
|
|
68
83
|
executeReadonlySql,
|
|
@@ -70,15 +85,12 @@ import {
|
|
|
70
85
|
exportSessionToJson,
|
|
71
86
|
export_service_exports,
|
|
72
87
|
fetchRemoteModels,
|
|
73
|
-
findEntryFileInDirectory,
|
|
74
88
|
getAvailableYears,
|
|
75
89
|
getBuiltinModelsByProvider,
|
|
76
90
|
getCatchphraseAnalysis,
|
|
77
91
|
getCheckInAnalysis,
|
|
78
92
|
getClusterGraph,
|
|
79
93
|
getDailyActivity,
|
|
80
|
-
getDbFileVersion,
|
|
81
|
-
getDefaultNodeUserDataDir,
|
|
82
94
|
getDefaultRulesForLocale,
|
|
83
95
|
getDictList,
|
|
84
96
|
getDivingAnalysis,
|
|
@@ -98,44 +110,40 @@ import {
|
|
|
98
110
|
getMessageTypeStats,
|
|
99
111
|
getMonthlyActivity,
|
|
100
112
|
getNightOwlAnalysis,
|
|
101
|
-
getOrComputeAnalysisCache,
|
|
102
|
-
getPendingNodeDataDirMigration,
|
|
103
113
|
getRelationshipStats,
|
|
104
114
|
getRepeatAnalysis,
|
|
105
115
|
getSchemaDetailed,
|
|
106
116
|
getSessionInfo,
|
|
107
117
|
getSessionMeta,
|
|
108
118
|
getSessionOverview,
|
|
109
|
-
getSupportedFormats,
|
|
110
119
|
getTextLengthPercentiles,
|
|
111
120
|
getTextStats,
|
|
112
121
|
getTimeRange,
|
|
113
122
|
getWeekdayActivity,
|
|
114
123
|
getYearlyActivity,
|
|
115
|
-
hasPendingElectronDataWarning,
|
|
116
124
|
initNlpDir,
|
|
117
125
|
isDictDownloaded,
|
|
118
126
|
isNewerStableVersion,
|
|
127
|
+
isSemanticIndexConfigured,
|
|
119
128
|
loadConfig,
|
|
120
129
|
member_service_exports,
|
|
121
130
|
mergeRulesForLocale,
|
|
122
131
|
owner_profile_service_exports,
|
|
132
|
+
persistSemanticIndexConfig,
|
|
123
133
|
queryMessages,
|
|
124
134
|
resolveApiKey,
|
|
135
|
+
resolveSemanticIndexApiKeySet,
|
|
125
136
|
runSimpleLlmStream,
|
|
126
|
-
scanMultiChatFile,
|
|
127
137
|
segmentText,
|
|
128
|
-
serializeChatLabToJsonl,
|
|
129
138
|
session_index_service_exports,
|
|
130
139
|
session_service_exports,
|
|
131
|
-
streamParseFileInfo,
|
|
132
140
|
stripAvatarFields,
|
|
133
141
|
summary_service_exports,
|
|
134
142
|
validateApiKey,
|
|
135
143
|
verifyCliDataPath,
|
|
136
144
|
writeAuthProfile,
|
|
137
145
|
writeConfigField
|
|
138
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-I7BHOZPX.mjs";
|
|
139
147
|
|
|
140
148
|
// src/http/index.ts
|
|
141
149
|
import * as fs11 from "fs";
|
|
@@ -1401,17 +1409,21 @@ function registerAiToolRoutes(server2, ctx) {
|
|
|
1401
1409
|
if (!entry) {
|
|
1402
1410
|
return reply.code(404).send({ success: false, error: `Tool not found: ${toolName}` });
|
|
1403
1411
|
}
|
|
1404
|
-
const db = ctx.dbManager.open(sessionId);
|
|
1405
|
-
if (!db) {
|
|
1406
|
-
return reply.code(404).send({ success: false, error: `Session not found: ${sessionId}` });
|
|
1407
|
-
}
|
|
1408
1412
|
const abortController = new AbortController();
|
|
1409
1413
|
activeToolTests.set(testId, abortController);
|
|
1410
1414
|
try {
|
|
1415
|
+
if (ctx.executeAiTool) {
|
|
1416
|
+
return await ctx.executeAiTool({ testId, toolName, params, sessionId, abortSignal: abortController.signal });
|
|
1417
|
+
}
|
|
1418
|
+
const db = ctx.dbManager.open(sessionId);
|
|
1419
|
+
if (!db) {
|
|
1420
|
+
return reply.code(404).send({ success: false, error: `Session not found: ${sessionId}` });
|
|
1421
|
+
}
|
|
1411
1422
|
const execCtx = {
|
|
1412
1423
|
sessionId,
|
|
1413
1424
|
db,
|
|
1414
|
-
dataProvider: new CoreDataProvider(db)
|
|
1425
|
+
dataProvider: new CoreDataProvider(db),
|
|
1426
|
+
abortSignal: abortController.signal
|
|
1415
1427
|
};
|
|
1416
1428
|
const startTime = Date.now();
|
|
1417
1429
|
const result = await entry.handler(params, execCtx);
|
|
@@ -1612,10 +1624,93 @@ function registerAiSummaryRoutes(server2, ctx) {
|
|
|
1612
1624
|
});
|
|
1613
1625
|
}
|
|
1614
1626
|
|
|
1627
|
+
// ../../packages/http-routes/src/routes/web/ai-semantic-index.ts
|
|
1628
|
+
import path4 from "path";
|
|
1629
|
+
function registerSemanticIndexRoutes(server2, ctx) {
|
|
1630
|
+
const service = ctx.semanticIndexService;
|
|
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
|
+
}
|
|
1656
|
+
server2.get("/_web/ai/semantic-index/config", async () => {
|
|
1657
|
+
return {
|
|
1658
|
+
config: await service.getConfig(),
|
|
1659
|
+
apiKeySet: await service.hasApiKey(),
|
|
1660
|
+
configured: await service.isConfigured()
|
|
1661
|
+
};
|
|
1662
|
+
});
|
|
1663
|
+
server2.put(
|
|
1664
|
+
"/_web/ai/semantic-index/config",
|
|
1665
|
+
async (request) => {
|
|
1666
|
+
const config = await service.setConfig(request.body.config, { apiKey: request.body.apiKey });
|
|
1667
|
+
return { config, apiKeySet: await service.hasApiKey(), configured: await service.isConfigured() };
|
|
1668
|
+
}
|
|
1669
|
+
);
|
|
1670
|
+
server2.get("/_web/ai/semantic-index/enabled", async () => {
|
|
1671
|
+
return { sessions: await service.listEnabledStatuses() };
|
|
1672
|
+
});
|
|
1673
|
+
server2.get("/_web/ai/semantic-index/status", async (request) => {
|
|
1674
|
+
return { status: await service.status(request.query.sessionId) };
|
|
1675
|
+
});
|
|
1676
|
+
server2.post("/_web/ai/semantic-index/status", async (request) => {
|
|
1677
|
+
return { sessions: await service.statusForSessions(request.body.sessionIds ?? []) };
|
|
1678
|
+
});
|
|
1679
|
+
const sessionAction = (path13, action) => {
|
|
1680
|
+
server2.post(path13, async (request, reply) => {
|
|
1681
|
+
const { sessionId } = request.body;
|
|
1682
|
+
if (!sessionId) return reply.code(400).send({ error: "sessionId is required" });
|
|
1683
|
+
await action(sessionId);
|
|
1684
|
+
return { status: await service.status(sessionId) };
|
|
1685
|
+
});
|
|
1686
|
+
};
|
|
1687
|
+
sessionAction("/_web/ai/semantic-index/enable", (id) => service.enable(id));
|
|
1688
|
+
sessionAction("/_web/ai/semantic-index/disable", (id) => service.disable(id));
|
|
1689
|
+
sessionAction("/_web/ai/semantic-index/build", (id) => service.build(id));
|
|
1690
|
+
sessionAction("/_web/ai/semantic-index/pause", (id) => service.pause(id));
|
|
1691
|
+
sessionAction("/_web/ai/semantic-index/cancel", (id) => service.cancel(id));
|
|
1692
|
+
sessionAction("/_web/ai/semantic-index/rebuild", (id) => service.rebuild(id));
|
|
1693
|
+
server2.post("/_web/ai/semantic-index/build-pending", async () => {
|
|
1694
|
+
await service.buildAllPending();
|
|
1695
|
+
return { sessions: await service.listEnabledStatuses() };
|
|
1696
|
+
});
|
|
1697
|
+
server2.post("/_web/ai/semantic-index/cleanup", async () => {
|
|
1698
|
+
return await service.cleanupUnused();
|
|
1699
|
+
});
|
|
1700
|
+
server2.post(
|
|
1701
|
+
"/_web/ai/semantic-index/search",
|
|
1702
|
+
async (request, reply) => {
|
|
1703
|
+
const { sessionId, query, finalTopK } = request.body;
|
|
1704
|
+
if (!sessionId || !query) return reply.code(400).send({ error: "sessionId and query are required" });
|
|
1705
|
+
return service.search(sessionId, query, { finalTopK });
|
|
1706
|
+
}
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1615
1710
|
// ../../packages/http-routes/src/routes/web/merge.ts
|
|
1616
1711
|
import * as fs3 from "fs";
|
|
1617
1712
|
import * as os from "os";
|
|
1618
|
-
import * as
|
|
1713
|
+
import * as path5 from "path";
|
|
1619
1714
|
function ensureDb2(ctx, sessionId) {
|
|
1620
1715
|
const db = ctx.dbManager.open(sessionId);
|
|
1621
1716
|
if (!db) throw sessionNotFound(sessionId);
|
|
@@ -1632,8 +1727,8 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1632
1727
|
if (contentType.includes("multipart/form-data")) {
|
|
1633
1728
|
const data = await request.file();
|
|
1634
1729
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
1635
|
-
const tmpDir = fs3.mkdtempSync(
|
|
1636
|
-
const tmpPath =
|
|
1730
|
+
const tmpDir = fs3.mkdtempSync(path5.join(os.tmpdir(), "chatlab-merge-"));
|
|
1731
|
+
const tmpPath = path5.join(tmpDir, data.filename || "upload");
|
|
1637
1732
|
const chunks = [];
|
|
1638
1733
|
for await (const chunk of data.file) {
|
|
1639
1734
|
chunks.push(chunk);
|
|
@@ -1651,12 +1746,12 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1651
1746
|
try {
|
|
1652
1747
|
const result = await streamParseFileInfo(filePath, {
|
|
1653
1748
|
createTempDatabase(sourceFilePath) {
|
|
1654
|
-
return mergeCache.createTempDatabase(
|
|
1749
|
+
return mergeCache.createTempDatabase(path5.basename(sourceFilePath));
|
|
1655
1750
|
},
|
|
1656
1751
|
onProgress() {
|
|
1657
1752
|
}
|
|
1658
1753
|
});
|
|
1659
|
-
const filename =
|
|
1754
|
+
const filename = path5.basename(filePath);
|
|
1660
1755
|
const handle = mergeCache.store(filename, result.tempDbPath);
|
|
1661
1756
|
return {
|
|
1662
1757
|
handle,
|
|
@@ -1725,9 +1820,9 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1725
1820
|
return reply.code(501).send({ error: "Import not available on this server" });
|
|
1726
1821
|
}
|
|
1727
1822
|
const jsonData = JSON.stringify(merged.chatLabData);
|
|
1728
|
-
const tmpDir = fs3.mkdtempSync(
|
|
1729
|
-
const safeName =
|
|
1730
|
-
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`);
|
|
1731
1826
|
fs3.writeFileSync(tmpPath, jsonData, "utf-8");
|
|
1732
1827
|
try {
|
|
1733
1828
|
const importResult = await streamImport2(dbManager2, tmpPath);
|
|
@@ -1814,14 +1909,14 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1814
1909
|
// ../../packages/http-routes/src/routes/web/cache.ts
|
|
1815
1910
|
import * as fs4 from "fs";
|
|
1816
1911
|
import * as fsp from "fs/promises";
|
|
1817
|
-
import * as
|
|
1912
|
+
import * as path6 from "path";
|
|
1818
1913
|
async function getDirSize(dirPath) {
|
|
1819
1914
|
let totalSize = 0;
|
|
1820
1915
|
try {
|
|
1821
1916
|
if (!fs4.existsSync(dirPath)) return 0;
|
|
1822
1917
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1823
1918
|
for (const file of files) {
|
|
1824
|
-
const filePath =
|
|
1919
|
+
const filePath = path6.join(dirPath, file.name);
|
|
1825
1920
|
if (file.isDirectory()) {
|
|
1826
1921
|
totalSize += await getDirSize(filePath);
|
|
1827
1922
|
} else {
|
|
@@ -1839,7 +1934,7 @@ async function getFileCount(dirPath) {
|
|
|
1839
1934
|
if (!fs4.existsSync(dirPath)) return 0;
|
|
1840
1935
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1841
1936
|
for (const file of files) {
|
|
1842
|
-
const filePath =
|
|
1937
|
+
const filePath = path6.join(dirPath, file.name);
|
|
1843
1938
|
if (file.isDirectory()) {
|
|
1844
1939
|
count += await getFileCount(filePath);
|
|
1845
1940
|
} else {
|
|
@@ -1852,8 +1947,8 @@ async function getFileCount(dirPath) {
|
|
|
1852
1947
|
}
|
|
1853
1948
|
function hasChatLabDatabases(dirPath) {
|
|
1854
1949
|
try {
|
|
1855
|
-
const markerPath =
|
|
1856
|
-
const dbDir =
|
|
1950
|
+
const markerPath = path6.join(dirPath, ".chatlab");
|
|
1951
|
+
const dbDir = path6.join(dirPath, "databases");
|
|
1857
1952
|
if (!fs4.existsSync(markerPath) || !fs4.existsSync(dbDir)) return false;
|
|
1858
1953
|
return fs4.readdirSync(dbDir).some((file) => file.endsWith(".db"));
|
|
1859
1954
|
} catch {
|
|
@@ -1921,7 +2016,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1921
2016
|
if (!fs4.existsSync(dirPath)) return { success: true };
|
|
1922
2017
|
const files = await fsp.readdir(dirPath);
|
|
1923
2018
|
for (const file of files) {
|
|
1924
|
-
const filePath =
|
|
2019
|
+
const filePath = path6.join(dirPath, file);
|
|
1925
2020
|
const stat2 = await fsp.stat(filePath);
|
|
1926
2021
|
if (stat2.isDirectory()) {
|
|
1927
2022
|
await fsp.rm(filePath, { recursive: true });
|
|
@@ -1938,7 +2033,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1938
2033
|
defaultPath: ctx.defaultUserDataDir,
|
|
1939
2034
|
isCustom: ctx.isCustomDataDir ?? false,
|
|
1940
2035
|
canSetDataDir: ctx.canSetDataDir ?? Boolean(ctx.setDataDir),
|
|
1941
|
-
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) &&
|
|
2036
|
+
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) && path6.resolve(pp.getUserDataDir()) !== path6.resolve(ctx.defaultUserDataDir ?? "") && hasChatLabDatabases(ctx.defaultUserDataDir ?? ""),
|
|
1942
2037
|
pendingMigration: pending ? {
|
|
1943
2038
|
from: pending.from,
|
|
1944
2039
|
to: pending.to,
|
|
@@ -1955,7 +2050,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1955
2050
|
return ctx.setDataDir(targetPath, migrate);
|
|
1956
2051
|
});
|
|
1957
2052
|
server2.get("/_web/cache/latest-import-log", async () => {
|
|
1958
|
-
const importLogDir =
|
|
2053
|
+
const importLogDir = path6.join(pp.getLogsDir(), "import");
|
|
1959
2054
|
if (!fs4.existsSync(importLogDir)) {
|
|
1960
2055
|
return { success: false, error: "Log directory not found" };
|
|
1961
2056
|
}
|
|
@@ -1966,7 +2061,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1966
2061
|
}
|
|
1967
2062
|
const fileStats = await Promise.all(
|
|
1968
2063
|
logFiles.map(async (f) => {
|
|
1969
|
-
const filePath =
|
|
2064
|
+
const filePath = path6.join(importLogDir, f);
|
|
1970
2065
|
const stat2 = await fsp.stat(filePath);
|
|
1971
2066
|
return { name: f, path: filePath, mtime: stat2.mtime.getTime() };
|
|
1972
2067
|
})
|
|
@@ -1993,7 +2088,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1993
2088
|
if (!fs4.existsSync(downloadsDir)) {
|
|
1994
2089
|
fs4.mkdirSync(downloadsDir, { recursive: true });
|
|
1995
2090
|
}
|
|
1996
|
-
const filePath =
|
|
2091
|
+
const filePath = path6.join(downloadsDir, filename);
|
|
1997
2092
|
fs4.writeFileSync(filePath, buffer);
|
|
1998
2093
|
return { success: true, filePath };
|
|
1999
2094
|
});
|
|
@@ -2068,6 +2163,7 @@ function registerSharedRoutes(server2, ctx, options) {
|
|
|
2068
2163
|
registerAiToolRoutes(server2, resolvedCtx);
|
|
2069
2164
|
registerAiChatRoutes(server2, resolvedCtx);
|
|
2070
2165
|
registerAiSummaryRoutes(server2, resolvedCtx);
|
|
2166
|
+
registerSemanticIndexRoutes(server2, resolvedCtx);
|
|
2071
2167
|
registerMergeRoutes(server2, resolvedCtx);
|
|
2072
2168
|
registerCacheRoutes(server2, resolvedCtx);
|
|
2073
2169
|
}
|
|
@@ -2147,12 +2243,12 @@ function createServer() {
|
|
|
2147
2243
|
|
|
2148
2244
|
// src/http/routes/web/index.ts
|
|
2149
2245
|
import * as os3 from "os";
|
|
2150
|
-
import * as
|
|
2246
|
+
import * as path9 from "path";
|
|
2151
2247
|
|
|
2152
2248
|
// src/http/routes/web/import.ts
|
|
2153
2249
|
import * as fs6 from "fs";
|
|
2154
2250
|
import * as os2 from "os";
|
|
2155
|
-
import * as
|
|
2251
|
+
import * as path7 from "path";
|
|
2156
2252
|
|
|
2157
2253
|
// src/http/routes/web/helpers.ts
|
|
2158
2254
|
import * as fs5 from "fs";
|
|
@@ -2185,8 +2281,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2185
2281
|
server2.post("/_web/detect-format", async (request, reply) => {
|
|
2186
2282
|
const data = await request.file();
|
|
2187
2283
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2188
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2189
|
-
const tmpPath =
|
|
2284
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-detect-"));
|
|
2285
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2190
2286
|
try {
|
|
2191
2287
|
const chunks = [];
|
|
2192
2288
|
for await (const chunk of data.file) {
|
|
@@ -2203,8 +2299,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2203
2299
|
server2.post("/_web/scan-multi-chat", async (request, reply) => {
|
|
2204
2300
|
const data = await request.file();
|
|
2205
2301
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2206
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2207
|
-
const tmpPath =
|
|
2302
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-scan-"));
|
|
2303
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2208
2304
|
try {
|
|
2209
2305
|
const chunks = [];
|
|
2210
2306
|
for await (const chunk of data.file) {
|
|
@@ -2220,8 +2316,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2220
2316
|
server2.post("/_web/import", async (request, reply) => {
|
|
2221
2317
|
const data = await request.file();
|
|
2222
2318
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2223
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2224
|
-
const tmpPath =
|
|
2319
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-import-"));
|
|
2320
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2225
2321
|
const chunks = [];
|
|
2226
2322
|
for await (const chunk of data.file) {
|
|
2227
2323
|
chunks.push(chunk);
|
|
@@ -2269,7 +2365,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2269
2365
|
server2.post("/_web/import-directory", async (request, reply) => {
|
|
2270
2366
|
const parts = request.parts();
|
|
2271
2367
|
if (!parts) return reply.code(400).send({ error: "No files uploaded" });
|
|
2272
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2368
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-dir-import-"));
|
|
2273
2369
|
const relativePaths = [];
|
|
2274
2370
|
const fileBuffers = [];
|
|
2275
2371
|
try {
|
|
@@ -2297,9 +2393,9 @@ data: ${JSON.stringify(eventData)}
|
|
|
2297
2393
|
if (segments.length > 1) {
|
|
2298
2394
|
relPath = segments.slice(1).join("/");
|
|
2299
2395
|
}
|
|
2300
|
-
const targetPath =
|
|
2301
|
-
if (!targetPath.startsWith(tmpDir +
|
|
2302
|
-
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 });
|
|
2303
2399
|
fs6.writeFileSync(targetPath, fileBuffers[i].data);
|
|
2304
2400
|
}
|
|
2305
2401
|
const entryPath = findEntryFileInDirectory(tmpDir);
|
|
@@ -2345,8 +2441,8 @@ data: ${JSON.stringify({ success: false, error: err instanceof Error ? err.messa
|
|
|
2345
2441
|
const sessionId = request.params.id;
|
|
2346
2442
|
const data = await request.file();
|
|
2347
2443
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2348
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2349
|
-
const tmpPath =
|
|
2444
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-inc-"));
|
|
2445
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2350
2446
|
const chunks = [];
|
|
2351
2447
|
for await (const chunk of data.file) {
|
|
2352
2448
|
chunks.push(chunk);
|
|
@@ -2383,8 +2479,8 @@ data: ${JSON.stringify(eventData)}
|
|
|
2383
2479
|
const sessionId = request.params.id;
|
|
2384
2480
|
const data = await request.file();
|
|
2385
2481
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2386
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2387
|
-
const tmpPath =
|
|
2482
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2483
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2388
2484
|
const chunks = [];
|
|
2389
2485
|
for await (const chunk of data.file) {
|
|
2390
2486
|
chunks.push(chunk);
|
|
@@ -2401,8 +2497,8 @@ data: ${JSON.stringify(eventData)}
|
|
|
2401
2497
|
server2.post("/_web/import/analyze", async (request, reply) => {
|
|
2402
2498
|
const data = await request.file();
|
|
2403
2499
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2404
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2405
|
-
const tmpPath =
|
|
2500
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2501
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2406
2502
|
const chunks = [];
|
|
2407
2503
|
for await (const chunk of data.file) {
|
|
2408
2504
|
chunks.push(chunk);
|
|
@@ -2437,12 +2533,12 @@ data: ${JSON.stringify(eventData)}
|
|
|
2437
2533
|
|
|
2438
2534
|
`);
|
|
2439
2535
|
}
|
|
2440
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2536
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-demo-"));
|
|
2441
2537
|
try {
|
|
2442
2538
|
const localPaths = [];
|
|
2443
2539
|
for (let i = 0; i < total; i++) {
|
|
2444
2540
|
sendEvent("progress", { stage: "downloading", current: i + 1, total });
|
|
2445
|
-
const localPath =
|
|
2541
|
+
const localPath = path7.join(tmpDir, DEMO_FILES[i]);
|
|
2446
2542
|
const resp = await fetch(`${DEMO_BASE_URL}/${locale}/${DEMO_FILES[i]}`, {
|
|
2447
2543
|
signal: AbortSignal.timeout(6e4)
|
|
2448
2544
|
});
|
|
@@ -2478,7 +2574,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2478
2574
|
}
|
|
2479
2575
|
|
|
2480
2576
|
// src/http/routes/web/cache.ts
|
|
2481
|
-
import * as
|
|
2577
|
+
import * as path8 from "path";
|
|
2482
2578
|
import { execFile } from "child_process";
|
|
2483
2579
|
function runExecFile(file, args, runner = execFile) {
|
|
2484
2580
|
return new Promise((resolve4, reject) => {
|
|
@@ -2506,7 +2602,7 @@ async function showPathInFolder(filePath, platform = process.platform, runner) {
|
|
|
2506
2602
|
} else if (platform === "win32") {
|
|
2507
2603
|
await runExecFile("explorer.exe", [`/select,${filePath}`], runner);
|
|
2508
2604
|
} else {
|
|
2509
|
-
await runExecFile("xdg-open", [
|
|
2605
|
+
await runExecFile("xdg-open", [path8.dirname(filePath)], runner);
|
|
2510
2606
|
}
|
|
2511
2607
|
}
|
|
2512
2608
|
|
|
@@ -2529,26 +2625,28 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2529
2625
|
const mergeCache = options?.pathProvider ? new MergeSessionCache(options.pathProvider, { nativeBinding: options.nativeBinding }) : null;
|
|
2530
2626
|
mergeCache?.cleanupOrphans();
|
|
2531
2627
|
const fallbackPathProvider = {
|
|
2532
|
-
getSystemDir: () =>
|
|
2533
|
-
getUserDataDir: () =>
|
|
2534
|
-
getDatabaseDir: () =>
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
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")
|
|
2541
2638
|
};
|
|
2542
2639
|
const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
|
|
2543
2640
|
const ai = options?.aiContext;
|
|
2544
2641
|
const cliStreamImport = async (dm, filePath) => {
|
|
2545
|
-
const { streamImport: streamImport2 } = await import("./stream-import-
|
|
2642
|
+
const { streamImport: streamImport2 } = await import("./stream-import-FQFNRQ2B.mjs");
|
|
2546
2643
|
const result = await streamImport2(dm, filePath);
|
|
2547
2644
|
if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
|
|
2548
2645
|
return { sessionId: result.sessionId };
|
|
2549
2646
|
};
|
|
2550
2647
|
const defaultUserDataDir = getDefaultNodeUserDataDir();
|
|
2551
|
-
const isCustom =
|
|
2648
|
+
const isCustom = path9.resolve(resolvedPathProvider.getUserDataDir()) !== path9.resolve(defaultUserDataDir);
|
|
2649
|
+
const semanticIndexService = options?.semanticIndexService;
|
|
2552
2650
|
registerSharedRoutes(
|
|
2553
2651
|
server2,
|
|
2554
2652
|
{
|
|
@@ -2557,6 +2655,7 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2557
2655
|
pathProvider: resolvedPathProvider,
|
|
2558
2656
|
getVersion,
|
|
2559
2657
|
nativeBinding: options?.nativeBinding,
|
|
2658
|
+
semanticIndexService,
|
|
2560
2659
|
openDirectory: openDirectoryPath,
|
|
2561
2660
|
showInFolder: showPathInFolder,
|
|
2562
2661
|
downloadsDir: resolvedPathProvider.getDownloadsDir(),
|
|
@@ -2640,7 +2739,7 @@ function registerProxyRoutes(server2) {
|
|
|
2640
2739
|
|
|
2641
2740
|
// src/ai/manager-factory.ts
|
|
2642
2741
|
import * as fs7 from "fs";
|
|
2643
|
-
import * as
|
|
2742
|
+
import * as path10 from "path";
|
|
2644
2743
|
import { createHash, randomUUID } from "crypto";
|
|
2645
2744
|
var nodeFs = {
|
|
2646
2745
|
ensureDir(dir) {
|
|
@@ -2663,7 +2762,7 @@ var nodeFs = {
|
|
|
2663
2762
|
return fs7.existsSync(filePath);
|
|
2664
2763
|
},
|
|
2665
2764
|
joinPath(...parts) {
|
|
2666
|
-
return
|
|
2765
|
+
return path10.join(...parts);
|
|
2667
2766
|
}
|
|
2668
2767
|
};
|
|
2669
2768
|
var managerCache = /* @__PURE__ */ new Map();
|
|
@@ -2673,13 +2772,13 @@ function getAssistantManager(aiDataDir) {
|
|
|
2673
2772
|
cached = {
|
|
2674
2773
|
assistant: new AssistantManager({
|
|
2675
2774
|
fs: nodeFs,
|
|
2676
|
-
assistantsDir:
|
|
2775
|
+
assistantsDir: path10.join(aiDataDir, "assistants"),
|
|
2677
2776
|
builtinRawConfigs: [],
|
|
2678
2777
|
generateId: () => `custom_${randomUUID().replace(/-/g, "").slice(0, 12)}`
|
|
2679
2778
|
}),
|
|
2680
2779
|
skill: new SkillManagerCore({
|
|
2681
2780
|
fs: nodeFs,
|
|
2682
|
-
skillsDir:
|
|
2781
|
+
skillsDir: path10.join(aiDataDir, "skills"),
|
|
2683
2782
|
builtinRawSkills: [],
|
|
2684
2783
|
contentHash: (content) => createHash("md5").update(content).digest("hex")
|
|
2685
2784
|
})
|
|
@@ -2704,7 +2803,7 @@ var NOOP_LOGGER = { info: noop, warn: noop, error: noop };
|
|
|
2704
2803
|
|
|
2705
2804
|
// ../../packages/sync/src/data-source-manager.ts
|
|
2706
2805
|
import * as fs8 from "fs";
|
|
2707
|
-
import * as
|
|
2806
|
+
import * as path11 from "path";
|
|
2708
2807
|
import * as crypto from "crypto";
|
|
2709
2808
|
var CONFIG_FILE = "data-sources.json";
|
|
2710
2809
|
function generateId(prefix = "ds") {
|
|
@@ -2732,7 +2831,7 @@ var DataSourceManager = class {
|
|
|
2732
2831
|
this.logger = logger ?? NOOP_LOGGER;
|
|
2733
2832
|
}
|
|
2734
2833
|
getConfigPath() {
|
|
2735
|
-
return
|
|
2834
|
+
return path11.join(this.configDir, CONFIG_FILE);
|
|
2736
2835
|
}
|
|
2737
2836
|
ensureDir() {
|
|
2738
2837
|
fs8.mkdirSync(this.configDir, { recursive: true });
|
|
@@ -2959,6 +3058,41 @@ function fileContainsMessages(filePath) {
|
|
|
2959
3058
|
return false;
|
|
2960
3059
|
}
|
|
2961
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
|
+
}
|
|
2962
3096
|
function cleanupTempFile(filePath) {
|
|
2963
3097
|
try {
|
|
2964
3098
|
if (fs9.existsSync(filePath)) fs9.unlinkSync(filePath);
|
|
@@ -3012,6 +3146,8 @@ var PullEngine = class {
|
|
|
3012
3146
|
this.logger.info(`[Pull] Pulling "${sess.name}" from ${ds.baseUrl}`);
|
|
3013
3147
|
let totalNewMessages = 0;
|
|
3014
3148
|
let since = sess.lastPullAt;
|
|
3149
|
+
let offset;
|
|
3150
|
+
let nextPullSince = sess.lastPullAt;
|
|
3015
3151
|
let pageCount = 0;
|
|
3016
3152
|
let resyncAttempted = false;
|
|
3017
3153
|
this.progressMap.set(sess.id, { sessionId: sess.id, sessionName: sess.name, current: 0, pages: 0, done: false });
|
|
@@ -3020,6 +3156,7 @@ var PullEngine = class {
|
|
|
3020
3156
|
pageCount++;
|
|
3021
3157
|
const tempFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
3022
3158
|
since,
|
|
3159
|
+
offset,
|
|
3023
3160
|
limit: ds.pullLimit
|
|
3024
3161
|
});
|
|
3025
3162
|
try {
|
|
@@ -3029,6 +3166,7 @@ var PullEngine = class {
|
|
|
3029
3166
|
if (stat2.size < 1024) {
|
|
3030
3167
|
if (!fileContainsMessages(tempFile) && sync0?.hasMore === false) {
|
|
3031
3168
|
cleanupTempFile(tempFile);
|
|
3169
|
+
if (sync0?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, sync0.nextSince);
|
|
3032
3170
|
const retryDelays = [2e3, 3e3, 5e3];
|
|
3033
3171
|
let retrySuccess = false;
|
|
3034
3172
|
let retryHasMore = false;
|
|
@@ -3039,21 +3177,26 @@ var PullEngine = class {
|
|
|
3039
3177
|
await new Promise((r) => setTimeout(r, retryDelays[ri]));
|
|
3040
3178
|
const retryFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
3041
3179
|
since,
|
|
3180
|
+
offset,
|
|
3042
3181
|
limit: ds.pullLimit
|
|
3043
3182
|
});
|
|
3044
3183
|
const retryStat = fs9.statSync(retryFile);
|
|
3045
3184
|
this.logger.info(`[Pull] "${sess.name}" retry ${ri + 1}: fetched ${retryStat.size} bytes`);
|
|
3046
3185
|
const retrySync = parseSyncFromFile(retryFile);
|
|
3047
3186
|
if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {
|
|
3187
|
+
if (retrySync.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, retrySync.nextSince);
|
|
3048
3188
|
cleanupTempFile(retryFile);
|
|
3049
3189
|
continue;
|
|
3050
3190
|
}
|
|
3191
|
+
const retryMaxTs = getMaxMessageTimestampFromFile(retryFile);
|
|
3051
3192
|
const retryResult = await this.importTempFile(ds.baseUrl, sess, retryFile);
|
|
3052
3193
|
cleanupTempFile(retryFile);
|
|
3053
3194
|
if (retryResult.needFullResync && !resyncAttempted) {
|
|
3054
3195
|
resyncAttempted = true;
|
|
3055
3196
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
3056
3197
|
since = 0;
|
|
3198
|
+
offset = void 0;
|
|
3199
|
+
nextPullSince = 0;
|
|
3057
3200
|
pageCount = 0;
|
|
3058
3201
|
sess.targetSessionId = "";
|
|
3059
3202
|
sess.lastPullAt = 0;
|
|
@@ -3090,6 +3233,8 @@ var PullEngine = class {
|
|
|
3090
3233
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: retryResult.sessionId });
|
|
3091
3234
|
}
|
|
3092
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);
|
|
3093
3238
|
this.progressMap.set(sess.id, {
|
|
3094
3239
|
sessionId: sess.id,
|
|
3095
3240
|
sessionName: sess.name,
|
|
@@ -3099,6 +3244,9 @@ var PullEngine = class {
|
|
|
3099
3244
|
});
|
|
3100
3245
|
if (retrySync?.hasMore && retrySync.nextSince !== void 0) {
|
|
3101
3246
|
since = retrySync.nextSince;
|
|
3247
|
+
offset = void 0;
|
|
3248
|
+
} else if (retrySync?.hasMore && retrySync.nextOffset !== void 0) {
|
|
3249
|
+
offset = retrySync.nextOffset;
|
|
3102
3250
|
}
|
|
3103
3251
|
retryHasMore = !!retrySync?.hasMore;
|
|
3104
3252
|
retrySuccess = true;
|
|
@@ -3114,12 +3262,15 @@ var PullEngine = class {
|
|
|
3114
3262
|
break;
|
|
3115
3263
|
}
|
|
3116
3264
|
const sync = sync0;
|
|
3265
|
+
const maxMessageTs = getMaxMessageTimestampFromFile(tempFile);
|
|
3117
3266
|
const result = await this.importTempFile(ds.baseUrl, sess, tempFile);
|
|
3118
3267
|
cleanupTempFile(tempFile);
|
|
3119
3268
|
if (result.needFullResync && !resyncAttempted) {
|
|
3120
3269
|
resyncAttempted = true;
|
|
3121
3270
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
3122
3271
|
since = 0;
|
|
3272
|
+
offset = void 0;
|
|
3273
|
+
nextPullSince = 0;
|
|
3123
3274
|
pageCount = 0;
|
|
3124
3275
|
sess.targetSessionId = "";
|
|
3125
3276
|
sess.lastPullAt = 0;
|
|
@@ -3154,6 +3305,7 @@ var PullEngine = class {
|
|
|
3154
3305
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: result.sessionId });
|
|
3155
3306
|
}
|
|
3156
3307
|
totalNewMessages += result.newMessageCount;
|
|
3308
|
+
if (maxMessageTs !== null) nextPullSince = Math.max(nextPullSince, maxMessageTs);
|
|
3157
3309
|
this.progressMap.set(sess.id, {
|
|
3158
3310
|
sessionId: sess.id,
|
|
3159
3311
|
sessionName: sess.name,
|
|
@@ -3161,8 +3313,17 @@ var PullEngine = class {
|
|
|
3161
3313
|
pages: pageCount,
|
|
3162
3314
|
done: false
|
|
3163
3315
|
});
|
|
3316
|
+
if (sync?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, sync.nextSince);
|
|
3164
3317
|
if (!sync || !sync.hasMore) break;
|
|
3165
|
-
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
|
+
}
|
|
3166
3327
|
} catch (importErr) {
|
|
3167
3328
|
cleanupTempFile(tempFile);
|
|
3168
3329
|
throw importErr;
|
|
@@ -3171,8 +3332,9 @@ var PullEngine = class {
|
|
|
3171
3332
|
if (pageCount >= MAX_PAGES_PER_PULL) {
|
|
3172
3333
|
this.logger.warn(`[Pull] "${sess.name}" reached page limit (${MAX_PAGES_PER_PULL}), data may be incomplete`);
|
|
3173
3334
|
}
|
|
3335
|
+
const savedLastPullAt = Math.max(sess.lastPullAt, Math.max(0, nextPullSince - PULL_OVERLAP_SECONDS));
|
|
3174
3336
|
this.dsManager.updateSession(sourceId, sess.id, {
|
|
3175
|
-
lastPullAt:
|
|
3337
|
+
lastPullAt: savedLastPullAt,
|
|
3176
3338
|
lastStatus: "success",
|
|
3177
3339
|
lastNewMessages: totalNewMessages,
|
|
3178
3340
|
lastError: ""
|
|
@@ -3324,11 +3486,11 @@ function reloadTimer(dsId, skipInitialPull = false) {
|
|
|
3324
3486
|
// src/sync/adapters.ts
|
|
3325
3487
|
import * as fs10 from "fs";
|
|
3326
3488
|
import * as os4 from "os";
|
|
3327
|
-
import * as
|
|
3489
|
+
import * as path12 from "path";
|
|
3328
3490
|
import * as crypto3 from "crypto";
|
|
3329
3491
|
function getTempFilePath(ext) {
|
|
3330
3492
|
const id = crypto3.randomBytes(8).toString("hex");
|
|
3331
|
-
return
|
|
3493
|
+
return path12.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
|
|
3332
3494
|
}
|
|
3333
3495
|
var NodeFetcher = class {
|
|
3334
3496
|
async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
|
|
@@ -3666,9 +3828,23 @@ async function startHttpServer(options) {
|
|
|
3666
3828
|
limits: { fileSize: 1024 * 1024 * 1024 }
|
|
3667
3829
|
// 1GB
|
|
3668
3830
|
});
|
|
3831
|
+
let semanticIndexService;
|
|
3832
|
+
try {
|
|
3833
|
+
semanticIndexService = createSemanticIndexWorkerRuntimeClient({
|
|
3834
|
+
pathProvider,
|
|
3835
|
+
runtime,
|
|
3836
|
+
nativeBinding,
|
|
3837
|
+
workerEntryUrl: import.meta.url.endsWith(".ts") ? void 0 : new URL("./semantic-index-worker.mjs", import.meta.url)
|
|
3838
|
+
});
|
|
3839
|
+
server.addHook("onClose", async () => semanticIndexService?.close());
|
|
3840
|
+
} catch (err) {
|
|
3841
|
+
console.warn("[semantic-index] worker client unavailable:", err instanceof Error ? err.message : String(err));
|
|
3842
|
+
semanticIndexService = void 0;
|
|
3843
|
+
}
|
|
3669
3844
|
registerWebRoutes(server, dbManager, {
|
|
3670
3845
|
pathProvider,
|
|
3671
3846
|
nativeBinding,
|
|
3847
|
+
semanticIndexService,
|
|
3672
3848
|
aiContext: {
|
|
3673
3849
|
aiDataDir,
|
|
3674
3850
|
aiChatManager,
|
|
@@ -3677,7 +3853,7 @@ async function startHttpServer(options) {
|
|
|
3677
3853
|
llmConfigStore,
|
|
3678
3854
|
customProviderStore: new CustomProviderStore(createFileConfigStorage(aiDataDir)),
|
|
3679
3855
|
customModelStore: new CustomModelStore(createFileConfigStorage(aiDataDir)),
|
|
3680
|
-
runAgentStream: createCliRunAgentStream(dbManager, aiChatManager)
|
|
3856
|
+
runAgentStream: createCliRunAgentStream(dbManager, aiChatManager, semanticIndexService)
|
|
3681
3857
|
}
|
|
3682
3858
|
});
|
|
3683
3859
|
initSync(server, dbManager, pathProvider, { port, host, token });
|
|
@@ -3722,4 +3898,4 @@ export {
|
|
|
3722
3898
|
startHttpServer,
|
|
3723
3899
|
stopHttpServer
|
|
3724
3900
|
};
|
|
3725
|
-
//# sourceMappingURL=chunk-
|
|
3901
|
+
//# sourceMappingURL=chunk-SIVERPF5.mjs.map
|