chatlab-cli 0.21.1 → 0.22.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.
Files changed (61) hide show
  1. package/README.md +5 -5
  2. package/dist/{chunk-2AIOU3PW.mjs → chunk-6NB475AA.mjs} +12 -3
  3. package/dist/chunk-6NB475AA.mjs.map +1 -0
  4. package/dist/{chunk-OZWXLRJL.mjs → chunk-LZ3W6NS5.mjs} +24 -15
  5. package/dist/chunk-LZ3W6NS5.mjs.map +1 -0
  6. package/dist/{chunk-OQVKZTVD.mjs → chunk-OC2W5Q5T.mjs} +2 -2
  7. package/dist/{chunk-AIR7EAF4.mjs → chunk-QRC3RSER.mjs} +2 -2
  8. package/dist/{chunk-7HQWGLX6.mjs → chunk-SQKT45MM.mjs} +174 -120
  9. package/dist/chunk-SQKT45MM.mjs.map +1 -0
  10. package/dist/chunk-VSOWNKPA.mjs +49 -0
  11. package/dist/{chunk-LI4X52E7.mjs → chunk-XPBPKH6B.mjs} +350 -100
  12. package/dist/chunk-XPBPKH6B.mjs.map +1 -0
  13. package/dist/{chunk-4GI2UPCS.mjs → chunk-Z2LYMKCC.mjs} +2 -2
  14. package/dist/cli.mjs +4 -3
  15. package/dist/{http-DHQI4G5J.mjs → http-O5P4BYXU.mjs} +8 -7
  16. package/dist/{import-CQWGIMZQ.mjs → import-BDLL3DG7.mjs} +5 -4
  17. package/dist/index.mjs +8 -7
  18. package/dist/{mcp-7Q3FEI3Z.mjs → mcp-L2TPZFE7.mjs} +8 -7
  19. package/dist/mcp-L2TPZFE7.mjs.map +1 -0
  20. package/dist/{src-QBT5SYW5.mjs → src-FVJL5ENA.mjs} +3 -2
  21. package/dist/{stream-import-VG7RP6KJ.mjs → stream-import-ZTEW3YVL.mjs} +4 -3
  22. package/dist/stream-import-ZTEW3YVL.mjs.map +1 -0
  23. package/dist/update-checker-MQMQ6A4B.mjs +191 -0
  24. package/dist/update-checker-MQMQ6A4B.mjs.map +1 -0
  25. package/dist-web/assets/{DebugToolsPanel-CoBtqb--.css → DebugToolsPanel-DkbsB6lr.css} +1 -1
  26. package/dist-web/assets/{DebugToolsPanel.vue_vue_type_script_setup_true_lang-CpFGhsl5.js → DebugToolsPanel.vue_vue_type_script_setup_true_lang-CqacsKDU.js} +5 -5
  27. package/dist-web/assets/{EChartWordcloud-BYLFxPAX.js → EChartWordcloud-Ubal_aYg.js} +1 -1
  28. package/dist-web/assets/{MessageExportModal-DTgxz1eQ.js → MessageExportModal-D1GY6WSV.js} +1 -1
  29. package/dist-web/assets/{electron-CTK4NJag.js → electron-CRSL7qPM.js} +1 -1
  30. package/dist-web/assets/{electron-H65bUnhW.js → electron-CsUM2O_Y.js} +1 -1
  31. package/dist-web/assets/{fetch-CTZXLLcn.js → fetch-BOogCPfg.js} +1 -1
  32. package/dist-web/assets/{fetch-C2vUkdnA.js → fetch-CxwnEEqk.js} +1 -1
  33. package/dist-web/assets/index-CM29Kc4p.js +173 -0
  34. package/dist-web/assets/index-D183wYuz.js +7 -0
  35. package/dist-web/assets/{index-DeG0EHOT.js → index-DOwQB7In.js} +1 -1
  36. package/dist-web/assets/index-DSpvXged.css +1 -0
  37. package/dist-web/assets/{index-C4B0hv6C.js → index-DTxRy2FH.js} +4 -4
  38. package/dist-web/assets/{index-DuhN8jAf.js → index-grds3iG-.js} +2 -2
  39. package/dist-web/assets/logo-DXIuG_WE.svg +17 -0
  40. package/dist-web/assets/{vendor-echarts-C13vDgZW.js → vendor-echarts-C5u62NnM.js} +1 -1
  41. package/dist-web/assets/{vendor-echarts-wordcloud-uVdwYsYa.js → vendor-echarts-wordcloud-CZ9gsX8l.js} +1 -1
  42. package/dist-web/assets/{vendor-nuxt-ui-CYMNNdeD.js → vendor-nuxt-ui-7OAuiz_i.js} +1 -1
  43. package/dist-web/assets/{vendor-zrender-5DcYjSZk.js → vendor-zrender-DFl4U2Oe.js} +1 -1
  44. package/dist-web/assets/{web-DImo6Kjz.js → web-Cx5APyCN.js} +1 -1
  45. package/dist-web/index.html +3 -3
  46. package/package.json +4 -3
  47. package/dist/chunk-2AIOU3PW.mjs.map +0 -1
  48. package/dist/chunk-7HQWGLX6.mjs.map +0 -1
  49. package/dist/chunk-LI4X52E7.mjs.map +0 -1
  50. package/dist/chunk-OZWXLRJL.mjs.map +0 -1
  51. package/dist/mcp-7Q3FEI3Z.mjs.map +0 -1
  52. package/dist-web/assets/index-B8867dX7.css +0 -1
  53. package/dist-web/assets/index-DUXf21MT.js +0 -173
  54. package/dist-web/assets/index-DZiH2cC1.js +0 -7
  55. /package/dist/{chunk-OQVKZTVD.mjs.map → chunk-OC2W5Q5T.mjs.map} +0 -0
  56. /package/dist/{chunk-AIR7EAF4.mjs.map → chunk-QRC3RSER.mjs.map} +0 -0
  57. /package/dist/{http-DHQI4G5J.mjs.map → chunk-VSOWNKPA.mjs.map} +0 -0
  58. /package/dist/{chunk-4GI2UPCS.mjs.map → chunk-Z2LYMKCC.mjs.map} +0 -0
  59. /package/dist/{import-CQWGIMZQ.mjs.map → http-O5P4BYXU.mjs.map} +0 -0
  60. /package/dist/{src-QBT5SYW5.mjs.map → import-BDLL3DG7.mjs.map} +0 -0
  61. /package/dist/{stream-import-VG7RP6KJ.mjs.map → src-FVJL5ENA.mjs.map} +0 -0
@@ -7,20 +7,21 @@ const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  importData,
9
9
  parseFile
10
- } from "./chunk-OQVKZTVD.mjs";
10
+ } from "./chunk-OC2W5Q5T.mjs";
11
11
  import {
12
12
  analyzeIncrementalImport,
13
13
  analyzeNewImport,
14
14
  incrementalImport,
15
15
  streamImport
16
- } from "./chunk-AIR7EAF4.mjs";
16
+ } from "./chunk-QRC3RSER.mjs";
17
17
  import {
18
18
  AGENT_TOOL_REGISTRY,
19
19
  CoreDataProvider
20
- } from "./chunk-4GI2UPCS.mjs";
20
+ } from "./chunk-Z2LYMKCC.mjs";
21
21
  import {
22
- getVersion
23
- } from "./chunk-2AIOU3PW.mjs";
22
+ getVersion,
23
+ resolveCliPath
24
+ } from "./chunk-6NB475AA.mjs";
24
25
  import {
25
26
  AIConversationManager,
26
27
  ALL_MIGRATIONS,
@@ -114,11 +115,10 @@ import {
114
115
  verifyCliDataPath,
115
116
  writeAuthProfile,
116
117
  writeConfigField
117
- } from "./chunk-7HQWGLX6.mjs";
118
+ } from "./chunk-SQKT45MM.mjs";
118
119
 
119
120
  // src/http/index.ts
120
121
  import * as fs14 from "fs";
121
- import * as path15 from "path";
122
122
  import * as crypto5 from "crypto";
123
123
 
124
124
  // src/http/server.ts
@@ -207,6 +207,10 @@ async function authHook(request, reply) {
207
207
  if (!cachedToken) return;
208
208
  if (request.url.startsWith("/_web/")) return;
209
209
  if (webModeEnabled && !request.url.startsWith("/api/")) return;
210
+ return requireBearerToken(request, reply);
211
+ }
212
+ function requireBearerToken(request, reply) {
213
+ if (!cachedToken) return;
210
214
  const authHeader = request.headers.authorization;
211
215
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
212
216
  const err = unauthorized();
@@ -492,7 +496,7 @@ function registerSessionRoutes(server2, dbManager2) {
492
496
 
493
497
  // src/http/routes/web/index.ts
494
498
  import * as os3 from "os";
495
- import * as path7 from "path";
499
+ import * as path6 from "path";
496
500
 
497
501
  // src/merger/merge-cache.ts
498
502
  import * as fs from "fs";
@@ -653,7 +657,6 @@ function registerMemberRoutes(server2, adapter) {
653
657
 
654
658
  // src/http/routes/web/helpers.ts
655
659
  import * as fs2 from "fs";
656
- import * as path2 from "path";
657
660
  function parseTimeFilter(query) {
658
661
  const { startTs, endTs, memberId } = query;
659
662
  if (!startTs && !endTs && !memberId) return void 0;
@@ -665,7 +668,7 @@ function parseTimeFilter(query) {
665
668
  }
666
669
  function resolveNativeBinding() {
667
670
  if (process.versions.electron) return void 0;
668
- const nativePath = path2.resolve(__dirname, "../../../../native/better_sqlite3.node");
671
+ const nativePath = resolveCliPath("native/better_sqlite3.node");
669
672
  if (fs2.existsSync(nativePath)) return nativePath;
670
673
  return void 0;
671
674
  }
@@ -879,10 +882,10 @@ function registerSessionIndexRoutes(server2, adapter) {
879
882
 
880
883
  // src/ai/llm-config.ts
881
884
  import * as fs3 from "fs";
882
- import * as path3 from "path";
885
+ import * as path2 from "path";
883
886
  import { randomUUID as randomUUID2 } from "crypto";
884
887
  function loadLlmConfig(aiDataDir) {
885
- const configPath = path3.join(aiDataDir, "llm-config.json");
888
+ const configPath = path2.join(aiDataDir, "llm-config.json");
886
889
  if (!fs3.existsSync(configPath)) {
887
890
  return { configs: [], defaultAssistant: null, fastModel: null };
888
891
  }
@@ -924,7 +927,7 @@ function getDefaultAssistantConfig(aiDataDir) {
924
927
  }
925
928
  var MAX_CONFIG_COUNT = 99;
926
929
  function saveLlmConfig(aiDataDir, store) {
927
- const configPath = path3.join(aiDataDir, "llm-config.json");
930
+ const configPath = path2.join(aiDataDir, "llm-config.json");
928
931
  const toSave = {
929
932
  ...store,
930
933
  configs: store.configs.map((c) => {
@@ -1028,7 +1031,7 @@ function setFastModelSlot(aiDataDir, slot) {
1028
1031
  return { success: true };
1029
1032
  }
1030
1033
  function loadRawConfigStore(aiDataDir) {
1031
- const configPath = path3.join(aiDataDir, "llm-config.json");
1034
+ const configPath = path2.join(aiDataDir, "llm-config.json");
1032
1035
  if (!fs3.existsSync(configPath)) {
1033
1036
  return { configs: [], defaultAssistant: null, fastModel: null };
1034
1037
  }
@@ -1062,10 +1065,11 @@ function createSummaryDeps(dbManager2) {
1062
1065
  function registerSummaryRoutes(server2, dbManager2, adapter) {
1063
1066
  const deps = createSummaryDeps(dbManager2);
1064
1067
  server2.post("/_web/sessions/:id/summaries/generate", async (request, reply) => {
1065
- const { chatSessionId, locale, forceRegenerate } = request.body;
1068
+ const { chatSessionId, locale, forceRegenerate, strategy } = request.body;
1066
1069
  const result = await summary_service_exports.generateSummary(adapter, request.params.id, chatSessionId, deps, {
1067
1070
  locale,
1068
- forceRegenerate
1071
+ forceRegenerate,
1072
+ strategy
1069
1073
  });
1070
1074
  if ("error" in result && !result.success) {
1071
1075
  return reply.code(400).send({ error: result.error });
@@ -1083,18 +1087,22 @@ function registerSummaryRoutes(server2, dbManager2, adapter) {
1083
1087
  }
1084
1088
  return result;
1085
1089
  });
1090
+ server2.post("/_web/sessions/:id/summaries/check-can-generate", async (request) => {
1091
+ const { chatSessionIds } = request.body;
1092
+ return summary_service_exports.checkCanGenerate(adapter, request.params.id, chatSessionIds);
1093
+ });
1086
1094
  }
1087
1095
 
1088
1096
  // src/http/routes/web/import.ts
1089
1097
  import * as fs4 from "fs";
1090
1098
  import * as os from "os";
1091
- import * as path4 from "path";
1099
+ import * as path3 from "path";
1092
1100
  var DEMO_BASE_URL = "https://chatlab.fun/assets/demo";
1093
1101
  function cleanupTemp(...paths) {
1094
1102
  for (const p of paths) {
1095
1103
  try {
1096
- const stat = fs4.statSync(p);
1097
- if (stat.isDirectory()) {
1104
+ const stat2 = fs4.statSync(p);
1105
+ if (stat2.isDirectory()) {
1098
1106
  fs4.rmSync(p, { recursive: true, force: true });
1099
1107
  } else {
1100
1108
  fs4.unlinkSync(p);
@@ -1110,8 +1118,8 @@ function registerImportRoutes(server2, dbManager2) {
1110
1118
  server2.post("/_web/detect-format", async (request, reply) => {
1111
1119
  const data = await request.file();
1112
1120
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1113
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-detect-"));
1114
- const tmpPath = path4.join(tmpDir, data.filename || "upload");
1121
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-detect-"));
1122
+ const tmpPath = path3.join(tmpDir, data.filename || "upload");
1115
1123
  try {
1116
1124
  const chunks = [];
1117
1125
  for await (const chunk of data.file) {
@@ -1128,8 +1136,8 @@ function registerImportRoutes(server2, dbManager2) {
1128
1136
  server2.post("/_web/scan-multi-chat", async (request, reply) => {
1129
1137
  const data = await request.file();
1130
1138
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1131
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-scan-"));
1132
- const tmpPath = path4.join(tmpDir, data.filename || "upload");
1139
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-scan-"));
1140
+ const tmpPath = path3.join(tmpDir, data.filename || "upload");
1133
1141
  try {
1134
1142
  const chunks = [];
1135
1143
  for await (const chunk of data.file) {
@@ -1145,8 +1153,8 @@ function registerImportRoutes(server2, dbManager2) {
1145
1153
  server2.post("/_web/import", async (request, reply) => {
1146
1154
  const data = await request.file();
1147
1155
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1148
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-import-"));
1149
- const tmpPath = path4.join(tmpDir, data.filename || "upload");
1156
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-import-"));
1157
+ const tmpPath = path3.join(tmpDir, data.filename || "upload");
1150
1158
  const chunks = [];
1151
1159
  for await (const chunk of data.file) {
1152
1160
  chunks.push(chunk);
@@ -1194,7 +1202,7 @@ data: ${JSON.stringify(eventData)}
1194
1202
  server2.post("/_web/import-directory", async (request, reply) => {
1195
1203
  const parts = request.parts();
1196
1204
  if (!parts) return reply.code(400).send({ error: "No files uploaded" });
1197
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-dir-import-"));
1205
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-dir-import-"));
1198
1206
  const relativePaths = [];
1199
1207
  const fileBuffers = [];
1200
1208
  try {
@@ -1222,9 +1230,9 @@ data: ${JSON.stringify(eventData)}
1222
1230
  if (segments.length > 1) {
1223
1231
  relPath = segments.slice(1).join("/");
1224
1232
  }
1225
- const targetPath = path4.resolve(tmpDir, relPath);
1226
- if (!targetPath.startsWith(tmpDir + path4.sep)) continue;
1227
- fs4.mkdirSync(path4.dirname(targetPath), { recursive: true });
1233
+ const targetPath = path3.resolve(tmpDir, relPath);
1234
+ if (!targetPath.startsWith(tmpDir + path3.sep)) continue;
1235
+ fs4.mkdirSync(path3.dirname(targetPath), { recursive: true });
1228
1236
  fs4.writeFileSync(targetPath, fileBuffers[i].data);
1229
1237
  }
1230
1238
  const entryPath = findEntryFileInDirectory(tmpDir);
@@ -1270,8 +1278,8 @@ data: ${JSON.stringify({ success: false, error: err instanceof Error ? err.messa
1270
1278
  const sessionId = request.params.id;
1271
1279
  const data = await request.file();
1272
1280
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1273
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-inc-"));
1274
- const tmpPath = path4.join(tmpDir, data.filename || "upload");
1281
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-inc-"));
1282
+ const tmpPath = path3.join(tmpDir, data.filename || "upload");
1275
1283
  const chunks = [];
1276
1284
  for await (const chunk of data.file) {
1277
1285
  chunks.push(chunk);
@@ -1308,8 +1316,8 @@ data: ${JSON.stringify(eventData)}
1308
1316
  const sessionId = request.params.id;
1309
1317
  const data = await request.file();
1310
1318
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1311
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-analyze-"));
1312
- const tmpPath = path4.join(tmpDir, data.filename || "upload");
1319
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-analyze-"));
1320
+ const tmpPath = path3.join(tmpDir, data.filename || "upload");
1313
1321
  const chunks = [];
1314
1322
  for await (const chunk of data.file) {
1315
1323
  chunks.push(chunk);
@@ -1326,8 +1334,8 @@ data: ${JSON.stringify(eventData)}
1326
1334
  server2.post("/_web/import/analyze", async (request, reply) => {
1327
1335
  const data = await request.file();
1328
1336
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1329
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-analyze-"));
1330
- const tmpPath = path4.join(tmpDir, data.filename || "upload");
1337
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-analyze-"));
1338
+ const tmpPath = path3.join(tmpDir, data.filename || "upload");
1331
1339
  const chunks = [];
1332
1340
  for await (const chunk of data.file) {
1333
1341
  chunks.push(chunk);
@@ -1355,9 +1363,9 @@ data: ${JSON.stringify(eventData)}
1355
1363
 
1356
1364
  `);
1357
1365
  }
1358
- const tmpDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "chatlab-demo-"));
1359
- const groupPath = path4.join(tmpDir, "demo-group.json");
1360
- const privatePath = path4.join(tmpDir, "demo-private.json");
1366
+ const tmpDir = fs4.mkdtempSync(path3.join(os.tmpdir(), "chatlab-demo-"));
1367
+ const groupPath = path3.join(tmpDir, "demo-group.json");
1368
+ const privatePath = path3.join(tmpDir, "demo-private.json");
1361
1369
  try {
1362
1370
  sendEvent("progress", { stage: "downloading", current: 1, total: 2 });
1363
1371
  const groupResp = await fetch(`${DEMO_BASE_URL}/${locale}/demo-group.json`, {
@@ -1397,13 +1405,13 @@ data: ${JSON.stringify(eventData)}
1397
1405
  // src/http/routes/web/merge.ts
1398
1406
  import * as fs5 from "fs";
1399
1407
  import * as os2 from "os";
1400
- import * as path5 from "path";
1408
+ import * as path4 from "path";
1401
1409
  function registerMergeRoutes(server2, dbManager2, mergeCache) {
1402
1410
  server2.post("/_web/merge/parse", async (request, reply) => {
1403
1411
  const data = await request.file();
1404
1412
  if (!data) return reply.code(400).send({ error: "No file uploaded" });
1405
- const tmpDir = fs5.mkdtempSync(path5.join(os2.tmpdir(), "chatlab-merge-"));
1406
- const tmpPath = path5.join(tmpDir, data.filename || "upload");
1413
+ const tmpDir = fs5.mkdtempSync(path4.join(os2.tmpdir(), "chatlab-merge-"));
1414
+ const tmpPath = path4.join(tmpDir, data.filename || "upload");
1407
1415
  const chunks = [];
1408
1416
  for await (const chunk of data.file) {
1409
1417
  chunks.push(chunk);
@@ -1412,7 +1420,7 @@ function registerMergeRoutes(server2, dbManager2, mergeCache) {
1412
1420
  try {
1413
1421
  const result = await streamParseFileInfo(tmpPath, {
1414
1422
  createTempDatabase(sourceFilePath) {
1415
- return mergeCache.createTempDatabase(path5.basename(sourceFilePath));
1423
+ return mergeCache.createTempDatabase(path4.basename(sourceFilePath));
1416
1424
  },
1417
1425
  onProgress() {
1418
1426
  }
@@ -1477,10 +1485,10 @@ function registerMergeRoutes(server2, dbManager2, mergeCache) {
1477
1485
  const merged = buildMergedOutput(dataSources, outputName);
1478
1486
  let sessionId;
1479
1487
  if (andImport) {
1480
- const { streamImport: serverStreamImport } = await import("./stream-import-VG7RP6KJ.mjs");
1488
+ const { streamImport: serverStreamImport } = await import("./stream-import-ZTEW3YVL.mjs");
1481
1489
  const jsonData = JSON.stringify(merged.chatLabData);
1482
- const tmpDir = fs5.mkdtempSync(path5.join(os2.tmpdir(), "chatlab-merged-"));
1483
- const tmpPath = path5.join(tmpDir, `${outputName}.json`);
1490
+ const tmpDir = fs5.mkdtempSync(path4.join(os2.tmpdir(), "chatlab-merged-"));
1491
+ const tmpPath = path4.join(tmpDir, `${outputName}.json`);
1484
1492
  fs5.writeFileSync(tmpPath, jsonData, "utf-8");
1485
1493
  try {
1486
1494
  const importResult = await serverStreamImport(dbManager2, tmpPath);
@@ -1530,7 +1538,7 @@ function registerMergeRoutes(server2, dbManager2, mergeCache) {
1530
1538
  const db = ensureDb2(dbManager2, sid);
1531
1539
  const exported = exportSessionToJson(db);
1532
1540
  const { db: tempDb, tempDbPath } = mergeCache.createTempDatabase(exported.meta.name);
1533
- const { TempDbWriter } = await import("./src-QBT5SYW5.mjs");
1541
+ const { TempDbWriter } = await import("./src-FVJL5ENA.mjs");
1534
1542
  const writer = new TempDbWriter(tempDb);
1535
1543
  writer.writeMeta({
1536
1544
  name: exported.meta.name,
@@ -1592,8 +1600,192 @@ function registerExportRoutes(server2, adapter) {
1592
1600
 
1593
1601
  // src/http/routes/web/cache.ts
1594
1602
  import * as fs6 from "fs";
1595
- import * as path6 from "path";
1596
- function registerCacheRoutes(server2, downloadsDir) {
1603
+ import * as fsp from "fs/promises";
1604
+ import * as path5 from "path";
1605
+ import { execFile } from "child_process";
1606
+ function runExecFile(file, args, runner = execFile) {
1607
+ return new Promise((resolve2, reject) => {
1608
+ runner(file, args, (error) => {
1609
+ if (error) {
1610
+ reject(error);
1611
+ return;
1612
+ }
1613
+ resolve2();
1614
+ });
1615
+ });
1616
+ }
1617
+ async function openDirectoryPath(dirPath, platform = process.platform, runner) {
1618
+ if (platform === "darwin") {
1619
+ await runExecFile("open", [dirPath], runner);
1620
+ } else if (platform === "win32") {
1621
+ await runExecFile("explorer.exe", [dirPath], runner);
1622
+ } else {
1623
+ await runExecFile("xdg-open", [dirPath], runner);
1624
+ }
1625
+ }
1626
+ async function showPathInFolder(filePath, platform = process.platform, runner) {
1627
+ if (platform === "darwin") {
1628
+ await runExecFile("open", ["-R", filePath], runner);
1629
+ } else if (platform === "win32") {
1630
+ await runExecFile("explorer.exe", [`/select,${filePath}`], runner);
1631
+ } else {
1632
+ await runExecFile("xdg-open", [path5.dirname(filePath)], runner);
1633
+ }
1634
+ }
1635
+ async function getDirSize(dirPath) {
1636
+ let totalSize = 0;
1637
+ try {
1638
+ if (!fs6.existsSync(dirPath)) return 0;
1639
+ const files = await fsp.readdir(dirPath, { withFileTypes: true });
1640
+ for (const file of files) {
1641
+ const filePath = path5.join(dirPath, file.name);
1642
+ if (file.isDirectory()) {
1643
+ totalSize += await getDirSize(filePath);
1644
+ } else {
1645
+ const stat2 = await fsp.stat(filePath);
1646
+ totalSize += stat2.size;
1647
+ }
1648
+ }
1649
+ } catch {
1650
+ }
1651
+ return totalSize;
1652
+ }
1653
+ async function getFileCount(dirPath) {
1654
+ let count = 0;
1655
+ try {
1656
+ if (!fs6.existsSync(dirPath)) return 0;
1657
+ const files = await fsp.readdir(dirPath, { withFileTypes: true });
1658
+ for (const file of files) {
1659
+ const filePath = path5.join(dirPath, file.name);
1660
+ if (file.isDirectory()) {
1661
+ count += await getFileCount(filePath);
1662
+ } else {
1663
+ count++;
1664
+ }
1665
+ }
1666
+ } catch {
1667
+ }
1668
+ return count;
1669
+ }
1670
+ function registerCacheRoutes(server2, pathProvider) {
1671
+ const downloadsDir = pathProvider.getDownloadsDir();
1672
+ server2.get("/_web/cache/info", async () => {
1673
+ const directories = [
1674
+ {
1675
+ id: "databases",
1676
+ name: "settings.storage.cache.databases.name",
1677
+ description: "settings.storage.cache.databases.description",
1678
+ path: pathProvider.getDatabaseDir(),
1679
+ icon: "i-heroicons-circle-stack",
1680
+ canClear: false
1681
+ },
1682
+ {
1683
+ id: "ai",
1684
+ name: "settings.storage.cache.ai.name",
1685
+ description: "settings.storage.cache.ai.description",
1686
+ path: pathProvider.getAiDataDir(),
1687
+ icon: "i-heroicons-sparkles",
1688
+ canClear: false
1689
+ },
1690
+ {
1691
+ id: "cache",
1692
+ name: "settings.storage.cache.statsCache.name",
1693
+ description: "settings.storage.cache.statsCache.description",
1694
+ path: pathProvider.getCacheDir(),
1695
+ icon: "i-heroicons-bolt",
1696
+ canClear: true
1697
+ },
1698
+ {
1699
+ id: "logs",
1700
+ name: "settings.storage.cache.logs.name",
1701
+ description: "settings.storage.cache.logs.description",
1702
+ path: pathProvider.getLogsDir(),
1703
+ icon: "i-heroicons-document-text",
1704
+ canClear: true
1705
+ }
1706
+ ];
1707
+ const results = await Promise.all(
1708
+ directories.map(async (dir) => {
1709
+ const [size, fileCount] = await Promise.all([getDirSize(dir.path), getFileCount(dir.path)]);
1710
+ return { ...dir, size, fileCount, exists: fs6.existsSync(dir.path) };
1711
+ })
1712
+ );
1713
+ return {
1714
+ baseDir: pathProvider.getUserDataDir(),
1715
+ systemDir: pathProvider.getSystemDir(),
1716
+ directories: results,
1717
+ totalSize: results.reduce((sum, d) => sum + d.size, 0)
1718
+ };
1719
+ });
1720
+ server2.post("/_web/cache/clear", async (request) => {
1721
+ const { cacheId } = request.body;
1722
+ const allowedDirs = {
1723
+ cache: pathProvider.getCacheDir(),
1724
+ logs: pathProvider.getLogsDir()
1725
+ };
1726
+ const dirPath = allowedDirs[cacheId];
1727
+ if (!dirPath) return { success: false, error: "Not allowed to clear this directory" };
1728
+ if (!fs6.existsSync(dirPath)) return { success: true };
1729
+ const files = await fsp.readdir(dirPath);
1730
+ for (const file of files) {
1731
+ const filePath = path5.join(dirPath, file);
1732
+ const stat2 = await fsp.stat(filePath);
1733
+ if (stat2.isDirectory()) {
1734
+ await fsp.rm(filePath, { recursive: true });
1735
+ } else {
1736
+ await fsp.unlink(filePath);
1737
+ }
1738
+ }
1739
+ return { success: true };
1740
+ });
1741
+ server2.post("/_web/cache/open-dir", async (request) => {
1742
+ const { cacheId } = request.body;
1743
+ const dirPaths = {
1744
+ base: pathProvider.getUserDataDir(),
1745
+ system: pathProvider.getSystemDir(),
1746
+ databases: pathProvider.getDatabaseDir(),
1747
+ cache: pathProvider.getCacheDir(),
1748
+ ai: pathProvider.getAiDataDir(),
1749
+ logs: pathProvider.getLogsDir(),
1750
+ downloads: downloadsDir
1751
+ };
1752
+ const dirPath = dirPaths[cacheId];
1753
+ if (!dirPath) return { success: false, error: "Unknown directory" };
1754
+ if (!fs6.existsSync(dirPath)) {
1755
+ await fsp.mkdir(dirPath, { recursive: true });
1756
+ }
1757
+ try {
1758
+ await openDirectoryPath(dirPath);
1759
+ } catch (error) {
1760
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
1761
+ }
1762
+ return { success: true };
1763
+ });
1764
+ server2.get("/_web/cache/data-dir", async () => {
1765
+ const config = loadConfig();
1766
+ const isCustom = Boolean(config.data.user_data_dir || process.env.CHATLAB_DATA_DIR);
1767
+ return { path: pathProvider.getUserDataDir(), isCustom };
1768
+ });
1769
+ server2.get("/_web/cache/latest-import-log", async () => {
1770
+ const importLogDir = path5.join(pathProvider.getLogsDir(), "import");
1771
+ if (!fs6.existsSync(importLogDir)) {
1772
+ return { success: false, error: "Log directory not found" };
1773
+ }
1774
+ const files = await fsp.readdir(importLogDir);
1775
+ const logFiles = files.filter((f) => f.startsWith("import_") && f.endsWith(".log"));
1776
+ if (logFiles.length === 0) {
1777
+ return { success: false, error: "No import logs found" };
1778
+ }
1779
+ const fileStats = await Promise.all(
1780
+ logFiles.map(async (f) => {
1781
+ const filePath = path5.join(importLogDir, f);
1782
+ const stat2 = await fsp.stat(filePath);
1783
+ return { name: f, path: filePath, mtime: stat2.mtime.getTime() };
1784
+ })
1785
+ );
1786
+ fileStats.sort((a, b) => b.mtime - a.mtime);
1787
+ return { success: true, path: fileStats[0].path, name: fileStats[0].name };
1788
+ });
1597
1789
  server2.post("/_web/cache/save-to-downloads", async (request) => {
1598
1790
  const { filename, dataUrl } = request.body;
1599
1791
  if (!filename || !dataUrl) {
@@ -1605,7 +1797,7 @@ function registerCacheRoutes(server2, downloadsDir) {
1605
1797
  if (!fs6.existsSync(downloadsDir)) {
1606
1798
  fs6.mkdirSync(downloadsDir, { recursive: true });
1607
1799
  }
1608
- const filePath = path6.join(downloadsDir, filename);
1800
+ const filePath = path5.join(downloadsDir, filename);
1609
1801
  fs6.writeFileSync(filePath, buffer);
1610
1802
  return { success: true, filePath };
1611
1803
  });
@@ -1614,26 +1806,46 @@ function registerCacheRoutes(server2, downloadsDir) {
1614
1806
  if (!filePath) {
1615
1807
  return { success: false, error: "filePath is required" };
1616
1808
  }
1617
- const { exec } = await import("child_process");
1618
- const platform = process.platform;
1619
- const dir = path6.dirname(filePath);
1620
- if (platform === "darwin") {
1621
- exec(`open -R "${filePath}"`);
1622
- } else if (platform === "win32") {
1623
- exec(`explorer /select,"${filePath}"`);
1624
- } else {
1625
- exec(`xdg-open "${dir}"`);
1809
+ try {
1810
+ await showPathInFolder(filePath);
1811
+ } catch (error) {
1812
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
1626
1813
  }
1627
1814
  return { success: true };
1628
1815
  });
1629
1816
  }
1630
1817
 
1631
1818
  // src/http/routes/web/index.ts
1819
+ function isNewerVersion(latest, current) {
1820
+ const parse = (v) => {
1821
+ const [core, pre] = v.split("-", 2);
1822
+ const parts = core.split(".").map(Number);
1823
+ return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0, pre };
1824
+ };
1825
+ const l = parse(latest);
1826
+ const c = parse(current);
1827
+ if (l.major !== c.major) return l.major > c.major;
1828
+ if (l.minor !== c.minor) return l.minor > c.minor;
1829
+ if (l.patch !== c.patch) return l.patch > c.patch;
1830
+ if (c.pre && !l.pre) return true;
1831
+ return false;
1832
+ }
1632
1833
  function registerWebRoutes(server2, dbManager2, options) {
1633
1834
  const adapter = createDatabaseManagerAdapter(dbManager2);
1634
1835
  const mergeCache = options?.pathProvider ? new MergeSessionCache(options.pathProvider, { nativeBinding: options.nativeBinding }) : null;
1635
1836
  mergeCache?.cleanupOrphans();
1636
- const downloadsDir = options?.pathProvider?.getDownloadsDir() || path7.join(os3.homedir(), "Downloads");
1837
+ const fallbackPathProvider = {
1838
+ getSystemDir: () => path6.join(os3.homedir(), ".chatlab"),
1839
+ getUserDataDir: () => path6.join(os3.homedir(), ".chatlab", "data"),
1840
+ getDatabaseDir: () => path6.join(os3.homedir(), ".chatlab", "data", "databases"),
1841
+ getAiDataDir: () => path6.join(os3.homedir(), ".chatlab", "ai"),
1842
+ getSettingsDir: () => path6.join(os3.homedir(), ".chatlab", "settings"),
1843
+ getCacheDir: () => path6.join(os3.homedir(), ".chatlab", "cache"),
1844
+ getTempDir: () => path6.join(os3.homedir(), ".chatlab", "temp"),
1845
+ getLogsDir: () => path6.join(os3.homedir(), ".chatlab", "logs"),
1846
+ getDownloadsDir: () => path6.join(os3.homedir(), "Downloads")
1847
+ };
1848
+ const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
1637
1849
  registerSessionRoutes2(server2, adapter);
1638
1850
  registerMemberRoutes(server2, adapter);
1639
1851
  registerAnalyticsRoutes(server2, dbManager2, adapter);
@@ -1645,11 +1857,34 @@ function registerWebRoutes(server2, dbManager2, options) {
1645
1857
  registerMergeRoutes(server2, dbManager2, mergeCache);
1646
1858
  }
1647
1859
  registerExportRoutes(server2, adapter);
1648
- registerCacheRoutes(server2, downloadsDir);
1860
+ registerCacheRoutes(server2, resolvedPathProvider);
1861
+ server2.get("/_web/system/check-update", async () => {
1862
+ const currentVersion = getVersion();
1863
+ const packageName = "chatlab-cli";
1864
+ try {
1865
+ const resp = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
1866
+ headers: { Accept: "application/json" },
1867
+ signal: AbortSignal.timeout(1e4)
1868
+ });
1869
+ if (!resp.ok) {
1870
+ return { hasUpdate: false, currentVersion, error: `npm registry HTTP ${resp.status}` };
1871
+ }
1872
+ const data = await resp.json();
1873
+ const latestVersion = data.version || currentVersion;
1874
+ const hasUpdate = isNewerVersion(latestVersion, currentVersion);
1875
+ return { hasUpdate, currentVersion, latestVersion };
1876
+ } catch (err) {
1877
+ return {
1878
+ hasUpdate: false,
1879
+ currentVersion,
1880
+ error: err instanceof Error ? err.message : String(err)
1881
+ };
1882
+ }
1883
+ });
1649
1884
  }
1650
1885
 
1651
1886
  // src/http/routes/nlp.ts
1652
- import * as path8 from "path";
1887
+ import * as path7 from "path";
1653
1888
  function ensureDb3(dbManager2, sessionId) {
1654
1889
  const db = dbManager2.open(sessionId);
1655
1890
  if (!db) {
@@ -1660,7 +1895,7 @@ function ensureDb3(dbManager2, sessionId) {
1660
1895
  function registerNlpRoutes(server2, dbManager2) {
1661
1896
  const pathProvider = dbManager2["pathProvider"];
1662
1897
  if (pathProvider) {
1663
- const nlpDir = path8.join(pathProvider.getUserDataDir(), "nlp");
1898
+ const nlpDir = path7.join(pathProvider.getSystemDir(), "nlp");
1664
1899
  initNlpDir(nlpDir);
1665
1900
  ensureDefaultDict(nlpDir).catch((err) => console.warn("[NLP] Auto-download zh-CN dict failed:", err));
1666
1901
  }
@@ -1698,12 +1933,12 @@ function registerNlpRoutes(server2, dbManager2) {
1698
1933
  }
1699
1934
  function resolveNlpDir(dbManager2) {
1700
1935
  const pathProvider = dbManager2["pathProvider"];
1701
- return path8.join(pathProvider.getUserDataDir(), "nlp");
1936
+ return path7.join(pathProvider.getSystemDir(), "nlp");
1702
1937
  }
1703
1938
 
1704
1939
  // src/http/routes/ai.ts
1705
1940
  import * as fs10 from "fs";
1706
- import * as path12 from "path";
1941
+ import * as path11 from "path";
1707
1942
 
1708
1943
  // src/ai/logger.ts
1709
1944
  var logger = null;
@@ -1752,6 +1987,7 @@ function adaptToolsForAgent(tools, getContext, options) {
1752
1987
  description: tool.description,
1753
1988
  parameters: convertJsonSchemaToParameters(tool.inputSchema),
1754
1989
  async execute(_toolCallId, params) {
1990
+ const toolParams = params && typeof params === "object" ? params : {};
1755
1991
  const ctx = getContext();
1756
1992
  const execCtx = {
1757
1993
  db: ctx.db,
@@ -1761,7 +1997,7 @@ function adaptToolsForAgent(tools, getContext, options) {
1761
1997
  segmentText: (texts, locale, options2) => batchSegmentWithFrequency(texts, locale, options2)
1762
1998
  };
1763
1999
  try {
1764
- const result = await tool.handler(params, execCtx);
2000
+ const result = await tool.handler(toolParams, execCtx);
1765
2001
  if (result.rawMessages && result.rawMessages.length > 0) {
1766
2002
  const pipelineResult = applyPreprocessingPipeline({
1767
2003
  rawMessages: result.rawMessages,
@@ -1784,9 +2020,9 @@ function adaptToolsForAgent(tools, getContext, options) {
1784
2020
 
1785
2021
  // src/ai/assistant-loader.ts
1786
2022
  import * as fs7 from "fs";
1787
- import * as path9 from "path";
2023
+ import * as path8 from "path";
1788
2024
  function loadAssistantConfig(aiDataDir, assistantId) {
1789
- const filePath = path9.join(aiDataDir, "assistants", `${assistantId}.md`);
2025
+ const filePath = path8.join(aiDataDir, "assistants", `${assistantId}.md`);
1790
2026
  if (!fs7.existsSync(filePath)) return null;
1791
2027
  try {
1792
2028
  const content = fs7.readFileSync(filePath, "utf-8");
@@ -1798,7 +2034,7 @@ function loadAssistantConfig(aiDataDir, assistantId) {
1798
2034
 
1799
2035
  // src/ai/manager-factory.ts
1800
2036
  import * as fs8 from "fs";
1801
- import * as path10 from "path";
2037
+ import * as path9 from "path";
1802
2038
  import { createHash, randomUUID as randomUUID3 } from "crypto";
1803
2039
  var nodeFs = {
1804
2040
  ensureDir(dir) {
@@ -1821,7 +2057,7 @@ var nodeFs = {
1821
2057
  return fs8.existsSync(filePath);
1822
2058
  },
1823
2059
  joinPath(...parts) {
1824
- return path10.join(...parts);
2060
+ return path9.join(...parts);
1825
2061
  }
1826
2062
  };
1827
2063
  var managerCache = /* @__PURE__ */ new Map();
@@ -1831,13 +2067,13 @@ function getAssistantManager(aiDataDir) {
1831
2067
  cached = {
1832
2068
  assistant: new AssistantManager({
1833
2069
  fs: nodeFs,
1834
- assistantsDir: path10.join(aiDataDir, "assistants"),
2070
+ assistantsDir: path9.join(aiDataDir, "assistants"),
1835
2071
  builtinRawConfigs: [],
1836
2072
  generateId: () => `custom_${randomUUID3().replace(/-/g, "").slice(0, 12)}`
1837
2073
  }),
1838
2074
  skill: new SkillManagerCore({
1839
2075
  fs: nodeFs,
1840
- skillsDir: path10.join(aiDataDir, "skills"),
2076
+ skillsDir: path9.join(aiDataDir, "skills"),
1841
2077
  builtinRawSkills: [],
1842
2078
  contentHash: (content) => createHash("md5").update(content).digest("hex")
1843
2079
  })
@@ -1980,10 +2216,10 @@ async function runServerAgent(options) {
1980
2216
 
1981
2217
  // src/ai/custom-store.ts
1982
2218
  import * as fs9 from "fs";
1983
- import * as path11 from "path";
2219
+ import * as path10 from "path";
1984
2220
  import { randomUUID as randomUUID4 } from "crypto";
1985
2221
  function readProviders(aiDataDir) {
1986
- const storePath = path11.join(aiDataDir, "custom-providers.json");
2222
+ const storePath = path10.join(aiDataDir, "custom-providers.json");
1987
2223
  if (!fs9.existsSync(storePath)) return [];
1988
2224
  try {
1989
2225
  const content = fs9.readFileSync(storePath, "utf-8");
@@ -1993,8 +2229,8 @@ function readProviders(aiDataDir) {
1993
2229
  }
1994
2230
  }
1995
2231
  function writeProviders(aiDataDir, providers) {
1996
- const storePath = path11.join(aiDataDir, "custom-providers.json");
1997
- const dir = path11.dirname(storePath);
2232
+ const storePath = path10.join(aiDataDir, "custom-providers.json");
2233
+ const dir = path10.dirname(storePath);
1998
2234
  if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
1999
2235
  fs9.writeFileSync(storePath, JSON.stringify(providers, null, 2), "utf-8");
2000
2236
  }
@@ -2027,7 +2263,7 @@ function deleteCustomProvider(aiDataDir, id) {
2027
2263
  return { success: true };
2028
2264
  }
2029
2265
  function readModels(aiDataDir) {
2030
- const storePath = path11.join(aiDataDir, "custom-models.json");
2266
+ const storePath = path10.join(aiDataDir, "custom-models.json");
2031
2267
  if (!fs9.existsSync(storePath)) return [];
2032
2268
  try {
2033
2269
  const content = fs9.readFileSync(storePath, "utf-8");
@@ -2037,8 +2273,8 @@ function readModels(aiDataDir) {
2037
2273
  }
2038
2274
  }
2039
2275
  function writeModels(aiDataDir, models) {
2040
- const storePath = path11.join(aiDataDir, "custom-models.json");
2041
- const dir = path11.dirname(storePath);
2276
+ const storePath = path10.join(aiDataDir, "custom-models.json");
2277
+ const dir = path10.dirname(storePath);
2042
2278
  if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
2043
2279
  fs9.writeFileSync(storePath, JSON.stringify(models, null, 2), "utf-8");
2044
2280
  }
@@ -2074,6 +2310,23 @@ function deleteCustomModel(aiDataDir, providerId, modelId) {
2074
2310
  return { success: true };
2075
2311
  }
2076
2312
 
2313
+ // src/http/routes/ai-config-display.ts
2314
+ var NO_KEY_PLACEHOLDER = "sk-no-key-required";
2315
+ function hasRealApiKey(apiKey) {
2316
+ return !!apiKey && apiKey !== NO_KEY_PLACEHOLDER;
2317
+ }
2318
+ function toLlmConfigDisplay(config, resolveApiKey2) {
2319
+ const { apiKey: _rawApiKey, ...rest } = config;
2320
+ const provider = typeof config.provider === "string" ? config.provider : "";
2321
+ const authProfile = typeof config.authProfile === "string" ? config.authProfile : void 0;
2322
+ const resolvedApiKey = provider ? resolveApiKey2(provider, authProfile) : "";
2323
+ return {
2324
+ ...rest,
2325
+ apiKey: "",
2326
+ apiKeySet: hasRealApiKey(resolvedApiKey || "")
2327
+ };
2328
+ }
2329
+
2077
2330
  // src/http/routes/ai.ts
2078
2331
  function getAiDir(dbManager2) {
2079
2332
  const pathProvider = dbManager2["pathProvider"];
@@ -2154,7 +2407,7 @@ function registerAiRoutes(server2, dbManager2, convManager2) {
2154
2407
  return mgr.getBuiltinCatalog();
2155
2408
  });
2156
2409
  server2.get("/_web/ai/llm/has-config", async () => {
2157
- const configPath = path12.join(getAiDir(dbManager2), "llm-config.json");
2410
+ const configPath = path11.join(getAiDir(dbManager2), "llm-config.json");
2158
2411
  if (!fs10.existsSync(configPath)) return false;
2159
2412
  try {
2160
2413
  const data = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
@@ -2165,14 +2418,11 @@ function registerAiRoutes(server2, dbManager2, convManager2) {
2165
2418
  }
2166
2419
  });
2167
2420
  server2.get("/_web/ai/llm/configs", async () => {
2168
- const configPath = path12.join(getAiDir(dbManager2), "llm-config.json");
2421
+ const configPath = path11.join(getAiDir(dbManager2), "llm-config.json");
2169
2422
  if (!fs10.existsSync(configPath)) return { configs: [], defaultAssistant: null, fastModel: null };
2170
2423
  try {
2171
2424
  const data = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
2172
- const configs = (data.configs || []).map((c) => {
2173
- const { apiKey: _k, ...rest } = c;
2174
- return { ...rest, apiKey: "" };
2175
- });
2425
+ const configs = (data.configs || []).map((c) => toLlmConfigDisplay(c, resolveApiKey));
2176
2426
  return {
2177
2427
  configs,
2178
2428
  defaultAssistant: data.defaultAssistant ?? null,
@@ -2194,7 +2444,7 @@ function registerAiRoutes(server2, dbManager2, convManager2) {
2194
2444
  });
2195
2445
  });
2196
2446
  server2.get("/_web/ai/llm/provider-registry", async () => {
2197
- const customPath = path12.join(getAiDir(dbManager2), "custom-providers.json");
2447
+ const customPath = path11.join(getAiDir(dbManager2), "custom-providers.json");
2198
2448
  let custom = [];
2199
2449
  if (fs10.existsSync(customPath)) {
2200
2450
  try {
@@ -2207,7 +2457,7 @@ function registerAiRoutes(server2, dbManager2, convManager2) {
2207
2457
  return [...BUILTIN_PROVIDERS, ...custom];
2208
2458
  });
2209
2459
  server2.get("/_web/ai/llm/model-catalog", async () => {
2210
- const customPath = path12.join(getAiDir(dbManager2), "custom-models.json");
2460
+ const customPath = path11.join(getAiDir(dbManager2), "custom-models.json");
2211
2461
  let custom = [];
2212
2462
  if (fs10.existsSync(customPath)) {
2213
2463
  try {
@@ -2220,7 +2470,7 @@ function registerAiRoutes(server2, dbManager2, convManager2) {
2220
2470
  return [...BUILTIN_MODELS, ...custom];
2221
2471
  });
2222
2472
  server2.get("/_web/ai/llm/default-assistant-slot", async () => {
2223
- const configPath = path12.join(getAiDir(dbManager2), "llm-config.json");
2473
+ const configPath = path11.join(getAiDir(dbManager2), "llm-config.json");
2224
2474
  if (!fs10.existsSync(configPath)) return null;
2225
2475
  try {
2226
2476
  const data = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
@@ -2230,7 +2480,7 @@ function registerAiRoutes(server2, dbManager2, convManager2) {
2230
2480
  }
2231
2481
  });
2232
2482
  server2.get("/_web/ai/llm/fast-model-slot", async () => {
2233
- const configPath = path12.join(getAiDir(dbManager2), "llm-config.json");
2483
+ const configPath = path11.join(getAiDir(dbManager2), "llm-config.json");
2234
2484
  if (!fs10.existsSync(configPath)) return null;
2235
2485
  try {
2236
2486
  const data = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
@@ -2587,7 +2837,7 @@ var NOOP_LOGGER = { info: noop, warn: noop, error: noop };
2587
2837
 
2588
2838
  // ../../packages/sync/src/data-source-manager.ts
2589
2839
  import * as fs11 from "fs";
2590
- import * as path13 from "path";
2840
+ import * as path12 from "path";
2591
2841
  import * as crypto2 from "crypto";
2592
2842
  var CONFIG_FILE = "data-sources.json";
2593
2843
  function generateId(prefix = "ds") {
@@ -2615,7 +2865,7 @@ var DataSourceManager = class {
2615
2865
  this.logger = logger2 ?? NOOP_LOGGER;
2616
2866
  }
2617
2867
  getConfigPath() {
2618
- return path13.join(this.configDir, CONFIG_FILE);
2868
+ return path12.join(this.configDir, CONFIG_FILE);
2619
2869
  }
2620
2870
  ensureDir() {
2621
2871
  fs11.mkdirSync(this.configDir, { recursive: true });
@@ -2904,10 +3154,10 @@ var PullEngine = class {
2904
3154
  limit: ds.pullLimit
2905
3155
  });
2906
3156
  try {
2907
- const stat = fs12.statSync(tempFile);
2908
- this.logger.info(`[Pull] "${sess.name}" page ${pageCount}: fetched ${stat.size} bytes`);
3157
+ const stat2 = fs12.statSync(tempFile);
3158
+ this.logger.info(`[Pull] "${sess.name}" page ${pageCount}: fetched ${stat2.size} bytes`);
2909
3159
  const sync0 = parseSyncFromFile(tempFile);
2910
- if (stat.size < 1024) {
3160
+ if (stat2.size < 1024) {
2911
3161
  if (!fileContainsMessages(tempFile) && sync0?.hasMore === false) {
2912
3162
  cleanupTempFile(tempFile);
2913
3163
  const retryDelays = [2e3, 3e3, 5e3];
@@ -2990,7 +3240,7 @@ var PullEngine = class {
2990
3240
  continue;
2991
3241
  }
2992
3242
  }
2993
- if (stat.size === 0) {
3243
+ if (stat2.size === 0) {
2994
3244
  cleanupTempFile(tempFile);
2995
3245
  break;
2996
3246
  }
@@ -3198,11 +3448,11 @@ function reloadTimer(dsId, skipInitialPull = false) {
3198
3448
  // src/sync/adapters.ts
3199
3449
  import * as fs13 from "fs";
3200
3450
  import * as os4 from "os";
3201
- import * as path14 from "path";
3451
+ import * as path13 from "path";
3202
3452
  import * as crypto4 from "crypto";
3203
3453
  function getTempFilePath(ext) {
3204
3454
  const id = crypto4.randomBytes(8).toString("hex");
3205
- return path14.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
3455
+ return path13.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
3206
3456
  }
3207
3457
  var NodeFetcher = class {
3208
3458
  async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
@@ -3225,7 +3475,7 @@ var NodeFetcher = class {
3225
3475
  };
3226
3476
  function resolveNativeBinding2() {
3227
3477
  if (process.versions.electron) return void 0;
3228
- const nativePath = path14.resolve(__dirname, "../../native/better_sqlite3.node");
3478
+ const nativePath = resolveCliPath("native/better_sqlite3.node");
3229
3479
  if (fs13.existsSync(nativePath)) return nativePath;
3230
3480
  return void 0;
3231
3481
  }
@@ -3456,7 +3706,7 @@ var dbManager = null;
3456
3706
  var convManager = null;
3457
3707
  function resolveNativeBinding3() {
3458
3708
  if (process.versions.electron) return void 0;
3459
- const nativePath = path15.resolve(__dirname, "../../native/better_sqlite3.node");
3709
+ const nativePath = resolveCliPath("native/better_sqlite3.node");
3460
3710
  if (fs14.existsSync(nativePath)) return nativePath;
3461
3711
  return void 0;
3462
3712
  }
@@ -3481,7 +3731,7 @@ async function startHttpServer(options) {
3481
3731
  const pathProvider = new NodePathProvider(userDataDir);
3482
3732
  pathProvider.ensureAllDirs();
3483
3733
  if (hasPendingElectronDataWarning() || !verifyCliDataPath(pathProvider.getDatabaseDir())) {
3484
- throw new Error(
3734
+ console.error(
3485
3735
  "\n" + "=".repeat(68) + "\n ChatLab: Electron desktop data not found\n" + "=".repeat(68) + '\n\n Detected that ChatLab desktop app was installed on this machine,\n but could not locate your chat databases.\n\n This usually means you changed the data directory in desktop settings.\n\n To fix this, choose one of:\n\n 1. Open ChatLab desktop app \u2014 it will auto-migrate your data\n 2. Set the data directory manually:\n export CHATLAB_DATA_DIR="/path/to/your/data"\n 3. Edit ~/.chatlab/config.toml:\n [data]\n user_data_dir = "/path/to/your/data"\n\n' + "=".repeat(68) + "\n"
3486
3736
  );
3487
3737
  }
@@ -3558,4 +3808,4 @@ export {
3558
3808
  startHttpServer,
3559
3809
  stopHttpServer
3560
3810
  };
3561
- //# sourceMappingURL=chunk-LI4X52E7.mjs.map
3811
+ //# sourceMappingURL=chunk-XPBPKH6B.mjs.map