chatlab-cli 0.27.2 → 0.28.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 +1 -1
- package/dist/{chat-command-QVCZVDSB.mjs → chat-command-ISJ2DC7R.mjs} +5 -5
- package/dist/{chunk-OD3YH23N.mjs → chunk-3QBVO4J7.mjs} +2 -2
- package/dist/chunk-5FGB42EQ.mjs +7 -0
- package/dist/{chunk-JOXF6ROV.mjs → chunk-AB6TAXTQ.mjs} +206 -50
- package/dist/chunk-AB6TAXTQ.mjs.map +1 -0
- package/dist/{chunk-PXWAYFII.mjs → chunk-ERAAWLEF.mjs} +3 -3
- package/dist/{chunk-K7UUN3HT.mjs → chunk-GHTGFM6O.mjs} +26 -11
- package/dist/chunk-GHTGFM6O.mjs.map +1 -0
- package/dist/{chunk-H22VDCPB.mjs → chunk-NJB2NNB2.mjs} +2 -2
- package/dist/{chunk-MDDWX2MG.mjs → chunk-T7IETWHN.mjs} +6 -22
- package/dist/chunk-T7IETWHN.mjs.map +1 -0
- package/dist/chunk-YBS3YQB6.mjs +1336 -0
- package/dist/chunk-YBS3YQB6.mjs.map +1 -0
- package/dist/{chunk-B2VLK3FB.mjs → chunk-ZVDOFWL7.mjs} +13377 -4714
- package/dist/chunk-ZVDOFWL7.mjs.map +1 -0
- package/dist/cli.mjs +4 -4
- package/dist/{http-LSCVGWCI.mjs → http-MBILV37U.mjs} +9 -9
- package/dist/{import-E6HBJMMT.mjs → import-EYV3GXHE.mjs} +5 -12
- package/dist/index.mjs +9 -9
- package/dist/{mcp-I7JUC5JV.mjs → mcp-H55AEXU5.mjs} +5 -5
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-HZILDI7C.mjs → src-36ZIR65K.mjs} +39 -21
- package/dist/{stream-import-IMRULRS2.mjs → stream-import-YZMZ56B5.mjs} +4 -4
- package/dist/stream-import-YZMZ56B5.mjs.map +1 -0
- package/dist/undici-ZSXBT7EA.mjs +18389 -0
- package/dist/undici-ZSXBT7EA.mjs.map +1 -0
- package/dist/{worker-runtime-WWQ7W74Q.mjs → worker-runtime-YDYS2C6T.mjs} +9 -5
- package/dist/worker-runtime-YDYS2C6T.mjs.map +1 -0
- package/dist-web/assets/{DebugToolsPanel.vue_vue_type_script_setup_true_lang-Du1FDD8L.js → DebugToolsPanel.vue_vue_type_script_setup_true_lang-Do3x4aL3.js} +5 -5
- package/dist-web/assets/{MessageExportModal-4ehLHG4x.js → MessageExportModal-rijqUusq.js} +1 -1
- package/dist-web/assets/electron-D9vE5t3H.js +1 -0
- package/dist-web/assets/{electron-B3AteJC8.js → electron-DWDCqx_d.js} +1 -1
- package/dist-web/assets/{fetch-BUcl-Frr.js → fetch-29ZBtGV0.js} +1 -1
- package/dist-web/assets/{fetch-BQxv_UGQ.js → fetch-BAxKmbKF.js} +1 -1
- package/dist-web/assets/{fetch-CZDFhvxY.js → fetch-BYczbT4C.js} +1 -1
- package/dist-web/assets/{fetch-ChZEF_n3.js → fetch-BcxrU2mr.js} +1 -1
- package/dist-web/assets/{fetch-BwQh9WUD.js → fetch-Bh1fo3Df.js} +1 -1
- package/dist-web/assets/{fetch-DlJFgbum.js → fetch-C3yhWO2S.js} +1 -1
- package/dist-web/assets/{fetch-DZFx8FA4.js → fetch-Da_TBxrX.js} +1 -1
- package/dist-web/assets/{fetch-C2mSdG3h.js → fetch-DyD8wDhb.js} +1 -1
- package/dist-web/assets/fetch-TCeykOkO.js +3 -0
- package/dist-web/assets/{fetch-DCQN6wfR.js → fetch-tIIVdXSv.js} +1 -1
- package/dist-web/assets/index-BzjLqlW_.js +173 -0
- package/dist-web/assets/{index-qVTX1tLg.js → index-C74qEDFh.js} +3 -3
- package/dist-web/assets/index-CM6xNPFp.css +1 -0
- package/dist-web/assets/index-CgK2LLIF.js +12 -0
- package/dist-web/assets/{index-DTlfOd_u.js → index-CjkOvM3N.js} +2 -2
- package/dist-web/assets/{index-DlkH2E7N.js → index-Dno7CADA.js} +1 -1
- package/dist-web/assets/{index-KAFPL6dl.js → index-fbWrQpgH.js} +1 -1
- package/dist-web/assets/{web-CoKgy4Oo.js → web-H3XLx159.js} +1 -1
- package/dist-web/index.html +2 -2
- package/package.json +1 -1
- package/dist/chunk-B2VLK3FB.mjs.map +0 -1
- package/dist/chunk-DHRSLYUM.mjs +0 -7433
- package/dist/chunk-DHRSLYUM.mjs.map +0 -1
- package/dist/chunk-JOXF6ROV.mjs.map +0 -1
- package/dist/chunk-K7UUN3HT.mjs.map +0 -1
- package/dist/chunk-MDDWX2MG.mjs.map +0 -1
- package/dist/chunk-ST5APJB2.mjs +0 -389
- package/dist/chunk-ST5APJB2.mjs.map +0 -1
- package/dist/worker-runtime-WWQ7W74Q.mjs.map +0 -1
- package/dist-web/assets/electron-2m4Vdk2z.js +0 -1
- package/dist-web/assets/fetch-O8M5ZWsc.js +0 -3
- package/dist-web/assets/index-B_uZZGqi.js +0 -173
- package/dist-web/assets/index-CoX0L-A8.css +0 -1
- package/dist-web/assets/index-DR78oafF.js +0 -11
- /package/dist/{chat-command-QVCZVDSB.mjs.map → chat-command-ISJ2DC7R.mjs.map} +0 -0
- /package/dist/{chunk-OD3YH23N.mjs.map → chunk-3QBVO4J7.mjs.map} +0 -0
- /package/dist/{http-LSCVGWCI.mjs.map → chunk-5FGB42EQ.mjs.map} +0 -0
- /package/dist/{chunk-PXWAYFII.mjs.map → chunk-ERAAWLEF.mjs.map} +0 -0
- /package/dist/{chunk-H22VDCPB.mjs.map → chunk-NJB2NNB2.mjs.map} +0 -0
- /package/dist/{import-E6HBJMMT.mjs.map → http-MBILV37U.mjs.map} +0 -0
- /package/dist/{src-HZILDI7C.mjs.map → import-EYV3GXHE.mjs.map} +0 -0
- /package/dist/{mcp-I7JUC5JV.mjs.map → mcp-H55AEXU5.mjs.map} +0 -0
- /package/dist/{stream-import-IMRULRS2.mjs.map → src-36ZIR65K.mjs.map} +0 -0
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ English | [简体中文](./README.zh-CN.md)
|
|
|
14
14
|
|
|
15
15
|
ChatLab is an open-source desktop app for understanding your social conversations. It combines a flexible SQL engine with AI agents so you can explore patterns, ask better questions, and extract insights from chat data, all on your own machine.
|
|
16
16
|
|
|
17
|
-
Currently supported: **WhatsApp, LINE, QQ, Discord, Instagram, Telegram, and
|
|
17
|
+
Currently supported: **WhatsApp, LINE, QQ, Discord, Instagram, Telegram, iMessage, and Google Chat**. Coming next: **Messenger and KakaoTalk**.
|
|
18
18
|
|
|
19
19
|
> New install? Start here: [Getting started](https://docs.chatlab.fun/usage/quick-start)
|
|
20
20
|
|
|
@@ -6,10 +6,10 @@ const __filename = __fileURLToPath(import.meta.url);
|
|
|
6
6
|
const __dirname = __pathDirname(__filename);
|
|
7
7
|
import {
|
|
8
8
|
createCliRunAgentStream
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-ERAAWLEF.mjs";
|
|
10
|
+
import "./chunk-3QBVO4J7.mjs";
|
|
11
|
+
import "./chunk-YBS3YQB6.mjs";
|
|
12
|
+
import "./chunk-ZVDOFWL7.mjs";
|
|
13
13
|
import "./chunk-GFHSSCCR.mjs";
|
|
14
14
|
|
|
15
15
|
// src/ai/chat-command.ts
|
|
@@ -302,4 +302,4 @@ export {
|
|
|
302
302
|
runChatCommand,
|
|
303
303
|
runChatTurn
|
|
304
304
|
};
|
|
305
|
-
//# sourceMappingURL=chat-command-
|
|
305
|
+
//# sourceMappingURL=chat-command-ISJ2DC7R.mjs.map
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
getSessionOverview,
|
|
27
27
|
getWeekdayActivity,
|
|
28
28
|
searchMessagesByKeywords
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-ZVDOFWL7.mjs";
|
|
30
30
|
|
|
31
31
|
// ../../packages/tools/src/definitions/sql-query.ts
|
|
32
32
|
var inputSchema = {
|
|
@@ -1828,4 +1828,4 @@ export {
|
|
|
1828
1828
|
MCP_TOOL_REGISTRY,
|
|
1829
1829
|
CoreDataProvider
|
|
1830
1830
|
};
|
|
1831
|
-
//# sourceMappingURL=chunk-
|
|
1831
|
+
//# sourceMappingURL=chunk-3QBVO4J7.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'module';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
//# sourceMappingURL=chunk-5FGB42EQ.mjs.map
|
|
@@ -8,30 +8,26 @@ import {
|
|
|
8
8
|
closeServerAiLogger,
|
|
9
9
|
createCliRunAgentStream,
|
|
10
10
|
initServerAiLogger
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ERAAWLEF.mjs";
|
|
12
12
|
import {
|
|
13
13
|
AGENT_TOOL_REGISTRY,
|
|
14
14
|
CoreDataProvider
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-3QBVO4J7.mjs";
|
|
16
16
|
import {
|
|
17
17
|
assertCliDataDirCompatible
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-NJB2NNB2.mjs";
|
|
19
19
|
import {
|
|
20
20
|
getVersion
|
|
21
21
|
} from "./chunk-5ADKYYNA.mjs";
|
|
22
22
|
import {
|
|
23
23
|
resolveCliPath
|
|
24
24
|
} from "./chunk-FJ35V3TE.mjs";
|
|
25
|
-
import {
|
|
26
|
-
importData,
|
|
27
|
-
parseFile
|
|
28
|
-
} from "./chunk-ST5APJB2.mjs";
|
|
29
25
|
import {
|
|
30
26
|
analyzeIncrementalImport,
|
|
31
27
|
analyzeNewImport,
|
|
32
28
|
incrementalImport,
|
|
33
29
|
streamImport
|
|
34
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-T7IETWHN.mjs";
|
|
35
31
|
import {
|
|
36
32
|
AnalyticsService,
|
|
37
33
|
NodePathProvider,
|
|
@@ -42,22 +38,18 @@ import {
|
|
|
42
38
|
createJiebaNlpProvider,
|
|
43
39
|
createNodeDataDirSwitch,
|
|
44
40
|
createSemanticIndexWorkerRuntimeClient,
|
|
45
|
-
detectAllFormats,
|
|
46
|
-
detectFormat,
|
|
47
|
-
findEntryFileInDirectory,
|
|
48
41
|
getDbFileVersion,
|
|
49
42
|
getDefaultNodeUserDataDir,
|
|
50
43
|
getOrComputeAnalysisCache,
|
|
51
44
|
getPendingNodeDataDirMigration,
|
|
52
|
-
getSupportedFormats,
|
|
53
45
|
hasPendingElectronDataWarning,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
streamParseFileInfo
|
|
57
|
-
} from "./chunk-DHRSLYUM.mjs";
|
|
46
|
+
serializeChatLabToJsonl
|
|
47
|
+
} from "./chunk-YBS3YQB6.mjs";
|
|
58
48
|
import {
|
|
59
49
|
AIChatManager,
|
|
60
50
|
ALL_MIGRATIONS,
|
|
51
|
+
ArchiveImportError,
|
|
52
|
+
ArchiveImportSourceManager,
|
|
61
53
|
AssistantManager,
|
|
62
54
|
BUILTIN_MODELS,
|
|
63
55
|
BUILTIN_PROVIDERS,
|
|
@@ -74,12 +66,15 @@ import {
|
|
|
74
66
|
SemanticIndexConfigStore,
|
|
75
67
|
SkillManagerCore,
|
|
76
68
|
TempDbWriter,
|
|
69
|
+
appLogger,
|
|
77
70
|
buildPiModel,
|
|
78
71
|
computeWordFrequency,
|
|
79
72
|
countMessagesTokens,
|
|
80
73
|
createDatabaseManagerAdapter,
|
|
81
74
|
deleteAuthProfile,
|
|
82
75
|
deleteDict,
|
|
76
|
+
detectAllFormats,
|
|
77
|
+
detectFormat,
|
|
83
78
|
downloadDict,
|
|
84
79
|
ensureDefaultDict,
|
|
85
80
|
executeReadonlySql,
|
|
@@ -87,6 +82,7 @@ import {
|
|
|
87
82
|
exportSessionToJson,
|
|
88
83
|
export_service_exports,
|
|
89
84
|
fetchRemoteModels,
|
|
85
|
+
findEntryFileInDirectory,
|
|
90
86
|
getAvailableYears,
|
|
91
87
|
getBuiltinModelsByProvider,
|
|
92
88
|
getCatchphraseAnalysis,
|
|
@@ -99,6 +95,7 @@ import {
|
|
|
99
95
|
getDragonKingAnalysis,
|
|
100
96
|
getHourlyActivity,
|
|
101
97
|
getLanguagePreferenceAnalysis,
|
|
98
|
+
getLastPlatformMessageId,
|
|
102
99
|
getLaughAnalysis,
|
|
103
100
|
getLongMessageCount,
|
|
104
101
|
getMemberActivity,
|
|
@@ -118,11 +115,13 @@ import {
|
|
|
118
115
|
getSessionInfo,
|
|
119
116
|
getSessionMeta,
|
|
120
117
|
getSessionOverview,
|
|
118
|
+
getSupportedFormats,
|
|
121
119
|
getTextLengthPercentiles,
|
|
122
120
|
getTextStats,
|
|
123
121
|
getTimeRange,
|
|
124
122
|
getWeekdayActivity,
|
|
125
123
|
getYearlyActivity,
|
|
124
|
+
initAppLogger,
|
|
126
125
|
initNlpDir,
|
|
127
126
|
isDictDownloaded,
|
|
128
127
|
isNewerStableVersion,
|
|
@@ -132,20 +131,23 @@ import {
|
|
|
132
131
|
mergeRulesForLocale,
|
|
133
132
|
owner_profile_service_exports,
|
|
134
133
|
persistSemanticIndexConfig,
|
|
134
|
+
pushImport,
|
|
135
135
|
queryMessages,
|
|
136
136
|
resolveApiKey,
|
|
137
137
|
resolveSemanticIndexApiKeySet,
|
|
138
138
|
runSimpleLlmStream,
|
|
139
|
+
scanMultiChatFile,
|
|
139
140
|
segmentText,
|
|
140
141
|
session_index_service_exports,
|
|
141
142
|
session_service_exports,
|
|
143
|
+
streamParseFileInfo,
|
|
142
144
|
stripAvatarFields,
|
|
143
145
|
summary_service_exports,
|
|
144
146
|
validateApiKey,
|
|
145
147
|
verifyCliDataPath,
|
|
146
148
|
writeAuthProfile,
|
|
147
149
|
writeConfigField
|
|
148
|
-
} from "./chunk-
|
|
150
|
+
} from "./chunk-ZVDOFWL7.mjs";
|
|
149
151
|
|
|
150
152
|
// src/http/index.ts
|
|
151
153
|
import * as fs11 from "fs";
|
|
@@ -164,6 +166,8 @@ var HTTP_STATUS = {
|
|
|
164
166
|
["SQL_EXECUTION_ERROR" /* SQL_EXECUTION_ERROR */]: 400,
|
|
165
167
|
["EXPORT_TOO_LARGE" /* EXPORT_TOO_LARGE */]: 400,
|
|
166
168
|
["BODY_TOO_LARGE" /* BODY_TOO_LARGE */]: 413,
|
|
169
|
+
["IMPORT_IN_PROGRESS" /* IMPORT_IN_PROGRESS */]: 409,
|
|
170
|
+
["IMPORT_FAILED" /* IMPORT_FAILED */]: 500,
|
|
167
171
|
["DATA_DIR_INCOMPATIBLE" /* DATA_DIR_INCOMPATIBLE */]: 409,
|
|
168
172
|
["SERVER_ERROR" /* SERVER_ERROR */]: 500
|
|
169
173
|
};
|
|
@@ -183,6 +187,9 @@ function unauthorized(message = "Invalid or missing token") {
|
|
|
183
187
|
function sessionNotFound(id) {
|
|
184
188
|
return new ApiError("SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */, `Session not found: ${id}`);
|
|
185
189
|
}
|
|
190
|
+
function invalidPayload(message) {
|
|
191
|
+
return new ApiError("INVALID_PAYLOAD" /* INVALID_PAYLOAD */, message);
|
|
192
|
+
}
|
|
186
193
|
function sqlExecutionError(message) {
|
|
187
194
|
return new ApiError("SQL_EXECUTION_ERROR" /* SQL_EXECUTION_ERROR */, message);
|
|
188
195
|
}
|
|
@@ -195,6 +202,12 @@ function exportTooLarge(count, limit) {
|
|
|
195
202
|
function serverError(message = "Internal server error") {
|
|
196
203
|
return new ApiError("SERVER_ERROR" /* SERVER_ERROR */, message);
|
|
197
204
|
}
|
|
205
|
+
function importInProgress() {
|
|
206
|
+
return new ApiError("IMPORT_IN_PROGRESS" /* IMPORT_IN_PROGRESS */, "Another import is already in progress");
|
|
207
|
+
}
|
|
208
|
+
function importFailed(message) {
|
|
209
|
+
return new ApiError("IMPORT_FAILED" /* IMPORT_FAILED */, message);
|
|
210
|
+
}
|
|
198
211
|
function dataDirIncompatible(message) {
|
|
199
212
|
return new ApiError("DATA_DIR_INCOMPATIBLE" /* DATA_DIR_INCOMPATIBLE */, message);
|
|
200
213
|
}
|
|
@@ -343,7 +356,9 @@ function registerRestSessionRoutes(server2, ctx) {
|
|
|
343
356
|
messageCount: info.messageCount,
|
|
344
357
|
memberCount: info.memberCount,
|
|
345
358
|
firstTimestamp: info.firstMessageTs,
|
|
346
|
-
lastTimestamp: info.lastMessageTs
|
|
359
|
+
lastTimestamp: info.lastMessageTs,
|
|
360
|
+
lastPlatformMessageId: getLastPlatformMessageId(db),
|
|
361
|
+
importedAt: info.importedAt
|
|
347
362
|
});
|
|
348
363
|
});
|
|
349
364
|
server2.get("/api/v1/sessions/:id/messages", async (request) => {
|
|
@@ -464,6 +479,39 @@ function registerRestSessionRoutes(server2, ctx) {
|
|
|
464
479
|
});
|
|
465
480
|
}
|
|
466
481
|
|
|
482
|
+
// ../../packages/http-routes/src/routes/imports.ts
|
|
483
|
+
function registerImportRoutes(server2, ctx) {
|
|
484
|
+
server2.post(
|
|
485
|
+
"/api/v1/imports/:sessionId",
|
|
486
|
+
async (request, reply) => {
|
|
487
|
+
const { sessionId } = request.params;
|
|
488
|
+
const contentType = request.headers["content-type"] || "";
|
|
489
|
+
if (!contentType.includes("application/json")) {
|
|
490
|
+
const err = invalidPayload("Content-Type must be application/json (JSONL is not yet supported)");
|
|
491
|
+
return reply.code(err.statusCode).send(errorResponse(err));
|
|
492
|
+
}
|
|
493
|
+
if (request.headers["x-dry-run"] === "true") {
|
|
494
|
+
const err = invalidPayload("X-Dry-Run is not yet supported");
|
|
495
|
+
return reply.code(err.statusCode).send(errorResponse(err));
|
|
496
|
+
}
|
|
497
|
+
const outcome = await pushImport(ctx.dbManager, sessionId, request.body ?? {});
|
|
498
|
+
if (!outcome.ok) {
|
|
499
|
+
if (outcome.reason === "import_in_progress") {
|
|
500
|
+
const err2 = importInProgress();
|
|
501
|
+
return reply.code(err2.statusCode).send(errorResponse(err2));
|
|
502
|
+
}
|
|
503
|
+
if (outcome.reason === "invalid_payload") {
|
|
504
|
+
const err2 = invalidPayload(outcome.message);
|
|
505
|
+
return reply.code(err2.statusCode).send(errorResponse(err2));
|
|
506
|
+
}
|
|
507
|
+
const err = importFailed(outcome.message);
|
|
508
|
+
return reply.code(err.statusCode).send(errorResponse(err));
|
|
509
|
+
}
|
|
510
|
+
return successResponse(outcome.result);
|
|
511
|
+
}
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
467
515
|
// ../../packages/http-routes/src/routes/web/sessions.ts
|
|
468
516
|
function registerSessionRoutes(server2, ctx) {
|
|
469
517
|
const { sessionAdapter: adapter } = ctx;
|
|
@@ -1638,7 +1686,10 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1638
1686
|
apiKeySet: resolveSemanticIndexApiKeySet(config, ctx.resolveApiKey),
|
|
1639
1687
|
configured: isSemanticIndexConfigured(config)
|
|
1640
1688
|
});
|
|
1641
|
-
server2.get("/_web/ai/semantic-index/config", async () =>
|
|
1689
|
+
server2.get("/_web/ai/semantic-index/config", async () => ({
|
|
1690
|
+
...configResponse(configStore.get()),
|
|
1691
|
+
modelStatus: "idle"
|
|
1692
|
+
}));
|
|
1642
1693
|
server2.put(
|
|
1643
1694
|
"/_web/ai/semantic-index/config",
|
|
1644
1695
|
async (request) => {
|
|
@@ -1646,7 +1697,7 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1646
1697
|
apiKey: request.body.apiKey,
|
|
1647
1698
|
writeAuthProfile: ctx.writeAuthProfile
|
|
1648
1699
|
});
|
|
1649
|
-
return configResponse(config);
|
|
1700
|
+
return { ...configResponse(config), modelStatus: "idle" };
|
|
1650
1701
|
}
|
|
1651
1702
|
);
|
|
1652
1703
|
}
|
|
@@ -1659,14 +1710,20 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1659
1710
|
return {
|
|
1660
1711
|
config: await service.getConfig(),
|
|
1661
1712
|
apiKeySet: await service.hasApiKey(),
|
|
1662
|
-
configured: await service.isConfigured()
|
|
1713
|
+
configured: await service.isConfigured(),
|
|
1714
|
+
modelStatus: await service.getModelStatus()
|
|
1663
1715
|
};
|
|
1664
1716
|
});
|
|
1665
1717
|
server2.put(
|
|
1666
1718
|
"/_web/ai/semantic-index/config",
|
|
1667
1719
|
async (request) => {
|
|
1668
1720
|
const config = await service.setConfig(request.body.config, { apiKey: request.body.apiKey });
|
|
1669
|
-
return {
|
|
1721
|
+
return {
|
|
1722
|
+
config,
|
|
1723
|
+
apiKeySet: await service.hasApiKey(),
|
|
1724
|
+
configured: await service.isConfigured(),
|
|
1725
|
+
modelStatus: await service.getModelStatus()
|
|
1726
|
+
};
|
|
1670
1727
|
}
|
|
1671
1728
|
);
|
|
1672
1729
|
server2.get("/_web/ai/semantic-index/enabled", async () => {
|
|
@@ -1687,7 +1744,7 @@ function registerSemanticIndexRoutes(server2, ctx) {
|
|
|
1687
1744
|
});
|
|
1688
1745
|
};
|
|
1689
1746
|
sessionAction("/_web/ai/semantic-index/enable", (id) => service.enable(id));
|
|
1690
|
-
sessionAction("/_web/ai/semantic-index/
|
|
1747
|
+
sessionAction("/_web/ai/semantic-index/remove", (id) => service.remove(id));
|
|
1691
1748
|
sessionAction("/_web/ai/semantic-index/build", (id) => service.build(id));
|
|
1692
1749
|
sessionAction("/_web/ai/semantic-index/pause", (id) => service.pause(id));
|
|
1693
1750
|
sessionAction("/_web/ai/semantic-index/cancel", (id) => service.cancel(id));
|
|
@@ -2156,11 +2213,25 @@ function registerTelemetryRoutes(server2, ctx) {
|
|
|
2156
2213
|
);
|
|
2157
2214
|
}
|
|
2158
2215
|
|
|
2216
|
+
// ../../packages/http-routes/src/routes/web/logs.ts
|
|
2217
|
+
function registerLogRoutes(server2, _ctx) {
|
|
2218
|
+
server2.post("/_web/logs/report", async (req, reply) => {
|
|
2219
|
+
const { level, message, stack, url } = req.body ?? {};
|
|
2220
|
+
if (!message) return reply.code(400).send({ error: "message required" });
|
|
2221
|
+
const detail = [url ? `url=${url}` : null, stack ? `
|
|
2222
|
+
${stack}` : null].filter(Boolean).join(" ");
|
|
2223
|
+
if (level === "warn") appLogger.warn("web", message, detail || void 0);
|
|
2224
|
+
else appLogger.error("web", message, detail || void 0);
|
|
2225
|
+
return { ok: true };
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2159
2229
|
// ../../packages/http-routes/src/register.ts
|
|
2160
2230
|
function registerSharedRoutes(server2, ctx, options) {
|
|
2161
2231
|
const resolvedCtx = ctx.preferencesManager ? ctx : { ...ctx, preferencesManager: new PreferencesManager(ctx.pathProvider.getSystemDir()) };
|
|
2162
2232
|
registerSystemRoutes(server2, resolvedCtx);
|
|
2163
2233
|
registerRestSessionRoutes(server2, resolvedCtx);
|
|
2234
|
+
registerImportRoutes(server2, resolvedCtx);
|
|
2164
2235
|
registerSessionRoutes(server2, resolvedCtx);
|
|
2165
2236
|
registerMemberRoutes(server2, resolvedCtx);
|
|
2166
2237
|
registerPreferencesRoutes(server2, resolvedCtx);
|
|
@@ -2195,6 +2266,7 @@ function registerSharedRoutes(server2, ctx, options) {
|
|
|
2195
2266
|
registerMergeRoutes(server2, resolvedCtx);
|
|
2196
2267
|
registerCacheRoutes(server2, resolvedCtx);
|
|
2197
2268
|
registerTelemetryRoutes(server2, resolvedCtx);
|
|
2269
|
+
registerLogRoutes(server2, resolvedCtx);
|
|
2198
2270
|
}
|
|
2199
2271
|
|
|
2200
2272
|
// ../../packages/http-routes/src/auth.ts
|
|
@@ -2248,7 +2320,7 @@ function createServer() {
|
|
|
2248
2320
|
bodyLimit: JSON_BODY_LIMIT
|
|
2249
2321
|
});
|
|
2250
2322
|
server2.addHook("onRequest", authHook);
|
|
2251
|
-
server2.setErrorHandler((error,
|
|
2323
|
+
server2.setErrorHandler((error, request, reply) => {
|
|
2252
2324
|
const apiError = apiErrorFromUnknown(error);
|
|
2253
2325
|
if (apiError) {
|
|
2254
2326
|
reply.code(apiError.statusCode).send(errorResponse(apiError));
|
|
@@ -2264,6 +2336,7 @@ function createServer() {
|
|
|
2264
2336
|
reply.code(statusCode).send({ success: false, error: { code: "CLIENT_ERROR", message: error.message } });
|
|
2265
2337
|
return;
|
|
2266
2338
|
}
|
|
2339
|
+
appLogger.error("http", `${request.method} ${request.url} -> 500`, error);
|
|
2267
2340
|
const err = serverError(error.message);
|
|
2268
2341
|
reply.code(err.statusCode).send(errorResponse(err));
|
|
2269
2342
|
});
|
|
@@ -2278,6 +2351,8 @@ import * as path9 from "path";
|
|
|
2278
2351
|
import * as fs6 from "fs";
|
|
2279
2352
|
import * as os2 from "os";
|
|
2280
2353
|
import * as path7 from "path";
|
|
2354
|
+
import { randomUUID } from "crypto";
|
|
2355
|
+
import { pipeline } from "stream/promises";
|
|
2281
2356
|
|
|
2282
2357
|
// src/http/routes/web/helpers.ts
|
|
2283
2358
|
import * as fs5 from "fs";
|
|
@@ -2290,6 +2365,7 @@ function resolveNativeBinding() {
|
|
|
2290
2365
|
|
|
2291
2366
|
// src/http/routes/web/import.ts
|
|
2292
2367
|
var DEMO_BASE_URL = "https://chatlab.fun/assets/demo";
|
|
2368
|
+
var ARCHIVE_UPLOAD_LIMIT = 50 * 1024 * 1024 * 1024;
|
|
2293
2369
|
function cleanupTemp(...paths) {
|
|
2294
2370
|
for (const p of paths) {
|
|
2295
2371
|
try {
|
|
@@ -2303,7 +2379,93 @@ function cleanupTemp(...paths) {
|
|
|
2303
2379
|
}
|
|
2304
2380
|
}
|
|
2305
2381
|
}
|
|
2306
|
-
function
|
|
2382
|
+
function registerImportRoutes2(server2, dbManager2, options = {}) {
|
|
2383
|
+
const sourceManager = options.sourceManager ?? new ArchiveImportSourceManager({
|
|
2384
|
+
tempRoot: fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-import-sources-"))
|
|
2385
|
+
});
|
|
2386
|
+
const runPreparedImport = options.runPreparedImport ?? (async (manifestPath, onProgress) => {
|
|
2387
|
+
const result = await streamImport(dbManager2, manifestPath, {
|
|
2388
|
+
formatId: "google-chat-takeout",
|
|
2389
|
+
nativeBinding: resolveNativeBinding(),
|
|
2390
|
+
onProgress
|
|
2391
|
+
});
|
|
2392
|
+
return {
|
|
2393
|
+
success: result.success,
|
|
2394
|
+
sessionId: result.sessionId,
|
|
2395
|
+
error: result.error,
|
|
2396
|
+
messageCount: result.diagnostics?.messagesWritten ?? 0,
|
|
2397
|
+
memberCount: 0
|
|
2398
|
+
};
|
|
2399
|
+
});
|
|
2400
|
+
server2.addHook("onClose", async () => {
|
|
2401
|
+
await sourceManager.close();
|
|
2402
|
+
});
|
|
2403
|
+
server2.post("/_web/import-sources", async (request, reply) => {
|
|
2404
|
+
const data = await request.file({
|
|
2405
|
+
limits: { fileSize: ARCHIVE_UPLOAD_LIMIT }
|
|
2406
|
+
});
|
|
2407
|
+
if (!data) return reply.code(400).send({ success: false, error: "error.no_file_selected" });
|
|
2408
|
+
const uploadPath = path7.join(os2.tmpdir(), `chatlab-archive-${randomUUID()}.zip`);
|
|
2409
|
+
try {
|
|
2410
|
+
await pipeline(data.file, fs6.createWriteStream(uploadPath, { flags: "wx" }));
|
|
2411
|
+
if (data.file.truncated) {
|
|
2412
|
+
cleanupTemp(uploadPath);
|
|
2413
|
+
return reply.code(413).send({ success: false, error: "error.archive_limit_exceeded" });
|
|
2414
|
+
}
|
|
2415
|
+
const source = await sourceManager.prepareOwnedArchive(uploadPath);
|
|
2416
|
+
return { success: true, source };
|
|
2417
|
+
} catch (error) {
|
|
2418
|
+
cleanupTemp(uploadPath);
|
|
2419
|
+
if (error instanceof ArchiveImportError) {
|
|
2420
|
+
return reply.code(400).send({ success: false, error: error.code });
|
|
2421
|
+
}
|
|
2422
|
+
return reply.code(400).send({
|
|
2423
|
+
success: false,
|
|
2424
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2425
|
+
});
|
|
2426
|
+
}
|
|
2427
|
+
});
|
|
2428
|
+
server2.post(
|
|
2429
|
+
"/_web/import-sources/:sourceId/import",
|
|
2430
|
+
async (request, reply) => {
|
|
2431
|
+
const chatId = request.body?.chatId;
|
|
2432
|
+
if (!chatId) return reply.code(400).send({ success: false, error: "error.no_chat_selected" });
|
|
2433
|
+
reply.raw.writeHead(200, {
|
|
2434
|
+
"Content-Type": "text/event-stream",
|
|
2435
|
+
"Cache-Control": "no-cache",
|
|
2436
|
+
Connection: "keep-alive"
|
|
2437
|
+
});
|
|
2438
|
+
function sendEvent(event, eventData) {
|
|
2439
|
+
reply.raw.write(`event: ${event}
|
|
2440
|
+
data: ${JSON.stringify(eventData)}
|
|
2441
|
+
|
|
2442
|
+
`);
|
|
2443
|
+
}
|
|
2444
|
+
try {
|
|
2445
|
+
const result = await sourceManager.withMaterializedChat(
|
|
2446
|
+
request.params.sourceId,
|
|
2447
|
+
chatId,
|
|
2448
|
+
(manifestPath) => runPreparedImport(manifestPath, (progress) => sendEvent("progress", progress))
|
|
2449
|
+
);
|
|
2450
|
+
if (result.success) {
|
|
2451
|
+
sendEvent("done", result);
|
|
2452
|
+
} else {
|
|
2453
|
+
sendEvent("error", { success: false, error: result.error || "error.import_failed" });
|
|
2454
|
+
}
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
sendEvent("error", {
|
|
2457
|
+
success: false,
|
|
2458
|
+
error: error instanceof ArchiveImportError ? error.code : error instanceof Error ? error.message : String(error)
|
|
2459
|
+
});
|
|
2460
|
+
} finally {
|
|
2461
|
+
reply.raw.end();
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
);
|
|
2465
|
+
server2.delete("/_web/import-sources/:sourceId", async (request) => {
|
|
2466
|
+
await sourceManager.release(request.params.sourceId);
|
|
2467
|
+
return { success: true };
|
|
2468
|
+
});
|
|
2307
2469
|
server2.get("/_web/supported-formats", async () => {
|
|
2308
2470
|
return getSupportedFormats();
|
|
2309
2471
|
});
|
|
@@ -2668,7 +2830,7 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2668
2830
|
const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
|
|
2669
2831
|
const ai = options?.aiContext;
|
|
2670
2832
|
const cliStreamImport = async (dm, filePath) => {
|
|
2671
|
-
const { streamImport: streamImport2 } = await import("./stream-import-
|
|
2833
|
+
const { streamImport: streamImport2 } = await import("./stream-import-YZMZ56B5.mjs");
|
|
2672
2834
|
const result = await streamImport2(dm, filePath);
|
|
2673
2835
|
if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
|
|
2674
2836
|
return { sessionId: result.sessionId };
|
|
@@ -2719,7 +2881,7 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2719
2881
|
},
|
|
2720
2882
|
ai ? { requireAi: true } : void 0
|
|
2721
2883
|
);
|
|
2722
|
-
|
|
2884
|
+
registerImportRoutes2(server2, dbManager2);
|
|
2723
2885
|
server2.get("/_web/system/check-update", async () => {
|
|
2724
2886
|
const currentVersion = getVersion();
|
|
2725
2887
|
try {
|
|
@@ -2771,7 +2933,7 @@ function registerProxyRoutes(server2) {
|
|
|
2771
2933
|
// src/ai/manager-factory.ts
|
|
2772
2934
|
import * as fs7 from "fs";
|
|
2773
2935
|
import * as path10 from "path";
|
|
2774
|
-
import { createHash, randomUUID } from "crypto";
|
|
2936
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
2775
2937
|
var nodeFs = {
|
|
2776
2938
|
ensureDir(dir) {
|
|
2777
2939
|
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
@@ -2805,7 +2967,7 @@ function getAssistantManager(aiDataDir) {
|
|
|
2805
2967
|
fs: nodeFs,
|
|
2806
2968
|
assistantsDir: path10.join(aiDataDir, "assistants"),
|
|
2807
2969
|
builtinRawConfigs: [],
|
|
2808
|
-
generateId: () => `custom_${
|
|
2970
|
+
generateId: () => `custom_${randomUUID2().replace(/-/g, "").slice(0, 12)}`
|
|
2809
2971
|
}),
|
|
2810
2972
|
skill: new SkillManagerCore({
|
|
2811
2973
|
fs: nodeFs,
|
|
@@ -3170,7 +3332,8 @@ var PullEngine = class {
|
|
|
3170
3332
|
this.logger.info(`[Pull] Skipping "${sess.name}": session no longer exists`);
|
|
3171
3333
|
return { success: true, newMessageCount: 0 };
|
|
3172
3334
|
}
|
|
3173
|
-
|
|
3335
|
+
const importStatusSessionId = sess.targetSessionId || deriveLocalSessionId(ds.baseUrl, sess.remoteSessionId);
|
|
3336
|
+
if (this.isImporting(importStatusSessionId)) {
|
|
3174
3337
|
this.logger.info(`[Pull] Skipping "${sess.name}": import in progress`);
|
|
3175
3338
|
return { success: false, newMessageCount: 0, error: "Import in progress" };
|
|
3176
3339
|
}
|
|
@@ -3587,22 +3750,17 @@ var DirectImporter = class {
|
|
|
3587
3750
|
}
|
|
3588
3751
|
async incrementalImportFile(sessionId, tempFile) {
|
|
3589
3752
|
try {
|
|
3590
|
-
const data = await parseFile(tempFile);
|
|
3591
3753
|
this.dbManager.close(sessionId);
|
|
3592
|
-
const result = await
|
|
3593
|
-
sessionId
|
|
3594
|
-
});
|
|
3754
|
+
const result = await incrementalImport(this.dbManager, sessionId, tempFile);
|
|
3595
3755
|
if (result.success) {
|
|
3756
|
+
const newMessageCount = result.newMessageCount;
|
|
3757
|
+
const duplicateCount = result.batch?.duplicateCount ?? 0;
|
|
3596
3758
|
this.logger.info(
|
|
3597
|
-
`[DirectImporter] Incremental OK: +${
|
|
3759
|
+
`[DirectImporter] Incremental OK: +${newMessageCount} messages (${duplicateCount} duplicates skipped)`
|
|
3598
3760
|
);
|
|
3599
|
-
return {
|
|
3600
|
-
success: true,
|
|
3601
|
-
newMessageCount: result.messageCount,
|
|
3602
|
-
sessionId
|
|
3603
|
-
};
|
|
3761
|
+
return { success: true, newMessageCount, sessionId };
|
|
3604
3762
|
}
|
|
3605
|
-
if (result.error
|
|
3763
|
+
if (result.error === "error.session_not_found" || result.error?.includes("no such table")) {
|
|
3606
3764
|
return { success: false, newMessageCount: 0, sessionId, needFullResync: true };
|
|
3607
3765
|
}
|
|
3608
3766
|
return { success: false, newMessageCount: 0, sessionId, error: result.error };
|
|
@@ -3613,15 +3771,11 @@ var DirectImporter = class {
|
|
|
3613
3771
|
}
|
|
3614
3772
|
async fullImportFile(tempFile, externalId) {
|
|
3615
3773
|
try {
|
|
3616
|
-
const
|
|
3617
|
-
const result = await importData(this.dbManager, data, {
|
|
3618
|
-
sessionId: externalId
|
|
3619
|
-
});
|
|
3774
|
+
const result = await streamImport(this.dbManager, tempFile, { sessionId: externalId });
|
|
3620
3775
|
if (result.success) {
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
return { success: true, newMessageCount: result.messageCount, sessionId: externalId };
|
|
3776
|
+
const newMessageCount = result.diagnostics?.messagesWritten ?? 0;
|
|
3777
|
+
this.logger.info(`[DirectImporter] Full import OK: +${newMessageCount} messages`);
|
|
3778
|
+
return { success: true, newMessageCount, sessionId: result.sessionId ?? externalId };
|
|
3625
3779
|
}
|
|
3626
3780
|
return { success: false, newMessageCount: 0, error: result.error };
|
|
3627
3781
|
} catch (err) {
|
|
@@ -3854,7 +4008,9 @@ async function startHttpServer(options) {
|
|
|
3854
4008
|
if (profileName) deleteAuthProfile(profileName);
|
|
3855
4009
|
}
|
|
3856
4010
|
});
|
|
4011
|
+
initAppLogger(pathProvider.getLogsDir());
|
|
3857
4012
|
initServerAiLogger(pathProvider.getLogsDir());
|
|
4013
|
+
appLogger.info("server", `HTTP server starting on ${host}:${port}`);
|
|
3858
4014
|
setAuthToken(token);
|
|
3859
4015
|
setRequireAuth(!!(options?.requireAuth ?? config.api.require_auth));
|
|
3860
4016
|
server = createServer();
|
|
@@ -3933,4 +4089,4 @@ export {
|
|
|
3933
4089
|
startHttpServer,
|
|
3934
4090
|
stopHttpServer
|
|
3935
4091
|
};
|
|
3936
|
-
//# sourceMappingURL=chunk-
|
|
4092
|
+
//# sourceMappingURL=chunk-AB6TAXTQ.mjs.map
|