chatlab-cli 0.27.0 → 0.27.2
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-QVCZVDSB.mjs} +5 -4
- package/dist/{chat-command-SKGPS3PG.mjs.map → chat-command-QVCZVDSB.mjs.map} +1 -1
- package/dist/{chunk-KCFVHVO4.mjs → chunk-B2VLK3FB.mjs} +11184 -17915
- package/dist/chunk-B2VLK3FB.mjs.map +1 -0
- package/dist/chunk-DHRSLYUM.mjs +7433 -0
- package/dist/chunk-DHRSLYUM.mjs.map +1 -0
- package/dist/{chunk-FHLPXRDL.mjs → chunk-H22VDCPB.mjs} +2 -2
- package/dist/{chunk-3HOTLLFC.mjs → chunk-JOXF6ROV.mjs} +250 -130
- package/dist/chunk-JOXF6ROV.mjs.map +1 -0
- package/dist/{chunk-MJITS5CE.mjs → chunk-K7UUN3HT.mjs} +15 -13
- package/dist/{chunk-MJITS5CE.mjs.map → chunk-K7UUN3HT.mjs.map} +1 -1
- package/dist/{chunk-6FXGC6HE.mjs → chunk-MDDWX2MG.mjs} +7 -5
- package/dist/{chunk-6FXGC6HE.mjs.map → chunk-MDDWX2MG.mjs.map} +1 -1
- package/dist/{chunk-M6ABWESL.mjs → chunk-OD3YH23N.mjs} +5 -5
- package/dist/chunk-OD3YH23N.mjs.map +1 -0
- package/dist/{chunk-7LPVQR77.mjs → chunk-PXWAYFII.mjs} +4 -4
- package/dist/chunk-PXWAYFII.mjs.map +1 -0
- package/dist/{chunk-UBJHT3BU.mjs → chunk-ST5APJB2.mjs} +6 -4
- package/dist/{chunk-UBJHT3BU.mjs.map → chunk-ST5APJB2.mjs.map} +1 -1
- package/dist/cli.mjs +4 -3
- package/dist/{http-CPFUTIUB.mjs → http-LSCVGWCI.mjs} +9 -8
- package/dist/{import-UJXKIKYN.mjs → import-E6HBJMMT.mjs} +5 -4
- package/dist/index.mjs +9 -8
- package/dist/{mcp-SW4DTCWJ.mjs → mcp-I7JUC5JV.mjs} +8 -6
- package/dist/{mcp-SW4DTCWJ.mjs.map → mcp-I7JUC5JV.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-HZILDI7C.mjs} +59 -41
- package/dist/{stream-import-4VDJZHMY.mjs → stream-import-IMRULRS2.mjs} +4 -3
- package/dist/worker-runtime-WWQ7W74Q.mjs +71 -0
- package/dist/worker-runtime-WWQ7W74Q.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-Du1FDD8L.js +110 -0
- package/dist-web/assets/{MessageExportModal-DCB-mzf2.js → MessageExportModal-4ehLHG4x.js} +1 -1
- package/dist-web/assets/{electron-DDUv0ohD.js → electron-B3AteJC8.js} +1 -1
- package/dist-web/assets/electron-DGxVMsvC.js +1 -0
- package/dist-web/assets/{fetch-C1aC5Fd1.js → fetch-BQxv_UGQ.js} +1 -1
- package/dist-web/assets/{fetch-CwHncc6x.js → fetch-BUcl-Frr.js} +1 -1
- package/dist-web/assets/{fetch-Bry8iJpq.js → fetch-BwQh9WUD.js} +1 -1
- package/dist-web/assets/{fetch-DOtBAxUS.js → fetch-C2mSdG3h.js} +1 -1
- package/dist-web/assets/{fetch-Ck4rGxkO.js → fetch-CZDFhvxY.js} +1 -1
- package/dist-web/assets/{fetch-B9Oy0bcD.js → fetch-ChZEF_n3.js} +1 -1
- package/dist-web/assets/{fetch-D8Ng59an.js → fetch-DCQN6wfR.js} +1 -1
- package/dist-web/assets/{fetch-C69hj3wS.js → fetch-DZFx8FA4.js} +1 -1
- package/dist-web/assets/{fetch-Ckang-F8.js → fetch-DlJFgbum.js} +1 -1
- package/dist-web/assets/{fetch-B3gsbY_U.js → fetch-O8M5ZWsc.js} +1 -1
- package/dist-web/assets/index-B_uZZGqi.js +173 -0
- package/dist-web/assets/{index-YmzTgkb2.css → index-CoX0L-A8.css} +1 -1
- package/dist-web/assets/{index-C16V6EoP.js → index-DR78oafF.js} +9 -9
- package/dist-web/assets/{index-zAi37ZQ4.js → index-DTlfOd_u.js} +2 -2
- package/dist-web/assets/{index-Bd9j73nw.js → index-DlkH2E7N.js} +1 -1
- package/dist-web/assets/{index-D-J8dY7w.js → index-KAFPL6dl.js} +1 -1
- package/dist-web/assets/{index-BfFj8Evo.js → index-qVTX1tLg.js} +3 -3
- package/dist-web/assets/web-CoKgy4Oo.js +1 -0
- package/dist-web/index.html +2 -2
- 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/electron-CRSL7qPM.js +0 -1
- package/dist-web/assets/index-B40SKtW8.js +0 -173
- package/dist-web/assets/web-DKFeBb_F.js +0 -1
- /package/dist/{chunk-FHLPXRDL.mjs.map → chunk-H22VDCPB.mjs.map} +0 -0
- /package/dist/{http-CPFUTIUB.mjs.map → http-LSCVGWCI.mjs.map} +0 -0
- /package/dist/{import-UJXKIKYN.mjs.map → import-E6HBJMMT.mjs.map} +0 -0
- /package/dist/{src-M3MO3LEL.mjs.map → src-HZILDI7C.mjs.map} +0 -0
- /package/dist/{stream-import-4VDJZHMY.mjs.map → stream-import-IMRULRS2.mjs.map} +0 -0
|
@@ -8,30 +8,53 @@ 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-PXWAYFII.mjs";
|
|
22
12
|
import {
|
|
23
13
|
AGENT_TOOL_REGISTRY,
|
|
24
14
|
CoreDataProvider
|
|
25
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OD3YH23N.mjs";
|
|
26
16
|
import {
|
|
27
17
|
assertCliDataDirCompatible
|
|
28
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-H22VDCPB.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-ST5APJB2.mjs";
|
|
29
|
+
import {
|
|
30
|
+
analyzeIncrementalImport,
|
|
31
|
+
analyzeNewImport,
|
|
32
|
+
incrementalImport,
|
|
33
|
+
streamImport
|
|
34
|
+
} from "./chunk-MDDWX2MG.mjs";
|
|
35
|
+
import {
|
|
36
|
+
AnalyticsService,
|
|
37
|
+
NodePathProvider,
|
|
38
|
+
PreferencesManager,
|
|
39
|
+
applyPendingNodeDataDirMigrationIfNeeded,
|
|
40
|
+
buildMergedOutput,
|
|
41
|
+
checkConflictsFromSources,
|
|
42
|
+
createJiebaNlpProvider,
|
|
43
|
+
createNodeDataDirSwitch,
|
|
44
|
+
createSemanticIndexWorkerRuntimeClient,
|
|
45
|
+
detectAllFormats,
|
|
46
|
+
detectFormat,
|
|
47
|
+
findEntryFileInDirectory,
|
|
48
|
+
getDbFileVersion,
|
|
49
|
+
getDefaultNodeUserDataDir,
|
|
50
|
+
getOrComputeAnalysisCache,
|
|
51
|
+
getPendingNodeDataDirMigration,
|
|
52
|
+
getSupportedFormats,
|
|
53
|
+
hasPendingElectronDataWarning,
|
|
54
|
+
scanMultiChatFile,
|
|
55
|
+
serializeChatLabToJsonl,
|
|
56
|
+
streamParseFileInfo
|
|
57
|
+
} from "./chunk-DHRSLYUM.mjs";
|
|
35
58
|
import {
|
|
36
59
|
AIChatManager,
|
|
37
60
|
ALL_MIGRATIONS,
|
|
@@ -46,24 +69,17 @@ import {
|
|
|
46
69
|
LLMConfigStore,
|
|
47
70
|
MergeSessionCache,
|
|
48
71
|
MigrationRunner,
|
|
49
|
-
NodePathProvider,
|
|
50
72
|
POS_TAG_DEFINITIONS,
|
|
51
|
-
|
|
73
|
+
SEMANTIC_INDEX_CONFIG_FILE,
|
|
74
|
+
SemanticIndexConfigStore,
|
|
52
75
|
SkillManagerCore,
|
|
53
76
|
TempDbWriter,
|
|
54
|
-
applyPendingNodeDataDirMigrationIfNeeded,
|
|
55
|
-
buildMergedOutput,
|
|
56
77
|
buildPiModel,
|
|
57
|
-
checkConflictsFromSources,
|
|
58
78
|
computeWordFrequency,
|
|
59
79
|
countMessagesTokens,
|
|
60
80
|
createDatabaseManagerAdapter,
|
|
61
|
-
|
|
62
|
-
createNodeDataDirSwitch,
|
|
63
|
-
createSemanticIndexService,
|
|
81
|
+
deleteAuthProfile,
|
|
64
82
|
deleteDict,
|
|
65
|
-
detectAllFormats,
|
|
66
|
-
detectFormat,
|
|
67
83
|
downloadDict,
|
|
68
84
|
ensureDefaultDict,
|
|
69
85
|
executeReadonlySql,
|
|
@@ -71,15 +87,12 @@ import {
|
|
|
71
87
|
exportSessionToJson,
|
|
72
88
|
export_service_exports,
|
|
73
89
|
fetchRemoteModels,
|
|
74
|
-
findEntryFileInDirectory,
|
|
75
90
|
getAvailableYears,
|
|
76
91
|
getBuiltinModelsByProvider,
|
|
77
92
|
getCatchphraseAnalysis,
|
|
78
93
|
getCheckInAnalysis,
|
|
79
94
|
getClusterGraph,
|
|
80
95
|
getDailyActivity,
|
|
81
|
-
getDbFileVersion,
|
|
82
|
-
getDefaultNodeUserDataDir,
|
|
83
96
|
getDefaultRulesForLocale,
|
|
84
97
|
getDictList,
|
|
85
98
|
getDivingAnalysis,
|
|
@@ -99,44 +112,40 @@ import {
|
|
|
99
112
|
getMessageTypeStats,
|
|
100
113
|
getMonthlyActivity,
|
|
101
114
|
getNightOwlAnalysis,
|
|
102
|
-
getOrComputeAnalysisCache,
|
|
103
|
-
getPendingNodeDataDirMigration,
|
|
104
115
|
getRelationshipStats,
|
|
105
116
|
getRepeatAnalysis,
|
|
106
117
|
getSchemaDetailed,
|
|
107
118
|
getSessionInfo,
|
|
108
119
|
getSessionMeta,
|
|
109
120
|
getSessionOverview,
|
|
110
|
-
getSupportedFormats,
|
|
111
121
|
getTextLengthPercentiles,
|
|
112
122
|
getTextStats,
|
|
113
123
|
getTimeRange,
|
|
114
124
|
getWeekdayActivity,
|
|
115
125
|
getYearlyActivity,
|
|
116
|
-
hasPendingElectronDataWarning,
|
|
117
126
|
initNlpDir,
|
|
118
127
|
isDictDownloaded,
|
|
119
128
|
isNewerStableVersion,
|
|
129
|
+
isSemanticIndexConfigured,
|
|
120
130
|
loadConfig,
|
|
121
131
|
member_service_exports,
|
|
122
132
|
mergeRulesForLocale,
|
|
123
133
|
owner_profile_service_exports,
|
|
134
|
+
persistSemanticIndexConfig,
|
|
124
135
|
queryMessages,
|
|
125
136
|
resolveApiKey,
|
|
137
|
+
resolveSemanticIndexApiKeySet,
|
|
126
138
|
runSimpleLlmStream,
|
|
127
|
-
scanMultiChatFile,
|
|
128
139
|
segmentText,
|
|
129
|
-
serializeChatLabToJsonl,
|
|
130
140
|
session_index_service_exports,
|
|
131
141
|
session_service_exports,
|
|
132
|
-
streamParseFileInfo,
|
|
133
142
|
stripAvatarFields,
|
|
134
143
|
summary_service_exports,
|
|
135
144
|
validateApiKey,
|
|
136
145
|
verifyCliDataPath,
|
|
137
146
|
writeAuthProfile,
|
|
138
147
|
writeConfigField
|
|
139
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-B2VLK3FB.mjs";
|
|
140
149
|
|
|
141
150
|
// src/http/index.ts
|
|
142
151
|
import * as fs11 from "fs";
|
|
@@ -1618,34 +1627,63 @@ function registerAiSummaryRoutes(server2, ctx) {
|
|
|
1618
1627
|
}
|
|
1619
1628
|
|
|
1620
1629
|
// ../../packages/http-routes/src/routes/web/ai-semantic-index.ts
|
|
1630
|
+
import path4 from "path";
|
|
1621
1631
|
function registerSemanticIndexRoutes(server2, ctx) {
|
|
1622
1632
|
const service = ctx.semanticIndexService;
|
|
1623
|
-
if (!service)
|
|
1633
|
+
if (!service) {
|
|
1634
|
+
if (ctx.aiDataDir) {
|
|
1635
|
+
const configStore = new SemanticIndexConfigStore(path4.join(ctx.aiDataDir, SEMANTIC_INDEX_CONFIG_FILE));
|
|
1636
|
+
const configResponse = (config) => ({
|
|
1637
|
+
config,
|
|
1638
|
+
apiKeySet: resolveSemanticIndexApiKeySet(config, ctx.resolveApiKey),
|
|
1639
|
+
configured: isSemanticIndexConfigured(config)
|
|
1640
|
+
});
|
|
1641
|
+
server2.get("/_web/ai/semantic-index/config", async () => configResponse(configStore.get()));
|
|
1642
|
+
server2.put(
|
|
1643
|
+
"/_web/ai/semantic-index/config",
|
|
1644
|
+
async (request) => {
|
|
1645
|
+
const config = persistSemanticIndexConfig(configStore, request.body.config, {
|
|
1646
|
+
apiKey: request.body.apiKey,
|
|
1647
|
+
writeAuthProfile: ctx.writeAuthProfile
|
|
1648
|
+
});
|
|
1649
|
+
return configResponse(config);
|
|
1650
|
+
}
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
server2.get("/_web/ai/semantic-index/enabled", async () => ({ sessions: [] }));
|
|
1654
|
+
server2.get("/_web/ai/semantic-index/status", async () => ({ status: null }));
|
|
1655
|
+
server2.post("/_web/ai/semantic-index/status", async () => ({ sessions: [] }));
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1624
1658
|
server2.get("/_web/ai/semantic-index/config", async () => {
|
|
1625
|
-
return {
|
|
1659
|
+
return {
|
|
1660
|
+
config: await service.getConfig(),
|
|
1661
|
+
apiKeySet: await service.hasApiKey(),
|
|
1662
|
+
configured: await service.isConfigured()
|
|
1663
|
+
};
|
|
1626
1664
|
});
|
|
1627
1665
|
server2.put(
|
|
1628
1666
|
"/_web/ai/semantic-index/config",
|
|
1629
1667
|
async (request) => {
|
|
1630
|
-
const config = service.setConfig(request.body.config, { apiKey: request.body.apiKey });
|
|
1631
|
-
return { config, apiKeySet: service.hasApiKey(), configured: service.isConfigured() };
|
|
1668
|
+
const config = await service.setConfig(request.body.config, { apiKey: request.body.apiKey });
|
|
1669
|
+
return { config, apiKeySet: await service.hasApiKey(), configured: await service.isConfigured() };
|
|
1632
1670
|
}
|
|
1633
1671
|
);
|
|
1634
1672
|
server2.get("/_web/ai/semantic-index/enabled", async () => {
|
|
1635
|
-
return { sessions: service.listEnabledStatuses() };
|
|
1673
|
+
return { sessions: await service.listEnabledStatuses() };
|
|
1636
1674
|
});
|
|
1637
1675
|
server2.get("/_web/ai/semantic-index/status", async (request) => {
|
|
1638
|
-
return { status: service.status(request.query.sessionId) };
|
|
1676
|
+
return { status: await service.status(request.query.sessionId) };
|
|
1639
1677
|
});
|
|
1640
1678
|
server2.post("/_web/ai/semantic-index/status", async (request) => {
|
|
1641
|
-
return { sessions: service.statusForSessions(request.body.sessionIds ?? []) };
|
|
1679
|
+
return { sessions: await service.statusForSessions(request.body.sessionIds ?? []) };
|
|
1642
1680
|
});
|
|
1643
|
-
const sessionAction = (
|
|
1644
|
-
server2.post(
|
|
1681
|
+
const sessionAction = (path13, action) => {
|
|
1682
|
+
server2.post(path13, async (request, reply) => {
|
|
1645
1683
|
const { sessionId } = request.body;
|
|
1646
1684
|
if (!sessionId) return reply.code(400).send({ error: "sessionId is required" });
|
|
1647
1685
|
await action(sessionId);
|
|
1648
|
-
return { status: service.status(sessionId) };
|
|
1686
|
+
return { status: await service.status(sessionId) };
|
|
1649
1687
|
});
|
|
1650
1688
|
};
|
|
1651
1689
|
sessionAction("/_web/ai/semantic-index/enable", (id) => service.enable(id));
|
|
@@ -1655,11 +1693,11 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1655
1693
|
sessionAction("/_web/ai/semantic-index/cancel", (id) => service.cancel(id));
|
|
1656
1694
|
sessionAction("/_web/ai/semantic-index/rebuild", (id) => service.rebuild(id));
|
|
1657
1695
|
server2.post("/_web/ai/semantic-index/build-pending", async () => {
|
|
1658
|
-
service.buildAllPending();
|
|
1659
|
-
return { sessions: service.listEnabledStatuses() };
|
|
1696
|
+
await service.buildAllPending();
|
|
1697
|
+
return { sessions: await service.listEnabledStatuses() };
|
|
1660
1698
|
});
|
|
1661
1699
|
server2.post("/_web/ai/semantic-index/cleanup", async () => {
|
|
1662
|
-
return service.cleanupUnused();
|
|
1700
|
+
return await service.cleanupUnused();
|
|
1663
1701
|
});
|
|
1664
1702
|
server2.post(
|
|
1665
1703
|
"/_web/ai/semantic-index/search",
|
|
@@ -1674,7 +1712,7 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1674
1712
|
// ../../packages/http-routes/src/routes/web/merge.ts
|
|
1675
1713
|
import * as fs3 from "fs";
|
|
1676
1714
|
import * as os from "os";
|
|
1677
|
-
import * as
|
|
1715
|
+
import * as path5 from "path";
|
|
1678
1716
|
function ensureDb2(ctx, sessionId) {
|
|
1679
1717
|
const db = ctx.dbManager.open(sessionId);
|
|
1680
1718
|
if (!db) throw sessionNotFound(sessionId);
|
|
@@ -1691,8 +1729,8 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1691
1729
|
if (contentType.includes("multipart/form-data")) {
|
|
1692
1730
|
const data = await request.file();
|
|
1693
1731
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
1694
|
-
const tmpDir = fs3.mkdtempSync(
|
|
1695
|
-
const tmpPath =
|
|
1732
|
+
const tmpDir = fs3.mkdtempSync(path5.join(os.tmpdir(), "chatlab-merge-"));
|
|
1733
|
+
const tmpPath = path5.join(tmpDir, data.filename || "upload");
|
|
1696
1734
|
const chunks = [];
|
|
1697
1735
|
for await (const chunk of data.file) {
|
|
1698
1736
|
chunks.push(chunk);
|
|
@@ -1710,12 +1748,12 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1710
1748
|
try {
|
|
1711
1749
|
const result = await streamParseFileInfo(filePath, {
|
|
1712
1750
|
createTempDatabase(sourceFilePath) {
|
|
1713
|
-
return mergeCache.createTempDatabase(
|
|
1751
|
+
return mergeCache.createTempDatabase(path5.basename(sourceFilePath));
|
|
1714
1752
|
},
|
|
1715
1753
|
onProgress() {
|
|
1716
1754
|
}
|
|
1717
1755
|
});
|
|
1718
|
-
const filename =
|
|
1756
|
+
const filename = path5.basename(filePath);
|
|
1719
1757
|
const handle = mergeCache.store(filename, result.tempDbPath);
|
|
1720
1758
|
return {
|
|
1721
1759
|
handle,
|
|
@@ -1784,9 +1822,9 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1784
1822
|
return reply.code(501).send({ error: "Import not available on this server" });
|
|
1785
1823
|
}
|
|
1786
1824
|
const jsonData = JSON.stringify(merged.chatLabData);
|
|
1787
|
-
const tmpDir = fs3.mkdtempSync(
|
|
1788
|
-
const safeName =
|
|
1789
|
-
const tmpPath =
|
|
1825
|
+
const tmpDir = fs3.mkdtempSync(path5.join(os.tmpdir(), "chatlab-merged-"));
|
|
1826
|
+
const safeName = path5.basename(outputName).replace(/[/\\?%*:|"<>]/g, "_") || "merged";
|
|
1827
|
+
const tmpPath = path5.join(tmpDir, `${safeName}.json`);
|
|
1790
1828
|
fs3.writeFileSync(tmpPath, jsonData, "utf-8");
|
|
1791
1829
|
try {
|
|
1792
1830
|
const importResult = await streamImport2(dbManager2, tmpPath);
|
|
@@ -1873,14 +1911,14 @@ function registerMergeRoutes(server2, ctx) {
|
|
|
1873
1911
|
// ../../packages/http-routes/src/routes/web/cache.ts
|
|
1874
1912
|
import * as fs4 from "fs";
|
|
1875
1913
|
import * as fsp from "fs/promises";
|
|
1876
|
-
import * as
|
|
1914
|
+
import * as path6 from "path";
|
|
1877
1915
|
async function getDirSize(dirPath) {
|
|
1878
1916
|
let totalSize = 0;
|
|
1879
1917
|
try {
|
|
1880
1918
|
if (!fs4.existsSync(dirPath)) return 0;
|
|
1881
1919
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1882
1920
|
for (const file of files) {
|
|
1883
|
-
const filePath =
|
|
1921
|
+
const filePath = path6.join(dirPath, file.name);
|
|
1884
1922
|
if (file.isDirectory()) {
|
|
1885
1923
|
totalSize += await getDirSize(filePath);
|
|
1886
1924
|
} else {
|
|
@@ -1898,7 +1936,7 @@ async function getFileCount(dirPath) {
|
|
|
1898
1936
|
if (!fs4.existsSync(dirPath)) return 0;
|
|
1899
1937
|
const files = await fsp.readdir(dirPath, { withFileTypes: true });
|
|
1900
1938
|
for (const file of files) {
|
|
1901
|
-
const filePath =
|
|
1939
|
+
const filePath = path6.join(dirPath, file.name);
|
|
1902
1940
|
if (file.isDirectory()) {
|
|
1903
1941
|
count += await getFileCount(filePath);
|
|
1904
1942
|
} else {
|
|
@@ -1911,8 +1949,8 @@ async function getFileCount(dirPath) {
|
|
|
1911
1949
|
}
|
|
1912
1950
|
function hasChatLabDatabases(dirPath) {
|
|
1913
1951
|
try {
|
|
1914
|
-
const markerPath =
|
|
1915
|
-
const dbDir =
|
|
1952
|
+
const markerPath = path6.join(dirPath, ".chatlab");
|
|
1953
|
+
const dbDir = path6.join(dirPath, "databases");
|
|
1916
1954
|
if (!fs4.existsSync(markerPath) || !fs4.existsSync(dbDir)) return false;
|
|
1917
1955
|
return fs4.readdirSync(dbDir).some((file) => file.endsWith(".db"));
|
|
1918
1956
|
} catch {
|
|
@@ -1980,7 +2018,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1980
2018
|
if (!fs4.existsSync(dirPath)) return { success: true };
|
|
1981
2019
|
const files = await fsp.readdir(dirPath);
|
|
1982
2020
|
for (const file of files) {
|
|
1983
|
-
const filePath =
|
|
2021
|
+
const filePath = path6.join(dirPath, file);
|
|
1984
2022
|
const stat2 = await fsp.stat(filePath);
|
|
1985
2023
|
if (stat2.isDirectory()) {
|
|
1986
2024
|
await fsp.rm(filePath, { recursive: true });
|
|
@@ -1997,7 +2035,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
1997
2035
|
defaultPath: ctx.defaultUserDataDir,
|
|
1998
2036
|
isCustom: ctx.isCustomDataDir ?? false,
|
|
1999
2037
|
canSetDataDir: ctx.canSetDataDir ?? Boolean(ctx.setDataDir),
|
|
2000
|
-
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) &&
|
|
2038
|
+
hasLegacyDataAtDefaultDir: Boolean(ctx.defaultUserDataDir) && path6.resolve(pp.getUserDataDir()) !== path6.resolve(ctx.defaultUserDataDir ?? "") && hasChatLabDatabases(ctx.defaultUserDataDir ?? ""),
|
|
2001
2039
|
pendingMigration: pending ? {
|
|
2002
2040
|
from: pending.from,
|
|
2003
2041
|
to: pending.to,
|
|
@@ -2014,7 +2052,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2014
2052
|
return ctx.setDataDir(targetPath, migrate);
|
|
2015
2053
|
});
|
|
2016
2054
|
server2.get("/_web/cache/latest-import-log", async () => {
|
|
2017
|
-
const importLogDir =
|
|
2055
|
+
const importLogDir = path6.join(pp.getLogsDir(), "import");
|
|
2018
2056
|
if (!fs4.existsSync(importLogDir)) {
|
|
2019
2057
|
return { success: false, error: "Log directory not found" };
|
|
2020
2058
|
}
|
|
@@ -2025,7 +2063,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2025
2063
|
}
|
|
2026
2064
|
const fileStats = await Promise.all(
|
|
2027
2065
|
logFiles.map(async (f) => {
|
|
2028
|
-
const filePath =
|
|
2066
|
+
const filePath = path6.join(importLogDir, f);
|
|
2029
2067
|
const stat2 = await fsp.stat(filePath);
|
|
2030
2068
|
return { name: f, path: filePath, mtime: stat2.mtime.getTime() };
|
|
2031
2069
|
})
|
|
@@ -2052,7 +2090,7 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2052
2090
|
if (!fs4.existsSync(downloadsDir)) {
|
|
2053
2091
|
fs4.mkdirSync(downloadsDir, { recursive: true });
|
|
2054
2092
|
}
|
|
2055
|
-
const filePath =
|
|
2093
|
+
const filePath = path6.join(downloadsDir, filename);
|
|
2056
2094
|
fs4.writeFileSync(filePath, buffer);
|
|
2057
2095
|
return { success: true, filePath };
|
|
2058
2096
|
});
|
|
@@ -2092,6 +2130,32 @@ function registerCacheRoutes(server2, ctx) {
|
|
|
2092
2130
|
});
|
|
2093
2131
|
}
|
|
2094
2132
|
|
|
2133
|
+
// ../../packages/http-routes/src/routes/web/telemetry.ts
|
|
2134
|
+
function registerTelemetryRoutes(server2, ctx) {
|
|
2135
|
+
server2.get("/_web/telemetry/enabled", async () => {
|
|
2136
|
+
return { enabled: ctx.analyticsService?.getEnabled() ?? false };
|
|
2137
|
+
});
|
|
2138
|
+
server2.post("/_web/telemetry/enabled", async (req) => {
|
|
2139
|
+
if (!ctx.analyticsService || typeof req.body?.enabled !== "boolean") return { success: false };
|
|
2140
|
+
ctx.analyticsService.setEnabled(req.body.enabled);
|
|
2141
|
+
return { success: true };
|
|
2142
|
+
});
|
|
2143
|
+
server2.post(
|
|
2144
|
+
"/_web/telemetry/track",
|
|
2145
|
+
async (req, reply) => {
|
|
2146
|
+
if (!ctx.analyticsService) return { ok: true };
|
|
2147
|
+
const { eventName, properties } = req.body ?? {};
|
|
2148
|
+
if (!eventName) return reply.code(400).send({ error: "eventName required" });
|
|
2149
|
+
if (eventName === "app_active") {
|
|
2150
|
+
await ctx.analyticsService.trackDailyActive(properties);
|
|
2151
|
+
} else {
|
|
2152
|
+
await ctx.analyticsService.track(eventName, properties);
|
|
2153
|
+
}
|
|
2154
|
+
return { ok: true };
|
|
2155
|
+
}
|
|
2156
|
+
);
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2095
2159
|
// ../../packages/http-routes/src/register.ts
|
|
2096
2160
|
function registerSharedRoutes(server2, ctx, options) {
|
|
2097
2161
|
const resolvedCtx = ctx.preferencesManager ? ctx : { ...ctx, preferencesManager: new PreferencesManager(ctx.pathProvider.getSystemDir()) };
|
|
@@ -2130,6 +2194,7 @@ function registerSharedRoutes(server2, ctx, options) {
|
|
|
2130
2194
|
registerSemanticIndexRoutes(server2, resolvedCtx);
|
|
2131
2195
|
registerMergeRoutes(server2, resolvedCtx);
|
|
2132
2196
|
registerCacheRoutes(server2, resolvedCtx);
|
|
2197
|
+
registerTelemetryRoutes(server2, resolvedCtx);
|
|
2133
2198
|
}
|
|
2134
2199
|
|
|
2135
2200
|
// ../../packages/http-routes/src/auth.ts
|
|
@@ -2207,12 +2272,12 @@ function createServer() {
|
|
|
2207
2272
|
|
|
2208
2273
|
// src/http/routes/web/index.ts
|
|
2209
2274
|
import * as os3 from "os";
|
|
2210
|
-
import * as
|
|
2275
|
+
import * as path9 from "path";
|
|
2211
2276
|
|
|
2212
2277
|
// src/http/routes/web/import.ts
|
|
2213
2278
|
import * as fs6 from "fs";
|
|
2214
2279
|
import * as os2 from "os";
|
|
2215
|
-
import * as
|
|
2280
|
+
import * as path7 from "path";
|
|
2216
2281
|
|
|
2217
2282
|
// src/http/routes/web/helpers.ts
|
|
2218
2283
|
import * as fs5 from "fs";
|
|
@@ -2245,8 +2310,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2245
2310
|
server2.post("/_web/detect-format", async (request, reply) => {
|
|
2246
2311
|
const data = await request.file();
|
|
2247
2312
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2248
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2249
|
-
const tmpPath =
|
|
2313
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-detect-"));
|
|
2314
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2250
2315
|
try {
|
|
2251
2316
|
const chunks = [];
|
|
2252
2317
|
for await (const chunk of data.file) {
|
|
@@ -2263,8 +2328,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2263
2328
|
server2.post("/_web/scan-multi-chat", async (request, reply) => {
|
|
2264
2329
|
const data = await request.file();
|
|
2265
2330
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2266
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2267
|
-
const tmpPath =
|
|
2331
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-scan-"));
|
|
2332
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2268
2333
|
try {
|
|
2269
2334
|
const chunks = [];
|
|
2270
2335
|
for await (const chunk of data.file) {
|
|
@@ -2280,8 +2345,8 @@ function registerImportRoutes(server2, dbManager2) {
|
|
|
2280
2345
|
server2.post("/_web/import", async (request, reply) => {
|
|
2281
2346
|
const data = await request.file();
|
|
2282
2347
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2283
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2284
|
-
const tmpPath =
|
|
2348
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-import-"));
|
|
2349
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2285
2350
|
const chunks = [];
|
|
2286
2351
|
for await (const chunk of data.file) {
|
|
2287
2352
|
chunks.push(chunk);
|
|
@@ -2329,7 +2394,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2329
2394
|
server2.post("/_web/import-directory", async (request, reply) => {
|
|
2330
2395
|
const parts = request.parts();
|
|
2331
2396
|
if (!parts) return reply.code(400).send({ error: "No files uploaded" });
|
|
2332
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2397
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-dir-import-"));
|
|
2333
2398
|
const relativePaths = [];
|
|
2334
2399
|
const fileBuffers = [];
|
|
2335
2400
|
try {
|
|
@@ -2357,9 +2422,9 @@ data: ${JSON.stringify(eventData)}
|
|
|
2357
2422
|
if (segments.length > 1) {
|
|
2358
2423
|
relPath = segments.slice(1).join("/");
|
|
2359
2424
|
}
|
|
2360
|
-
const targetPath =
|
|
2361
|
-
if (!targetPath.startsWith(tmpDir +
|
|
2362
|
-
fs6.mkdirSync(
|
|
2425
|
+
const targetPath = path7.resolve(tmpDir, relPath);
|
|
2426
|
+
if (!targetPath.startsWith(tmpDir + path7.sep)) continue;
|
|
2427
|
+
fs6.mkdirSync(path7.dirname(targetPath), { recursive: true });
|
|
2363
2428
|
fs6.writeFileSync(targetPath, fileBuffers[i].data);
|
|
2364
2429
|
}
|
|
2365
2430
|
const entryPath = findEntryFileInDirectory(tmpDir);
|
|
@@ -2405,8 +2470,8 @@ data: ${JSON.stringify({ success: false, error: err instanceof Error ? err.messa
|
|
|
2405
2470
|
const sessionId = request.params.id;
|
|
2406
2471
|
const data = await request.file();
|
|
2407
2472
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2408
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2409
|
-
const tmpPath =
|
|
2473
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-inc-"));
|
|
2474
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2410
2475
|
const chunks = [];
|
|
2411
2476
|
for await (const chunk of data.file) {
|
|
2412
2477
|
chunks.push(chunk);
|
|
@@ -2443,8 +2508,8 @@ data: ${JSON.stringify(eventData)}
|
|
|
2443
2508
|
const sessionId = request.params.id;
|
|
2444
2509
|
const data = await request.file();
|
|
2445
2510
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2446
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2447
|
-
const tmpPath =
|
|
2511
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2512
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2448
2513
|
const chunks = [];
|
|
2449
2514
|
for await (const chunk of data.file) {
|
|
2450
2515
|
chunks.push(chunk);
|
|
@@ -2461,8 +2526,8 @@ data: ${JSON.stringify(eventData)}
|
|
|
2461
2526
|
server2.post("/_web/import/analyze", async (request, reply) => {
|
|
2462
2527
|
const data = await request.file();
|
|
2463
2528
|
if (!data) return reply.code(400).send({ error: "No file uploaded" });
|
|
2464
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2465
|
-
const tmpPath =
|
|
2529
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-analyze-"));
|
|
2530
|
+
const tmpPath = path7.join(tmpDir, data.filename || "upload");
|
|
2466
2531
|
const chunks = [];
|
|
2467
2532
|
for await (const chunk of data.file) {
|
|
2468
2533
|
chunks.push(chunk);
|
|
@@ -2497,12 +2562,12 @@ data: ${JSON.stringify(eventData)}
|
|
|
2497
2562
|
|
|
2498
2563
|
`);
|
|
2499
2564
|
}
|
|
2500
|
-
const tmpDir = fs6.mkdtempSync(
|
|
2565
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-demo-"));
|
|
2501
2566
|
try {
|
|
2502
2567
|
const localPaths = [];
|
|
2503
2568
|
for (let i = 0; i < total; i++) {
|
|
2504
2569
|
sendEvent("progress", { stage: "downloading", current: i + 1, total });
|
|
2505
|
-
const localPath =
|
|
2570
|
+
const localPath = path7.join(tmpDir, DEMO_FILES[i]);
|
|
2506
2571
|
const resp = await fetch(`${DEMO_BASE_URL}/${locale}/${DEMO_FILES[i]}`, {
|
|
2507
2572
|
signal: AbortSignal.timeout(6e4)
|
|
2508
2573
|
});
|
|
@@ -2538,7 +2603,7 @@ data: ${JSON.stringify(eventData)}
|
|
|
2538
2603
|
}
|
|
2539
2604
|
|
|
2540
2605
|
// src/http/routes/web/cache.ts
|
|
2541
|
-
import * as
|
|
2606
|
+
import * as path8 from "path";
|
|
2542
2607
|
import { execFile } from "child_process";
|
|
2543
2608
|
function runExecFile(file, args, runner = execFile) {
|
|
2544
2609
|
return new Promise((resolve4, reject) => {
|
|
@@ -2566,7 +2631,7 @@ async function showPathInFolder(filePath, platform = process.platform, runner) {
|
|
|
2566
2631
|
} else if (platform === "win32") {
|
|
2567
2632
|
await runExecFile("explorer.exe", [`/select,${filePath}`], runner);
|
|
2568
2633
|
} else {
|
|
2569
|
-
await runExecFile("xdg-open", [
|
|
2634
|
+
await runExecFile("xdg-open", [path8.dirname(filePath)], runner);
|
|
2570
2635
|
}
|
|
2571
2636
|
}
|
|
2572
2637
|
|
|
@@ -2589,42 +2654,29 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2589
2654
|
const mergeCache = options?.pathProvider ? new MergeSessionCache(options.pathProvider, { nativeBinding: options.nativeBinding }) : null;
|
|
2590
2655
|
mergeCache?.cleanupOrphans();
|
|
2591
2656
|
const fallbackPathProvider = {
|
|
2592
|
-
getSystemDir: () =>
|
|
2593
|
-
getUserDataDir: () =>
|
|
2594
|
-
getDatabaseDir: () =>
|
|
2595
|
-
getVectorDir: () =>
|
|
2596
|
-
getAiDataDir: () =>
|
|
2597
|
-
getSettingsDir: () =>
|
|
2598
|
-
getCacheDir: () =>
|
|
2599
|
-
getTempDir: () =>
|
|
2600
|
-
getLogsDir: () =>
|
|
2601
|
-
getDownloadsDir: () =>
|
|
2657
|
+
getSystemDir: () => path9.join(os3.homedir(), ".chatlab"),
|
|
2658
|
+
getUserDataDir: () => path9.join(os3.homedir(), ".chatlab", "data"),
|
|
2659
|
+
getDatabaseDir: () => path9.join(os3.homedir(), ".chatlab", "data", "databases"),
|
|
2660
|
+
getVectorDir: () => path9.join(os3.homedir(), ".chatlab", "data", "vector"),
|
|
2661
|
+
getAiDataDir: () => path9.join(os3.homedir(), ".chatlab", "ai"),
|
|
2662
|
+
getSettingsDir: () => path9.join(os3.homedir(), ".chatlab", "settings"),
|
|
2663
|
+
getCacheDir: () => path9.join(os3.homedir(), ".chatlab", "cache"),
|
|
2664
|
+
getTempDir: () => path9.join(os3.homedir(), ".chatlab", "temp"),
|
|
2665
|
+
getLogsDir: () => path9.join(os3.homedir(), ".chatlab", "logs"),
|
|
2666
|
+
getDownloadsDir: () => path9.join(os3.homedir(), "Downloads")
|
|
2602
2667
|
};
|
|
2603
2668
|
const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
|
|
2604
2669
|
const ai = options?.aiContext;
|
|
2605
2670
|
const cliStreamImport = async (dm, filePath) => {
|
|
2606
|
-
const { streamImport: streamImport2 } = await import("./stream-import-
|
|
2671
|
+
const { streamImport: streamImport2 } = await import("./stream-import-IMRULRS2.mjs");
|
|
2607
2672
|
const result = await streamImport2(dm, filePath);
|
|
2608
2673
|
if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
|
|
2609
2674
|
return { sessionId: result.sessionId };
|
|
2610
2675
|
};
|
|
2611
2676
|
const defaultUserDataDir = getDefaultNodeUserDataDir();
|
|
2612
|
-
const isCustom =
|
|
2613
|
-
|
|
2614
|
-
|
|
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
|
-
}
|
|
2677
|
+
const isCustom = path9.resolve(resolvedPathProvider.getUserDataDir()) !== path9.resolve(defaultUserDataDir);
|
|
2678
|
+
const semanticIndexService = options?.semanticIndexService;
|
|
2679
|
+
const analyticsService = "A-US-0629338532" ? new AnalyticsService(resolvedPathProvider.getSystemDir(), "A-US-0629338532", getVersion()) : void 0;
|
|
2628
2680
|
registerSharedRoutes(
|
|
2629
2681
|
server2,
|
|
2630
2682
|
{
|
|
@@ -2634,6 +2686,7 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2634
2686
|
getVersion,
|
|
2635
2687
|
nativeBinding: options?.nativeBinding,
|
|
2636
2688
|
semanticIndexService,
|
|
2689
|
+
analyticsService,
|
|
2637
2690
|
openDirectory: openDirectoryPath,
|
|
2638
2691
|
showInFolder: showPathInFolder,
|
|
2639
2692
|
downloadsDir: resolvedPathProvider.getDownloadsDir(),
|
|
@@ -2717,7 +2770,7 @@ function registerProxyRoutes(server2) {
|
|
|
2717
2770
|
|
|
2718
2771
|
// src/ai/manager-factory.ts
|
|
2719
2772
|
import * as fs7 from "fs";
|
|
2720
|
-
import * as
|
|
2773
|
+
import * as path10 from "path";
|
|
2721
2774
|
import { createHash, randomUUID } from "crypto";
|
|
2722
2775
|
var nodeFs = {
|
|
2723
2776
|
ensureDir(dir) {
|
|
@@ -2740,7 +2793,7 @@ var nodeFs = {
|
|
|
2740
2793
|
return fs7.existsSync(filePath);
|
|
2741
2794
|
},
|
|
2742
2795
|
joinPath(...parts) {
|
|
2743
|
-
return
|
|
2796
|
+
return path10.join(...parts);
|
|
2744
2797
|
}
|
|
2745
2798
|
};
|
|
2746
2799
|
var managerCache = /* @__PURE__ */ new Map();
|
|
@@ -2750,13 +2803,13 @@ function getAssistantManager(aiDataDir) {
|
|
|
2750
2803
|
cached = {
|
|
2751
2804
|
assistant: new AssistantManager({
|
|
2752
2805
|
fs: nodeFs,
|
|
2753
|
-
assistantsDir:
|
|
2806
|
+
assistantsDir: path10.join(aiDataDir, "assistants"),
|
|
2754
2807
|
builtinRawConfigs: [],
|
|
2755
2808
|
generateId: () => `custom_${randomUUID().replace(/-/g, "").slice(0, 12)}`
|
|
2756
2809
|
}),
|
|
2757
2810
|
skill: new SkillManagerCore({
|
|
2758
2811
|
fs: nodeFs,
|
|
2759
|
-
skillsDir:
|
|
2812
|
+
skillsDir: path10.join(aiDataDir, "skills"),
|
|
2760
2813
|
builtinRawSkills: [],
|
|
2761
2814
|
contentHash: (content) => createHash("md5").update(content).digest("hex")
|
|
2762
2815
|
})
|
|
@@ -2781,7 +2834,7 @@ var NOOP_LOGGER = { info: noop, warn: noop, error: noop };
|
|
|
2781
2834
|
|
|
2782
2835
|
// ../../packages/sync/src/data-source-manager.ts
|
|
2783
2836
|
import * as fs8 from "fs";
|
|
2784
|
-
import * as
|
|
2837
|
+
import * as path11 from "path";
|
|
2785
2838
|
import * as crypto from "crypto";
|
|
2786
2839
|
var CONFIG_FILE = "data-sources.json";
|
|
2787
2840
|
function generateId(prefix = "ds") {
|
|
@@ -2809,7 +2862,7 @@ var DataSourceManager = class {
|
|
|
2809
2862
|
this.logger = logger ?? NOOP_LOGGER;
|
|
2810
2863
|
}
|
|
2811
2864
|
getConfigPath() {
|
|
2812
|
-
return
|
|
2865
|
+
return path11.join(this.configDir, CONFIG_FILE);
|
|
2813
2866
|
}
|
|
2814
2867
|
ensureDir() {
|
|
2815
2868
|
fs8.mkdirSync(this.configDir, { recursive: true });
|
|
@@ -3036,6 +3089,41 @@ function fileContainsMessages(filePath) {
|
|
|
3036
3089
|
return false;
|
|
3037
3090
|
}
|
|
3038
3091
|
}
|
|
3092
|
+
function getMaxMessageTimestampFromFile(filePath) {
|
|
3093
|
+
try {
|
|
3094
|
+
let maxTs = null;
|
|
3095
|
+
const visitTimestamp = (value) => {
|
|
3096
|
+
const ts = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
|
|
3097
|
+
if (typeof ts === "number" && Number.isFinite(ts)) {
|
|
3098
|
+
maxTs = maxTs === null ? ts : Math.max(maxTs, ts);
|
|
3099
|
+
}
|
|
3100
|
+
};
|
|
3101
|
+
if (filePath.endsWith(".jsonl")) {
|
|
3102
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
3103
|
+
for (const line of content.split("\n")) {
|
|
3104
|
+
const trimmed = line.trim();
|
|
3105
|
+
if (!trimmed) continue;
|
|
3106
|
+
try {
|
|
3107
|
+
const obj = JSON.parse(trimmed);
|
|
3108
|
+
if (obj._type === "message") visitTimestamp(obj.timestamp);
|
|
3109
|
+
} catch {
|
|
3110
|
+
continue;
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
return maxTs;
|
|
3114
|
+
}
|
|
3115
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
3116
|
+
const parsed = JSON.parse(raw);
|
|
3117
|
+
if (Array.isArray(parsed.messages)) {
|
|
3118
|
+
for (const message of parsed.messages) {
|
|
3119
|
+
visitTimestamp(message?.timestamp);
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
return maxTs;
|
|
3123
|
+
} catch {
|
|
3124
|
+
return null;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3039
3127
|
function cleanupTempFile(filePath) {
|
|
3040
3128
|
try {
|
|
3041
3129
|
if (fs9.existsSync(filePath)) fs9.unlinkSync(filePath);
|
|
@@ -3089,6 +3177,8 @@ var PullEngine = class {
|
|
|
3089
3177
|
this.logger.info(`[Pull] Pulling "${sess.name}" from ${ds.baseUrl}`);
|
|
3090
3178
|
let totalNewMessages = 0;
|
|
3091
3179
|
let since = sess.lastPullAt;
|
|
3180
|
+
let offset;
|
|
3181
|
+
let nextPullSince = sess.lastPullAt;
|
|
3092
3182
|
let pageCount = 0;
|
|
3093
3183
|
let resyncAttempted = false;
|
|
3094
3184
|
this.progressMap.set(sess.id, { sessionId: sess.id, sessionName: sess.name, current: 0, pages: 0, done: false });
|
|
@@ -3097,6 +3187,7 @@ var PullEngine = class {
|
|
|
3097
3187
|
pageCount++;
|
|
3098
3188
|
const tempFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
3099
3189
|
since,
|
|
3190
|
+
offset,
|
|
3100
3191
|
limit: ds.pullLimit
|
|
3101
3192
|
});
|
|
3102
3193
|
try {
|
|
@@ -3106,6 +3197,7 @@ var PullEngine = class {
|
|
|
3106
3197
|
if (stat2.size < 1024) {
|
|
3107
3198
|
if (!fileContainsMessages(tempFile) && sync0?.hasMore === false) {
|
|
3108
3199
|
cleanupTempFile(tempFile);
|
|
3200
|
+
if (sync0?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, sync0.nextSince);
|
|
3109
3201
|
const retryDelays = [2e3, 3e3, 5e3];
|
|
3110
3202
|
let retrySuccess = false;
|
|
3111
3203
|
let retryHasMore = false;
|
|
@@ -3116,21 +3208,26 @@ var PullEngine = class {
|
|
|
3116
3208
|
await new Promise((r) => setTimeout(r, retryDelays[ri]));
|
|
3117
3209
|
const retryFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
3118
3210
|
since,
|
|
3211
|
+
offset,
|
|
3119
3212
|
limit: ds.pullLimit
|
|
3120
3213
|
});
|
|
3121
3214
|
const retryStat = fs9.statSync(retryFile);
|
|
3122
3215
|
this.logger.info(`[Pull] "${sess.name}" retry ${ri + 1}: fetched ${retryStat.size} bytes`);
|
|
3123
3216
|
const retrySync = parseSyncFromFile(retryFile);
|
|
3124
3217
|
if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {
|
|
3218
|
+
if (retrySync.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, retrySync.nextSince);
|
|
3125
3219
|
cleanupTempFile(retryFile);
|
|
3126
3220
|
continue;
|
|
3127
3221
|
}
|
|
3222
|
+
const retryMaxTs = getMaxMessageTimestampFromFile(retryFile);
|
|
3128
3223
|
const retryResult = await this.importTempFile(ds.baseUrl, sess, retryFile);
|
|
3129
3224
|
cleanupTempFile(retryFile);
|
|
3130
3225
|
if (retryResult.needFullResync && !resyncAttempted) {
|
|
3131
3226
|
resyncAttempted = true;
|
|
3132
3227
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
3133
3228
|
since = 0;
|
|
3229
|
+
offset = void 0;
|
|
3230
|
+
nextPullSince = 0;
|
|
3134
3231
|
pageCount = 0;
|
|
3135
3232
|
sess.targetSessionId = "";
|
|
3136
3233
|
sess.lastPullAt = 0;
|
|
@@ -3167,6 +3264,8 @@ var PullEngine = class {
|
|
|
3167
3264
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: retryResult.sessionId });
|
|
3168
3265
|
}
|
|
3169
3266
|
totalNewMessages += retryResult.newMessageCount;
|
|
3267
|
+
if (retryMaxTs !== null) nextPullSince = Math.max(nextPullSince, retryMaxTs);
|
|
3268
|
+
if (retrySync?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, retrySync.nextSince);
|
|
3170
3269
|
this.progressMap.set(sess.id, {
|
|
3171
3270
|
sessionId: sess.id,
|
|
3172
3271
|
sessionName: sess.name,
|
|
@@ -3176,6 +3275,9 @@ var PullEngine = class {
|
|
|
3176
3275
|
});
|
|
3177
3276
|
if (retrySync?.hasMore && retrySync.nextSince !== void 0) {
|
|
3178
3277
|
since = retrySync.nextSince;
|
|
3278
|
+
offset = void 0;
|
|
3279
|
+
} else if (retrySync?.hasMore && retrySync.nextOffset !== void 0) {
|
|
3280
|
+
offset = retrySync.nextOffset;
|
|
3179
3281
|
}
|
|
3180
3282
|
retryHasMore = !!retrySync?.hasMore;
|
|
3181
3283
|
retrySuccess = true;
|
|
@@ -3191,12 +3293,15 @@ var PullEngine = class {
|
|
|
3191
3293
|
break;
|
|
3192
3294
|
}
|
|
3193
3295
|
const sync = sync0;
|
|
3296
|
+
const maxMessageTs = getMaxMessageTimestampFromFile(tempFile);
|
|
3194
3297
|
const result = await this.importTempFile(ds.baseUrl, sess, tempFile);
|
|
3195
3298
|
cleanupTempFile(tempFile);
|
|
3196
3299
|
if (result.needFullResync && !resyncAttempted) {
|
|
3197
3300
|
resyncAttempted = true;
|
|
3198
3301
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
3199
3302
|
since = 0;
|
|
3303
|
+
offset = void 0;
|
|
3304
|
+
nextPullSince = 0;
|
|
3200
3305
|
pageCount = 0;
|
|
3201
3306
|
sess.targetSessionId = "";
|
|
3202
3307
|
sess.lastPullAt = 0;
|
|
@@ -3231,6 +3336,7 @@ var PullEngine = class {
|
|
|
3231
3336
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: result.sessionId });
|
|
3232
3337
|
}
|
|
3233
3338
|
totalNewMessages += result.newMessageCount;
|
|
3339
|
+
if (maxMessageTs !== null) nextPullSince = Math.max(nextPullSince, maxMessageTs);
|
|
3234
3340
|
this.progressMap.set(sess.id, {
|
|
3235
3341
|
sessionId: sess.id,
|
|
3236
3342
|
sessionName: sess.name,
|
|
@@ -3238,8 +3344,17 @@ var PullEngine = class {
|
|
|
3238
3344
|
pages: pageCount,
|
|
3239
3345
|
done: false
|
|
3240
3346
|
});
|
|
3347
|
+
if (sync?.nextSince !== void 0) nextPullSince = Math.max(nextPullSince, sync.nextSince);
|
|
3241
3348
|
if (!sync || !sync.hasMore) break;
|
|
3242
|
-
if (sync.nextSince !== void 0)
|
|
3349
|
+
if (sync.nextSince !== void 0) {
|
|
3350
|
+
since = sync.nextSince;
|
|
3351
|
+
offset = void 0;
|
|
3352
|
+
} else if (sync.nextOffset !== void 0) {
|
|
3353
|
+
offset = sync.nextOffset;
|
|
3354
|
+
} else {
|
|
3355
|
+
this.logger.warn(`[Pull] "${sess.name}" returned hasMore=true without nextSince or nextOffset, stopping`);
|
|
3356
|
+
break;
|
|
3357
|
+
}
|
|
3243
3358
|
} catch (importErr) {
|
|
3244
3359
|
cleanupTempFile(tempFile);
|
|
3245
3360
|
throw importErr;
|
|
@@ -3248,8 +3363,9 @@ var PullEngine = class {
|
|
|
3248
3363
|
if (pageCount >= MAX_PAGES_PER_PULL) {
|
|
3249
3364
|
this.logger.warn(`[Pull] "${sess.name}" reached page limit (${MAX_PAGES_PER_PULL}), data may be incomplete`);
|
|
3250
3365
|
}
|
|
3366
|
+
const savedLastPullAt = Math.max(sess.lastPullAt, Math.max(0, nextPullSince - PULL_OVERLAP_SECONDS));
|
|
3251
3367
|
this.dsManager.updateSession(sourceId, sess.id, {
|
|
3252
|
-
lastPullAt:
|
|
3368
|
+
lastPullAt: savedLastPullAt,
|
|
3253
3369
|
lastStatus: "success",
|
|
3254
3370
|
lastNewMessages: totalNewMessages,
|
|
3255
3371
|
lastError: ""
|
|
@@ -3401,11 +3517,11 @@ function reloadTimer(dsId, skipInitialPull = false) {
|
|
|
3401
3517
|
// src/sync/adapters.ts
|
|
3402
3518
|
import * as fs10 from "fs";
|
|
3403
3519
|
import * as os4 from "os";
|
|
3404
|
-
import * as
|
|
3520
|
+
import * as path12 from "path";
|
|
3405
3521
|
import * as crypto3 from "crypto";
|
|
3406
3522
|
function getTempFilePath(ext) {
|
|
3407
3523
|
const id = crypto3.randomBytes(8).toString("hex");
|
|
3408
|
-
return
|
|
3524
|
+
return path12.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
|
|
3409
3525
|
}
|
|
3410
3526
|
var NodeFetcher = class {
|
|
3411
3527
|
async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
|
|
@@ -3732,6 +3848,10 @@ async function startHttpServer(options) {
|
|
|
3732
3848
|
const profileName = config2.name?.toLowerCase().replace(/\s+/g, "-") || config2.provider;
|
|
3733
3849
|
writeAuthProfile(profileName, { type: "api_key", provider: config2.provider, key: apiKey });
|
|
3734
3850
|
return profileName;
|
|
3851
|
+
},
|
|
3852
|
+
onApiKeyDeleted: (config2) => {
|
|
3853
|
+
const profileName = config2.authProfile;
|
|
3854
|
+
if (profileName) deleteAuthProfile(profileName);
|
|
3735
3855
|
}
|
|
3736
3856
|
});
|
|
3737
3857
|
initServerAiLogger(pathProvider.getLogsDir());
|
|
@@ -3745,15 +3865,15 @@ async function startHttpServer(options) {
|
|
|
3745
3865
|
});
|
|
3746
3866
|
let semanticIndexService;
|
|
3747
3867
|
try {
|
|
3748
|
-
semanticIndexService =
|
|
3868
|
+
semanticIndexService = createSemanticIndexWorkerRuntimeClient({
|
|
3749
3869
|
pathProvider,
|
|
3750
|
-
|
|
3751
|
-
nativeBinding
|
|
3870
|
+
runtime,
|
|
3871
|
+
nativeBinding,
|
|
3872
|
+
workerEntryUrl: import.meta.url.endsWith(".ts") ? void 0 : new URL("./semantic-index-worker.mjs", import.meta.url)
|
|
3752
3873
|
});
|
|
3753
|
-
semanticIndexService.recover();
|
|
3754
3874
|
server.addHook("onClose", async () => semanticIndexService?.close());
|
|
3755
3875
|
} catch (err) {
|
|
3756
|
-
console.warn("[semantic-index]
|
|
3876
|
+
console.warn("[semantic-index] worker client unavailable:", err instanceof Error ? err.message : String(err));
|
|
3757
3877
|
semanticIndexService = void 0;
|
|
3758
3878
|
}
|
|
3759
3879
|
registerWebRoutes(server, dbManager, {
|
|
@@ -3813,4 +3933,4 @@ export {
|
|
|
3813
3933
|
startHttpServer,
|
|
3814
3934
|
stopHttpServer
|
|
3815
3935
|
};
|
|
3816
|
-
//# sourceMappingURL=chunk-
|
|
3936
|
+
//# sourceMappingURL=chunk-JOXF6ROV.mjs.map
|